From b4fe22b23411aea796f28125d78e1ab7d1cd1675 Mon Sep 17 00:00:00 2001 From: Joris Wouter Jonkers Date: Thu, 5 Nov 2026 13:02:24 +0100 Subject: [PATCH] chore: retire the model-driven implementation at its sunset The coursework is complete and its graded snapshot is tagged mde-task-3; the frozen implementation, its split history and the oracles it was held to now live in JorisJonkers-dev/mde-project. This deletes the emf tree and every root line that named it: the emf CI job and ADR lint step, the CodeQL java-kotlin entry, the release-please and Renovate entries, the lint scopes and their fixtures, and the ledger rows for the gates it carried. Closes #99 0068 leaves with the tree, per #362: the one clause that outlives it, that an oracle file is reviewed by hand and never written by CI, moves into 0088, and the parity contract section of docs/architecture.md becomes The oracles, held by the one implementation left. Citations of the retired records are repointed by hand, among them the comments in src/read/env.ts and src/check/project.ts. The docs/mde reports stay, their six links into emf/ repointed into the archive; the course's own text goes later, on #354. --- .agents/skills/adr/SKILL.md | 14 +- .agents/skills/spec-change/SKILL.md | 9 +- .github/CODEOWNERS | 3 - .github/codeql/codeql-config.yml | 4 +- .github/workflows/ci.yml | 78 - .github/workflows/codeql.yml | 8 +- .prettierignore | 8 +- AGENTS.md | 66 +- CONTEXT.md | 11 +- CONTRIBUTING.md | 3 +- README.md | 1 - docs/adr/README.md | 5 - ...the-compiler-is-a-chain-of-typed-models.md | 2 - .../0062-tests-run-in-process-on-vitest.md | 4 +- ...0063-coverage-and-mutation-are-ratchets.md | 2 +- ...ery-spec-error-code-is-proved-by-a-test.md | 4 +- ...mplementations-meet-at-the-parity-table.md | 97 - ...hemas-and-their-corpus-are-the-contract.md | 7 +- docs/adr/architecture/README.md | 8 +- ...2-shared-intent-descends-and-is-lowered.md | 2 - ...ed-role-names-the-project-that-holds-it.md | 2 +- docs/agents/domain.md | 2 - docs/architecture-rules/gates.md | 5 +- docs/architecture.md | 162 +- docs/mde/README.md | 8 +- docs/mde/assignment.md | 2 +- docs/mde/practicals.md | 2 +- docs/requirements.md | 2 +- docs/requirements/repository.md | 7 +- emf/.gitignore | 4 - emf/.java-version | 1 - emf/.mvn/maven.config | 2 - emf/.mvn/wrapper/maven-wrapper.properties | 4 - emf/README.md | 135 - emf/bundles/cli/META-INF/MANIFEST.MF | 17 - emf/bundles/cli/build.properties | 11 - emf/bundles/cli/pom.xml | 56 - .../deploykit/emf/cli/Authored.java | 30 - .../deploykit/emf/cli/Collisions.java | 112 - .../deploykit/emf/cli/Constraints.java | 102 - .../deploykit/emf/cli/DataFile.java | 498 -- .../deploykit/emf/cli/Diagnostic.java | 12 - .../deploykit/emf/cli/EnvFiles.java | 187 - .../deploykit/emf/cli/IntentJson.java | 134 - .../deploykit/emf/cli/L4Checks.java | 181 - .../deploykit/emf/cli/NodeAgentChecks.java | 61 - .../deploykit/emf/cli/OperatedChecks.java | 99 - .../deploykit/emf/cli/Outputs.java | 465 -- .../deploykit/emf/cli/Parsed.java | 28 - .../deploykit/emf/cli/Pipeline.java | 793 ---- .../deploykit/emf/cli/Placement.java | 65 - .../deploykit/emf/cli/Pointer.java | 41 - .../deploykit/emf/cli/Resolved.java | 32 - .../deploykit/emf/cli/ShippedFiles.java | 264 -- .../deploykit/emf/cli/AtlLowering.java | 135 - .../deploykit/emf/cli/Benchmark.java | 191 - .../deploykit/emf/cli/BenchmarkInputs.java | 132 - .../deploykit/emf/cli/ColdRun.java | 152 - .../deploykit/emf/cli/CollisionsTest.java | 139 - .../deploykit/emf/cli/Comparison.java | 397 -- .../deploykit/emf/cli/ComparisonTest.java | 244 - .../deploykit/emf/cli/ConstraintsTest.java | 132 - .../deploykit/emf/cli/DataFileTest.java | 159 - .../deploykit/emf/cli/DiagnosticTest.java | 32 - .../deploykit/emf/cli/EnvFilesTest.java | 136 - .../deploykit/emf/cli/Examples.java | 42 - .../deploykit/emf/cli/FieldCoverage.java | 432 -- .../deploykit/emf/cli/FieldCoverageTest.java | 142 - .../deploykit/emf/cli/IntentJsonTest.java | 147 - .../deploykit/emf/cli/IntentSetTest.java | 412 -- .../deploykit/emf/cli/L4ChecksTest.java | 219 - .../emf/cli/LoweringBenchmarkTest.java | 255 - .../emf/cli/LoweringEquivalenceTest.java | 84 - .../deploykit/emf/cli/ModelDiff.java | 566 --- .../deploykit/emf/cli/ModelDiffTest.java | 520 -- .../deploykit/emf/cli/ModelWitnessesTest.java | 1605 ------- .../emf/cli/NodeAgentChecksTest.java | 124 - .../deploykit/emf/cli/OperatedChecksTest.java | 116 - .../deploykit/emf/cli/OracleDistanceTest.java | 516 -- .../deploykit/emf/cli/OutputsTest.java | 426 -- .../deploykit/emf/cli/PinnedInputsTest.java | 103 - .../emf/cli/PipelineBenchmarkTest.java | 284 -- .../emf/cli/PipelineRefusalsTest.java | 231 - .../deploykit/emf/cli/PipelineTest.java | 270 -- .../deploykit/emf/cli/PlatformIntentTest.java | 63 - .../deploykit/emf/cli/PointerTest.java | 61 - .../deploykit/emf/cli/QvtoLowering.java | 48 - .../deploykit/emf/cli/QvtoResolution.java | 61 - .../deploykit/emf/cli/RenderedTreeTest.java | 194 - .../deploykit/emf/cli/ResolutionTest.java | 268 -- .../deploykit/emf/cli/ShippedFilesTest.java | 215 - .../deploykit/emf/cli/StageTest.java | 125 - .../deploykit/emf/cli/Stages.java | 380 -- .../deploykit/emf/cli/WorkedExamplesTest.java | 85 - .../src/test/resources/benchmark/lower.atl | 625 --- .../estate/expected/agents.effective.json | 1 - .../lower/estate/expected/auth.effective.json | 1 - .../estate/expected/coverage.effective.json | 1 - .../lower/estate/expected/data.effective.json | 1 - .../estate/expected/delivery.effective.json | 1 - .../lower/estate/expected/edge.effective.json | 1 - .../lower/estate/expected/effective.xmi | 1840 ------- .../estate/expected/identity.effective.json | 1 - .../knowledge-platform.effective.json | 1 - .../estate/expected/knowledge.effective.json | 1 - .../lower/estate/expected/mail.effective.json | 1 - .../estate/expected/notes.effective.json | 1 - .../expected/observability.effective.json | 1 - .../estate/expected/secrets.effective.json | 1 - .../estate/expected/utility.effective.json | 1 - .../src/test/resources/stages/lower/gaps.txt | 26 - .../expected/agents/agents.project.json | 1 - .../estate/expected/auth/auth.project.json | 1 - .../expected/breadth/coverage.project.json | 1 - .../estate/expected/data/data.project.json | 1 - .../expected/delivery/delivery.project.json | 1 - .../estate/expected/edge/edge.project.json | 1 - .../expected/identity/identity.project.json | 1 - .../stages/parse/estate/expected/intent.xmi | 1898 -------- .../knowledge-platform.project.json | 1 - .../expected/knowledge/knowledge.project.json | 1 - .../estate/expected/mail/mail.project.json | 1 - .../expected/minimal/notes.project.json | 1 - .../observability/observability.project.json | 1 - .../stages/parse/estate/expected/pinned.xmi | 248 - .../expected/platform/platform.intent.json | 1 - .../expected/secrets/secrets.project.json | 1 - .../expected/utility/utility.project.json | 1 - .../estate/input/agents/agents.project.yml | 230 - .../input/agents/config/hermes/config.yaml | 15 - .../estate/input/agents/env/hermes/base.env | 27 - .../parse/estate/input/auth/auth.project.yml | 439 -- .../estate/input/auth/env/auth-api/base.env | 83 - .../estate/input/auth/migration-proof.yml | 18 - .../estate/input/breadth/config/coverage.conf | 1 - .../estate/input/breadth/config/seed.conf | 1 - .../estate/input/breadth/coverage.project.yml | 123 - .../env/_applications/coverage-api/base.env | 1 - .../input/breadth/env/_project/base.env | 1 - .../input/breadth/env/coverage-api/base.env | 1 - .../estate/input/data/config/garage.toml | 20 - .../estate/input/data/config/postgresql.conf | 39 - .../input/data/dashboards/rabbitmq.json | 29 - .../parse/estate/input/data/data.project.yml | 590 --- .../estate/input/data/env/garage/base.env | 7 - .../estate/input/data/env/postgres/base.env | 24 - .../input/delivery/delivery.project.yml | 195 - .../parse/estate/input/edge/edge.project.yml | 91 - .../input/identity/identity.project.yml | 120 - .../env/basic-memory/base.env | 26 - .../env/docling-serve/base.env | 3 - .../env/hindsight-api/base.env | 18 - .../env/hindsight-control-plane/base.env | 5 - .../env/hindsight-tei-embedding/base.env | 3 - .../env/hindsight-worker/base.env | 16 - .../knowledge-platform/env/karakeep/base.env | 25 - .../knowledge-platform.project.yml | 323 -- .../input/knowledge/env/_project/base.env | 31 - .../knowledge/env/knowledge-api/base.env | 36 - .../env/knowledge-ingest-worker/base.env | 16 - .../input/knowledge/knowledge.project.yml | 352 -- .../estate/input/mail/config/manifest.json | 4 - .../parse/estate/input/mail/mail.project.yml | 85 - .../input/minimal/env/notes-api/base.env | 14 - .../estate/input/minimal/notes.project.yml | 81 - .../input/observability/env/grafana/base.env | 16 - .../observability/observability.project.yml | 351 -- .../input/observability/rules/platform.yaml | 32 - .../estate/input/platform/cluster-state.yml | 18 - .../estate/input/platform/images.lock.yml | 429 -- .../estate/input/platform/node-contract.yml | 135 - .../estate/input/platform/platform.intent.yml | 424 -- .../estate/input/secrets/secrets.project.yml | 71 - .../utility/config/adguard/AdGuardHome.yaml | 14 - .../estate/input/utility/utility.project.yml | 92 - .../src/test/resources/stages/parse/gaps.txt | 118 - .../apps/agents/agents-api/kustomization.yaml | 9 - .../apps/agents/agents-api/networkpolicy.yaml | 117 - .../expected/apps/agents/agents-api/rbac.yaml | 58 - .../apps/agents/agents-api/service.yaml | 20 - .../agents/agents-api/serviceaccount.yaml | 13 - .../apps/agents/agents-api/workload.yaml | 110 - .../apps/agents/agents-ui/configmap.yaml | 14 - .../apps/agents/agents-ui/kustomization.yaml | 10 - .../apps/agents/agents-ui/networkpolicy.yaml | 51 - .../apps/agents/agents-ui/route-public.yaml | 30 - .../apps/agents/agents-ui/service.yaml | 20 - .../apps/agents/agents-ui/serviceaccount.yaml | 13 - .../apps/agents/agents-ui/workload.yaml | 104 - .../expected/apps/agents/hermes/backup.yaml | 65 - .../expected/apps/agents/hermes/client.yaml | 20 - .../apps/agents/hermes/configmap.yaml | 44 - .../apps/agents/hermes/kustomization.yaml | 15 - .../apps/agents/hermes/networkpolicy.yaml | 122 - .../expected/apps/agents/hermes/pvc.yaml | 41 - .../apps/agents/hermes/route-lan.yaml | 26 - .../apps/agents/hermes/route-public.yaml | 30 - .../expected/apps/agents/hermes/service.yaml | 20 - .../apps/agents/hermes/serviceaccount.yaml | 25 - .../expected/apps/agents/hermes/vso.yaml | 47 - .../expected/apps/agents/hermes/workload.yaml | 229 - .../agents/kubernetes-mcp-server/canary.yaml | 69 - .../kubernetes-mcp-server/configmap.yaml | 13 - .../kubernetes-mcp-server/kustomization.yaml | 10 - .../kubernetes-mcp-server/networkpolicy.yaml | 57 - .../agents/kubernetes-mcp-server/rbac.yaml | 110 - .../kubernetes-mcp-server/serviceaccount.yaml | 13 - .../kubernetes-mcp-server/workload.yaml | 104 - .../expected/apps/agents/kustomization.yaml | 13 - .../expected/apps/agents/namespace.yaml | 10 - .../expected/apps/agents/networkpolicy.yaml | 15 - .../apps/agents/rollout-events/alert.yaml | 18 - .../agents/rollout-events/kustomization.yaml | 7 - .../apps/agents/rollout-events/provider.yaml | 12 - .../apps/agents/vault-policy/configmap.yaml | 19 - .../apps/agents/vault-policy/cronjob.yaml | 95 - .../apps/agents/vault-policy/job.yaml | 85 - .../agents/vault-policy/kustomization.yaml | 9 - .../agents/vault-policy/networkpolicy.yaml | 40 - .../policies/agents-system-hermes.policy.json | 14 - .../policies/agents-system-hermes.role.json | 11 - .../agents/vault-policy/serviceaccount.yaml | 13 - .../expected/apps/agents/vaultconnection.yaml | 12 - .../resources/stages/render/agents/oracles | 47 - .../auth/expected/apps/auth/aliases.yaml | 45 - .../auth/expected/apps/auth/auth/canary.yaml | 176 - .../expected/apps/auth/auth/configmap.yaml | 26 - .../apps/auth/auth/kustomization.yaml | 13 - .../expected/apps/auth/auth/migration.yaml | 171 - .../apps/auth/auth/networkpolicy.yaml | 232 - .../auth/expected/apps/auth/auth/pdb.yaml | 18 - .../expected/apps/auth/auth/podmonitor.yaml | 27 - .../expected/apps/auth/auth/route-public.yaml | 68 - .../apps/auth/auth/serviceaccount.yaml | 25 - .../expected/apps/auth/auth/workload.yaml | 265 -- .../expected/apps/auth/kustomization.yaml | 11 - .../auth/expected/apps/auth/namespace.yaml | 10 - .../expected/apps/auth/networkpolicy.yaml | 15 - .../apps/auth/rollout-events/alert.yaml | 18 - .../auth/rollout-events/kustomization.yaml | 7 - .../apps/auth/rollout-events/provider.yaml | 12 - .../apps/auth/vault-policy/configmap.yaml | 23 - .../apps/auth/vault-policy/cronjob.yaml | 99 - .../expected/apps/auth/vault-policy/job.yaml | 89 - .../apps/auth/vault-policy/kustomization.yaml | 9 - .../apps/auth/vault-policy/networkpolicy.yaml | 40 - .../policies/auth-system-auth-api.policy.json | 44 - .../policies/auth-system-auth-api.role.json | 11 - .../auth-system-auth-migration.policy.json | 9 - .../auth-system-auth-migration.role.json | 11 - .../auth/vault-policy/serviceaccount.yaml | 13 - .../expected/apps/auth/vaultconnection.yaml | 12 - .../human-grants/clusterrolebindings.yaml | 16 - .../estate/human-grants/kustomization.yaml | 6 - .../priority-classes/kustomization.yaml | 6 - .../priority-classes/priorityclasses.yaml | 23 - .../stable-addresses/kustomization.yaml | 7 - .../estate/stable-addresses/namespace.yaml | 10 - .../estate/stable-addresses/services.yaml | 45 - .../test/resources/stages/render/auth/oracles | 35 - .../expected/apps/data/kustomization.yaml | 15 - .../expected/apps/data/namespace.yaml | 10 - .../expected/apps/data/networkpolicy.yaml | 15 - .../apps/data/platform-postgres/backup.yaml | 80 - .../data/platform-postgres/configmap.yaml | 55 - .../data/platform-postgres/kustomization.yaml | 13 - .../data/platform-postgres/networkpolicy.yaml | 128 - .../apps/data/platform-postgres/pvc.yaml | 41 - .../apps/data/platform-postgres/service.yaml | 23 - .../platform-postgres/serviceaccount.yaml | 25 - .../platform-postgres/servicemonitor.yaml | 27 - .../apps/data/platform-postgres/vso.yaml | 114 - .../apps/data/platform-postgres/workload.yaml | 166 - .../apps/data/platform-rabbitmq/backup.yaml | 72 - .../data/platform-rabbitmq/kustomization.yaml | 16 - .../data/platform-rabbitmq/networkpolicy.yaml | 156 - .../apps/data/platform-rabbitmq/pvc.yaml | 41 - .../platform-rabbitmq/route-management.yaml | 32 - .../apps/data/platform-rabbitmq/service.yaml | 53 - .../platform-rabbitmq/serviceaccount.yaml | 25 - .../platform-rabbitmq/servicemonitor.yaml | 27 - .../apps/data/platform-rabbitmq/vso.yaml | 44 - .../apps/data/platform-rabbitmq/workload.yaml | 108 - .../data/platform-valkey/kustomization.yaml | 9 - .../data/platform-valkey/networkpolicy.yaml | 41 - .../apps/data/platform-valkey/pvc.yaml | 19 - .../apps/data/platform-valkey/service.yaml | 20 - .../data/platform-valkey/serviceaccount.yaml | 13 - .../apps/data/platform-valkey/workload.yaml | 102 - .../apps/data/rollout-events/alert.yaml | 18 - .../data/rollout-events/kustomization.yaml | 7 - .../apps/data/rollout-events/provider.yaml | 12 - .../apps/data/vault-policy/configmap.yaml | 39 - .../apps/data/vault-policy/cronjob.yaml | 115 - .../expected/apps/data/vault-policy/job.yaml | 105 - .../apps/data/vault-policy/kustomization.yaml | 9 - .../apps/data/vault-policy/networkpolicy.yaml | 40 - .../data-system-postgres-backup.policy.json | 24 - .../data-system-postgres-backup.role.json | 11 - .../policies/data-system-postgres.policy.json | 14 - .../policies/data-system-postgres.role.json | 11 - .../data-system-rabbitmq-backup.policy.json | 14 - .../data-system-rabbitmq-backup.role.json | 11 - .../data/vault-policy/serviceaccount.yaml | 13 - .../expected/apps/data/vaultconnection.yaml | 12 - .../resources/stages/render/data-full/oracles | 45 - .../apps/data/asset-sync/kustomization.yaml | 8 - .../apps/data/asset-sync/networkpolicy.yaml | 52 - .../apps/data/asset-sync/serviceaccount.yaml | 13 - .../expected/apps/data/asset-sync/vso.yaml | 44 - .../apps/data/asset-sync/workload.yaml | 75 - .../expected/apps/data/kustomization.yaml | 15 - .../expected/apps/data/namespace.yaml | 10 - .../expected/apps/data/networkpolicy.yaml | 15 - .../apps/data/platform-garage/backup.yaml | 129 - .../apps/data/platform-garage/configmap.yaml | 36 - .../data/platform-garage/kustomization.yaml | 12 - .../data/platform-garage/networkpolicy.yaml | 92 - .../apps/data/platform-garage/pvc.yaml | 99 - .../apps/data/platform-garage/service.yaml | 23 - .../data/platform-garage/serviceaccount.yaml | 25 - .../apps/data/platform-garage/vso.yaml | 47 - .../apps/data/platform-garage/workload.yaml | 131 - .../apps/data/platform-mongo/backup.yaml | 80 - .../data/platform-mongo/kustomization.yaml | 11 - .../data/platform-mongo/networkpolicy.yaml | 96 - .../apps/data/platform-mongo/pvc.yaml | 41 - .../apps/data/platform-mongo/service.yaml | 20 - .../data/platform-mongo/serviceaccount.yaml | 25 - .../apps/data/platform-mongo/vso.yaml | 68 - .../apps/data/platform-mongo/workload.yaml | 120 - .../apps/data/platform-postgres/backup.yaml | 80 - .../data/platform-postgres/configmap.yaml | 55 - .../data/platform-postgres/kustomization.yaml | 13 - .../data/platform-postgres/networkpolicy.yaml | 128 - .../apps/data/platform-postgres/pvc.yaml | 41 - .../apps/data/platform-postgres/service.yaml | 23 - .../platform-postgres/serviceaccount.yaml | 25 - .../platform-postgres/servicemonitor.yaml | 27 - .../apps/data/platform-postgres/vso.yaml | 114 - .../apps/data/platform-postgres/workload.yaml | 166 - .../apps/data/platform-rabbitmq/backup.yaml | 72 - .../data/platform-rabbitmq/configmap.yaml | 14 - .../data/platform-rabbitmq/dashboards.yaml | 49 - .../data/platform-rabbitmq/kustomization.yaml | 16 - .../data/platform-rabbitmq/networkpolicy.yaml | 156 - .../apps/data/platform-rabbitmq/pvc.yaml | 41 - .../data/platform-rabbitmq/route-lan.yaml | 26 - .../platform-rabbitmq/route-management.yaml | 32 - .../apps/data/platform-rabbitmq/service.yaml | 53 - .../platform-rabbitmq/serviceaccount.yaml | 25 - .../platform-rabbitmq/servicemonitor.yaml | 27 - .../apps/data/platform-rabbitmq/vso.yaml | 44 - .../apps/data/platform-rabbitmq/workload.yaml | 108 - .../data/platform-valkey/kustomization.yaml | 9 - .../data/platform-valkey/networkpolicy.yaml | 41 - .../apps/data/platform-valkey/pvc.yaml | 19 - .../apps/data/platform-valkey/service.yaml | 20 - .../data/platform-valkey/serviceaccount.yaml | 13 - .../apps/data/platform-valkey/workload.yaml | 102 - .../apps/data/rollout-events/alert.yaml | 18 - .../data/rollout-events/kustomization.yaml | 7 - .../apps/data/rollout-events/provider.yaml | 12 - .../apps/data/vault-policy/configmap.yaml | 39 - .../apps/data/vault-policy/cronjob.yaml | 115 - .../expected/apps/data/vault-policy/job.yaml | 105 - .../apps/data/vault-policy/kustomization.yaml | 9 - .../apps/data/vault-policy/networkpolicy.yaml | 40 - .../data-system-asset-sync.policy.json | 14 - .../policies/data-system-asset-sync.role.json | 11 - .../policies/data-system-garage.policy.json | 14 - .../policies/data-system-garage.role.json | 11 - .../data-system-mongo-backup.policy.json | 24 - .../data-system-mongo-backup.role.json | 11 - .../data-system-postgres-backup.policy.json | 24 - .../data-system-postgres-backup.role.json | 11 - .../policies/data-system-postgres.policy.json | 14 - .../policies/data-system-postgres.role.json | 11 - .../data-system-rabbitmq-backup.policy.json | 14 - .../data-system-rabbitmq-backup.role.json | 11 - .../data/vault-policy/serviceaccount.yaml | 13 - .../expected/apps/data/vaultconnection.yaml | 12 - .../resources/stages/render/data-main/oracles | 76 - .../delivery/collector/kustomization.yaml | 9 - .../delivery/collector/networkpolicy.yaml | 47 - .../apps/delivery/collector/rbac.yaml | 41 - .../apps/delivery/collector/service.yaml | 20 - .../delivery/collector/serviceaccount.yaml | 13 - .../apps/delivery/collector/workload.yaml | 98 - .../apps/delivery/flagger/kustomization.yaml | 9 - .../apps/delivery/flagger/networkpolicy.yaml | 57 - .../expected/apps/delivery/flagger/rbac.yaml | 94 - .../apps/delivery/flagger/service.yaml | 20 - .../apps/delivery/flagger/serviceaccount.yaml | 13 - .../apps/delivery/flagger/workload.yaml | 112 - .../expected/apps/delivery/kustomization.yaml | 11 - .../expected/apps/delivery/namespace.yaml | 10 - .../expected/apps/delivery/networkpolicy.yaml | 15 - .../delivery/release-gate/kustomization.yaml | 10 - .../delivery/release-gate/networkpolicy.yaml | 64 - .../apps/delivery/release-gate/rbac.yaml | 113 - .../apps/delivery/release-gate/service.yaml | 20 - .../delivery/release-gate/serviceaccount.yaml | 13 - .../delivery/release-gate/servicemonitor.yaml | 27 - .../apps/delivery/release-gate/workload.yaml | 101 - .../apps/delivery/reporter/kustomization.yaml | 9 - .../apps/delivery/reporter/networkpolicy.yaml | 57 - .../expected/apps/delivery/reporter/rbac.yaml | 48 - .../apps/delivery/reporter/service.yaml | 20 - .../delivery/reporter/serviceaccount.yaml | 13 - .../apps/delivery/reporter/workload.yaml | 98 - .../apps/delivery/rollout-events/alert.yaml | 18 - .../rollout-events/kustomization.yaml | 7 - .../delivery/rollout-events/provider.yaml | 12 - .../resources/stages/render/delivery/oracles | 31 - .../apps/edge/external-dns/kustomization.yaml | 9 - .../apps/edge/external-dns/networkpolicy.yaml | 57 - .../expected/apps/edge/external-dns/rbac.yaml | 51 - .../apps/edge/external-dns/service.yaml | 20 - .../edge/external-dns/serviceaccount.yaml | 13 - .../apps/edge/external-dns/workload.yaml | 98 - .../expected/apps/edge/kustomization.yaml | 12 - .../edge/expected/apps/edge/namespace.yaml | 10 - .../expected/apps/edge/networkpolicy.yaml | 15 - .../apps/edge/rollout-events/alert.yaml | 18 - .../edge/rollout-events/kustomization.yaml | 7 - .../apps/edge/rollout-events/provider.yaml | 12 - .../apps/edge/traefik-lan/kustomization.yaml | 10 - .../apps/edge/traefik-lan/middlewares.yaml | 85 - .../apps/edge/traefik-lan/networkpolicy.yaml | 63 - .../expected/apps/edge/traefik-lan/rbac.yaml | 75 - .../apps/edge/traefik-lan/service.yaml | 47 - .../apps/edge/traefik-lan/serviceaccount.yaml | 13 - .../apps/edge/traefik-lan/workload.yaml | 123 - .../edge/traefik-public/kustomization.yaml | 11 - .../edge/traefik-public/networkpolicy.yaml | 101 - .../apps/edge/traefik-public/pvc.yaml | 19 - .../apps/edge/traefik-public/rbac.yaml | 75 - .../apps/edge/traefik-public/service.yaml | 26 - .../edge/traefik-public/serviceaccount.yaml | 13 - .../apps/edge/traefik-public/vso.yaml | 47 - .../apps/edge/traefik-public/workload.yaml | 142 - .../apps/edge/vault-policy/configmap.yaml | 19 - .../apps/edge/vault-policy/cronjob.yaml | 95 - .../expected/apps/edge/vault-policy/job.yaml | 85 - .../apps/edge/vault-policy/kustomization.yaml | 9 - .../apps/edge/vault-policy/networkpolicy.yaml | 40 - .../edge-system-traefik-public.policy.json | 14 - .../edge-system-traefik-public.role.json | 11 - .../edge/vault-policy/serviceaccount.yaml | 13 - .../expected/apps/edge/vaultconnection.yaml | 12 - .../human-grants/clusterrolebindings.yaml | 16 - .../estate/human-grants/kustomization.yaml | 6 - .../priority-classes/kustomization.yaml | 6 - .../priority-classes/priorityclasses.yaml | 23 - .../test/resources/stages/render/edge/oracles | 40 - .../estate/expected/apps/auth/aliases.yaml | 45 - .../expected/apps/auth/auth/canary.yaml | 176 - .../expected/apps/auth/auth/configmap.yaml | 26 - .../apps/auth/auth/kustomization.yaml | 13 - .../expected/apps/auth/auth/migration.yaml | 171 - .../apps/auth/auth/networkpolicy.yaml | 232 - .../estate/expected/apps/auth/auth/pdb.yaml | 18 - .../expected/apps/auth/auth/podmonitor.yaml | 27 - .../expected/apps/auth/auth/route-public.yaml | 68 - .../apps/auth/auth/serviceaccount.yaml | 25 - .../expected/apps/auth/auth/workload.yaml | 265 -- .../expected/apps/auth/kustomization.yaml | 11 - .../estate/expected/apps/auth/namespace.yaml | 10 - .../expected/apps/auth/networkpolicy.yaml | 15 - .../apps/auth/rollout-events/alert.yaml | 18 - .../auth/rollout-events/kustomization.yaml | 7 - .../apps/auth/rollout-events/provider.yaml | 12 - .../apps/auth/vault-policy/configmap.yaml | 23 - .../apps/auth/vault-policy/cronjob.yaml | 99 - .../expected/apps/auth/vault-policy/job.yaml | 89 - .../apps/auth/vault-policy/kustomization.yaml | 9 - .../apps/auth/vault-policy/networkpolicy.yaml | 40 - .../policies/auth-system-auth-api.policy.json | 44 - .../policies/auth-system-auth-api.role.json | 11 - .../auth-system-auth-migration.policy.json | 9 - .../auth-system-auth-migration.role.json | 11 - .../auth/vault-policy/serviceaccount.yaml | 13 - .../expected/apps/auth/vaultconnection.yaml | 12 - .../apps/data/asset-sync/kustomization.yaml | 8 - .../apps/data/asset-sync/networkpolicy.yaml | 52 - .../apps/data/asset-sync/serviceaccount.yaml | 13 - .../expected/apps/data/asset-sync/vso.yaml | 44 - .../apps/data/asset-sync/workload.yaml | 75 - .../expected/apps/data/kustomization.yaml | 15 - .../estate/expected/apps/data/namespace.yaml | 10 - .../expected/apps/data/networkpolicy.yaml | 15 - .../apps/data/platform-garage/backup.yaml | 129 - .../apps/data/platform-garage/configmap.yaml | 36 - .../garage-catalog-networkpolicy.yaml | 50 - .../data/platform-garage/garage-catalog.yaml | 205 - .../data/platform-garage/kustomization.yaml | 13 - .../data/platform-garage/networkpolicy.yaml | 92 - .../apps/data/platform-garage/pvc.yaml | 99 - .../apps/data/platform-garage/service.yaml | 23 - .../data/platform-garage/serviceaccount.yaml | 25 - .../apps/data/platform-garage/vso.yaml | 47 - .../apps/data/platform-garage/workload.yaml | 131 - .../apps/data/platform-mongo/backup.yaml | 80 - .../data/platform-mongo/kustomization.yaml | 11 - .../data/platform-mongo/networkpolicy.yaml | 96 - .../apps/data/platform-mongo/pvc.yaml | 41 - .../apps/data/platform-mongo/service.yaml | 20 - .../data/platform-mongo/serviceaccount.yaml | 25 - .../apps/data/platform-mongo/vso.yaml | 68 - .../apps/data/platform-mongo/workload.yaml | 120 - .../apps/data/platform-postgres/backup.yaml | 80 - .../data/platform-postgres/configmap.yaml | 55 - .../data/platform-postgres/kustomization.yaml | 14 - .../data/platform-postgres/networkpolicy.yaml | 128 - .../postgres-catalog-networkpolicy.yaml | 50 - .../platform-postgres/postgres-catalog.yaml | 205 - .../apps/data/platform-postgres/pvc.yaml | 41 - .../apps/data/platform-postgres/service.yaml | 23 - .../platform-postgres/serviceaccount.yaml | 25 - .../platform-postgres/servicemonitor.yaml | 27 - .../apps/data/platform-postgres/vso.yaml | 141 - .../apps/data/platform-postgres/workload.yaml | 179 - .../apps/data/platform-rabbitmq/backup.yaml | 72 - .../data/platform-rabbitmq/configmap.yaml | 14 - .../data/platform-rabbitmq/dashboards.yaml | 49 - .../data/platform-rabbitmq/kustomization.yaml | 16 - .../data/platform-rabbitmq/networkpolicy.yaml | 156 - .../apps/data/platform-rabbitmq/pvc.yaml | 41 - .../data/platform-rabbitmq/route-lan.yaml | 27 - .../platform-rabbitmq/route-management.yaml | 32 - .../apps/data/platform-rabbitmq/service.yaml | 53 - .../platform-rabbitmq/serviceaccount.yaml | 25 - .../platform-rabbitmq/servicemonitor.yaml | 28 - .../apps/data/platform-rabbitmq/vso.yaml | 44 - .../apps/data/platform-rabbitmq/workload.yaml | 108 - .../data/platform-valkey/kustomization.yaml | 9 - .../data/platform-valkey/networkpolicy.yaml | 41 - .../apps/data/platform-valkey/pvc.yaml | 19 - .../apps/data/platform-valkey/service.yaml | 20 - .../data/platform-valkey/serviceaccount.yaml | 13 - .../apps/data/platform-valkey/workload.yaml | 102 - .../apps/data/rollout-events/alert.yaml | 18 - .../data/rollout-events/kustomization.yaml | 7 - .../apps/data/rollout-events/provider.yaml | 12 - .../apps/data/vault-policy/configmap.yaml | 49 - .../apps/data/vault-policy/cronjob.yaml | 125 - .../expected/apps/data/vault-policy/job.yaml | 115 - .../apps/data/vault-policy/kustomization.yaml | 9 - .../apps/data/vault-policy/networkpolicy.yaml | 40 - .../data-system-asset-sync.policy.json | 14 - .../policies/data-system-asset-sync.role.json | 11 - .../data-system-garage-catalog.policy.json | 21 - .../data-system-garage-catalog.role.json | 11 - .../policies/data-system-garage.policy.json | 14 - .../policies/data-system-garage.role.json | 11 - .../data-system-mongo-backup.policy.json | 24 - .../data-system-mongo-backup.role.json | 11 - .../data-system-postgres-backup.policy.json | 24 - .../data-system-postgres-backup.role.json | 11 - .../data-system-postgres-catalog.policy.json | 56 - .../data-system-postgres-catalog.role.json | 11 - .../policies/data-system-postgres.policy.json | 24 - .../policies/data-system-postgres.role.json | 11 - .../data-system-rabbitmq-backup.policy.json | 14 - .../data-system-rabbitmq-backup.role.json | 11 - .../policies/data-system.generated.json | 14 - .../data/vault-policy/serviceaccount.yaml | 13 - .../expected/apps/data/vaultconnection.yaml | 12 - .../delivery/collector/kustomization.yaml | 9 - .../delivery/collector/networkpolicy.yaml | 47 - .../apps/delivery/collector/rbac.yaml | 41 - .../apps/delivery/collector/service.yaml | 20 - .../delivery/collector/serviceaccount.yaml | 13 - .../apps/delivery/collector/workload.yaml | 98 - .../apps/delivery/flagger/kustomization.yaml | 9 - .../apps/delivery/flagger/networkpolicy.yaml | 57 - .../expected/apps/delivery/flagger/rbac.yaml | 94 - .../apps/delivery/flagger/service.yaml | 20 - .../apps/delivery/flagger/serviceaccount.yaml | 13 - .../apps/delivery/flagger/workload.yaml | 112 - .../expected/apps/delivery/kustomization.yaml | 11 - .../expected/apps/delivery/namespace.yaml | 10 - .../expected/apps/delivery/networkpolicy.yaml | 15 - .../delivery/release-gate/kustomization.yaml | 10 - .../delivery/release-gate/networkpolicy.yaml | 64 - .../apps/delivery/release-gate/rbac.yaml | 113 - .../apps/delivery/release-gate/service.yaml | 20 - .../delivery/release-gate/serviceaccount.yaml | 13 - .../delivery/release-gate/servicemonitor.yaml | 27 - .../apps/delivery/release-gate/workload.yaml | 101 - .../apps/delivery/reporter/kustomization.yaml | 9 - .../apps/delivery/reporter/networkpolicy.yaml | 57 - .../expected/apps/delivery/reporter/rbac.yaml | 48 - .../apps/delivery/reporter/service.yaml | 20 - .../delivery/reporter/serviceaccount.yaml | 13 - .../apps/delivery/reporter/workload.yaml | 98 - .../apps/delivery/rollout-events/alert.yaml | 18 - .../rollout-events/kustomization.yaml | 7 - .../delivery/rollout-events/provider.yaml | 12 - .../apps/edge/external-dns/kustomization.yaml | 9 - .../apps/edge/external-dns/networkpolicy.yaml | 57 - .../expected/apps/edge/external-dns/rbac.yaml | 51 - .../apps/edge/external-dns/service.yaml | 20 - .../edge/external-dns/serviceaccount.yaml | 13 - .../apps/edge/external-dns/workload.yaml | 98 - .../expected/apps/edge/kustomization.yaml | 12 - .../estate/expected/apps/edge/namespace.yaml | 10 - .../expected/apps/edge/networkpolicy.yaml | 15 - .../apps/edge/rollout-events/alert.yaml | 18 - .../edge/rollout-events/kustomization.yaml | 7 - .../apps/edge/rollout-events/provider.yaml | 12 - .../apps/edge/traefik-lan/kustomization.yaml | 12 - .../apps/edge/traefik-lan/middlewares.yaml | 85 - .../apps/edge/traefik-lan/networkpolicy.yaml | 79 - .../expected/apps/edge/traefik-lan/rbac.yaml | 75 - .../apps/edge/traefik-lan/service.yaml | 54 - .../apps/edge/traefik-lan/serviceaccount.yaml | 13 - .../apps/edge/traefik-lan/tlsstore.yaml | 13 - .../expected/apps/edge/traefik-lan/vso.yaml | 44 - .../apps/edge/traefik-lan/workload.yaml | 127 - .../edge/traefik-public/kustomization.yaml | 11 - .../edge/traefik-public/networkpolicy.yaml | 101 - .../apps/edge/traefik-public/pvc.yaml | 19 - .../apps/edge/traefik-public/rbac.yaml | 75 - .../apps/edge/traefik-public/service.yaml | 26 - .../edge/traefik-public/serviceaccount.yaml | 13 - .../apps/edge/traefik-public/vso.yaml | 47 - .../apps/edge/traefik-public/workload.yaml | 142 - .../apps/edge/vault-policy/configmap.yaml | 23 - .../apps/edge/vault-policy/cronjob.yaml | 99 - .../expected/apps/edge/vault-policy/job.yaml | 89 - .../apps/edge/vault-policy/kustomization.yaml | 9 - .../apps/edge/vault-policy/networkpolicy.yaml | 40 - .../edge-system-traefik-lan.policy.json | 14 - .../edge-system-traefik-lan.role.json | 11 - .../edge-system-traefik-public.policy.json | 14 - .../edge-system-traefik-public.role.json | 11 - .../edge/vault-policy/serviceaccount.yaml | 13 - .../expected/apps/edge/vaultconnection.yaml | 12 - .../apps/identity/identity/canary.yaml | 77 - .../apps/identity/identity/configmap.yaml | 26 - .../apps/identity/identity/kustomization.yaml | 10 - .../apps/identity/identity/networkpolicy.yaml | 73 - .../apps/identity/identity/route-public.yaml | 30 - .../identity/identity/serviceaccount.yaml | 13 - .../apps/identity/identity/workload.yaml | 101 - .../expected/apps/identity/kustomization.yaml | 12 - .../expected/apps/identity/namespace.yaml | 10 - .../expected/apps/identity/networkpolicy.yaml | 15 - .../expected/apps/identity/portal/canary.yaml | 77 - .../expected/apps/identity/portal/client.yaml | 21 - .../apps/identity/portal/configmap.yaml | 26 - .../apps/identity/portal/kustomization.yaml | 11 - .../apps/identity/portal/networkpolicy.yaml | 61 - .../apps/identity/portal/route-public.yaml | 30 - .../apps/identity/portal/serviceaccount.yaml | 13 - .../apps/identity/portal/workload.yaml | 85 - .../apps/identity/rollout-events/alert.yaml | 18 - .../rollout-events/kustomization.yaml | 7 - .../identity/rollout-events/provider.yaml | 12 - .../apps/identity/vault-policy/configmap.yaml | 19 - .../apps/identity/vault-policy/cronjob.yaml | 95 - .../apps/identity/vault-policy/job.yaml | 85 - .../identity/vault-policy/kustomization.yaml | 9 - .../identity/vault-policy/networkpolicy.yaml | 40 - .../identity-system-identity.policy.json | 11 - .../identity-system-identity.role.json | 11 - .../identity/vault-policy/serviceaccount.yaml | 13 - .../apps/identity/vaultconnection.yaml | 12 - .../expected/apps/identity/whoami/canary.yaml | 100 - .../expected/apps/identity/whoami/client.yaml | 17 - .../apps/identity/whoami/configmap.yaml | 26 - .../apps/identity/whoami/kustomization.yaml | 12 - .../apps/identity/whoami/networkpolicy.yaml | 61 - .../expected/apps/identity/whoami/pdb.yaml | 18 - .../apps/identity/whoami/route-public.yaml | 52 - .../apps/identity/whoami/serviceaccount.yaml | 13 - .../apps/identity/whoami/workload.yaml | 93 - .../expected/apps/mail/kustomization.yaml | 8 - .../estate/expected/apps/mail/namespace.yaml | 10 - .../expected/apps/mail/networkpolicy.yaml | 15 - .../apps/mail/rollout-events/alert.yaml | 18 - .../mail/rollout-events/kustomization.yaml | 7 - .../apps/mail/rollout-events/provider.yaml | 12 - .../apps/mail/stalwart/configmap.yaml | 33 - .../apps/mail/stalwart/kustomization.yaml | 10 - .../apps/mail/stalwart/networkpolicy.yaml | 83 - .../apps/mail/stalwart/route-admin.yaml | 60 - .../expected/apps/mail/stalwart/service.yaml | 26 - .../apps/mail/stalwart/serviceaccount.yaml | 13 - .../expected/apps/mail/stalwart/workload.yaml | 148 - .../apps/node/gpu-device/configmap.yaml | 19 - .../apps/node/gpu-device/kustomization.yaml | 8 - .../apps/node/gpu-device/serviceaccount.yaml | 11 - .../apps/node/gpu-device/workload.yaml | 84 - .../apps/node/gpu-metrics/kustomization.yaml | 7 - .../apps/node/gpu-metrics/serviceaccount.yaml | 11 - .../apps/node/gpu-metrics/workload.yaml | 77 - .../expected/apps/node/kustomization.yaml | 12 - .../apps/node/l4-speaker/kustomization.yaml | 10 - .../expected/apps/node/l4-speaker/pools.yaml | 103 - .../expected/apps/node/l4-speaker/rbac.yaml | 258 - .../apps/node/l4-speaker/serviceaccount.yaml | 21 - .../expected/apps/node/l4-speaker/vso.yaml | 43 - .../apps/node/l4-speaker/workload.yaml | 172 - .../estate/expected/apps/node/namespace.yaml | 10 - .../apps/node/node-metrics/kustomization.yaml | 7 - .../node/node-metrics/serviceaccount.yaml | 11 - .../apps/node/node-metrics/workload.yaml | 94 - .../apps/node/vault-policy/configmap.yaml | 21 - .../apps/node/vault-policy/cronjob.yaml | 97 - .../expected/apps/node/vault-policy/job.yaml | 87 - .../apps/node/vault-policy/kustomization.yaml | 9 - .../apps/node/vault-policy/networkpolicy.yaml | 40 - .../node-system-l4-speaker.policy.json | 14 - .../policies/node-system-l4-speaker.role.json | 11 - .../policies/node-system.generated.json | 10 - .../node/vault-policy/serviceaccount.yaml | 13 - .../expected/apps/node/vaultconnection.yaml | 12 - .../expected/apps/notes/kustomization.yaml | 9 - .../estate/expected/apps/notes/libraries.yaml | 49 - .../estate/expected/apps/notes/namespace.yaml | 10 - .../expected/apps/notes/networkpolicy.yaml | 15 - .../expected/apps/notes/notes/canary.yaml | 77 - .../expected/apps/notes/notes/configmap.yaml | 26 - .../apps/notes/notes/kustomization.yaml | 11 - .../apps/notes/notes/networkpolicy.yaml | 71 - .../expected/apps/notes/notes/podmonitor.yaml | 27 - .../apps/notes/notes/route-public.yaml | 30 - .../apps/notes/notes/serviceaccount.yaml | 13 - .../expected/apps/notes/notes/workload.yaml | 119 - .../apps/notes/rollout-events/alert.yaml | 18 - .../notes/rollout-events/kustomization.yaml | 7 - .../apps/notes/rollout-events/provider.yaml | 12 - .../alertmanager/alertmanagerconfig.yaml | 38 - .../alertmanager/kustomization.yaml | 10 - .../alertmanager/networkpolicy.yaml | 41 - .../observability/alertmanager/service.yaml | 20 - .../alertmanager/serviceaccount.yaml | 13 - .../apps/observability/alertmanager/vso.yaml | 44 - .../observability/alertmanager/workload.yaml | 96 - .../apps/observability/alloy/canary.yaml | 69 - .../apps/observability/alloy/configmap.yaml | 13 - .../observability/alloy/kustomization.yaml | 10 - .../observability/alloy/networkpolicy.yaml | 57 - .../apps/observability/alloy/rbac.yaml | 42 - .../observability/alloy/serviceaccount.yaml | 13 - .../apps/observability/alloy/workload.yaml | 101 - .../observability/gatus/kustomization.yaml | 9 - .../observability/gatus/networkpolicy.yaml | 47 - .../apps/observability/gatus/rbac.yaml | 40 - .../apps/observability/gatus/service.yaml | 20 - .../observability/gatus/serviceaccount.yaml | 13 - .../apps/observability/gatus/workload.yaml | 113 - .../grafana-operator/kustomization.yaml | 9 - .../grafana-operator/networkpolicy.yaml | 57 - .../observability/grafana-operator/rbac.yaml | 54 - .../grafana-operator/service.yaml | 23 - .../grafana-operator/serviceaccount.yaml | 13 - .../grafana-operator/workload.yaml | 100 - .../apps/observability/grafana/canary.yaml | 77 - .../apps/observability/grafana/client.yaml | 25 - .../apps/observability/grafana/configmap.yaml | 26 - .../apps/observability/grafana/grafana.yaml | 20 - .../observability/grafana/kustomization.yaml | 13 - .../observability/grafana/networkpolicy.yaml | 73 - .../observability/grafana/route-public.yaml | 30 - .../observability/grafana/serviceaccount.yaml | 13 - .../apps/observability/grafana/vso.yaml | 83 - .../apps/observability/grafana/workload.yaml | 126 - .../kube-state-metrics/canary.yaml | 69 - .../kube-state-metrics/configmap.yaml | 13 - .../kube-state-metrics/kustomization.yaml | 10 - .../kube-state-metrics/networkpolicy.yaml | 67 - .../kube-state-metrics/rbac.yaml | 62 - .../kube-state-metrics/serviceaccount.yaml | 13 - .../kube-state-metrics/workload.yaml | 103 - .../apps/observability/kustomization.yaml | 21 - .../observability/loki/kustomization.yaml | 9 - .../observability/loki/networkpolicy.yaml | 41 - .../expected/apps/observability/loki/pvc.yaml | 19 - .../apps/observability/loki/service.yaml | 20 - .../observability/loki/serviceaccount.yaml | 13 - .../apps/observability/loki/workload.yaml | 105 - .../apps/observability/namespace.yaml | 10 - .../apps/observability/networkpolicy.yaml | 15 - .../observability/otel-collector/canary.yaml | 69 - .../otel-collector/configmap.yaml | 13 - .../otel-collector/kustomization.yaml | 9 - .../otel-collector/networkpolicy.yaml | 61 - .../otel-collector/serviceaccount.yaml | 13 - .../otel-collector/workload.yaml | 103 - .../prometheus-operator/kustomization.yaml | 9 - .../prometheus-operator/networkpolicy.yaml | 47 - .../prometheus-operator/rbac.yaml | 79 - .../prometheus-operator/service.yaml | 20 - .../prometheus-operator/serviceaccount.yaml | 13 - .../prometheus-operator/workload.yaml | 98 - .../observability/prometheus/alertrules.yaml | 41 - .../prometheus/flux-podmonitor.yaml | 24 - .../prometheus/k3s-monitors.yaml | 261 - .../prometheus/kustomization.yaml | 12 - .../prometheus/networkpolicy.yaml | 131 - .../apps/observability/prometheus/rbac.yaml | 50 - .../observability/prometheus/service.yaml | 20 - .../prometheus/serviceaccount.yaml | 13 - .../observability/prometheus/workload.yaml | 127 - .../pyroscope/kustomization.yaml | 9 - .../pyroscope/networkpolicy.yaml | 41 - .../apps/observability/pyroscope/pvc.yaml | 19 - .../apps/observability/pyroscope/service.yaml | 20 - .../pyroscope/serviceaccount.yaml | 13 - .../observability/pyroscope/workload.yaml | 105 - .../observability/rollout-events/alert.yaml | 18 - .../rollout-events/kustomization.yaml | 7 - .../rollout-events/provider.yaml | 12 - .../observability/tempo/kustomization.yaml | 9 - .../observability/tempo/networkpolicy.yaml | 41 - .../apps/observability/tempo/pvc.yaml | 19 - .../apps/observability/tempo/service.yaml | 20 - .../observability/tempo/serviceaccount.yaml | 13 - .../apps/observability/tempo/workload.yaml | 105 - .../observability/vault-policy/configmap.yaml | 25 - .../observability/vault-policy/cronjob.yaml | 101 - .../apps/observability/vault-policy/job.yaml | 91 - .../vault-policy/kustomization.yaml | 9 - .../vault-policy/networkpolicy.yaml | 40 - ...ervability-system-alertmanager.policy.json | 14 - ...bservability-system-alertmanager.role.json | 11 - .../observability-system-grafana.policy.json | 24 - .../observability-system-grafana.role.json | 11 - .../observability-system.generated.json | 16 - .../vault-policy/serviceaccount.yaml | 13 - .../apps/observability/vaultconnection.yaml | 12 - .../human-grants/clusterrolebindings.yaml | 61 - .../estate/human-grants/kustomization.yaml | 6 - .../priority-classes/kustomization.yaml | 6 - .../priority-classes/priorityclasses.yaml | 23 - .../stable-addresses/kustomization.yaml | 7 - .../estate/stable-addresses/namespace.yaml | 10 - .../estate/stable-addresses/services.yaml | 56 - .../src/test/resources/stages/render/gaps.txt | 9 - .../apps/identity/identity/canary.yaml | 77 - .../apps/identity/identity/configmap.yaml | 26 - .../apps/identity/identity/kustomization.yaml | 10 - .../apps/identity/identity/networkpolicy.yaml | 73 - .../apps/identity/identity/route-public.yaml | 30 - .../identity/identity/serviceaccount.yaml | 13 - .../apps/identity/identity/workload.yaml | 101 - .../expected/apps/identity/kustomization.yaml | 12 - .../expected/apps/identity/namespace.yaml | 10 - .../expected/apps/identity/networkpolicy.yaml | 15 - .../expected/apps/identity/portal/canary.yaml | 77 - .../expected/apps/identity/portal/client.yaml | 21 - .../apps/identity/portal/configmap.yaml | 26 - .../apps/identity/portal/kustomization.yaml | 11 - .../apps/identity/portal/networkpolicy.yaml | 61 - .../apps/identity/portal/route-public.yaml | 30 - .../apps/identity/portal/serviceaccount.yaml | 13 - .../apps/identity/portal/workload.yaml | 85 - .../apps/identity/rollout-events/alert.yaml | 18 - .../rollout-events/kustomization.yaml | 7 - .../identity/rollout-events/provider.yaml | 12 - .../apps/identity/vault-policy/configmap.yaml | 19 - .../apps/identity/vault-policy/cronjob.yaml | 95 - .../apps/identity/vault-policy/job.yaml | 85 - .../identity/vault-policy/kustomization.yaml | 9 - .../identity/vault-policy/networkpolicy.yaml | 40 - .../identity-system-identity.policy.json | 11 - .../identity-system-identity.role.json | 11 - .../identity/vault-policy/serviceaccount.yaml | 13 - .../apps/identity/vaultconnection.yaml | 12 - .../expected/apps/identity/whoami/canary.yaml | 100 - .../expected/apps/identity/whoami/client.yaml | 17 - .../apps/identity/whoami/configmap.yaml | 26 - .../apps/identity/whoami/kustomization.yaml | 12 - .../apps/identity/whoami/networkpolicy.yaml | 61 - .../expected/apps/identity/whoami/pdb.yaml | 18 - .../apps/identity/whoami/route-public.yaml | 52 - .../apps/identity/whoami/serviceaccount.yaml | 13 - .../apps/identity/whoami/workload.yaml | 93 - .../human-grants/clusterrolebindings.yaml | 16 - .../estate/human-grants/kustomization.yaml | 6 - .../priority-classes/kustomization.yaml | 6 - .../priority-classes/priorityclasses.yaml | 23 - .../resources/stages/render/identity/oracles | 43 - .../apps/knowledge-platform/aliases.yaml | 23 - .../basic-memory/configmap.yaml | 14 - .../basic-memory/kustomization.yaml | 12 - .../basic-memory/networkpolicy.yaml | 63 - .../knowledge-platform/basic-memory/pvc.yaml | 37 - .../basic-memory/route-mcp.yaml | 32 - .../basic-memory/service.yaml | 20 - .../basic-memory/serviceaccount.yaml | 13 - .../knowledge-platform/basic-memory/vso.yaml | 47 - .../basic-memory/workload.yaml | 313 -- .../docling-serve/backup.yaml | 74 - .../docling-serve/kustomization.yaml | 11 - .../docling-serve/networkpolicy.yaml | 76 - .../knowledge-platform/docling-serve/pvc.yaml | 41 - .../docling-serve/service.yaml | 20 - .../docling-serve/serviceaccount.yaml | 25 - .../knowledge-platform/docling-serve/vso.yaml | 44 - .../docling-serve/workload.yaml | 113 - .../hindsight-embedding/kustomization.yaml | 9 - .../hindsight-embedding/networkpolicy.yaml | 41 - .../hindsight-embedding/pvc.yaml | 19 - .../hindsight-embedding/service.yaml | 20 - .../hindsight-embedding/serviceaccount.yaml | 13 - .../hindsight-embedding/workload.yaml | 109 - .../knowledge-platform/hindsight/canary.yaml | 149 - .../hindsight/configmap.yaml | 26 - .../hindsight/kustomization.yaml | 13 - .../hindsight/networkpolicy.yaml | 235 - .../hindsight/route-api.yaml | 32 - .../hindsight/route-console.yaml | 32 - .../knowledge-platform/hindsight/service.yaml | 20 - .../hindsight/serviceaccount.yaml | 37 - .../knowledge-platform/hindsight/vso.yaml | 159 - .../hindsight/workload.yaml | 391 -- .../knowledge-platform/karakeep/backup.yaml | 65 - .../karakeep/configmap.yaml | 14 - .../karakeep/kustomization.yaml | 13 - .../karakeep/networkpolicy.yaml | 112 - .../apps/knowledge-platform/karakeep/pvc.yaml | 77 - .../karakeep/route-public.yaml | 32 - .../knowledge-platform/karakeep/service.yaml | 20 - .../karakeep/serviceaccount.yaml | 25 - .../apps/knowledge-platform/karakeep/vso.yaml | 95 - .../knowledge-platform/karakeep/workload.yaml | 383 -- .../knowledge-platform/kustomization.yaml | 15 - .../apps/knowledge-platform/namespace.yaml | 10 - .../knowledge-platform/networkpolicy.yaml | 15 - .../rollout-events/alert.yaml | 18 - .../rollout-events/kustomization.yaml | 7 - .../rollout-events/provider.yaml | 12 - .../vault-policy/configmap.yaml | 35 - .../vault-policy/cronjob.yaml | 111 - .../knowledge-platform/vault-policy/job.yaml | 101 - .../vault-policy/kustomization.yaml | 9 - .../vault-policy/networkpolicy.yaml | 40 - ...e-platform-system-basic-memory.policy.json | 14 - ...dge-platform-system-basic-memory.role.json | 11 - ...rm-system-docling-serve-backup.policy.json | 14 - ...form-system-docling-serve-backup.role.json | 11 - ...-platform-system-hindsight-api.policy.json | 19 - ...ge-platform-system-hindsight-api.role.json | 11 - ...atform-system-hindsight-worker.policy.json | 19 - ...platform-system-hindsight-worker.role.json | 11 - ...ledge-platform-system-karakeep.policy.json | 34 - ...owledge-platform-system-karakeep.role.json | 11 - .../vault-policy/serviceaccount.yaml | 13 - .../knowledge-platform/vaultconnection.yaml | 12 - .../human-grants/clusterrolebindings.yaml | 16 - .../estate/human-grants/kustomization.yaml | 6 - .../priority-classes/kustomization.yaml | 6 - .../priority-classes/priorityclasses.yaml | 23 - .../stable-addresses/kustomization.yaml | 7 - .../estate/stable-addresses/namespace.yaml | 10 - .../estate/stable-addresses/services.yaml | 45 - .../stages/render/knowledge-platform/oracles | 74 - .../expected/apps/mail/kustomization.yaml | 8 - .../mail/expected/apps/mail/namespace.yaml | 10 - .../expected/apps/mail/networkpolicy.yaml | 15 - .../apps/mail/rollout-events/alert.yaml | 18 - .../mail/rollout-events/kustomization.yaml | 7 - .../apps/mail/rollout-events/provider.yaml | 12 - .../apps/mail/stalwart/configmap.yaml | 33 - .../apps/mail/stalwart/kustomization.yaml | 10 - .../apps/mail/stalwart/networkpolicy.yaml | 83 - .../apps/mail/stalwart/route-admin.yaml | 60 - .../expected/apps/mail/stalwart/service.yaml | 26 - .../apps/mail/stalwart/serviceaccount.yaml | 13 - .../expected/apps/mail/stalwart/workload.yaml | 144 - .../test/resources/stages/render/mail/oracles | 13 - .../expected/apps/notes/kustomization.yaml | 9 - .../expected/apps/notes/libraries.yaml | 49 - .../expected/apps/notes/namespace.yaml | 10 - .../expected/apps/notes/networkpolicy.yaml | 15 - .../expected/apps/notes/notes/canary.yaml | 77 - .../expected/apps/notes/notes/configmap.yaml | 26 - .../apps/notes/notes/kustomization.yaml | 11 - .../apps/notes/notes/networkpolicy.yaml | 71 - .../expected/apps/notes/notes/podmonitor.yaml | 27 - .../apps/notes/notes/route-public.yaml | 30 - .../apps/notes/notes/serviceaccount.yaml | 13 - .../expected/apps/notes/notes/workload.yaml | 119 - .../apps/notes/rollout-events/alert.yaml | 18 - .../notes/rollout-events/kustomization.yaml | 7 - .../apps/notes/rollout-events/provider.yaml | 12 - .../stages/render/minimal-main/oracles | 15 - .../apps/node/gpu-device/configmap.yaml | 19 - .../apps/node/gpu-device/kustomization.yaml | 8 - .../apps/node/gpu-device/serviceaccount.yaml | 11 - .../apps/node/gpu-device/workload.yaml | 84 - .../apps/node/gpu-metrics/kustomization.yaml | 7 - .../apps/node/gpu-metrics/serviceaccount.yaml | 11 - .../apps/node/gpu-metrics/workload.yaml | 77 - .../expected/apps/node/kustomization.yaml | 12 - .../apps/node/l4-speaker/kustomization.yaml | 10 - .../expected/apps/node/l4-speaker/pools.yaml | 103 - .../expected/apps/node/l4-speaker/rbac.yaml | 258 - .../apps/node/l4-speaker/serviceaccount.yaml | 21 - .../expected/apps/node/l4-speaker/vso.yaml | 43 - .../apps/node/l4-speaker/workload.yaml | 172 - .../node/expected/apps/node/namespace.yaml | 10 - .../apps/node/node-metrics/kustomization.yaml | 7 - .../node/node-metrics/serviceaccount.yaml | 11 - .../apps/node/node-metrics/workload.yaml | 94 - .../apps/node/vault-policy/configmap.yaml | 21 - .../apps/node/vault-policy/cronjob.yaml | 97 - .../expected/apps/node/vault-policy/job.yaml | 87 - .../apps/node/vault-policy/kustomization.yaml | 9 - .../apps/node/vault-policy/networkpolicy.yaml | 40 - .../node-system-l4-speaker.policy.json | 14 - .../policies/node-system-l4-speaker.role.json | 11 - .../policies/node-system.generated.json | 10 - .../node/vault-policy/serviceaccount.yaml | 13 - .../expected/apps/node/vaultconnection.yaml | 12 - .../human-grants/clusterrolebindings.yaml | 16 - .../estate/human-grants/kustomization.yaml | 6 - .../priority-classes/kustomization.yaml | 6 - .../priority-classes/priorityclasses.yaml | 23 - .../test/resources/stages/render/node/oracles | 32 - .../alertmanager/alertmanagerconfig.yaml | 38 - .../alertmanager/kustomization.yaml | 10 - .../alertmanager/networkpolicy.yaml | 41 - .../observability/alertmanager/service.yaml | 20 - .../alertmanager/serviceaccount.yaml | 13 - .../apps/observability/alertmanager/vso.yaml | 44 - .../observability/alertmanager/workload.yaml | 96 - .../apps/observability/alloy/canary.yaml | 69 - .../apps/observability/alloy/configmap.yaml | 13 - .../observability/alloy/kustomization.yaml | 10 - .../observability/alloy/networkpolicy.yaml | 57 - .../apps/observability/alloy/rbac.yaml | 42 - .../observability/alloy/serviceaccount.yaml | 13 - .../apps/observability/alloy/workload.yaml | 101 - .../observability/gatus/kustomization.yaml | 9 - .../observability/gatus/networkpolicy.yaml | 47 - .../apps/observability/gatus/rbac.yaml | 40 - .../apps/observability/gatus/service.yaml | 20 - .../observability/gatus/serviceaccount.yaml | 13 - .../apps/observability/gatus/workload.yaml | 113 - .../grafana-operator/kustomization.yaml | 9 - .../grafana-operator/networkpolicy.yaml | 57 - .../observability/grafana-operator/rbac.yaml | 54 - .../grafana-operator/service.yaml | 23 - .../grafana-operator/serviceaccount.yaml | 13 - .../grafana-operator/workload.yaml | 100 - .../apps/observability/grafana/canary.yaml | 77 - .../apps/observability/grafana/client.yaml | 25 - .../apps/observability/grafana/configmap.yaml | 26 - .../apps/observability/grafana/grafana.yaml | 20 - .../observability/grafana/kustomization.yaml | 13 - .../observability/grafana/networkpolicy.yaml | 73 - .../observability/grafana/route-public.yaml | 30 - .../observability/grafana/serviceaccount.yaml | 13 - .../apps/observability/grafana/vso.yaml | 83 - .../apps/observability/grafana/workload.yaml | 126 - .../kube-state-metrics/canary.yaml | 69 - .../kube-state-metrics/configmap.yaml | 13 - .../kube-state-metrics/kustomization.yaml | 10 - .../kube-state-metrics/networkpolicy.yaml | 67 - .../kube-state-metrics/rbac.yaml | 62 - .../kube-state-metrics/serviceaccount.yaml | 13 - .../kube-state-metrics/workload.yaml | 103 - .../apps/observability/kustomization.yaml | 21 - .../observability/loki/kustomization.yaml | 9 - .../observability/loki/networkpolicy.yaml | 41 - .../expected/apps/observability/loki/pvc.yaml | 19 - .../apps/observability/loki/service.yaml | 20 - .../observability/loki/serviceaccount.yaml | 13 - .../apps/observability/loki/workload.yaml | 105 - .../apps/observability/namespace.yaml | 10 - .../apps/observability/networkpolicy.yaml | 15 - .../observability/otel-collector/canary.yaml | 69 - .../otel-collector/configmap.yaml | 13 - .../otel-collector/kustomization.yaml | 9 - .../otel-collector/networkpolicy.yaml | 61 - .../otel-collector/serviceaccount.yaml | 13 - .../otel-collector/workload.yaml | 103 - .../prometheus-operator/kustomization.yaml | 9 - .../prometheus-operator/networkpolicy.yaml | 47 - .../prometheus-operator/rbac.yaml | 79 - .../prometheus-operator/service.yaml | 20 - .../prometheus-operator/serviceaccount.yaml | 13 - .../prometheus-operator/workload.yaml | 98 - .../observability/prometheus/alertrules.yaml | 28 - .../prometheus/flux-podmonitor.yaml | 24 - .../prometheus/k3s-monitors.yaml | 261 - .../prometheus/kustomization.yaml | 12 - .../prometheus/networkpolicy.yaml | 107 - .../apps/observability/prometheus/rbac.yaml | 50 - .../observability/prometheus/service.yaml | 20 - .../prometheus/serviceaccount.yaml | 13 - .../observability/prometheus/workload.yaml | 117 - .../pyroscope/kustomization.yaml | 9 - .../pyroscope/networkpolicy.yaml | 41 - .../apps/observability/pyroscope/pvc.yaml | 19 - .../apps/observability/pyroscope/service.yaml | 20 - .../pyroscope/serviceaccount.yaml | 13 - .../observability/pyroscope/workload.yaml | 105 - .../observability/rollout-events/alert.yaml | 18 - .../rollout-events/kustomization.yaml | 7 - .../rollout-events/provider.yaml | 12 - .../observability/tempo/kustomization.yaml | 9 - .../observability/tempo/networkpolicy.yaml | 41 - .../apps/observability/tempo/pvc.yaml | 19 - .../apps/observability/tempo/service.yaml | 20 - .../observability/tempo/serviceaccount.yaml | 13 - .../apps/observability/tempo/workload.yaml | 105 - .../observability/vault-policy/configmap.yaml | 25 - .../observability/vault-policy/cronjob.yaml | 101 - .../apps/observability/vault-policy/job.yaml | 91 - .../vault-policy/kustomization.yaml | 9 - .../vault-policy/networkpolicy.yaml | 40 - ...ervability-system-alertmanager.policy.json | 14 - ...bservability-system-alertmanager.role.json | 11 - .../observability-system-grafana.policy.json | 24 - .../observability-system-grafana.role.json | 11 - .../observability-system.generated.json | 16 - .../vault-policy/serviceaccount.yaml | 13 - .../apps/observability/vaultconnection.yaml | 12 - .../human-grants/clusterrolebindings.yaml | 16 - .../estate/human-grants/kustomization.yaml | 6 - .../priority-classes/kustomization.yaml | 6 - .../priority-classes/priorityclasses.yaml | 23 - .../stages/render/observability/oracles | 104 - .../expected/projects/_estate/source.yaml | 59 - .../pins/expected/projects/data/source.yaml | 58 - .../expected/projects/delivery/source.yaml | 54 - .../pins/expected/projects/edge/source.yaml | 54 - .../pins/expected/projects/node/source.yaml | 49 - .../pins/expected/projects/notes/source.yaml | 57 - .../projects/observability/source.yaml | 57 - .../expected/projects/secrets/source.yaml | 54 - .../test/resources/stages/render/pins/oracles | 8 - .../human-grants/clusterrolebindings.yaml | 16 - .../estate/human-grants/kustomization.yaml | 6 - .../priority-classes/kustomization.yaml | 6 - .../priority-classes/priorityclasses.yaml | 23 - .../resources/stages/render/platform/oracles | 4 - .../expected/apps/utility/adguard/canary.yaml | 92 - .../apps/utility/adguard/configmap.yaml | 42 - .../apps/utility/adguard/kustomization.yaml | 11 - .../apps/utility/adguard/networkpolicy.yaml | 84 - .../expected/apps/utility/adguard/pdb.yaml | 18 - .../apps/utility/adguard/service.yaml | 29 - .../apps/utility/adguard/serviceaccount.yaml | 13 - .../apps/utility/adguard/workload.yaml | 165 - .../apps/utility/headlamp/canary.yaml | 73 - .../apps/utility/headlamp/configmap.yaml | 26 - .../apps/utility/headlamp/kustomization.yaml | 10 - .../apps/utility/headlamp/networkpolicy.yaml | 67 - .../apps/utility/headlamp/route-lan.yaml | 26 - .../apps/utility/headlamp/serviceaccount.yaml | 13 - .../apps/utility/headlamp/workload.yaml | 100 - .../expected/apps/utility/kustomization.yaml | 9 - .../expected/apps/utility/namespace.yaml | 10 - .../expected/apps/utility/networkpolicy.yaml | 15 - .../apps/utility/rollout-events/alert.yaml | 18 - .../utility/rollout-events/kustomization.yaml | 7 - .../apps/utility/rollout-events/provider.yaml | 12 - .../resources/stages/render/utility/oracles | 21 - .../agents/expected/agents.resolveddeployment | 482 -- .../resources/stages/resolve/agents/projects | 1 - .../auth/expected/auth.resolveddeployment | 358 -- .../resources/stages/resolve/auth/projects | 1 - .../expected/data.resolveddeployment | 359 -- .../stages/resolve/data-full/projects | 1 - .../expected/data.resolveddeployment | 577 --- .../stages/resolve/data-main/projects | 1 - .../expected/delivery.resolveddeployment | 349 -- .../stages/resolve/delivery/projects | 1 - .../edge/expected/edge.resolveddeployment | 364 -- .../resources/stages/resolve/edge/projects | 1 - .../estate/expected/auth.dependencies.json | 1 - .../estate/expected/auth.resolveddeployment | 414 -- .../estate/expected/data.dependencies.json | 1 - .../estate/expected/data.resolveddeployment | 713 --- .../expected/delivery.dependencies.json | 1 - .../expected/delivery.resolveddeployment | 436 -- .../estate/expected/edge.dependencies.json | 1 - .../estate/expected/edge.resolveddeployment | 486 -- .../expected/identity.dependencies.json | 1 - .../expected/identity.resolveddeployment | 365 -- .../estate/expected/mail.dependencies.json | 1 - .../estate/expected/mail.resolveddeployment | 203 - .../estate/expected/node.dependencies.json | 1 - .../estate/expected/node.resolveddeployment | 345 -- .../estate/expected/notes.dependencies.json | 1 - .../estate/expected/notes.resolveddeployment | 209 - .../expected/observability.dependencies.json | 1 - .../expected/observability.resolveddeployment | 1067 ----- .../resources/stages/resolve/estate/projects | 9 - .../test/resources/stages/resolve/gaps.txt | 73 - .../expected/identity.resolveddeployment | 278 -- .../stages/resolve/identity/projects | 1 - .../knowledge-platform.resolveddeployment | 782 --- .../resolve/knowledge-platform/projects | 1 - .../mail/expected/mail.resolveddeployment | 115 - .../resources/stages/resolve/mail/projects | 1 - .../expected/notes.resolveddeployment | 123 - .../stages/resolve/minimal-main/projects | 1 - .../node/expected/node.resolveddeployment | 337 -- .../resources/stages/resolve/node/projects | 1 - .../expected/observability.resolveddeployment | 929 ---- .../stages/resolve/observability/projects | 1 - .../pins/expected/pins.resolveddeployment | 84 - .../resources/stages/resolve/pins/projects | 1 - .../expected/platform.resolveddeployment | 27 - .../stages/resolve/platform/projects | 1 - .../expected/utility.resolveddeployment | 187 - .../resources/stages/resolve/utility/projects | 1 - emf/bundles/metamodel/META-INF/MANIFEST.MF | 27 - emf/bundles/metamodel/build.properties | 7 - .../metamodel/model/cache-continuous.xmi | 24 - emf/bundles/metamodel/model/cache.xmi | 23 - .../metamodel/model/pinned-inputs.ecore | 168 - .../metamodel/model/pinned-inputs.genmodel | 9 - .../metamodel/model/project-intent.ecore | 996 ---- .../metamodel/model/project-intent.genmodel | 9 - .../metamodel/model/project-intent.ocl | 1207 ----- .../metamodel/model/resolved-deployment.ecore | 1398 ------ .../model/resolved-deployment.genmodel | 9 - .../metamodel/model/resolved-deployment.ocl | 25 - emf/bundles/metamodel/plugin.properties | 4 - emf/bundles/metamodel/plugin.xml | 25 - emf/bundles/metamodel/pom.xml | 135 - .../emf/metamodel/GeneratePinnedInputs.mwe2 | 21 - .../emf/metamodel/GenerateProjectIntent.mwe2 | 21 - .../metamodel/GenerateResolvedDeployment.mwe2 | 21 - .../metamodel/descriptor/DependencyEdges.java | 83 - .../emf/metamodel/descriptor/Descriptor.java | 174 - .../metamodel/descriptor/DescriptorFile.java | 31 - .../emf/metamodel/json/CanonicalJson.java | 160 - .../emf/metamodel/revision/ModelDigest.java | 90 - .../emf/metamodel/ProjectIntentOclTest.java | 107 - .../emf/metamodel/ResolvedDeploymentTest.java | 403 -- .../descriptor/DescriptorFileTest.java | 35 - .../metamodel/descriptor/DescriptorTest.java | 192 - .../emf/metamodel/json/CanonicalJsonTest.java | 164 - .../metamodel/revision/ModelDigestTest.java | 116 - emf/bundles/render/META-INF/MANIFEST.MF | 13 - emf/bundles/render/build.properties | 5 - emf/bundles/render/model/render.mtl | 3607 -------------- emf/bundles/render/pom.xml | 17 - emf/bundles/render/render.launch | 15 - .../deploykit/emf/render/RenderModel.java | 34 - .../deploykit/emf/render/Rendering.java | 154 - .../deploykit/emf/render/RenderModelTest.java | 48 - .../deploykit/emf/render/RenderingTest.java | 204 - .../render/src/test/resources/halfway.mtl | 14 - .../render/src/test/resources/unindented.mtl | 10 - emf/bundles/resolve/META-INF/MANIFEST.MF | 12 - emf/bundles/resolve/build.properties | 6 - emf/bundles/resolve/model/lower.qvto | 474 -- emf/bundles/resolve/model/resolution.qvto | 4212 ----------------- emf/bundles/resolve/plugin.xml | 16 - emf/bundles/resolve/pom.xml | 17 - emf/bundles/resolve/resolution.launch | 21 - .../deploykit/emf/resolve/Hashing.java | 41 - .../deploykit/emf/resolve/Lowering.java | 47 - .../deploykit/emf/resolve/Resolution.java | 84 - .../deploykit/emf/resolve/LoweringTest.java | 255 - .../deploykit/emf/resolve/ResolutionTest.java | 216 - emf/bundles/syntax/META-INF/MANIFEST.MF | 26 - emf/bundles/syntax/build.properties | 4 - emf/bundles/syntax/pom.xml | 164 - .../deploykit/emf/syntax/ClusterState.xtext | 34 - .../emf/syntax/ClusterStateRuntimeModule.java | 17 - .../syntax/ClusterStateStandaloneSetup.java | 14 - .../emf/syntax/GenerateProjectIntent.mwe2 | 115 - .../deploykit/emf/syntax/ImagesLock.xtext | 34 - .../emf/syntax/ImagesLockRuntimeModule.java | 17 - .../emf/syntax/ImagesLockStandaloneSetup.java | 14 - .../deploykit/emf/syntax/MigrationProof.xtext | 27 - .../syntax/MigrationProofRuntimeModule.java | 17 - .../syntax/MigrationProofStandaloneSetup.java | 14 - .../deploykit/emf/syntax/NodeContract.xtext | 47 - .../emf/syntax/NodeContractRuntimeModule.java | 17 - .../syntax/NodeContractStandaloneSetup.java | 14 - .../deploykit/emf/syntax/PlatformIntent.xtext | 429 -- .../syntax/PlatformIntentRuntimeModule.java | 32 - .../syntax/PlatformIntentStandaloneSetup.java | 14 - .../deploykit/emf/syntax/ProjectIntent.xtext | 486 -- .../syntax/ProjectIntentRuntimeModule.java | 32 - .../syntax/ProjectIntentStandaloneSetup.java | 14 - .../emf/syntax/blocks/BlockTokenSource.java | 352 -- .../emf/syntax/blocks/BlockTokens.java | 42 - .../syntax/linking/ProjectIntentScopes.java | 120 - .../emf/syntax/linking/UnlinkedNames.java | 184 - .../parser/antlr/ClusterStateTokenSource.java | 31 - .../parser/antlr/ImagesLockTokenSource.java | 31 - .../antlr/MigrationProofTokenSource.java | 31 - .../parser/antlr/NodeContractTokenSource.java | 31 - .../antlr/PlatformIntentTokenSource.java | 31 - .../antlr/ProjectIntentTokenSource.java | 30 - .../deploykit/emf/syntax/schema/Shapes.java | 353 -- .../deploykit/emf/syntax/schema/Yaml.java | 319 -- .../values/ProjectIntentValueConverters.java | 53 - .../syntax/blocks/BlockTokenSourceTest.java | 288 -- .../emf/syntax/blocks/BlockTokensTest.java | 43 - .../emf/syntax/linking/LinkingTest.java | 384 -- .../emf/syntax/schema/ShapesTest.java | 337 -- .../deploykit/emf/syntax/schema/YamlTest.java | 302 -- .../ProjectIntentValueConvertersTest.java | 42 - emf/docs/adr/README.md | 50 - ...del-is-expressible-in-the-emf-toolchain.md | 50 - ...is-coursework-scoped-and-self-contained.md | 57 - ...-tycho-against-a-pinned-target-platform.md | 82 - ...-and-target-metamodels-are-hand-written.md | 75 - ...straints-are-complete-ocl-named-by-code.md | 58 - ...es-the-authored-yaml-into-the-metamodel.md | 59 - ...76-qvto-derives-the-resolved-deployment.md | 58 - ...7-acceleo-4-renders-the-deliverable-set.md | 50 - ...8-model-behaviours-have-a-junit-witness.md | 66 - .../0079-the-emf-gates-are-estate-shaped.md | 80 - ...0-parity-crosses-the-cli-file-interface.md | 118 - ...81-bundles-and-tests-are-separate-tiers.md | 109 - ...-env-files-are-read-not-parsed-by-xtext.md | 74 - ...file-invariants-navigate-an-estate-root.md | 75 - ...less-the-model-cannot-hold-what-it-asks.md | 80 - ...ile-is-read-as-data-into-a-generic-tree.md | 74 - ...des-and-explains-every-model-comparison.md | 86 - emf/docs/architecture.md | 658 --- emf/docs/benchmarks.md | 472 -- emf/docs/rules.md | 39 - emf/docs/witnesses.md | 122 - emf/emf.target | 35 - emf/models/minimal.resolveddeployment | 144 - emf/models/secrets.resolveddeployment | 269 -- emf/mvnw | 295 -- emf/mvnw.cmd | 189 - emf/pom.xml | 438 -- emf/scripts/summary.sh | 23 - emf/tests/parity/pom.xml | 93 - .../deploykit/emf/parity/Ledgers.kt | 189 - .../emf/cli/fixture/ComparingInMain.kt | 12 - .../emf/cli/fixture/UpperReachingDown.kt | 14 - .../emf/metamodel/fixture/LowerReachingUp.kt | 14 - .../deploykit/emf/parity/ArchitectureTest.kt | 84 - .../deploykit/emf/parity/LedgersTest.kt | 302 -- .../deploykit/emf/parity/ModuleRules.kt | 102 - .../deploykit/emf/parity/ParityTest.kt | 214 - .../deploykit/emf/parity/Repository.kt | 13 - .../emf/parity/TargetPlatformTest.kt | 76 - .../eclipse/emf/compare/fixture/StandIn.kt | 10 - eslint.config.js | 2 - release-please-config.json | 1 - renovate.json | 17 +- scripts/lib/change-buckets.ts | 32 - scripts/lint-adrs.ts | 3 - scripts/lint-codes.ts | 5 +- scripts/lint-links.ts | 4 +- scripts/lint-meaning.ts | 4 +- spec/v1/examples/refusals/README.md | 4 +- spec/v1/examples/schema-refusals/README.md | 11 +- src/check/project.ts | 13 +- src/model/descriptor.ts | 4 +- src/model/effective-intent.ts | 4 +- src/read/env.ts | 4 +- src/resolve/union.ts | 4 +- test/adr-contract.test.ts | 23 - test/canonical-json.test.ts | 2 +- test/codes-lint.test.ts | 20 - test/emf-wiring.test.ts | 271 -- test/link-contract.test.ts | 12 - test/meaning-lint-negative.test.ts | 3 +- test/mutation-scope.test.ts | 1 - test/schema-refusals.test.ts | 8 +- 1373 files changed, 153 insertions(+), 99645 deletions(-) delete mode 100644 docs/adr/architecture/0068-two-implementations-meet-at-the-parity-table.md delete mode 100644 emf/.gitignore delete mode 100644 emf/.java-version delete mode 100644 emf/.mvn/maven.config delete mode 100644 emf/.mvn/wrapper/maven-wrapper.properties delete mode 100644 emf/README.md delete mode 100644 emf/bundles/cli/META-INF/MANIFEST.MF delete mode 100644 emf/bundles/cli/build.properties delete mode 100644 emf/bundles/cli/pom.xml delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Authored.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Collisions.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Constraints.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/DataFile.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Diagnostic.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/EnvFiles.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/IntentJson.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/L4Checks.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/NodeAgentChecks.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/OperatedChecks.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Outputs.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Parsed.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Pipeline.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Placement.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Pointer.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Resolved.java delete mode 100644 emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/ShippedFiles.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/AtlLowering.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Benchmark.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/BenchmarkInputs.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ColdRun.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/CollisionsTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Comparison.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ComparisonTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ConstraintsTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/DataFileTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/DiagnosticTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/EnvFilesTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Examples.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/FieldCoverage.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/FieldCoverageTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/IntentJsonTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/IntentSetTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/L4ChecksTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/LoweringBenchmarkTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/LoweringEquivalenceTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelDiff.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelDiffTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelWitnessesTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/NodeAgentChecksTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OperatedChecksTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OracleDistanceTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OutputsTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PinnedInputsTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineBenchmarkTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineRefusalsTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PlatformIntentTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PointerTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/QvtoLowering.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/QvtoResolution.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/RenderedTreeTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ResolutionTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ShippedFilesTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/StageTest.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Stages.java delete mode 100644 emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/WorkedExamplesTest.java delete mode 100644 emf/bundles/cli/src/test/resources/benchmark/lower.atl delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/agents.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/auth.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/coverage.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/data.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/delivery.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/edge.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/effective.xmi delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/identity.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/knowledge-platform.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/knowledge.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/mail.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/notes.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/observability.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/secrets.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/estate/expected/utility.effective.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/lower/gaps.txt delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/agents/agents.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/auth/auth.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/breadth/coverage.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/data/data.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/delivery/delivery.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/edge/edge.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/identity/identity.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/intent.xmi delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/knowledge-platform/knowledge-platform.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/knowledge/knowledge.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/mail/mail.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/minimal/notes.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/observability/observability.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/pinned.xmi delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/platform/platform.intent.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/secrets/secrets.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/expected/utility/utility.project.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/agents/agents.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/agents/config/hermes/config.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/agents/env/hermes/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/auth/auth.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/auth/env/auth-api/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/auth/migration-proof.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/config/coverage.conf delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/config/seed.conf delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/coverage.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/env/_applications/coverage-api/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/env/_project/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/env/coverage-api/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/config/garage.toml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/config/postgresql.conf delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/dashboards/rabbitmq.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/data.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/env/garage/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/env/postgres/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/delivery/delivery.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/edge/edge.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/identity/identity.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/basic-memory/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/docling-serve/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-api/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-control-plane/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-tei-embedding/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-worker/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/karakeep/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/knowledge-platform.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/env/_project/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/env/knowledge-api/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/env/knowledge-ingest-worker/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/knowledge.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/mail/config/manifest.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/mail/mail.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/minimal/env/notes-api/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/minimal/notes.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/observability/env/grafana/base.env delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/observability/observability.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/observability/rules/platform.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/cluster-state.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/images.lock.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/node-contract.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/platform.intent.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/secrets/secrets.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/utility/config/adguard/AdGuardHome.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/estate/input/utility/utility.project.yml delete mode 100644 emf/bundles/cli/src/test/resources/stages/parse/gaps.txt delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/client.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/route-lan.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/policies/agents-system-hermes.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/policies/agents-system-hermes.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/agents/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/aliases.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/migration.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/pdb.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/podmonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-api.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-api.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/human-grants/clusterrolebindings.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/human-grants/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/priority-classes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/priority-classes/priorityclasses.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/stable-addresses/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/stable-addresses/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/stable-addresses/services.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/auth/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/servicemonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/route-management.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/servicemonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres-backup.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-full/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/servicemonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/dashboards.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/route-lan.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/route-management.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/servicemonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-asset-sync.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-asset-sync.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-garage.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-garage.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-mongo-backup.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-mongo-backup.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres-backup.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/data-main/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/servicemonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/delivery/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/middlewares.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/human-grants/clusterrolebindings.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/human-grants/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/priority-classes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/priority-classes/priorityclasses.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/edge/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/aliases.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/migration.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/pdb.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/podmonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-api.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-api.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/garage-catalog-networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/garage-catalog.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/postgres-catalog-networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/postgres-catalog.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/servicemonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/dashboards.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/route-lan.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/route-management.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/servicemonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-asset-sync.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-asset-sync.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage-catalog.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage-catalog.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-mongo-backup.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-mongo-backup.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-backup.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-catalog.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-catalog.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system.generated.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/servicemonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/middlewares.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/tlsstore.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-lan.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-lan.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/client.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/policies/identity-system-identity.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/policies/identity-system-identity.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/client.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/pdb.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/route-admin.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-metrics/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-metrics/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-metrics/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/pools.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/node-metrics/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/node-metrics/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/node-metrics/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/policies/node-system-l4-speaker.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/policies/node-system-l4-speaker.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/policies/node-system.generated.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/libraries.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/podmonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/alertmanagerconfig.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/client.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/grafana.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/alertrules.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/flux-podmonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/k3s-monitors.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-grafana.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-grafana.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system.generated.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/human-grants/clusterrolebindings.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/human-grants/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/priority-classes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/priority-classes/priorityclasses.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/stable-addresses/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/stable-addresses/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/stable-addresses/services.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/gaps.txt delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/client.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/policies/identity-system-identity.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/policies/identity-system-identity.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/client.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/pdb.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/human-grants/clusterrolebindings.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/human-grants/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/priority-classes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/priority-classes/priorityclasses.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/identity/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/aliases.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/route-mcp.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/route-api.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/route-console.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/backup.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-basic-memory.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-basic-memory.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-docling-serve-backup.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-docling-serve-backup.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-api.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-api.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-worker.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-worker.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-karakeep.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-karakeep.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/human-grants/clusterrolebindings.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/human-grants/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/priority-classes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/priority-classes/priorityclasses.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/stable-addresses/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/stable-addresses/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/stable-addresses/services.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/route-admin.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/mail/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/libraries.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/podmonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/minimal-main/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-metrics/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-metrics/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-metrics/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/pools.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/node-metrics/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/node-metrics/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/node-metrics/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/policies/node-system-l4-speaker.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/policies/node-system-l4-speaker.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/policies/node-system.generated.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/human-grants/clusterrolebindings.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/human-grants/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/priority-classes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/priority-classes/priorityclasses.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/node/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/alertmanagerconfig.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/client.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/grafana.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/route-public.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/vso.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/alertrules.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/flux-podmonitor.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/k3s-monitors.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/rbac.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/pvc.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/cronjob.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/job.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-grafana.policy.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-grafana.role.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system.generated.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vaultconnection.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/human-grants/clusterrolebindings.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/human-grants/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/priority-classes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/priority-classes/priorityclasses.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/observability/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/_estate/source.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/data/source.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/delivery/source.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/edge/source.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/node/source.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/notes/source.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/observability/source.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/secrets/source.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/pins/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/human-grants/clusterrolebindings.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/human-grants/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/priority-classes/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/priority-classes/priorityclasses.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/platform/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/pdb.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/service.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/canary.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/configmap.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/route-lan.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/serviceaccount.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/workload.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/namespace.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/networkpolicy.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/rollout-events/alert.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/rollout-events/kustomization.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/rollout-events/provider.yaml delete mode 100644 emf/bundles/cli/src/test/resources/stages/render/utility/oracles delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/agents/expected/agents.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/agents/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/auth/expected/auth.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/auth/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/data-full/expected/data.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/data-full/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/data-main/expected/data.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/data-main/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/delivery/expected/delivery.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/delivery/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/edge/expected/edge.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/edge/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/auth.dependencies.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/auth.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/data.dependencies.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/data.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/delivery.dependencies.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/delivery.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/edge.dependencies.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/edge.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/identity.dependencies.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/identity.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/mail.dependencies.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/mail.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/node.dependencies.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/node.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/notes.dependencies.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/notes.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/observability.dependencies.json delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/observability.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/estate/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/gaps.txt delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/identity/expected/identity.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/identity/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/knowledge-platform/expected/knowledge-platform.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/knowledge-platform/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/mail/expected/mail.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/mail/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/minimal-main/expected/notes.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/minimal-main/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/node/expected/node.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/node/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/observability/expected/observability.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/observability/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/pins/expected/pins.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/pins/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/platform/expected/platform.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/platform/projects delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/utility/expected/utility.resolveddeployment delete mode 100644 emf/bundles/cli/src/test/resources/stages/resolve/utility/projects delete mode 100644 emf/bundles/metamodel/META-INF/MANIFEST.MF delete mode 100644 emf/bundles/metamodel/build.properties delete mode 100644 emf/bundles/metamodel/model/cache-continuous.xmi delete mode 100644 emf/bundles/metamodel/model/cache.xmi delete mode 100644 emf/bundles/metamodel/model/pinned-inputs.ecore delete mode 100644 emf/bundles/metamodel/model/pinned-inputs.genmodel delete mode 100644 emf/bundles/metamodel/model/project-intent.ecore delete mode 100644 emf/bundles/metamodel/model/project-intent.genmodel delete mode 100644 emf/bundles/metamodel/model/project-intent.ocl delete mode 100644 emf/bundles/metamodel/model/resolved-deployment.ecore delete mode 100644 emf/bundles/metamodel/model/resolved-deployment.genmodel delete mode 100644 emf/bundles/metamodel/model/resolved-deployment.ocl delete mode 100644 emf/bundles/metamodel/plugin.properties delete mode 100644 emf/bundles/metamodel/plugin.xml delete mode 100644 emf/bundles/metamodel/pom.xml delete mode 100644 emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GeneratePinnedInputs.mwe2 delete mode 100644 emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GenerateProjectIntent.mwe2 delete mode 100644 emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GenerateResolvedDeployment.mwe2 delete mode 100644 emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DependencyEdges.java delete mode 100644 emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/Descriptor.java delete mode 100644 emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DescriptorFile.java delete mode 100644 emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/json/CanonicalJson.java delete mode 100644 emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/revision/ModelDigest.java delete mode 100644 emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/ProjectIntentOclTest.java delete mode 100644 emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/ResolvedDeploymentTest.java delete mode 100644 emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DescriptorFileTest.java delete mode 100644 emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DescriptorTest.java delete mode 100644 emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/json/CanonicalJsonTest.java delete mode 100644 emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/revision/ModelDigestTest.java delete mode 100644 emf/bundles/render/META-INF/MANIFEST.MF delete mode 100644 emf/bundles/render/build.properties delete mode 100644 emf/bundles/render/model/render.mtl delete mode 100644 emf/bundles/render/pom.xml delete mode 100644 emf/bundles/render/render.launch delete mode 100644 emf/bundles/render/src/main/java/dev/jorisjonkers/deploykit/emf/render/RenderModel.java delete mode 100644 emf/bundles/render/src/main/java/dev/jorisjonkers/deploykit/emf/render/Rendering.java delete mode 100644 emf/bundles/render/src/test/java/dev/jorisjonkers/deploykit/emf/render/RenderModelTest.java delete mode 100644 emf/bundles/render/src/test/java/dev/jorisjonkers/deploykit/emf/render/RenderingTest.java delete mode 100644 emf/bundles/render/src/test/resources/halfway.mtl delete mode 100644 emf/bundles/render/src/test/resources/unindented.mtl delete mode 100644 emf/bundles/resolve/META-INF/MANIFEST.MF delete mode 100644 emf/bundles/resolve/build.properties delete mode 100644 emf/bundles/resolve/model/lower.qvto delete mode 100644 emf/bundles/resolve/model/resolution.qvto delete mode 100644 emf/bundles/resolve/plugin.xml delete mode 100644 emf/bundles/resolve/pom.xml delete mode 100644 emf/bundles/resolve/resolution.launch delete mode 100644 emf/bundles/resolve/src/main/java/dev/jorisjonkers/deploykit/emf/resolve/Hashing.java delete mode 100644 emf/bundles/resolve/src/main/java/dev/jorisjonkers/deploykit/emf/resolve/Lowering.java delete mode 100644 emf/bundles/resolve/src/main/java/dev/jorisjonkers/deploykit/emf/resolve/Resolution.java delete mode 100644 emf/bundles/resolve/src/test/java/dev/jorisjonkers/deploykit/emf/resolve/LoweringTest.java delete mode 100644 emf/bundles/resolve/src/test/java/dev/jorisjonkers/deploykit/emf/resolve/ResolutionTest.java delete mode 100644 emf/bundles/syntax/META-INF/MANIFEST.MF delete mode 100644 emf/bundles/syntax/build.properties delete mode 100644 emf/bundles/syntax/pom.xml delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ClusterState.xtext delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ClusterStateRuntimeModule.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ClusterStateStandaloneSetup.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateProjectIntent.mwe2 delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ImagesLock.xtext delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ImagesLockRuntimeModule.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ImagesLockStandaloneSetup.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/MigrationProof.xtext delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/MigrationProofRuntimeModule.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/MigrationProofStandaloneSetup.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/NodeContract.xtext delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/NodeContractRuntimeModule.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/NodeContractStandaloneSetup.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntent.xtext delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntentRuntimeModule.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntentStandaloneSetup.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntent.xtext delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentRuntimeModule.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentStandaloneSetup.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSource.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokens.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/linking/ProjectIntentScopes.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/linking/UnlinkedNames.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ClusterStateTokenSource.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ImagesLockTokenSource.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/MigrationProofTokenSource.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/NodeContractTokenSource.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/PlatformIntentTokenSource.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ProjectIntentTokenSource.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/schema/Shapes.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/schema/Yaml.java delete mode 100644 emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/values/ProjectIntentValueConverters.java delete mode 100644 emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSourceTest.java delete mode 100644 emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokensTest.java delete mode 100644 emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/linking/LinkingTest.java delete mode 100644 emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/schema/ShapesTest.java delete mode 100644 emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/schema/YamlTest.java delete mode 100644 emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/values/ProjectIntentValueConvertersTest.java delete mode 100644 emf/docs/adr/README.md delete mode 100644 emf/docs/adr/emf/0070-the-model-is-expressible-in-the-emf-toolchain.md delete mode 100644 emf/docs/adr/emf/0071-emf-is-coursework-scoped-and-self-contained.md delete mode 100644 emf/docs/adr/emf/0072-maven-and-tycho-against-a-pinned-target-platform.md delete mode 100644 emf/docs/adr/emf/0073-source-and-target-metamodels-are-hand-written.md delete mode 100644 emf/docs/adr/emf/0074-constraints-are-complete-ocl-named-by-code.md delete mode 100644 emf/docs/adr/emf/0075-xtext-parses-the-authored-yaml-into-the-metamodel.md delete mode 100644 emf/docs/adr/emf/0076-qvto-derives-the-resolved-deployment.md delete mode 100644 emf/docs/adr/emf/0077-acceleo-4-renders-the-deliverable-set.md delete mode 100644 emf/docs/adr/emf/0078-model-behaviours-have-a-junit-witness.md delete mode 100644 emf/docs/adr/emf/0079-the-emf-gates-are-estate-shaped.md delete mode 100644 emf/docs/adr/emf/0080-parity-crosses-the-cli-file-interface.md delete mode 100644 emf/docs/adr/emf/0081-bundles-and-tests-are-separate-tiers.md delete mode 100644 emf/docs/adr/emf/0082-the-env-files-are-read-not-parsed-by-xtext.md delete mode 100644 emf/docs/adr/emf/0098-cross-file-invariants-navigate-an-estate-root.md delete mode 100644 emf/docs/adr/emf/0143-a-refusal-is-decided-in-ocl-unless-the-model-cannot-hold-what-it-asks.md delete mode 100644 emf/docs/adr/emf/0151-a-rule-group-file-is-read-as-data-into-a-generic-tree.md delete mode 100644 emf/docs/adr/emf/0152-emf-compare-decides-and-explains-every-model-comparison.md delete mode 100644 emf/docs/architecture.md delete mode 100644 emf/docs/benchmarks.md delete mode 100644 emf/docs/rules.md delete mode 100644 emf/docs/witnesses.md delete mode 100644 emf/emf.target delete mode 100644 emf/models/minimal.resolveddeployment delete mode 100644 emf/models/secrets.resolveddeployment delete mode 100755 emf/mvnw delete mode 100644 emf/mvnw.cmd delete mode 100644 emf/pom.xml delete mode 100755 emf/scripts/summary.sh delete mode 100644 emf/tests/parity/pom.xml delete mode 100644 emf/tests/parity/src/main/kotlin/dev/jorisjonkers/deploykit/emf/parity/Ledgers.kt delete mode 100644 emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/cli/fixture/ComparingInMain.kt delete mode 100644 emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/cli/fixture/UpperReachingDown.kt delete mode 100644 emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/metamodel/fixture/LowerReachingUp.kt delete mode 100644 emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ArchitectureTest.kt delete mode 100644 emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/LedgersTest.kt delete mode 100644 emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ModuleRules.kt delete mode 100644 emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ParityTest.kt delete mode 100644 emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/Repository.kt delete mode 100644 emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/TargetPlatformTest.kt delete mode 100644 emf/tests/parity/src/test/kotlin/org/eclipse/emf/compare/fixture/StandIn.kt delete mode 100644 test/emf-wiring.test.ts diff --git a/.agents/skills/adr/SKILL.md b/.agents/skills/adr/SKILL.md index 7671438fe..ef49e527d 100644 --- a/.agents/skills/adr/SKILL.md +++ b/.agents/skills/adr/SKILL.md @@ -18,13 +18,11 @@ pointing at it. `docs/adr/architecture/` for a decision about the compiler's own structure (its `normative:` pointer names a `docs/architecture.md` or `docs/architecture-rules.md` heading); `docs/adr/deferred/` only for - delivery or co-testing direction work, never for a v1 decision. While - `emf/` exists, a Java-side decision goes to `emf/docs/adr/` instead, using - the same numbering sequence. -2. **Take the next number.** Check `docs/adr/README.md`'s register **and** - `emf/docs/adr/README.md`'s, even when writing to the root register: the - sequence is estate-wide and a number already used in either register is - the fastest way to fail the register-integrity check. + delivery or co-testing direction work, never for a v1 decision. +2. **Take the next number.** Check `docs/adr/README.md`'s register: the + sequence is estate-wide, a number already used in it is never taken again, + and the next number is the highest the register holds plus one (which is + the fastest way to fail the register-integrity check). 3. **Write the frontmatter.** `tier: premise` (a falsifiable claim, no `rests-on`) or `tier: decision` (names only premises in `rests-on`, never another decision: a decision-to-decision dependency is prose, in `## Why`, @@ -38,7 +36,7 @@ pointing at it. here: that belongs in the chapter the `normative:` pointer names, and this record links to it instead. 5. **Add the register row**, in the numeric position its section of - `docs/adr/README.md` (or `emf/docs/adr/README.md`) already sorts by, with + `docs/adr/README.md` already sorts by, with the title and claim matching the file exactly. 6. **Cite it correctly everywhere else you touch.** Never a bare `ADR-NNNN` or bare number: always a Markdown link. A decision that changes is diff --git a/.agents/skills/spec-change/SKILL.md b/.agents/skills/spec-change/SKILL.md index f83e23e1c..2c2ecc643 100644 --- a/.agents/skills/spec-change/SKILL.md +++ b/.agents/skills/spec-change/SKILL.md @@ -32,14 +32,14 @@ next. `expected/dependencies.json`, `expected/resolved.json`, `.diagnostics.json`, `rendered/`, `expected/descriptor.json`. Written and reviewed by hand, never regenerated by CI - ([`docs/architecture.md#the-parity-contract`](../../../docs/architecture.md#the-parity-contract)). + ([`docs/architecture.md#the-oracles`](../../../docs/architecture.md#the-oracles)). A tool may propose a candidate; the committed file is the reviewed copy of it, canonical JSON (RFC 8785), byte for byte. - **The diagrams**, under `spec/v1/diagrams/`: one drawn SVG per chapter, the editable draw.io source embedded, one palette, colour carrying the layer. - **The TypeScript declarations.** A model change lands in the TypeScript - production implementation first; `emf/` catches up in a pull request of its - own ([`AGENTS.md`](../../../AGENTS.md#boundaries)). Nothing regenerates an + implementation and its oracle files together + ([`AGENTS.md`](../../../AGENTS.md#boundaries)). Nothing regenerates an oracle. ## Steps @@ -50,8 +50,7 @@ next. needs, or updating the pointer in the same commit if a heading moves. 3. Update or add the worked example(s) the change bears on, and hand-write the oracle files it touches. -4. Update the TypeScript declarations against the same oracle files; leave - `emf/` as it is. +4. Update the TypeScript declarations against the same oracle files. 5. Run `npm run lint:adrs` and `npm run lint:links`. ## Claiming a ticket diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 96a8a6198..067d35e57 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,6 +7,3 @@ # change that lands without its ADR is the drift this repository exists to stop. /docs/adr/ @JorisJonkers-dev/maintainers /spec/ @JorisJonkers-dev/maintainers - -# The model-driven implementation, deleted at its sunset. -/emf/ @JorisJonkers-dev/maintainers diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml index 938f760ec..4a23c9718 100644 --- a/.github/codeql/codeql-config.yml +++ b/.github/codeql/codeql-config.yml @@ -1,6 +1,6 @@ # Paths CodeQL does not analyse. Build output and generated sources are not -# code anyone wrote here; the model-driven build (emf/) generates Java from its -# genmodel and Xtext grammar into target/ and src-gen/. +# code anyone wrote here; generated code lands in target/, src-gen/ and +# xtend-gen/. 'name': 'deploy-kit CodeQL' 'paths-ignore': diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 59018ef51..73a979981 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,11 +114,6 @@ - 'name': 'ADR contract' 'run': 'npm run lint:adrs' - # The coursework implementation's register, linted as its own root. - # Deleted with emf/ (emf/docs/adr/emf/0107). - - 'name': 'ADR contract (emf)' - 'run': 'node scripts/lint-adrs.ts emf' - # Relative links and heading anchors across every Markdown file git does not ignore. # The ADR domain move rewrote about a hundred references outside the # decision set, and nothing checked them. @@ -496,79 +491,6 @@ 'security-events': 'write' 'uses': './.github/workflows/codeql.yml' - # The model-driven implementation under emf/ (docs/adr/emf/0107): its own - # Maven build, JDK and gates, deleted with the directory at its sunset. Every gate - # it runs is listed in emf/docs/rules.md; the thresholds are in emf/pom.xml. - # test/emf-wiring.test.ts proves this step names a real build. - # - # The model-driven build under emf/ (Maven and Tycho) runs its tests and its - # 100% JaCoCo gate on every change to its sources or to this workflow. Any - # other change skips its steps: a model change lands in TypeScript first and - # moves the oracles, and the model-driven build catches up in its own change. Its 100% PIT gate takes too long for every change, so it runs - # periodically: on the nightly run and on a dispatch. It is not one of - # Pipeline Complete's needs. - 'emf': - 'name': 'Model-driven build' - 'if': "!startsWith(github.head_ref, 'release-please--')" - 'runs-on': 'ubuntu-latest' - 'timeout-minutes': 60 - 'permissions': - 'contents': 'read' - 'steps': - # A pull request checks out its merge commit and a push to main the - # squashed commit; either way the first parent is main before it. - - 'uses': 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' # v7.0.1 - 'with': - 'fetch-depth': '2' - - 'name': 'Decide whether the change reaches the model-driven build' - 'id': 'scope' - 'shell': 'bash' - 'env': - 'EVENT': '${{ github.event_name }}' - 'run': | - set -euo pipefail - mutation='false' - if [ "${EVENT}" = 'workflow_dispatch' ] || [ "${EVENT}" = 'schedule' ]; then - needed='true' - mutation='true' - elif git diff --name-only HEAD^1 HEAD | grep -qE '^(emf/|\.github/workflows/ci\.yml$)'; then - needed='true' - else - needed='false' - fi - echo "needed=${needed}" >> "$GITHUB_OUTPUT" - echo "mutation=${mutation}" >> "$GITHUB_OUTPUT" - - 'name': 'Nothing the build reads changed' - 'if': "steps.scope.outputs.needed != 'true'" - 'run': 'echo "No model-driven build: this change reaches neither emf/ nor this workflow."' - - 'uses': 'actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6' # v6.0.1 - 'if': "steps.scope.outputs.needed == 'true'" - 'with': - 'distribution': 'temurin' - 'java-version-file': 'emf/.java-version' - 'cache': 'maven' - # Tycho caches p2 bundles in the Maven repository too, so the target - # platform is part of the key. - 'cache-dependency-path': | - emf/**/pom.xml - emf/emf.target - - 'name': 'Verify' - 'if': "steps.scope.outputs.needed == 'true'" - 'working-directory': 'emf' - 'shell': 'bash' - 'env': - 'MUTATION': '${{ steps.scope.outputs.mutation }}' - 'run': | - set -euo pipefail - if [ "${MUTATION}" = 'true' ]; then - ./mvnw -B -ntp verify - else - ./mvnw -B -ntp verify -DskipPitest=true - fi - - 'name': 'Summary' - 'if': "always() && steps.scope.outputs.needed == 'true'" - 'run': 'emf/scripts/summary.sh >> "$GITHUB_STEP_SUMMARY"' - # Two jobs land here together, for issue #33. Neither gates: neither joins # `pipeline-complete`'s `needs` below, per # docs/adr/architecture/0064-a-gate-is-a-script-or-a-named-job.md's own rule diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 60eee5f33..956ee1f5b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,8 +1,7 @@ -# CodeQL static analysis: JavaScript, TypeScript, the workflow logic, and the -# model-driven implementation's Java under emf/. +# CodeQL static analysis: JavaScript, TypeScript, and the workflow logic. # -# Every language is analysed without a build (`build-mode: none`), so Tycho and -# p2 resolution can never break the scan. Generated sources and build output +# Every language is analysed without a build (`build-mode: none`), so builds +# can never break the scan. Generated sources and build output # are ignored through .github/codeql/codeql-config.yml. # # A gate, not a report. ci.yml calls this workflow on every pull request and on @@ -37,7 +36,6 @@ 'include': - 'language': 'javascript-typescript' - 'language': 'actions' - - 'language': 'java-kotlin' 'steps': - 'uses': 'actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1' # v7.0.1 diff --git a/.prettierignore b/.prettierignore index be0cd95fe..89077b69f 100644 --- a/.prettierignore +++ b/.prettierignore @@ -21,10 +21,10 @@ spec/ .github/actions/ .github/codeql/ -# The model-driven implementation's stage goldens are canonical JSON its own -# writer produces, compared byte for byte, so prettier must not reflow them. -emf/bundles/cli/src/test/resources/stages/ - # Scratch. `.tmp/` is a working directory, not a deliverable, and its contents # are whatever a tool last dropped there. .tmp/ + +# Local working artifacts, not deliverables. +.playwright-mcp/ +.scratch/ diff --git a/AGENTS.md b/AGENTS.md index 04f65d602..a410f1cc6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,9 +23,8 @@ this file stays a pointer. Everything below is repository-specific. ## What this repository is `deploy-kit` holds the deployment model (`spec/v1`), its decision record -(`docs/adr/`), and the compiler that renders it: a TypeScript production -implementation under `src/` and, for the length of a -university course, a model-driven implementation under `emf/`. Start at +(`docs/adr/`), and the compiler that renders it: a TypeScript implementation +under `src/`. Start at [`README.md`](README.md) for the shape of the model, or [`docs/adr/README.md`](docs/adr/README.md) for why each rule is what it is. @@ -46,10 +45,6 @@ every rule a tool enforces on it. - Vitest for the suite, ESLint (`strictTypeChecked`, with type information) and Prettier for style, dependency-cruiser for the module graph, Stryker for mutation testing. -- `emf/` is a second, separate stack: Maven and Tycho on JDK 21, building Ecore, Xtext, OCL, QVT-Operational and - Acceleo. It has its own `AGENTS.md` equivalent in - [`emf/docs/architecture.md`](emf/docs/architecture.md); this file only - routes an agent into it, per [the parity contract](#the-model-driven-implementation-under-emf). ## Setup @@ -107,7 +102,7 @@ Coverage is a ratchet ([0063](docs/adr/architecture/0063-coverage-and-mutation-are-ratchets.md)): the thresholds in `vitest.config.ts` sit on what the suite reaches, over an explicit include list, and only ever rise. Mutation testing holds the same shape with a break -score in `stryker.config.json`. Neither covers `emf/`, which measures itself. +score in `stryker.config.json`. ## Code style @@ -138,11 +133,10 @@ tool runs it. enforcement. Changing what `spec/v1` says the model means. Anything that touches release, publishing or rulesets. - **Always:** land a model change in TypeScript and in the oracle files it - affects, in one pull request. `emf/` follows in a pull request of its own, - held to the same oracle files by its own build. Check both ADR registers - before taking a number. -- **Never:** generate one implementation from the other, regenerate an oracle - file in CI, or add a root dependency on anything under `emf/`. Push to + affects, in one pull request. Check the ADR register before taking a + number. +- **Never:** regenerate an oracle + file in CI. Push to `main` or force-push a shared branch. Edit a version or `CHANGELOG.md` by hand. Supersede an ADR or annotate it with an amendment note: a decision that changes is rewritten, in its one record, in the pull request that @@ -193,7 +187,7 @@ above instead of restating them. | skill | what it does | |---|---| -| [`adr`](.agents/skills/adr/SKILL.md) | Writes a decision record to this repository's own ADR contract: the right domain directory, the next estate-wide number (checking both registers while `emf/` exists), the frontmatter, premises only in `rests-on`, an Alternatives table, the register row, and an anchor that resolves. | +| [`adr`](.agents/skills/adr/SKILL.md) | Writes a decision record to this repository's own ADR contract: the right domain directory, the next estate-wide number, the frontmatter, premises only in `rests-on`, an Alternatives table, the register row, and an anchor that resolves. | | [`spec-change`](.agents/skills/spec-change/SKILL.md) | Edits a spec chapter as one change: its anchors, the ADRs that point at it, `CONTEXT.md`'s vocabulary, the worked examples, the rendered trees, the oracle files, the diagrams, and both implementations' declarations. | | [`gate-triage`](.agents/skills/gate-triage/SKILL.md) | Goes from a failing CI job or a quoted rule id to its ledger row and the ADR that decided it, so a red gate resolves to the document that explains it rather than a guess. | | [`new-rule`](.agents/skills/new-rule/SKILL.md) | Adds a rule ledger row, its enforcement and a failing fixture that proves it, in one change, per [0066](docs/adr/architecture/0066-every-enforced-rule-has-an-id-a-row-and-a-fixture.md). | @@ -252,48 +246,18 @@ both. See [`docs/agents/domain.md`](docs/agents/domain.md). structure, normative for code. - [`docs/architecture-rules.md`](docs/architecture-rules.md) and [`docs/requirements.md`](docs/requirements.md): the rule ledger and the - behaviour ledger, two different questions kept in two different documents. - -## The model-driven implementation under `emf/` - -The MDE course requires the compiler to be built with Ecore, Xtext, OCL, -QVT-Operational and Acceleo, so `emf/` holds the model-driven implementation: -a second, hand-written Java implementation beside the TypeScript production -implementation (Maven and Tycho, JDK 21, no Eclipse IDE to build, but -loadable in Eclipse for the course's examiners). A model change lands in -TypeScript first, and `emf/` catches up in a pull request of its own, held to -the same oracle files: - -- **The root stays TypeScript.** Every pom, module, check, ledger and - decision of the Java side lives under `emf/`. The root references it only - from CI (the `emf` job, which runs the build with its tests and coverage gate - on every change to `emf/`, its mutation gate nightly, and is needed by no - gate; the `emf` ADR lint step; and CodeQL's `java-kotlin` entry), `test/emf-wiring.test.ts` - with its ledger rows, the `emf` domain in `scripts/lint-adrs.ts` and its test, the release-please and Renovate - configuration, and - [`docs/architecture.md#the-parity-contract`](docs/architecture.md#the-parity-contract). -- **Never generate one implementation from the other.** Both are tested, - separately, against committed oracle files under `spec/v1/examples/`. -- **A model change lands in TypeScript first.** `emf/` may trail `main` between - catch-ups, and its `OracleDistanceTest` shows how far; the links, meaning - and codes lints skip it. -- EMF decisions live in [`emf/docs/adr/`](emf/docs/adr/README.md), numbered - from the root's sequence. Check both registers before taking a number, and - lint with `node scripts/lint-adrs.ts emf`. + behaviour ledger, two different questions kept in two different documents.## MDE coursework material + +`docs/mde/` holds a university course's reports, frozen as delivered: one +directory per task, plus [`docs/mde/README.md`](docs/mde/README.md), which +says which directory mirrors which task. The course's own assignment text +(`assignment.md`, `practicals.md`) and the course-material submodule are +retired later, on #354, once the grade is recorded. `deploy-config-schema` is the repository this one replaced. `deploy-kit` renders and delivers the whole estate, so it is archived: read it for history, never as a source of truth. -## MDE coursework material - -`docs/mde/` holds a university course's reports: one directory per task, plus -[`docs/mde/assignment.md`](docs/mde/assignment.md), the course's own task text, -which says what each task requires and hands in, and -[`docs/mde/practicals.md`](docs/mde/practicals.md), what each practical session -asks. [`docs/mde/README.md`](docs/mde/README.md) says which directory mirrors -which task. - The course's own hand-outs (the lecture decks, the background reading and the index over them) are **not in this repository**. They are third-party works, so they live in the private repository `JorisJonkers-dev/mde-course-material`, diff --git a/CONTEXT.md b/CONTEXT.md index 568bf83bf..ea28e0c25 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -27,11 +27,8 @@ and *layer 3* for its members. **Metamodel**: the definition of the language a model is written in, and nothing else. A metamodel is a model whose instances are models, so the word is never used for a layer, a document, an abstraction level or the pipeline as a -whole. The production implementation declares its languages as Zod schemas in -`src/model/`; -the model-driven implementation under `emf/` has two hand-written Ecore -metamodels, a source and a target, and generates the Deliverable Set as files -with no metamodel of its own. One word, `metamodel`, unhyphenated. +whole. The implementation declares its languages as Zod schemas in +`src/model/`. One word, `metamodel`, unhyphenated. **Project Intent**: layer 1. What a project's repository authors by hand: requirements, never mechanisms. Two kinds of file, a project file and one env file @@ -789,10 +786,6 @@ for a DNS name, an ADR decision domain, and the core ring of the compiler's hexagon. **Bootstrap.** The bootstrap set and the bootstrap order, and nothing else. -The first build of the model-driven implementation under `emf/` is the **EMF -scaffold** (its Maven build, gates and CI job, with no EMF dependency), and its -first change that depends on the modelling tools is the **walking skeleton**, -which proves each tool runs headless. **Config.** Avoid. Env files carry *configuration*; the platform's facts and policies are *Platform Intent*; an Application's authored document is *Project Intent*. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9c50ed324..2cf8ec322 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,8 +34,7 @@ document or one gate. A change is bigger than that shape when it: - adds a gate (its npm script and its CI job, in the same pull request; [0064](docs/adr/architecture/0064-a-gate-is-a-script-or-a-named-job.md)), or - changes what `spec/v1` says the model means, in which case it lands with - the ADR that decides it, in TypeScript first (`emf/` catches up in a pull - request of its own), and with every oracle file the change touches. + the ADR that decides it and with every oracle file the change touches. `AGENTS.md`'s Boundaries section states which of these an agent may do on its own and which need to be asked about first. diff --git a/README.md b/README.md index 870c00114..aacebea95 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,6 @@ lands, the **compiler** that turns that model into deployable artifacts. | [`spec/v1/diagrams/`](spec/v1/diagrams/README.md) | One drawn diagram per chapter, as an SVG with the editable draw.io diagram embedded. One palette; colour carries the layer. | | [`spec/v1/examples/minimal/`](spec/v1/examples/minimal/README.md) | The smallest complete Application: one project, one Application, one Process, 31 authored lines reaching 12 objects. | | [`spec/v1/examples/`](spec/v1/examples) | Worked examples: real Applications from this estate, written in the model. | -| [`emf/`](emf/README.md) | The model-driven implementation: a Java build on Ecore, Xtext, OCL, QVT-Operational and Acceleo, held to parity with the production implementation and deleted after the course. | | [`scripts/`](scripts/) | The gates: the ADR contract, links, manifests and layer boundaries. TypeScript that Node runs directly ([tooling](docs/architecture.md#tooling)). | ## The shape of the model diff --git a/docs/adr/README.md b/docs/adr/README.md index 5baf047f7..3d65fb693 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -35,10 +35,6 @@ resolves without knowing which domain it lands in. | [`architecture/`](architecture/README.md) | the compiler's own structure: layering, the trace, the error model, gates | `docs/architecture.md`, `docs/architecture-rules.md` | yes | | [`deferred/`](deferred/README.md) | co-testing and multi-cluster estates, parked | sections the chapters deliberately lack | no | -The model-driven implementation keeps its records at -[`emf/docs/adr/`](../../emf/docs/adr/README.md), numbered from the same sequence -and linted by the same script with `emf` as its root. - ## Premises @@ -209,7 +205,6 @@ Decisions about the compiler's own structure, not about the model; see | [0065](architecture/0065-a-behaviour-ledger-names-what-a-test-proves.md) | A behaviour ledger names every guarantee and the test that proves it, and a meta test holds the two together | settled | | [0066](architecture/0066-every-enforced-rule-has-an-id-a-row-and-a-fixture.md) | Every enforced rule has an id, a ledger row and a fixture that proves it fires, and a rule not enforced yet says so with a reason | settled | | [0067](architecture/0067-every-spec-error-code-is-proved-by-a-test.md) | Every error code the specification defines is proved by a test, or pending on the ticket that will prove it | settled | -| [0068](architecture/0068-two-implementations-meet-at-the-parity-table.md) | Two hand-written implementations meet at the oracles the parity table lists, each tree keeps its own rule for generated files, and constraint parity is checked by code | open | | [0088](architecture/0088-the-committed-schemas-and-their-corpus-are-the-contract.md) | The committed JSON Schemas and their accept/refuse corpus are the contract, and byte equality only proves the generator's output is committed | settled | | [0089](architecture/0089-the-package-ships-the-command-built-when-it-is-packed.md) | The package ships the command, built to JavaScript when it is packed, and the repository still runs its TypeScript directly | settled | diff --git a/docs/adr/architecture/0056-the-compiler-is-a-chain-of-typed-models.md b/docs/adr/architecture/0056-the-compiler-is-a-chain-of-typed-models.md index b869c1df8..4a0705c62 100644 --- a/docs/adr/architecture/0056-the-compiler-is-a-chain-of-typed-models.md +++ b/docs/adr/architecture/0056-the-compiler-is-a-chain-of-typed-models.md @@ -92,5 +92,3 @@ move: a day. Becomes irreversible once: an out-of-tree adapter imports a fixture, and one new row forbids a step importing another step. - `docs/architecture.md#layers` and `#ports` are rewritten to the chain in the same slice. -- The model-driven implementation shares the mapping names and nothing else - ([0068](0068-two-implementations-meet-at-the-parity-table.md)). diff --git a/docs/adr/architecture/0062-tests-run-in-process-on-vitest.md b/docs/adr/architecture/0062-tests-run-in-process-on-vitest.md index 076605546..8ec5194f0 100644 --- a/docs/adr/architecture/0062-tests-run-in-process-on-vitest.md +++ b/docs/adr/architecture/0062-tests-run-in-process-on-vitest.md @@ -9,9 +9,7 @@ rests-on: ["0001"] # Tests run in-process on Vitest, and the tooling is TypeScript that Node runs directly -This decision covers the repository root. The model-driven implementation -under `emf/` is tested with JUnit through Maven, inside `emf/` -([0068](0068-two-implementations-meet-at-the-parity-table.md)). +This decision covers the repository root. ## Rests on Every gate this repository runs can be exercised in-process by one test runner diff --git a/docs/adr/architecture/0063-coverage-and-mutation-are-ratchets.md b/docs/adr/architecture/0063-coverage-and-mutation-are-ratchets.md index 70d87165e..e17200c39 100644 --- a/docs/adr/architecture/0063-coverage-and-mutation-are-ratchets.md +++ b/docs/adr/architecture/0063-coverage-and-mutation-are-ratchets.md @@ -178,6 +178,6 @@ Undo cost today: numbers in two config files. Becomes irreversible once: never. - One top-level statement is the smallest share a shard takes, so a change that re-tests every mutant of one large statement waits on that statement. - A pull request passes the gate without a shard running; so does a push that - changes only documents, the release files or `emf/`. + changes only documents or the release files. - A mutant can sit undetected on `main` for up to a week when only a fixture, a test helper or a dependency changed. The weekly issue is where it surfaces. diff --git a/docs/adr/architecture/0067-every-spec-error-code-is-proved-by-a-test.md b/docs/adr/architecture/0067-every-spec-error-code-is-proved-by-a-test.md index 003e8bd6c..0e5fb2f88 100644 --- a/docs/adr/architecture/0067-every-spec-error-code-is-proved-by-a-test.md +++ b/docs/adr/architecture/0067-every-spec-error-code-is-proved-by-a-test.md @@ -44,9 +44,7 @@ exercising, so the two implementations meet this rule on the same codes. ## Reversibility Undo cost today: deleting one gate and its test. Becomes irreversible once: -never; the constraint parity test -([0068](0068-two-implementations-meet-at-the-parity-table.md)) reads the same -codes. +never; the tests that name a code read the same codes. ## Consequences - A change that adds a code to a chapter adds a test or a pending entry. Paid by diff --git a/docs/adr/architecture/0068-two-implementations-meet-at-the-parity-table.md b/docs/adr/architecture/0068-two-implementations-meet-at-the-parity-table.md deleted file mode 100644 index 884157656..000000000 --- a/docs/adr/architecture/0068-two-implementations-meet-at-the-parity-table.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -tier: decision -status: accepted -claim: open -owner: joris -date: 2026-09-29 -normative: docs/architecture.md#the-parity-contract -rests-on: ["0003", "0006"] ---- - -# Two hand-written implementations meet at the oracles the parity table lists, each tree keeps its own rule for generated files, and constraint parity is checked by code - -The TypeScript production implementation and the model-driven implementation -under `emf/` are both written by hand. Neither is generated from the other, and -neither is tested against the other. Each is tested on its own against the -committed oracle files the table in -[`docs/architecture.md#the-parity-contract`](../../architecture.md#the-parity-contract) -lists, with the implementation each binds; `resolved.json` binds the production -implementation only. An oracle file is reviewed by hand and never written by CI; -a tool may write a candidate. A generated file in the root tree is committed and -diff-checked in CI; the model-driven tree generates its Java and Xtext sources at -build time and commits neither. Constraint parity is a derived check: a test -lists every specification code three ways (the Complete OCL invariant named by -it, the TypeScript check named by it, the refusal fixture whose diagnostics name -it) and fails on any gap. A behaviour row that proves a production-only oracle is -marked production-only and needs no model-driven witness. A model change lands -in TypeScript and its oracle files first, and the model-driven implementation -catches up in a pull request of its own, held to the same oracles by its own -build: its tests and coverage gate run on every change to `emf/`, its mutation -gate nightly, and it is not in `Pipeline Complete`, so it may trail `main` -between catch-ups. - -## Rests on - -The layer boundaries give points where a run's state is a complete document -([0003](../model/0003-three-model-pipeline.md)), and pinned inputs make each a -function of the input ([0006](../model/0006-pinned-inputs.md)), so two -independent implementations can be held equal through committed files without -running beside each other. - -**False if:** the two disagree on a case every oracle binding both covers and no -oracle fails, or a constraint is enforced by one implementation and caught by no -check. **Settled by:** both implementations green against every oracle the table -marks as binding both, and the code parity test failing on today's gap: -`E_UNKNOWN_ENV_SCOPE` has a TypeScript check and no invariant or fixture. - -## Why - -**The course requires a second implementation.** The graded work uses Ecore, -Xtext, OCL, QVT-Operational and Acceleo, and grades the modelling artifacts as -authored work, so neither side may be generated from the other. Two -hand-written implementations can drift, so equality is proven. - -**Oracles name the side that is wrong.** A diff between two runs never does. A -committed canonical copy at each boundary lets each suite run alone. - -**The table is the contract.** A record that restated the oracle list went stale -when `resolved.json` became production-only and `effective.json` was added. -Pointing at the table keeps one list. - -**Generated files follow their tree.** A derived file that is not committed is -invisible to review; one committed but unchecked drifts. The model-driven build -regenerates its Java from the metamodel on every build, where a committed copy -would be a second, staler one -([0073](../../../emf/docs/adr/emf/0073-source-and-target-metamodels-are-hand-written.md)). - -**Names are the key for constraint parity.** The OCL names every invariant after -its code, and the TypeScript checks are one function per code with the same -name, so the three-way comparison needs no hand-kept ledger of constraints. - -## Alternatives - -| option | cost if taken | why rejected | -|---|---|---| -| Generate one implementation from the other | no structural parity tests | the course grades both as authored work, and a generated side cannot fail on its own | -| Diff the two implementations' outputs in CI | no committed intermediate files | a red diff does not say which side is wrong | -| Only the rendered tree as oracle | uses what exists | a resolution bug and a rendering bug look the same | -| A hand-written `CONS-NNN` constraint ledger | a readable register with stable ids | a third ledger duplicating what the names already say | -| Let CI refresh oracle files | no hand edits | an implementation becomes its own oracle | - -## Reversibility - -Undo cost today: the parity test and a ledger marker: an hour. Becomes -irreversible once: the model-driven implementation is deleted at its sunset, -when this record's two-implementation half goes with it -([0071](../../../emf/docs/adr/emf/0071-emf-is-coursework-scoped-and-self-contained.md)). - -## Consequences - -- An oracle file changes in the pull request that changes the behaviour it - records, the production implementation goes red until it is fixed, and the - model-driven implementation's `OracleDistanceTest` shows the gap until a - catch-up closes it. -- The behaviour ledger gains a production-only marker, and the model-driven - witness check skips rows carrying it. -- The constraint parity test is to be written, owned by joris, and fails first - on `E_UNKNOWN_ENV_SCOPE`. diff --git a/docs/adr/architecture/0088-the-committed-schemas-and-their-corpus-are-the-contract.md b/docs/adr/architecture/0088-the-committed-schemas-and-their-corpus-are-the-contract.md index 6db861552..c4a6ff049 100644 --- a/docs/adr/architecture/0088-the-committed-schemas-and-their-corpus-are-the-contract.md +++ b/docs/adr/architecture/0088-the-committed-schemas-and-their-corpus-are-the-contract.md @@ -49,9 +49,10 @@ JorisJonkers-dev/deploy-kit#223 the published Resolved Deployment schema accepted documents the model refused, and the byte check stayed green. Only a test that puts the same document to both catches that. -**Committed and hand-written, like every oracle.** A corpus regenerated by an -implementation would agree with that implementation by construction -([0068](0068-two-implementations-meet-at-the-parity-table.md)). +**Committed and hand-written, like every oracle.** An oracle file is reviewed +by hand and never written by CI; a tool may write a candidate. A corpus +regenerated by an implementation would agree with that implementation by +construction. ## Alternatives diff --git a/docs/adr/architecture/README.md b/docs/adr/architecture/README.md index 24477f2d8..fb9f917fd 100644 --- a/docs/adr/architecture/README.md +++ b/docs/adr/architecture/README.md @@ -16,8 +16,6 @@ Numbers come from the one estate-wide sequence; the register is [`../README.md`](../README.md). The scope boundary is stated in [chapter 00](../../../spec/v1/00-overview.md#programme-scope). -The records here bind the TypeScript tree. The model-driven implementation -under `emf/` decides its own structure in -[`emf/docs/adr/`](../../../emf/docs/adr/README.md), and -[0068](0068-two-implementations-meet-at-the-parity-table.md) is the contract -between the two. +The records here bind the TypeScript tree: +[`docs/architecture.md#the-oracles`](../../architecture.md#the-oracles) is the +contract between them. diff --git a/docs/adr/model/0012-shared-intent-descends-and-is-lowered.md b/docs/adr/model/0012-shared-intent-descends-and-is-lowered.md index bb8363e4a..38c062b76 100644 --- a/docs/adr/model/0012-shared-intent-descends-and-is-lowered.md +++ b/docs/adr/model/0012-shared-intent-descends-and-is-lowered.md @@ -116,5 +116,3 @@ exist under paths only some Processes hold. touching one, paid by the lowering, which grows one mapping per family. - The Effective Intent has no schema version and no digest; the pinned-input chain runs from the authored documents ([0006](0006-pinned-inputs.md)). -- Both implementations carry a lowering, held equal by the Effective Intent - oracle ([0068](../architecture/0068-two-implementations-meet-at-the-parity-table.md)). diff --git a/docs/adr/model/0113-a-privileged-role-names-the-project-that-holds-it.md b/docs/adr/model/0113-a-privileged-role-names-the-project-that-holds-it.md index 7f2346b9d..7282fde3f 100644 --- a/docs/adr/model/0113-a-privileged-role-names-the-project-that-holds-it.md +++ b/docs/adr/model/0113-a-privileged-role-names-the-project-that-holds-it.md @@ -28,7 +28,7 @@ Application under a role's id and that Application receives the role: its Process admitted to the API, its surface asked by a Canary, or its address handed out as the collector or the Secret Store. **Settled by:** the negative fixture per role in `test/model/intent-set.test.ts` -and the matching linking test in `emf/`, each refusing the reference as +and the matching linking test, each refusing the reference as unlinked when the named Project does not declare the Application. ## Why diff --git a/docs/agents/domain.md b/docs/agents/domain.md index 98c763889..2ccbef452 100644 --- a/docs/agents/domain.md +++ b/docs/agents/domain.md @@ -38,8 +38,6 @@ documentation when exploring it. Single context, one layout, no │ ├── model/ ← v1 model decisions, point at spec/v1 │ ├── architecture/ ← compiler decisions, point at docs/architecture.md │ └── deferred/ ← co-testing and retired delivery, not linted -└── emf/ ← a second implementation, with its own - docs/adr/ numbered from the same sequence ``` ## Use the glossary's vocabulary diff --git a/docs/architecture-rules/gates.md b/docs/architecture-rules/gates.md index a45b74b1a..786235f6e 100644 --- a/docs/architecture-rules/gates.md +++ b/docs/architecture-rules/gates.md @@ -5,7 +5,7 @@ Rules on this repository's own documents and pipeline. | id | family | the rule | enforced by | proved by | |---|---|---|---|---| | RULE-049 | gates | Every decision record satisfies the frontmatter, register, citation and normative-anchor contract | `npm:lint:adrs` | [test/adr-lint-negative.test.ts](../../test/adr-lint-negative.test.ts) `missing frontmatter block` | -| RULE-050 | gates | Every relative link and heading anchor in Markdown git does not ignore, outside `emf/`, resolves | `npm:lint:links` | [test/link-contract.test.ts](../../test/link-contract.test.ts) `anchor #the-old-name not found` | +| RULE-050 | gates | Every relative link and heading anchor in Markdown git does not ignore resolves | `npm:lint:links` | [test/link-contract.test.ts](../../test/link-contract.test.ts) `anchor #the-old-name not found` | | RULE-051 | gates | Every rendered example object validates against its pinned Kubernetes or CRD schema | `npm:lint:manifests` | [test/manifest-contract.test.ts](../../test/manifest-contract.test.ts) `no rendered examples found` | | RULE-052 | gates | Every behaviour ledger row sits in an area file, parses, carries an id no other row carries, names a real non-empty test, and is cited by no dangling id | `npm:lint:requirements` | [test/requirements-lint-negative.test.ts](../../test/requirements-lint-negative.test.ts) `holds a row, which belongs in an area file` | | RULE-053 | gates | Every script, path, coverage number and Node version README.md and CONTRIBUTING.md name matches the repository | `npm:lint:docs` | [test/docs-contract.test.ts](../../test/docs-contract.test.ts) `is not a script in package.json` | @@ -16,8 +16,6 @@ Rules on this repository's own documents and pipeline. | RULE-058 | gates | No em-dash enters tracked text outside `docs/mde/` and `CHANGELOG.md` | `file:test/emdash.test.ts` | [test/emdash.test.ts](../../test/emdash.test.ts) `contains an em-dash` | | RULE-059 | gates | A gate's npm script and the CI job that runs it land together, or the script is listed pending with a reason | `file:test/pipeline-wiring.test.ts` | [test/pipeline-wiring.test.ts](../../test/pipeline-wiring.test.ts) `every script either runs in some workflow` | | RULE-060 | gates | No committed secret matching the default gitleaks ruleset or this repository's own allowlist, checked locally by the same command CI runs | `npm:lint:secrets` | [test/secret-scan-contract.test.ts](../../test/secret-scan-contract.test.ts) `secret scan: could not run` | -| RULE-061 | gates | A workflow step that runs the Maven wrapper runs it in a directory holding a POM and the wrapper, and the model-driven reactor names only modules on disk | `file:test/emf-wiring.test.ts` | [test/emf-wiring.test.ts](../../test/emf-wiring.test.ts) `which names a POM that does not exist` | -| RULE-062 | gates | CodeQL analyses the model-driven implementation's Java without a build, ignoring build output and generated sources | `file:.github/codeql/codeql-config.yml` | [test/emf-wiring.test.ts](../../test/emf-wiring.test.ts) `'language': 'java-kotlin'` | | RULE-063 | gates | A CodeQL finding of any severity fails `Pipeline Complete`, unless the finding is filtered in the CodeQL configuration | `file:.github/workflows/codeql.yml` | [test/pipeline-wiring.test.ts](../../test/pipeline-wiring.test.ts) `'name': 'Fail on any finding'` | | RULE-064 | gates | A push to `main` re-tests each mutant under `src/` whose module or killing test changed since the last green `main` run, and a pull request runs none, in parallel shards, and a mutation score below the measured break threshold fails the build | `file:.github/workflows/ci.yml` | [test/mutation-contract.test.ts](../../test/mutation-contract.test.ts) `npm run test:mutation -- --incremental` | | RULE-065 | gates | Every file a pull request changes falls into a named shape bucket; a path no rule claims fails the fallback test rather than joining one silently | `file:scripts/lib/change-buckets.ts` | [test/change-buckets.test.ts](../../test/change-buckets.test.ts) `keeps every file this repository tracks inside a named bucket` | @@ -28,4 +26,3 @@ Rules on this repository's own documents and pipeline. | RULE-070 | gates | A decision record whose claim is settled carries `status: accepted`, in both registers, so the field distinguishes something | `npm:lint:adrs` | [test/adr-lint-negative.test.ts](../../test/adr-lint-negative.test.ts) `requires status accepted, got 'proposed'` | | RULE-075 | gates | `Pipeline Complete` needs the merging `mutation` job, which never skips and fails when the scope job or any mutation shard did not succeed; the shards run only where the scope job says the change reaches a mutant | `file:.github/workflows/ci.yml` | [test/pipeline-wiring.test.ts](../../test/pipeline-wiring.test.ts) `'name': 'Fail: the scope or a shard did not succeed'` | | RULE-076 | gates | Every rendered pod template meets Pod Security's `restricted` profile and the posture's read-only root filesystem, save the platform's VPN native sidecar, which is outside the posture and may add only `NET_ADMIN` and `NET_RAW`; a rendered file that does not parse fails rather than passing unread; the check runs in-process, so a machine without kubeconform still runs it | `npm:lint:manifests` | [test/manifest-contract.test.ts](../../test/manifest-contract.test.ts) `refuses a pod that breaks the restricted profile` | -| RULE-077 | gates | No workflow, and not the committed `emf/.mvn/maven.config`, passes the model-driven build's `quick` profile, which skips the coverage floor, PIT and the Spotless check for a local edit, so CI keeps every gate | `file:test/emf-wiring.test.ts` | [test/emf-wiring.test.ts](../../test/emf-wiring.test.ts) `passes the quick profile to the model-driven build` | diff --git a/docs/architecture.md b/docs/architecture.md index 62054c627..9c9b1d4f9 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -183,7 +183,7 @@ that will exercise it, and no code a chapter does not define is used in the tree; `npm run lint:codes` holds both ([0067](adr/architecture/0067-every-spec-error-code-is-proved-by-a-test.md)). A test exercises a code by naming it, in a TypeScript test or a refused case's -committed `diagnostics.json`; `emf/` is out of its scope. +committed `diagnostics.json`. The CLI renders diagnostics for a human by default, emits the array verbatim under `--json`, and maps failure classes to distinct exit statuses. @@ -194,8 +194,7 @@ A file a tool derives from another committed file is committed too, and CI regenerates it and fails on a diff, from the pull request that brings its generator: the JSON Schema derived from the metamodel, and the diagnostic catalogue. A reader sees the artifact without running anything, and a change -to the source cannot land without the artifact that depends on it -([0068](adr/architecture/0068-two-implementations-meet-at-the-parity-table.md)). +to the source cannot land without the artifact that depends on it. An oracle file is the opposite. The rendered example trees, `intent.json`, `resolved.json`, `dependencies.json`, `diagnostics.json` and the descriptor are @@ -302,59 +301,38 @@ CRD schemas, so a file that parses but cannot apply fails the build. Every gate carries negative fixtures. A check that has only ever run against a clean tree is untested: nothing proves it would fail. -## The parity contract - -This compiler has two implementations. The TypeScript code under `src/` is the -**production implementation**. The model-driven engineering course this -repository is coursework for requires Ecore, Xtext, OCL, QVT-Operational and -Acceleo, so a **model-driven implementation** in Java lives under -[`emf/`](../emf/README.md) -until its sunset condition holds -([0068](adr/architecture/0068-two-implementations-meet-at-the-parity-table.md)). -Everything about that implementation, its build, its checks and its decisions, -lives inside `emf/`. What lives here is the contract both implementations -answer to, because the contract outlives the model-driven implementation. - -**The contract holds with a lag.** A model change lands in TypeScript and its -oracle files first, and `emf/` catches up in a pull request of its own. Its -build runs its tests and coverage gate on every change to `emf/`, and its -mutation gate nightly; it is not in `Pipeline Complete`, so `emf/` may trail -`main` between catch-ups, and its `OracleDistanceTest` reports how far. - -Neither implementation is generated from the other, and neither is the oracle -for the other. Each is tested on its own against committed oracle files, and -agreement between the two follows from both agreeing with the oracle. - -The two are compared on what the project proposal names: validation, dependency -resolution, errors and generated resources. They are not required to agree on -anything else. In particular their intermediate models differ: the production -implementation keeps the Resolved Deployment and the typed object model its -adapters build as two things, while the model-driven implementation has one -target metamodel holding both, because a model-to-text template reads one model. - -| oracle | where | compared as | binds | -|---|---|---|---| -| the parsed Project Intent (validation) | `spec/v1/examples//expected/intent.json` | canonical JSON, byte for byte | both | -| the diagnostics of a refused case (errors) | `.diagnostics.json` beside the refused input, or the refused set of documents, in `refusals/` or `negative/` | a set of `(code, document, path)` triples | both | -| the resolved dependency edges (dependency resolution) | `spec/v1/examples//expected/dependencies.json` | canonical JSON, byte for byte | both | -| the Deliverable Set (generated resources) | `spec/v1/examples//rendered/` | the existing golden tree, byte for byte | both | -| the source metamodel's **authored** structure | `spec/v1/examples/expected/descriptor.json` | canonical JSON, byte for byte | both | -| the Effective Intent (the lowering) | `spec/v1/examples//expected/effective.json` | canonical JSON, byte for byte | both | -| the Resolved Deployment | `spec/v1/examples//expected/resolved.json` | canonical JSON, byte for byte | production only | -| the diagnostics of a file the reader refuses (code `schema`) | `.diagnostics.json` beside the refused input, in `schema-refusals/` | a set of `(code, document, path)` triples | production only | - -**A schema refusal binds the production implementation only.** The -model-driven implementation reads a file through a grammar, which refuses a -token where the production reader names the field the token belongs to, so the -two agree on the code and not on the place +## The oracles + +The compiler is tested against committed oracle files, one per boundary a run +crosses. The implementation is never its own oracle: a test compares a run +against the committed file, and a change to the source cannot land quietly +redesigning what a stage writes. + +The project proposal names what an oracle covers: validation, dependency +resolution, errors and generated resources. + +| oracle | where | compared as | +|---|---|---| +| the parsed Project Intent (validation) | `spec/v1/examples//expected/intent.json` | canonical JSON, byte for byte | +| the diagnostics of a refused case (errors) | `.diagnostics.json` beside the refused input, or the refused set of documents, in `refusals/` or `negative/` | a set of `(code, document, path)` triples | +| the resolved dependency edges (dependency resolution) | `spec/v1/examples//expected/dependencies.json` | canonical JSON, byte for byte | +| the Deliverable Set (generated resources) | `spec/v1/examples//rendered/` | the existing golden tree, byte for byte | +| the source metamodel's **authored** structure | `spec/v1/examples/expected/descriptor.json` | canonical JSON, byte for byte | +| the Effective Intent (the lowering) | `spec/v1/examples//expected/effective.json` | canonical JSON, byte for byte | +| the Resolved Deployment | `spec/v1/examples//expected/resolved.json` | canonical JSON, byte for byte | +| the diagnostics of a file the reader refuses (code `schema`) | `.diagnostics.json` beside the refused input, in `schema-refusals/` | a set of `(code, document, path)` triples | + +**A schema refusal reports a different place than a model refusal would.** The +reader names the field the token belongs to, where a refusing grammar would +point at the token ([chapter 10](../spec/v1/10-project-intent.md#what-a-schema-refusal-reports) fixes the place). The refused cases a rule answers, in `refusals/` and -`negative/`, bind both. +`negative/`, bind the model's own behaviour exactly. **The dependency edges** are, per Application, every dependency edge after resolution: the consumer, the provider Application and Surface, the address the consumer is given, and the policy peers that allow the connection. It is the -part of resolution both implementations must agree on before either renders. +part of resolution that must settle before the render runs. The file is an object with one `applications` entry per Application, each an `id` and its `edges`; an Application with no dependency carries an empty list. The edge's own fields are fixed by the first case that has one. @@ -363,23 +341,21 @@ The edge's own fields are fixed by the first case that has one. ([chapter 10](../spec/v1/10-project-intent.md#the-effective-intent)): the authored document and the env files beside it, merged onto the Processes that hold them. It is the one oracle that covers the env files at all, because they -are not part of the document `intent.json` fixes, and it is where the two -implementations' readers meet. +are not part of the document `intent.json` fixes. **The descriptor fixes the authored shape**, which is every class a document holds. `env` is the one feature it leaves out of a class: an env file is a directory beside the document rather than a key in it, so its own classes are -listed and the feature that would carry them is not. A shape a transformation writes and nobody authors is left out of it: the -Effective Intent's Project and Application are the two today -([0012](adr/model/0012-shared-intent-descends-and-is-lowered.md)), and what holds -them equal is the same thing that holds every other stage equal, the oracles -downstream of the lowering. An implementation that declared a lowered class where -the other did not would still render the same tree or fail the rendered oracle. - -**The canonical writers** are `src/infrastructure/canonical-json.ts` and -`emf/bundles/metamodel`'s `CanonicalJson`, held to the same cases. An oracle file is exactly -its canonical text, with no final newline, and a test fails any committed oracle -that is not byte-identical to its own canonicalisation. +listed and the feature that would carry them is not. A shape a transformation +writes and nobody authors is left out of it: the Effective Intent's Project and +Application are the two today +([0012](adr/model/0012-shared-intent-descends-and-is-lowered.md)), and what +holds them equal is the same thing that holds every other stage equal, the +oracles downstream of the lowering. + +**The canonical writer** is `src/infrastructure/canonical-json.ts`. An oracle +file is exactly its canonical text, with no final newline, and a test fails any +committed oracle that is not byte-identical to its own canonicalisation. **Canonical JSON** is RFC 8785 (JSON Canonicalization Scheme): keys sorted, numbers in their shortest form, no insignificant whitespace. An absent @@ -399,44 +375,35 @@ refused single file names itself. **The descriptor** lists every class of the source metamodel (Project Intent and the Platform Intent it is resolved against) with its features, each feature's type and multiplicity, and every closed vocabulary with its literals. -Target structures are compared through what they generate, not structurally. -The TypeScript side builds it from the Zod schemas with Zod's native -`z.toJSONSchema()` and a normaliser; the descriptor's shape is fixed here, not -by either source format: +The descriptor's shape is fixed here, not by the format that produces it: - `classes`, sorted by name. Each carries its `name` and its `features`, sorted by name; a class the language writes as one word carries that word as `scalar`. - A **feature** carries its `name`, the `types` it admits sorted by name, whether it is `required`, whether it holds `many` values, whether it is a - `map` keyed by string, and whether it is a `reference`: a name the document - writes that links to a model element, whose one type is the element's class. - A map also names what one of its entries is, as `entry`, so a reference can - point at a map's entries. A type is a class name, a vocabulary name, or one of - `string`, `int` and `boolean`. + `map` keyed by string, and whether it is a + `reference`: a name the document writes that links to a model element, whose + one type is the element's class. A map also names what one of its entries is, + as `entry`, so a reference can point at a map's entries. A type is a class + name, a vocabulary name, or one of `string`, `int` and `boolean`. - A union is not a class: a feature whose value may be one of several classes - names them all, so an abstract class on one side and a union on the other - describe the same model. + names them all, so an abstract class and a union on one side describe the + same model. - `vocabularies`, sorted by name, each with its `literals` in the order the model declares them. -**Constraint parity is checked by code, not kept in a ledger.** Every model -constraint is named by the diagnostic code it emits: the Complete OCL invariant -carries the code as its name, and the TypeScript check is one function per code -with the same name. A parity test lists every code three ways (the invariant, -the check, and the refused fixture whose diagnostics name it) and fails on any -gap ([0068](adr/architecture/0068-two-implementations-meet-at-the-parity-table.md)). +**Every model constraint is named by the diagnostic code it emits**, and the +check for a code is one function carrying the code's name, so a code's +enforcement is findable from the code alone. **Behaviour rows.** A row of the [behaviour ledger](requirements.md) whose -behaviour is the model's own (parse, validate, resolve, render) is proved in -both implementations. The row names the TypeScript test; the model-driven witness -for the same id is listed inside `emf/`, and `emf/`'s own gate fails when a model -row has no witness there. +behaviour is the model's own (parse, validate, resolve, render) is proved by +the test the row names. -**Whichever implementation lands a case first commits its reviewed oracle, -and the other matches it.** The first oracles are written by hand: `minimal`'s -parsed intent and dependency edges, and `minimal`'s and `knowledge`'s -`resolved.json` beside the metamodel that gives them a shape. +A case arrives with its reviewed oracle, written by hand: `minimal`'s parsed +intent and dependency edges, and `minimal`'s and `knowledge`'s `resolved.json` +beside the metamodel that gives them a shape. A `resolved.json` is held to the chapter as well as to the metamodel. [Chapter 20](../spec/v1/20-resolved-deployment.md#worked-example-knowledges-projection)'s @@ -446,15 +413,15 @@ value. The chapter is the readable half and the oracle is the complete one; neither may say something the other contradicts. An oracle file changes in the pull request that changes the behaviour it -records, and the TypeScript implementation goes red until it is fixed. CI -never regenerates an oracle file from either implementation: a tool may write a -candidate, and the committed file is the reviewed copy of it. A -case without every oracle file is not yet a parity case, and the ledger that -lists cases says so rather than skipping it silently. +records, and the implementation goes red until it is fixed. CI never +regenerates an oracle file: a tool may write a candidate, and the committed +file is the reviewed copy of it. A case without every oracle file it needs is +not yet a complete case, and the ledger that lists cases says so rather than +skipping it silently. ## Gates -Twenty gates hold the structure, and each exists because its absence has already +Nineteen gates hold the structure, and each exists because its absence has already cost something in the generation this compiler replaces. Gates are grouped into CI jobs, aggregated by one required check that fails when any gate job fails, is cancelled, or is skipped @@ -483,18 +450,13 @@ proves the two never drift apart. | package contents | `node scripts/check-package-contents.ts` | `npm pack` shipping a file outside `docs/adr/`, `spec/` and the JavaScript under `dist/`, the boundary the package's `files` field states but does not enforce on its own | | actionlint | a pinned `actionlint` binary | invalid workflow syntax, an undefined `${{ }}` expression, a shellcheck finding inside a `run:` step | | secret scan | `npm run lint:secrets` | a committed secret matching the default ruleset, or this repository's own allowlist entries | -| code scanning | CodeQL, called from `ci.yml` as the `codeql` job | any finding, of any severity, in JavaScript, TypeScript, workflow logic or the Java under `emf/`; a wrong one is filtered in `.github/codeql/codeql-config.yml` with its reason | -| model-driven build | `./mvnw -B -ntp verify` in `emf/` | every gate the [model-driven implementation](../emf/docs/architecture.md#gates) holds itself to: toolchain versions, compiler warnings, tests, coverage and mutation floors, formatting | +| code scanning | CodeQL, called from `ci.yml` as the `codeql` job | any finding, of any severity, in JavaScript, TypeScript or the workflow logic; a wrong one is filtered in `.github/codeql/codeql-config.yml` with its reason | Decisions, links, manifests, requirements, rules, codes, docs, agents and meaning share one CI job, `contracts`: all nine check a document against a rule rather than code against a graph. Boundaries runs alone as `architecture`, because it is the one gate that speaks for `docs/architecture.md` itself rather than for a document beside it. -The model-driven build runs alone as `emf`, on its own JDK and Maven: its -tests and coverage gate on every change to `emf/` or the workflow, and its -mutation gate nightly and on a dispatch. It is not in `Pipeline Complete`, so -it gates nothing, and it is deleted with `emf/`. Every rule these gates enforce is written down once, with a greppable id, in the [rule ledger](architecture-rules.md) diff --git a/docs/mde/README.md b/docs/mde/README.md index 389302afb..f82c08695 100644 --- a/docs/mde/README.md +++ b/docs/mde/README.md @@ -15,13 +15,13 @@ One directory per deadline, named after the course's own task numbering. | Directory | Due | Deliverable | Overleaf project | State | |---|---|---|---|---| | [`task-0-proposal/`](task-0-proposal/) | approved | Task 0 — project description, the proposal that must be approved before work starts | `6aa2ba0c3920baa59ec20901` | re-mirrored 2026-09-16, after the delivery and output-layout corrections in #56 | -| [`task-1-metamodelling/`](task-1-metamodelling/) | 2026-09-25 | Task 1 — domain analysis and modelling decisions for the two metamodels, **Project Intent** (source) and **Resolved Deployment** (target), their diagrams and example models | `6aaa9f1d3920baa59ec267f7` | drafted; both metamodels exist as Ecore under [`emf/bundles/metamodel/model/`](../../emf/bundles/metamodel/model/) | -| [`task-2-transformations/`](task-2-transformations/) | 2026-10-16 | Task 2 — the model-to-model transformation from **Project Intent** (resolved against the Platform document and the pinned inputs) to **Resolved Deployment**, its rules and limitations, evidence it runs | `6ad0ce4e3920baa59ec3d535` | written 2026-10-15; the transformations were [`resolution.qvto`](../../emf/bundles/resolve/model/resolution.qvto) and `estate.qvto`, which [#547](https://github.com/JorisJonkers-dev/deploy-kit/issues/547) has since removed | -| [`task-3-code-generation/`](task-3-code-generation/) | 2026-10-30 | Task 3 — the model-to-text transformation from **Resolved Deployment** to the Deliverable Set, the generated code, evidence it loads | `6ae33bae3afd0f952d331ed6` | finished 2026-11-03, after the deadline; the module is [`render.mtl`](../../emf/bundles/render/model/render.mtl) | +| [`task-1-metamodelling/`](task-1-metamodelling/) | 2026-09-25 | Task 1 — domain analysis and modelling decisions for the two metamodels, **Project Intent** (source) and **Resolved Deployment** (target), their diagrams and example models | `6aaa9f1d3920baa59ec267f7` | drafted; both metamodels exist as Ecore under [`emf/bundles/metamodel/model/`](https://github.com/JorisJonkers-dev/mde-project/tree/main/bundles/metamodel/model) | +| [`task-2-transformations/`](task-2-transformations/) | 2026-10-16 | Task 2 — the model-to-model transformation from **Project Intent** (resolved against the Platform document and the pinned inputs) to **Resolved Deployment**, its rules and limitations, evidence it runs | `6ad0ce4e3920baa59ec3d535` | written 2026-10-15; the transformations were [`resolution.qvto`](https://github.com/JorisJonkers-dev/mde-project/blob/main/bundles/resolve/model/resolution.qvto) and `estate.qvto`, which [#547](https://github.com/JorisJonkers-dev/deploy-kit/issues/547) has since removed | +| [`task-3-code-generation/`](task-3-code-generation/) | 2026-10-30 | Task 3 — the model-to-text transformation from **Resolved Deployment** to the Deliverable Set, the generated code, evidence it loads | `6ae33bae3afd0f952d331ed6` | finished 2026-11-03, after the deadline; the module is [`render.mtl`](https://github.com/JorisJonkers-dev/mde-project/blob/main/bundles/render/model/render.mtl) | Each task delivers an EMF artefact, and the table above says which directory documents it. What the artefact *is* lives in -[`emf/docs/architecture.md`](../../emf/docs/architecture.md#modules), whose +[`emf/docs/architecture.md`](https://github.com/JorisJonkers-dev/mde-project/blob/main/docs/architecture.md#modules), whose module table carries the same task numbering, so the two are read together and neither restates the other. diff --git a/docs/mde/assignment.md b/docs/mde/assignment.md index ced5e31ab..adea9567d 100644 --- a/docs/mde/assignment.md +++ b/docs/mde/assignment.md @@ -120,7 +120,7 @@ settle doubts. The report must stand on its own, carry the four parts above in roughly those proportions, and discuss limitations and reflect on the choices. Mirror: [`task-1-metamodelling/`](task-1-metamodelling/). The Ecore files are -under [`emf/bundles/metamodel/model/`](../../emf/bundles/metamodel/model/); the +under [`emf/bundles/metamodel/model/`](https://github.com/JorisJonkers-dev/mde-project/tree/main/bundles/metamodel/model); the hand-in zip is built by [`task-1-metamodelling/handin/build.py`](task-1-metamodelling/handin/build.py). diff --git a/docs/mde/practicals.md b/docs/mde/practicals.md index 19547b514..93b106580 100644 --- a/docs/mde/practicals.md +++ b/docs/mde/practicals.md @@ -5,7 +5,7 @@ assignment page states it. They are exercises and are separate from the project: each is a one-point `.zip` upload. They matter here because each one walks through a tool the project uses. Session 5 is the QVT Operational tooling that Task 2 is built with, session 6 the Acceleo 4 tooling of Task 3, and -sessions 1 and 3 are the Ecore and Xtext workflow behind [`emf/`](../../emf/). +sessions 1 and 3 are the Ecore and Xtext workflow behind [`emf/`](https://github.com/JorisJonkers-dev/mde-project). The project's own tasks are in [`assignment.md`](assignment.md). The lecture each session follows, and its slides, recording and reading, are indexed in diff --git a/docs/requirements.md b/docs/requirements.md index 9c993db17..d4f3aec86 100644 --- a/docs/requirements.md +++ b/docs/requirements.md @@ -28,7 +28,7 @@ files. Each file holds the same three-column table. | file | what goes there | |---|---| -| [`repository.md`](requirements/repository.md) | this repository's own tree: decision records, links, documents, module boundaries, the test harness, coverage, the ledgers, specification codes, the `emf/` wiring | +| [`repository.md`](requirements/repository.md) | this repository's own tree: decision records, links, documents, module boundaries, the test harness, coverage, the ledgers, specification codes | | [`pipeline.md`](requirements/pipeline.md) | a pull request, a push to `main` or a release: titles and commits, the pull request report, release candidates, the published package, mutation testing | | [`intent.md`](requirements/intent.md) | the authored documents before resolution: parsing, the metamodel and its JSON Schemas, refusals, env files, Shared Intent, canonical oracle JSON | | [`resolution.md`](requirements/resolution.md) | layer 2 as a whole: the Resolved Deployment, Application revisions, Aliases and Stable Addresses, the foundation, the render of the composed union | diff --git a/docs/requirements/repository.md b/docs/requirements/repository.md index 14e2ba812..1612fe685 100644 --- a/docs/requirements/repository.md +++ b/docs/requirements/repository.md @@ -1,11 +1,11 @@ # Repository contracts -A behaviour of this repository's own tree: its decision records, links, documents, module boundaries, test harness, coverage, ledgers, specification codes and the `emf/` wiring. +A behaviour of this repository's own tree: its decision records, links, documents, module boundaries, test harness, coverage, ledgers and specification codes. | id | a contributor or a consumer can rely on | proved by | |---|---|---| -| REQ-001 | Every decision record under `docs/adr/` and `emf/docs/adr/` satisfies its frontmatter, register and citation contract, and no number is used in both | [test/adr-contract.test.ts](../../test/adr-contract.test.ts) | -| REQ-002 | Every relative link and heading anchor in Markdown git does not ignore, outside `emf/`, resolves to a real target | [test/link-contract.test.ts](../../test/link-contract.test.ts) | +| REQ-001 | Every decision record under `docs/adr/` satisfies its frontmatter, register and citation contract | [test/adr-contract.test.ts](../../test/adr-contract.test.ts) | +| REQ-002 | Every relative link and heading anchor in Markdown git does not ignore resolves to a real target | [test/link-contract.test.ts](../../test/link-contract.test.ts) | | REQ-003 | Every rendered Kubernetes manifest in the worked examples validates against its pinned schema | [test/manifest-contract.test.ts](../../test/manifest-contract.test.ts) | | REQ-004 | The compiler's layer boundaries and module reachability are enforced on the dependency graph, not on review alone | [test/boundary-contract.test.ts](../../test/boundary-contract.test.ts) | | REQ-006 | No em-dash enters tracked text outside `docs/mde/` and `CHANGELOG.md` | [test/emdash.test.ts](../../test/emdash.test.ts) | @@ -15,7 +15,6 @@ A behaviour of this repository's own tree: its decision records, links, document | REQ-011 | Every script, path, coverage number and Node version README.md and CONTRIBUTING.md name matches the repository they describe | [test/docs-contract.test.ts](../../test/docs-contract.test.ts) | | REQ-013 | `npm run verify` runs the same secret scan CI runs, failing on a committed secret rather than only after a push | [test/secret-scan-contract.test.ts](../../test/secret-scan-contract.test.ts) | | REQ-014 | Every rule this repository enforces has a ledger row with a greppable id and a fixture that proves it fires, and a rule not enforced yet is listed as pending with a ticket and a reason rather than dropped | [test/rules-contract.test.ts](../../test/rules-contract.test.ts) | -| REQ-015 | The model-driven build CI runs is the build in the tree: no workflow runs the Maven wrapper where there is no build, the reactor names no missing module, and CodeQL scans its Java | [test/emf-wiring.test.ts](../../test/emf-wiring.test.ts) | | REQ-016 | A code scanning finding of any severity fails `Pipeline Complete`, so it blocks the merge rather than only landing in the Security tab | [test/pipeline-wiring.test.ts](../../test/pipeline-wiring.test.ts) | | REQ-017 | Every error code the specification defines is exercised by a test, or pending on the ticket that will exercise it, and no code the specification does not define is used in the tree | [test/codes-lint.test.ts](../../test/codes-lint.test.ts) | | REQ-018 | The compiler's inner rings cannot read the environment, the clock, randomness, a child process or the filesystem synchronously, and only `src/cli/boundary.ts` exits the process or writes output | [test/seams.test.ts](../../test/seams.test.ts) | diff --git a/emf/.gitignore b/emf/.gitignore deleted file mode 100644 index becc17471..000000000 --- a/emf/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Eclipse metadata m2e writes when the modules are imported; the Maven build is the source of truth. -.project -.classpath -.settings/ diff --git a/emf/.java-version b/emf/.java-version deleted file mode 100644 index aabe6ec39..000000000 --- a/emf/.java-version +++ /dev/null @@ -1 +0,0 @@ -21 diff --git a/emf/.mvn/maven.config b/emf/.mvn/maven.config deleted file mode 100644 index 318d96975..000000000 --- a/emf/.mvn/maven.config +++ /dev/null @@ -1,2 +0,0 @@ --Daether.syncContext.named.factory=file-lock --Daether.syncContext.named.nameMapper=file-gav diff --git a/emf/.mvn/wrapper/maven-wrapper.properties b/emf/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index a3c407ffc..000000000 --- a/emf/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,4 +0,0 @@ -wrapperVersion=3.3.4 -distributionType=only-script -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.16/apache-maven-3.9.16-bin.zip -distributionSha256Sum=5af3b743dd8b876b5c45da33b676251e5f1687712644abb4ee519ca56e1d89ce diff --git a/emf/README.md b/emf/README.md deleted file mode 100644 index e324241b2..000000000 --- a/emf/README.md +++ /dev/null @@ -1,135 +0,0 @@ -# emf: the model-driven implementation - -Everything under this directory is the model-driven implementation of the -deploy-kit compiler, the second implementation beside the TypeScript production -implementation, built with the Eclipse Modeling Framework toolchain the -model-driven engineering course at the University of Twente requires: Ecore, -Xtext, OCL, QVT-Operational and Acceleo. It is **deprecated from the day it -lands**: it exists for the length of the course and is deleted when its sunset -condition holds -([0071](docs/adr/emf/0071-emf-is-coursework-scoped-and-self-contained.md)). - -The repository root stays TypeScript. Nothing outside `emf/` builds, imports or -depends on anything inside it. The Maven build, its modules, its checks, its -ledgers and its decisions all live here, so the sunset is deleting this -directory and the few root lines that name it, listed in -[the architecture](docs/architecture.md#scope-and-sunset). - -The one thing this implementation shares with the production implementation is the -[parity contract](../docs/architecture.md#the-parity-contract): the committed -oracle files under `spec/v1/examples/` that both are tested against, separately. - -| read | for | -|---|---| -| [docs/architecture.md](docs/architecture.md) | the structure: toolchain, modules, how each stage meets the contract | -| [docs/adr/README.md](docs/adr/README.md) | the decisions that shaped it, and the register | -| [docs/benchmarks.md](docs/benchmarks.md) | how long each stage takes, and the lowering in QVTo against an ATL port of it | - -## Where each artefact lives - -This table says which artefact lives where and which course task grades -it, so the split tree -([0081](docs/adr/emf/0081-bundles-and-tests-are-separate-tiers.md)) -answers the navigation question without a search. - -| artefact | lives in | graded in | how an examiner opens it | -|---|---|---|---| -| the Ecore metamodels (source, target and pinned inputs) and their OCL | `emf/bundles/metamodel` | Task 1 | imported in step 2; `model/project-intent.ocl` validates `model/cache.xmi` clean and refuses `model/cache-continuous.xmi`, as step 3 describes | -| the Xtext grammars and generated editor | `emf/bundles/syntax` | Task 1 | imported in step 2; the generated editor reports OCL constraint violations while a source file is edited in it | -| the QVTo transformations | `emf/bundles/resolve` | Task 2 | imported in step 2; `resolution.launch` runs the resolution on `minimal`, as step 4 describes | -| the Acceleo templates | `emf/bundles/render` | Task 3 | imported in step 2; `render.launch` runs them, as step 4 describes | -| the pipeline entry point | `emf/bundles/cli` | Task 1 onward | imported in step 2, alongside the rest | -| the parity suite | `emf/tests/parity` | no task grades it | it is Maven-only; no examiner opens it | - -## Building - -```sh -cd emf -./mvnw verify -``` - -JDK 21 is required; the wrapper downloads the pinned Maven, and Tycho the -bundles `emf.target` pins. - -## A fast local loop - -The full build runs every gate, so a one-line change to a transformation -waits minutes. While editing, build the bundles without the parity tier, -offline, run only the test that covers the change, and skip the gates. This -takes about half a minute: - -```sh -cd emf -./mvnw -o -Pquick verify -pl '!tests/parity' -Dtest=StageTest -Dsurefire.failIfNoSpecifiedTests=false -``` - -- `-Pquick` skips the JaCoCo agent and its coverage floor, PIT and the - Spotless check. It runs the tests. CI never passes it, so every gate still - runs on the pull request. -- `-pl '!tests/parity'` builds every bundle and leaves out the parity tier; - the full build runs it. `bundles/cli` holds the pipeline tests, including - the stage cases. Maven's `-am` cannot stand in here: a bundle names the bundles - it needs in its `META-INF/MANIFEST.MF`, not its POM, so `-pl bundles/cli -am` - builds `cli` alone and Tycho cannot resolve the bundles it requires. -- `-o` works offline once one full build has filled the local repository. -- `-Dtest=` runs one test class, or `#` one method. - `-Dsurefire.failIfNoSpecifiedTests=false` lets the modules that have no - such test pass. -- `-Dgolden.update=true` rewrites the stage goldens from what the stages now - write, for review in `git diff`. - -[`mvnd`](https://github.com/apache/maven-mvnd), the Maven daemon, keeps a warm -JVM between builds and takes the same arguments. It is optional: nothing here -needs it. - -On a managed machine an antivirus scanner can slow every file Maven and Tycho -read and write. Excluding the local Maven repository and the `target/` -directories from scanning is a request to the machine's IT department, not a -setting in this repository. - -## Opening in Eclipse - -For examiners, in Eclipse Modeling Tools 2026-06 with the OCL, QVT-Operational -and Acceleo 4 SDKs installed from the same release: - -0. Run `./mvnw verify` once, from `emf/`, before importing anything. Each - metamodel's typed Java is generated into `target/generated-sources/emf/`, - which `build.properties` names as a source folder, and on a clean clone that - directory does not exist yet: import first and the workspace opens with - every reference to a generated package unresolved. One terminal build is - what makes the import land clean. -1. Open `emf/emf.target` and choose **Set as Active Target Platform**. -2. **File > Import > Maven > Existing Maven Projects**, with `emf/` as the - root directory. The importer walks the whole tree, so that one root - still finds the five bundles nested under `emf/bundles/` and the parity - suite nested under `emf/tests/parity`; import every module. Five of the six - are `eclipse-plugin` packaging, which m2e maps through the Tycho - configurator: accept the connector if the importer offers to install one, - and restart when it asks. -3. In `dev.jorisjonkers.deploykit.emf.metamodel`, open - `model/project-intent.ecore`, the Project Intent metamodel. Open - `model/cache.xmi` with the Sample Reflective Ecore Model Editor. It holds a - small Project, as the parser reads it from YAML. `model/cache-continuous.xmi` - is the same Project with one edit: its Process asks for a `continuous` - cutover over a ReadWriteOnce volume. Load `model/project-intent.ocl` into - each model's editor through **OCL > Load Document** (from the OCL Examples - and Editors SDK), one editor at a time. An invariant across documents ranges - over its editor's resources, so two Projects in one editor would each refuse - the other's name. Validated against the document, `cache.xmi` breaks - nothing, and `cache-continuous.xmi` breaks `E_CUTOVER_UNHONOURABLE` on its - Process and nothing else. `ProjectIntentOclTest`, which step 0's build runs, - holds both results. In Eclipse 2026-06 with OCL 6.24, the editor's - **Validate** after the load reports neither. The command's job disposes the - document it loaded before **Validate** runs, while the same loader kept open - over the editor's resources reports exactly that one invariant. -4. Run `resolution.launch` in `dev.jorisjonkers.deploykit.emf.resolve` and - `render.launch` in `dev.jorisjonkers.deploykit.emf.render` from **Run > Run - Configurations**. They write under each project's `target/`. The resolution - reads the two extents step 0's build left under - `dev.jorisjonkers.deploykit.emf.cli/target/parity/minimal/`, and its output - equals `models/minimal.resolveddeployment`. `render.launch` is a Java - application launch of `RenderModel`, which reads that committed model with - its package registered in its own resource set and renders it through - `Rendering.render`, the entry the pipeline uses: the files it writes under - `target/render/apps/notes/` equal - `spec/v1/examples/minimal/rendered/apps/notes/`, as `RenderModelTest` holds. diff --git a/emf/bundles/cli/META-INF/MANIFEST.MF b/emf/bundles/cli/META-INF/MANIFEST.MF deleted file mode 100644 index b3a3f9e87..000000000 --- a/emf/bundles/cli/META-INF/MANIFEST.MF +++ /dev/null @@ -1,17 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: deploy-kit model-driven pipeline -Bundle-SymbolicName: dev.jorisjonkers.deploykit.emf.cli;singleton:=true -Bundle-Version: 0.1.0.qualifier -Bundle-RequiredExecutionEnvironment: JavaSE-21 -Automatic-Module-Name: dev.jorisjonkers.deploykit.emf.cli -Export-Package: dev.jorisjonkers.deploykit.emf.cli -Require-Bundle: dev.jorisjonkers.deploykit.emf.metamodel, - dev.jorisjonkers.deploykit.emf.syntax, - dev.jorisjonkers.deploykit.emf.resolve, - dev.jorisjonkers.deploykit.emf.render, - org.eclipse.emf.ecore, - org.eclipse.emf.ecore.xmi, - org.eclipse.xtext, - org.eclipse.ocl.pivot, - org.eclipse.ocl.xtext.completeocl diff --git a/emf/bundles/cli/build.properties b/emf/bundles/cli/build.properties deleted file mode 100644 index fe08435df..000000000 --- a/emf/bundles/cli/build.properties +++ /dev/null @@ -1,11 +0,0 @@ -source.. = src/main/java/ -bin.includes = META-INF/,\ - . -# Test-only: EMF Compare decides every model comparison in the tests (docs/adr/emf/0152); EMF-021 keeps it out of shipped classes. -# Test-only too: the benchmark's ATL port of the lowering runs on EMFTVM, beside the QVTo lowering it is -# measured against (docs/benchmarks.md). -additional.bundles = org.eclipse.emf.compare,\ - com.google.guava,\ - org.eclipse.m2m.qvt.oml,\ - org.eclipse.m2m.atl.emftvm,\ - org.eclipse.m2m.atl.emftvm.compiler diff --git a/emf/bundles/cli/pom.xml b/emf/bundles/cli/pom.xml deleted file mode 100644 index 620f6d027..000000000 --- a/emf/bundles/cli/pom.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - 4.0.0 - - - dev.jorisjonkers.deploykit.emf - emf-parent - 0.1.0-SNAPSHOT - ../../pom.xml - - - dev.jorisjonkers.deploykit.emf.cli - eclipse-plugin - deploy-kit model-driven cli - - - - - org.pitest - pitest-maven - - - - dev.jorisjonkers.deploykit.emf.cli.* - - - - org.eclipse.ocl.xtext.completeocl.CompleteOCLStandaloneSetup - - - - dev.jorisjonkers.deploykit.emf.cli.ComparisonTest - dev.jorisjonkers.deploykit.emf.cli.ModelDiffTest - dev.jorisjonkers.deploykit.emf.cli.StageTest - dev.jorisjonkers.deploykit.emf.cli.FieldCoverageTest - dev.jorisjonkers.deploykit.emf.cli.OracleDistanceTest - - - - - - diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Authored.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Authored.java deleted file mode 100644 index 8b1a77b05..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Authored.java +++ /dev/null @@ -1,30 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import java.util.List; -import org.eclipse.emf.ecore.EObject; - -/** - * A set of documents read together as the resolution reads them, before any project is lowered: the - * authored Projects with their env files and the Platform document, and the pinned inputs, or the - * diagnostics that refused the set. A refused set holds no document. - */ -public record Authored(List intent, List pinned, List diagnostics) { - - public Authored { - intent = List.copyOf(intent); - pinned = List.copyOf(pinned); - diagnostics = List.copyOf(diagnostics); - } - - public static Authored of(List intent, List pinned) { - return new Authored(intent, pinned, List.of()); - } - - public static Authored refused(List diagnostics) { - return new Authored(List.of(), List.of(), diagnostics); - } - - public boolean ok() { - return diagnostics.isEmpty(); - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Collisions.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Collisions.java deleted file mode 100644 index f2b7ccbc2..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Collisions.java +++ /dev/null @@ -1,112 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.Deliverable; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Stream; - -/** - * One owner per path (spec/v1/30-deliverables.md#path-allocation): two Deliverables may never claim - * one path, no two documents one Vault name, and no two objects one ServiceAccount, since a Vault - * role is bound to the account's name and namespace alone. Every collision is refused before - * anything is written. - */ -final class Collisions { - - static final String PATH_COLLISION = "E_PATH_COLLISION"; - - /** - * The estate-scoped share: each Project's resolution plans the files of it its own model names, - * so a render of several Projects plans one such file once for each of them. - */ - private static final String ESTATE = "estate/"; - - /** Where a Vault document lands: a policies directory, under the name Vault holds it by. */ - private static final Pattern VAULT_DOCUMENT = Pattern.compile("/policies/([^/]+\\.(?:policy|role)\\.json)$"); - - /** A ServiceAccount as the templates write one: its kind, then its metadata's name and namespace. */ - private static final Pattern ACCOUNT = - Pattern.compile("(?m)^ *kind: ServiceAccount\\n( *)metadata:\\n((?:\\1 .*\\n)+)"); - - private static final Pattern NAME = Pattern.compile("(?m)^ *name: (.+)$"); - private static final Pattern NAMESPACE = Pattern.compile("(?m)^ *namespace: (.+)$"); - - private Collisions() {} - - /** Every path and every Vault name of the Deliverables {@code deployments} plan, owned twice. */ - static List ofPlan(List deployments) { - Map> owners = new TreeMap<>(); - Map> names = new TreeMap<>(); - for (ResolvedDeployment deployment : deployments) { - for (Deliverable deliverable : deployment.getDeliverables()) { - String path = deliverable.getPath(); - owners.computeIfAbsent(path, key -> key.startsWith(ESTATE) ? new LinkedHashSet<>() : new ArrayList<>()) - .add(deliverable.getAdapter().getLiteral()); - Matcher vault = VAULT_DOCUMENT.matcher(path); - if (vault.find()) { - names.computeIfAbsent(vault.group(1), key -> new LinkedHashSet<>()) - .add(path); - } - } - } - List refused = new ArrayList<>(); - names.forEach((name, paths) -> { - if (paths.size() > 1) { - refused.add(refusal("the Vault name " + name + " is claimed by " + String.join(" and ", paths))); - } - }); - owners.forEach((path, adapters) -> { - if (adapters.size() > 1) { - refused.add(refusal(path + " is claimed by " + String.join(" and ", adapters))); - } - }); - return refused; - } - - /** Every ServiceAccount the files written under {@code root} hold, held by two of them. */ - static List ofAccounts(Path root) { - Map> accounts = new TreeMap<>(); - try (Stream files = Files.walk(root)) { - for (Path file : files.filter(Files::isRegularFile).sorted().toList()) { - String text = Files.readString(file, StandardCharsets.UTF_8); - Matcher account = ACCOUNT.matcher(text); - while (account.find()) { - String metadata = account.group(2); - accounts.computeIfAbsent( - value(NAMESPACE, metadata) + "/" + value(NAME, metadata), key -> new ArrayList<>()) - .add(root.relativize(file).toString()); - } - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - List refused = new ArrayList<>(); - accounts.forEach((account, paths) -> { - if (paths.size() > 1) { - refused.add(refusal("the ServiceAccount " + account + " is claimed by " + String.join(" and ", paths))); - } - }); - return refused; - } - - private static String value(Pattern key, String metadata) { - Matcher matcher = key.matcher(metadata); - return matcher.find() ? matcher.group(1).strip() : ""; - } - - private static Diagnostic refusal(String message) { - return new Diagnostic(PATH_COLLISION, "", "", message); - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Constraints.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Constraints.java deleted file mode 100644 index cc7a80807..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Constraints.java +++ /dev/null @@ -1,102 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.EValidator; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.impl.ResourceImpl; -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import org.eclipse.emf.ecore.util.Diagnostician; -import org.eclipse.ocl.xtext.completeocl.CompleteOCLStandaloneSetup; -import org.eclipse.ocl.xtext.completeocl.validation.CompleteOCLEObjectValidator; - -/** - * The Complete OCL constraints of a metamodel, evaluated over one parsed document. An invariant is - * named by the diagnostic code it emits and its context is the object the diagnostic points at, so a - * violation becomes a {@link dev.jorisjonkers.deploykit.emf.cli.Diagnostic} without a lookup table - * (emf/docs/architecture.md#constraints). Every failed invariant is reported, never only the first. - */ -public final class Constraints { - - /** The invariant name inside the message Eclipse OCL builds for a violation. */ - private static final Pattern VIOLATED = Pattern.compile("'[^']*::([A-Za-z0-9_]+)' constraint is violated"); - - /** The constraints the metamodel carries, as the build puts them beside its classes. */ - public static URI beside(Class metamodel, String file) { - return URI.createURI(metamodel.getResource("/" + file).toString()); - } - - private Constraints() {} - - /** One failed invariant: its code, the object it refused, the feature it names, and what Eclipse said. */ - record Violation(String code, EObject object, String feature, String message) {} - - /** - * Evaluates {@code document} against the constraints at {@code constraints}, in document order. An - * invariant may read the other documents of the resource set the document was read into. - */ - public static List check(EObject document, URI constraints) { - String file = document.eResource().getURI().lastSegment(); - List refusals = new ArrayList<>(); - for (Violation violation : violations(document, constraints)) { - // An invariant named CODE__feature refuses one feature of the object, and its path says so. - refusals.add(new dev.jorisjonkers.deploykit.emf.cli.Diagnostic( - violation.code(), - file, - Pointer.of(violation.object()) + (violation.feature().isEmpty() ? "" : "/" + violation.feature()), - violation.message())); - } - return refusals; - } - - /** - * Every invariant of {@code constraints} that {@code document} and what it contains fail, in - * document order, each with the object it refused. The document needs no resource of its own. - */ - static List violations(EObject document, URI constraints) { - CompleteOCLStandaloneSetup.doSetup(); - EPackage metamodel = document.eClass().getEPackage(); - EValidator previous = EValidator.Registry.INSTANCE.getEValidator(metamodel); - EValidator.Registry.INSTANCE.put(metamodel, new CompleteOCLEObjectValidator(metamodel, constraints)); - // An invariant is evaluated in the resource set of its object, so a model a transformation - // built is held in one of its own for as long as it is asked. - Resource held = document.eResource() == null ? new ResourceImpl() : null; - if (held != null) { - new ResourceSetImpl().getResources().add(held); - held.getContents().add(document); - } - try { - // Validation walks the document's own containment, so every refusal points into its file. - return violations(Diagnostician.INSTANCE.validate(document)); - } finally { - EValidator.Registry.INSTANCE.put(metamodel, previous); - if (held != null) { - held.getContents().remove(document); - } - } - } - - private static List violations(Diagnostic diagnostic) { - List violations = new ArrayList<>(); - Matcher violated = VIOLATED.matcher(diagnostic.getMessage()); - if (violated.find()) { - // A violation carries the object it refused as its first datum. - String[] named = violated.group(1).split("__", 2); - violations.add(new Violation( - named[0], - (EObject) diagnostic.getData().get(0), - named.length == 1 ? "" : named[1], - diagnostic.getMessage())); - } - for (Diagnostic child : diagnostic.getChildren()) { - violations.addAll(violations(child)); - } - return violations; - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/DataFile.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/DataFile.java deleted file mode 100644 index 884948582..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/DataFile.java +++ /dev/null @@ -1,498 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.Datum; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.DatumEntry; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.DatumKind; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.DatumList; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.DatumMap; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.DatumScalar; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.PinnedInputsFactory; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.HashSet; -import java.util.Optional; -import java.util.Set; -import java.util.regex.Pattern; - -/** - * A data file an Application ships, read as YAML reads it, into the data it holds: a rule-group - * file, which the monitoring stack's rules are written from as the file writes them - * (spec/v1/10-project-intent.md#alert-rules). It reads the YAML such a file is written in: block - * mappings and sequences, flow collections over any number of lines, JSON among them, plain scalars - * over one line or several, single- and double-quoted scalars on one line, literal and folded block - * scalars, and comments. A plain scalar is typed as YAML's core schema types it. A file that is not - * YAML, or that uses what this reader has no meaning for (an anchor, an alias, a tag, a directive, a - * second document, an indentation indicator, a duplicated key), holds nothing. - */ -final class DataFile { - - private static final PinnedInputsFactory MODEL = PinnedInputsFactory.eINSTANCE; - private static final String KEY = "groups"; - - /** A line that opens or ends a document: after the first token, a second document. */ - private static final Pattern MARKER = Pattern.compile("(?m)^(---|\\.\\.\\.)([ \\t].*)?$"); - - private final String text; - private int at; - - private DataFile(String text) { - this.text = text.replace("\r\n", "\n"); - } - - /** What {@code text} holds, or nothing where it is not YAML this reader reads. */ - static Optional read(String text) { - DataFile file = new DataFile(text); - try { - file.blank(); - if (file.text.startsWith("---", file.at) && file.ends(file.at + 3)) { - file.at += 3; - file.blank(); - } - if (MARKER.matcher(file.text).region(file.at, file.text.length()).find()) { - throw new Malformed(); - } - Datum datum = file.more() ? file.node(-1) : scalar("null", DatumKind.EMPTY); - file.blank(); - if (file.more()) { - throw new Malformed(); - } - return Optional.of(datum); - } catch (Malformed e) { - return Optional.empty(); - } - } - - /** The rule groups {@code text} holds: the list a top-level mapping holds under `groups`, where it holds one. */ - static Optional groups(String text) { - return read(text) - .filter(DatumMap.class::isInstance) - .flatMap(root -> ((DatumMap) root) - .getEntries().stream() - .filter(entry -> entry.getKey().equals(KEY)) - .map(DatumEntry::getValue) - .findFirst()) - .filter(DatumList.class::isInstance) - .map(DatumList.class::cast) - .filter(list -> !list.getItems().isEmpty()); - } - - /** What YAML has no meaning for here, or no meaning for at all. */ - private static final class Malformed extends RuntimeException { - private static final long serialVersionUID = 1L; - } - - // ------------------------------------------------------------------ positions - - /** - * The character at {@code index}, where the end of the file reads as a line break. No index before - * the file is asked for: a comment's {@code #} is only looked behind past a token's first character. - */ - private char peek(int index) { - return index < text.length() ? text.charAt(index) : '\n'; - } - - /** The column {@code index} sits at on its line. */ - private int column(int index) { - return index - (text.lastIndexOf('\n', index - 1) + 1); - } - - /** Whether {@code index} ends a token: the end of the file, a space or a line break. */ - private boolean ends(int index) { - char c = peek(index); - return c == ' ' || c == '\t' || c == '\n'; - } - - /** Whether a block sequence's dash opens at {@code at}. */ - private boolean dash() { - return peek(at) == '-' && ends(at + 1); - } - - private boolean more() { - return at < text.length(); - } - - /** Spaces and tabs on the line. */ - private void spaces() { - while (peek(at) == ' ' || peek(at) == '\t') { - at++; - } - } - - /** Whether nothing but a comment is left on the line; the rest of the line is skipped if so. */ - private boolean lineEnds() { - spaces(); - if (peek(at) == '#') { - while (peek(at) != '\n') { - at++; - } - } - return peek(at) == '\n'; - } - - /** Every blank line and comment, up to the next token of the file. */ - private void blank() { - while (more() && lineEnds()) { - at++; - } - } - - /** The token on the line at {@code at} ends its value: nothing but a comment follows it. */ - private void endOfValue() { - if (!lineEnds()) { - throw new Malformed(); - } - } - - // ------------------------------------------------------------------ block structure - - /** The node at {@code at}, inside a parent at column {@code parent}. */ - private Datum node(int parent) { - int column = column(at); - if (dash()) { - return sequence(column); - } - if (keyAhead()) { - return mapping(column); - } - return value(parent); - } - - private DatumList sequence(int column) { - DatumList list = MODEL.createDatumList(); - while (more() && column(at) == column && dash()) { - at++; - list.getItems().add(lineEnds() ? below(column) : node(column)); - blank(); - } - if (more() && column(at) > column) { - throw new Malformed(); - } - return list; - } - - private DatumMap mapping(int column) { - DatumMap map = MODEL.createDatumMap(); - Set keys = new HashSet<>(); - do { - DatumEntry entry = MODEL.createDatumEntry(); - entry.setKey(key()); - if (!keys.add(entry.getKey())) { - throw new Malformed(); - } - if (lineEnds()) { - blank(); - entry.setValue(more() && column(at) == column && dash() ? sequence(column) : below(column)); - } else { - entry.setValue(value(column)); - } - map.getEntries().add(entry); - blank(); - } while (more() && column(at) == column && !dash() && keyAhead()); - if (more() && column(at) > column) { - throw new Malformed(); - } - return map; - } - - /** The node on the lines below a key or a dash at {@code column}, or an empty scalar where there is none. */ - private Datum below(int column) { - blank(); - return more() && column(at) > column ? node(column) : scalar("null", DatumKind.EMPTY); - } - - /** Whether a mapping key opens at {@code at}: a key, then a colon a space or the line's end follows. */ - private boolean keyAhead() { - int start = at; - try { - key(); - return true; - } catch (Malformed e) { - return false; - } finally { - at = start; - } - } - - /** The key at {@code at}, with the colon after it. */ - private String key() { - String key; - char c = peek(at); - if (c == '"' || c == '\'') { - key = quoted(); - spaces(); - } else { - int start = at; - while (!(peek(at) == ':' && ends(at + 1)) && peek(at) != '\n' && !(peek(at) == '#' && ends(at - 1))) { - at++; - } - key = text.substring(start, at).strip(); - // A key opens on no indicator: an anchor or a tag is outside the subset. - if (!key.isEmpty() && "[]{},#&*!|>'\"%@`".indexOf(key.charAt(0)) >= 0) { - throw new Malformed(); - } - } - if (peek(at) != ':' || !ends(at + 1)) { - throw new Malformed(); - } - at++; - return key; - } - - /** A value that is no collection of the block: a flow collection, a block scalar, or a scalar. */ - private Datum value(int parent) { - char c = peek(at); - if (c == '[' || c == '{') { - Datum flow = flow(); - endOfValue(); - return flow; - } - if (c == '|' || c == '>') { - return block(parent); - } - if (c == '"' || c == '\'') { - String quoted = quoted(); - endOfValue(); - return scalar(quoted, DatumKind.STRING); - } - if ("&*!%@`".indexOf(c) >= 0) { - throw new Malformed(); - } - return plain(parent); - } - - /** - * A plain scalar, to the end of its line or a comment, and every line after it indented further than - * its parent, folded: a line break is a space, and each blank line between two is one line break. - */ - private Datum plain(int parent) { - StringBuilder value = new StringBuilder(rest()); - int breaks = 0; - int resume = at; - while (more()) { - at++; - spaces(); - // The end of the file reads as a line break, so it is counted with the blank lines. - if (peek(at) == '\n') { - breaks++; - } else if (column(at) > parent && peek(at) != '#') { - // A key there would open a mapping inside a scalar, which YAML refuses. - if (keyAhead()) { - throw new Malformed(); - } - value.append(breaks == 0 ? " " : "\n".repeat(breaks)).append(rest()); - breaks = 0; - resume = at; - } else { - break; - } - } - at = resume; - return typed(value.toString()); - } - - /** The rest of the line from {@code at}, short of a comment, trimmed; {@code at} is left at the line's end. */ - private String rest() { - int start = at; - while (peek(at) != '\n' && !(peek(at) == '#' && ends(at - 1))) { - at++; - } - String line = text.substring(start, at).strip(); - lineEnds(); - return line; - } - - /** - * A literal or folded block scalar: every line under the indicator indented at least as far as its - * first, with that indentation removed, joined by a line break under {@code |} and folded under - * {@code >}, and its trailing line breaks clipped to one, stripped under {@code -} or kept under - * {@code +}. - */ - private Datum block(int parent) { - boolean literal = peek(at) == '|'; - at++; - char chomp = peek(at) == '-' || peek(at) == '+' ? text.charAt(at++) : ' '; - endOfValue(); - StringBuilder value = new StringBuilder(); - int indent = -1; - int breaks = 0; - boolean previousMore = false; - while (at + 1 < text.length()) { - int start = at + 1; - int end = text.indexOf('\n', start); - String line = text.substring(start, end < 0 ? text.length() : end); - int width = line.length() - line.stripLeading().length(); - if (line.isBlank()) { - breaks++; - } else if (width > parent && (indent < 0 || width >= indent)) { - indent = indent < 0 ? width : indent; - String content = line.substring(indent).stripTrailing(); - boolean more = content.startsWith(" ") || content.startsWith("\t"); - // A line break is kept under `|`, around a line indented further and before the first - // line; elsewhere under `>` it folds to a space, or into the blank lines after it. - boolean kept = literal || more || previousMore || value.length() == 0; - value.append(value.length() == 0 ? "" : kept || breaks > 0 ? "\n" : " ") - .append("\n".repeat(kept ? breaks : Math.max(breaks - 1, 0))) - .append(content); - previousMore = more; - breaks = 0; - } else { - break; - } - at = end < 0 ? text.length() : end; - } - String content = value.toString(); - String trailing = content.isEmpty() ? "" : "\n"; - return scalar( - content + (chomp == '-' ? "" : chomp == '+' ? trailing + "\n".repeat(breaks) : trailing), - DatumKind.STRING); - } - - // ------------------------------------------------------------------ flow structure - - /** Spaces, line breaks and comments inside a flow collection. */ - private void flowBlank() { - while (more() && lineEnds()) { - at++; - } - spaces(); - } - - private Datum flow() { - boolean map = text.charAt(at++) == '{'; - char close = map ? '}' : ']'; - DatumMap entries = MODEL.createDatumMap(); - DatumList items = MODEL.createDatumList(); - Set keys = new HashSet<>(); - flowBlank(); - while (peek(at) != close) { - if (map) { - DatumEntry entry = MODEL.createDatumEntry(); - entry.setKey(peek(at) == '"' || peek(at) == '\'' ? quoted() : flowPlain(true)); - if (!keys.add(entry.getKey())) { - throw new Malformed(); - } - flowBlank(); - if (peek(at) != ':') { - throw new Malformed(); - } - at++; - flowBlank(); - entry.setValue(peek(at) == ',' || peek(at) == close ? scalar("null", DatumKind.EMPTY) : flowNode()); - entries.getEntries().add(entry); - } else { - items.getItems().add(flowNode()); - } - flowBlank(); - if (peek(at) == ',') { - at++; - flowBlank(); - } else if (peek(at) != close) { - throw new Malformed(); - } - } - at++; - return map ? entries : items; - } - - private Datum flowNode() { - char c = peek(at); - if (c == '[' || c == '{') { - return flow(); - } - if (c == '"' || c == '\'') { - return scalar(quoted(), DatumKind.STRING); - } - return typed(flowPlain(false)); - } - - /** A plain scalar in a flow collection, to the next indicator; a key's also stops at its colon. */ - private String flowPlain(boolean key) { - int start = at; - while (more() - && ",[]{}".indexOf(peek(at)) < 0 - && !(peek(at) == ':' && (key || ends(at + 1))) - && !(peek(at) == '#' && ends(at - 1))) { - at++; - } - String plain = text.substring(start, at).strip().replaceAll("\\s*\\n\\s*", " "); - if (plain.isEmpty() || "&*!%@`|>".indexOf(plain.charAt(0)) >= 0) { - throw new Malformed(); - } - return plain; - } - - // ------------------------------------------------------------------ scalars - - /** A single- or double-quoted scalar on one line, its escapes read. */ - private String quoted() { - char quote = text.charAt(at++); - StringBuilder value = new StringBuilder(); - while (true) { - char c = peek(at++); - if (c == '\n') { - throw new Malformed(); - } else if (c == quote && quote == '\'' && peek(at) == '\'') { - value.append('\''); - at++; - } else if (c == quote) { - return value.toString(); - } else if (c == '\\' && quote == '"') { - value.append(escaped()); - } else { - value.append(c); - } - } - } - - /** The character a double-quoted scalar's escape after the backslash stands for. */ - private String escaped() { - char c = peek(at++); - return switch (c) { - case 'n' -> "\n"; - case 't' -> "\t"; - case 'r' -> "\r"; - case 'b' -> "\b"; - case 'f' -> "\f"; - case '0' -> "\0"; - case '"', '\\', '/', ' ' -> String.valueOf(c); - case 'u' -> { - try { - String hex = text.substring(at, at + 4); - at += 4; - yield String.valueOf((char) Integer.parseInt(hex, 16)); - } catch (NumberFormatException | StringIndexOutOfBoundsException e) { - throw new Malformed(); - } - } - default -> throw new Malformed(); - }; - } - - /** A plain scalar as YAML's core schema types it: null, a boolean, an integer, a float, or a string. */ - private static DatumScalar typed(String plain) { - if (plain.matches("~|null|Null|NULL")) { - return scalar("null", DatumKind.EMPTY); - } - if (plain.matches("true|True|TRUE|false|False|FALSE")) { - return scalar(plain.toLowerCase(java.util.Locale.ROOT), DatumKind.BOOLEAN); - } - if (plain.matches("[-+]?[0-9]+")) { - return scalar(new BigInteger(plain).toString(), DatumKind.NUMBER); - } - if (plain.matches("0o[0-7]+|0x[0-9a-fA-F]+")) { - return scalar( - new BigInteger(plain.substring(2), plain.charAt(1) == 'o' ? 8 : 16).toString(), DatumKind.NUMBER); - } - if (plain.matches("[-+]?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?")) { - return scalar(new BigDecimal(plain).stripTrailingZeros().toPlainString(), DatumKind.NUMBER); - } - return scalar(plain, DatumKind.STRING); - } - - private static DatumScalar scalar(String text, DatumKind kind) { - DatumScalar scalar = MODEL.createDatumScalar(); - scalar.setText(text); - scalar.setKind(kind); - return scalar; - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Diagnostic.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Diagnostic.java deleted file mode 100644 index 172aaffab..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Diagnostic.java +++ /dev/null @@ -1,12 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -/** - * A refusal: the code the specification gives it, the file name of the authored document it points - * into, the JSON Pointer of the authored value it concerns, and a message for a human. The code, the - * document and the path are the parity contract's; the message is this implementation's own. - */ -public record Diagnostic(String code, String document, String path, String message) { - - /** The code every refusal of a document's shape carries, until a rule gives it its own. */ - public static final String SCHEMA = "schema"; -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/EnvFiles.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/EnvFiles.java deleted file mode 100644 index fae0858bf..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/EnvFiles.java +++ /dev/null @@ -1,187 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EnvFile; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EnvLiteral; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EnvValue; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EnvVariable; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Placeholder; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.PlaceholderKind; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.regex.Pattern; - -/** - * The dotenv subset chapter 10 fixes, read into the model - * (spec/v1/10-project-intent.md#the-dotenv-subset-that-is-read). A reader rather than a grammar, for - * the reason emf/docs/adr/emf/0082-the-env-files-are-read-not-parsed-by-xtext.md records. - */ -public final class EnvFiles { - - /** Which level a scope directory names, and the name it names it by. */ - public record Scope(Level level, String name) { - public enum Level { - PROJECT, - APPLICATION, - PROCESS - } - } - - /** An authored env file, by the path that says which level it reaches. */ - public record Source(String path, String text) {} - - /** One file read, with the scope its directory put it in. */ - public record Scoped(String path, Scope scope, EnvFile file) {} - - /** What reading gave: the scoped files, or the diagnostics that refused them. */ - public record Read(List files, List diagnostics) { - - public Read { - files = List.copyOf(files); - diagnostics = List.copyOf(diagnostics); - } - - public boolean ok() { - return diagnostics.isEmpty(); - } - } - - private static final ProjectIntentFactory MODEL = ProjectIntentFactory.eINSTANCE; - private static final Pattern NAME = Pattern.compile("[A-Za-z_][A-Za-z0-9_]*"); - private static final String OPENS = "${"; - private static final String BASE = "base.env"; - private static final String PROJECT_SCOPE = "_project"; - private static final String APPLICATION_SCOPE = "_applications"; - - private EnvFiles() {} - - /** Every source read and scoped, or every line they break the subset on. */ - public static Read read(List sources) { - List files = new ArrayList<>(); - List refusals = new ArrayList<>(); - for (Source source : sources) { - Optional scope = scopeOf(source.path()); - if (scope.isEmpty()) { - refusals.add(schema(source.path(), source.path(), "this path names no env scope directory")); - continue; - } - // A scope holds one file, and no file varies by cluster. - if (!source.path().endsWith("/" + BASE)) { - refusals.add(schema(source.path(), source.path(), "a scope's one env file is " + BASE)); - continue; - } - List broke = new ArrayList<>(); - EnvFile file = readOne(source, broke); - if (broke.isEmpty()) { - files.add(new Scoped(source.path(), scope.get(), file)); - } else { - refusals.addAll(broke); - } - } - return new Read(files, refusals); - } - - /** The level {@code path}'s scope directory names, or nothing where it names none. */ - public static Optional scopeOf(String path) { - String[] segments = path.split("/"); - int env = List.of(segments).lastIndexOf("env"); - if (env < 0 || !path.endsWith(".env")) { - return Optional.empty(); - } - // A scope is a directory, so the file is one segment deeper than it, and one deeper - // again where the Application scope names which Application. - // The `.env` file is itself a segment after `env`, so `rest` is never empty here. - String[] rest = Arrays.copyOfRange(segments, env + 1, segments.length); - if (APPLICATION_SCOPE.equals(rest[0])) { - return rest.length == 3 ? Optional.of(new Scope(Scope.Level.APPLICATION, rest[1])) : Optional.empty(); - } - if (rest.length != 2) { - return Optional.empty(); - } - return Optional.of( - PROJECT_SCOPE.equals(rest[0]) - ? new Scope(Scope.Level.PROJECT, rest[0]) - : new Scope(Scope.Level.PROCESS, rest[0])); - } - - private static EnvFile readOne(Source source, List refusals) { - EnvFile file = MODEL.createEnvFile(); - Set seen = new LinkedHashSet<>(); - String[] lines = source.text().split("\n", -1); - for (int i = 0; i < lines.length; i++) { - String content = lines[i].trim(); - if (content.isEmpty() || content.startsWith("#")) { - continue; - } - String at = source.path() + ":" + (i + 1); - int equals = content.indexOf('='); - String name = equals < 1 ? "" : content.substring(0, equals); - if (equals < 1 || !NAME.matcher(name).matches()) { - refusals.add(schema(source.path(), at, "a line is not a NAME=value assignment")); - continue; - } - Optional value = value(content.substring(equals + 1)); - if (value.isEmpty()) { - refusals.add(schema(source.path(), at, "the value of " + name + " is outside the subset")); - continue; - } - if (!seen.add(name)) { - refusals.add(new Diagnostic( - "E_SHARED_DECLARATION_DUPLICATED", source.path(), at, name + " is set twice in one file")); - } - EnvVariable variable = MODEL.createEnvVariable(); - variable.setName(name); - variable.setValue(value.get()); - file.getEntries().add(variable); - } - return file; - } - - /** - * A literal, or one placeholder with literal text after it, and never a secret with text after - * it: a secret becomes one key of a Secret, and half a key is nothing. - */ - private static Optional value(String raw) { - if (raw.startsWith(OPENS)) { - int close = raw.indexOf('}'); - if (close == -1) { - return Optional.empty(); - } - // Split once: a source may hold colons, and the kind may hold none. - String[] parts = raw.substring(OPENS.length(), close).split(":", 2); - PlaceholderKind kind = parts.length == 2 ? PlaceholderKind.get(parts[0]) : null; - String source = parts.length == 2 ? parts[1] : ""; - String suffix = raw.substring(close + 1); - boolean whole = kind != PlaceholderKind.SECRET || suffix.isEmpty(); - if (kind == null || source.isEmpty() || !literal(suffix) || !whole) { - return Optional.empty(); - } - Placeholder placeholder = MODEL.createPlaceholder(); - placeholder.setKind(kind); - placeholder.setSource(source); - if (!suffix.isEmpty()) { - placeholder.setSuffix(suffix); - } - return Optional.of(placeholder); - } - if (raw.isEmpty() || !literal(raw)) { - return Optional.empty(); - } - EnvLiteral literal = MODEL.createEnvLiteral(); - literal.setText(raw); - return Optional.of(literal); - } - - /** Literal text: no {@code #}, which is a comment wherever it appears, and no placeholder. */ - private static boolean literal(String text) { - return !text.contains("#") && !text.contains(OPENS); - } - - private static Diagnostic schema(String document, String at, String message) { - return new Diagnostic(Diagnostic.SCHEMA, document, at, message); - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/IntentJson.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/IntentJson.java deleted file mode 100644 index 4e081024e..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/IntentJson.java +++ /dev/null @@ -1,134 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.descriptor.Descriptor; -import dev.jorisjonkers.deploykit.emf.syntax.values.ProjectIntentValueConverters; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import org.eclipse.emf.common.util.Enumerator; -import org.eclipse.emf.ecore.EAnnotation; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.eclipse.xtext.nodemodel.util.NodeModelUtils; - -/** - * Reads a parsed model as the JSON value the parity contract compares: every feature named as the - * authored key it holds, a map entry as an object, an enumeration as its literal, and an optional - * feature absent when the document left it out. A class the metamodel annotates as a scalar is - * written as that scalar, which is how {@code probes: none} stays the word it was authored as, and - * one it annotates with a value is written as that feature's value, which is how a plain key stays - * its name. The - * metamodel is walked reflectively, so a feature added to the {@code .ecore} reaches the intent - * without a line here. - */ -public final class IntentJson { - - private IntentJson() {} - - /** The annotation a class carries when the language writes it as one word rather than a block. */ - private static final String JSON = "https://jorisjonkers.dev/deploy-kit/json"; - - /** The JSON value of {@code root}, as a map of authored key to value. */ - public static Map of(EObject root) { - Map json = new LinkedHashMap<>(); - for (EStructuralFeature feature : root.eClass().getEAllStructuralFeatures()) { - if (isSet(root, feature)) { - json.put(Descriptor.keyOf(feature), value(root, feature)); - } - } - return json; - } - - /** Whether the document carries {@code feature}: a required feature always, an optional one when set. */ - private static boolean isSet(EObject owner, EStructuralFeature feature) { - return feature.isRequired() || owner.eIsSet(feature); - } - - /** - * The name a reference links by: an Application's ID, a Process's name, or a port's key. A Process - * and a port are named only within what holds them, so neither is an ID of the document. - */ - private static String nameOf(EObject target) { - String id = EcoreUtil.getID(target); - return id != null - ? id - : String.valueOf(target.eGet( - target.eClass().getEStructuralFeature(target instanceof Map.Entry ? "key" : "name"))); - } - - private static Object value(EObject owner, EStructuralFeature feature) { - Object value = owner.eGet(feature); - if (feature instanceof EReference reference && !reference.isContainment()) { - // A reference is written as the name that linked it: the identifier of what it points at, or, - // where it points into a document that was not read with this one, the name as written. - if (reference.isMany()) { - // A list of names, each the one its own position wrote. - List names = new ArrayList<>(); - List targets = (List) value; - for (int index = 0; index < targets.size(); index++) { - EObject target = (EObject) targets.get(index); - names.add(target.eIsProxy() ? written(owner, reference, index) : nameOf(target)); - } - return names; - } - EObject target = (EObject) value; - return target.eIsProxy() ? written(owner, reference, 0) : nameOf(target); - } - if (feature.isMany()) { - return many(feature, (List) value); - } - return single(value); - } - - /** The name a document wrote at {@code index} of {@code reference}, without the quotes that are only syntax. */ - private static String written(EObject owner, EReference reference, int index) { - return ProjectIntentValueConverters.unquote(NodeModelUtils.getTokenText( - NodeModelUtils.findNodesForFeature(owner, reference).get(index))); - } - - private static Object many(EStructuralFeature feature, List values) { - if (isMapEntry(feature)) { - Map entries = new LinkedHashMap<>(); - for (Object value : values) { - Map.Entry entry = (Map.Entry) value; - entries.put(String.valueOf(entry.getKey()), single(entry.getValue())); - } - return entries; - } - List items = new ArrayList<>(); - for (Object value : values) { - items.add(single(value)); - } - return items; - } - - /** The word a class is written as, or {@code null} when it is written as a block. */ - private static String scalar(EObject object) { - EAnnotation annotation = object.eClass().getEAnnotation(JSON); - return annotation == null ? null : annotation.getDetails().get("scalar"); - } - - /** Whether {@code feature} holds map entries, which are written as one object rather than a list. */ - private static boolean isMapEntry(EStructuralFeature feature) { - return Map.Entry.class.getName().equals(feature.getEType().getInstanceClassName()); - } - - /** The feature a class is written as the value of, or {@code null} when it is written as a block. */ - private static EStructuralFeature written(EObject object) { - EAnnotation annotation = object.eClass().getEAnnotation(JSON); - String name = annotation == null ? null : annotation.getDetails().get("value"); - return name == null ? null : object.eClass().getEStructuralFeature(name); - } - - private static Object single(Object value) { - return switch (value) { - case EObject child when written(child) != null -> child.eGet(written(child)); - case EObject child -> scalar(child) == null ? of(child) : scalar(child); - case Enumerator literal -> literal.getLiteral(); - default -> value; - }; - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/L4Checks.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/L4Checks.java deleted file mode 100644 index 860e0a62e..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/L4Checks.java +++ /dev/null @@ -1,181 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.L4AddressDeclaration; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.L4Exposure; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Listener; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.NodeAddress; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.PoolAddress; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Process; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Tier; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.OptionalLong; -import java.util.Set; - -/** - * What the L4 Addresses and the tiers' proxies of a Platform document and its project files break - * together (spec/v1/14-platform-intent.md#l4-addresses, #tiers): a tier whose proxy answers its - * listener on no Process, a pool with fewer addresses than Processes exposed on it, and a node's port - * two owners dial. A tier that names an address derives an exposure on its proxy for each port its - * listener derives, beside the exposures a project file authors. - */ -final class L4Checks { - - static final String TIER_SURFACE_MISSING = "E_TIER_SURFACE_MISSING"; - static final String L4_ADDRESS_EXHAUSTED = "E_L4_ADDRESS_EXHAUSTED"; - static final String NODE_PORT_TAKEN = "E_NODE_PORT_TAKEN"; - - /** The ports a listener derives on a tier's proxy, each to the surface the proxy answers it on. */ - private static final Map> LISTENER_PORTS = Map.of( - Listener.PLAIN, Map.of(80, "web"), Listener.TLS, new LinkedHashMap<>(Map.of(80, "web", 443, "websecure"))); - - /** One exposure, authored or derived: where it is written, who owns it, and what it dials. */ - private record Entry( - String document, - String path, - String owner, - String project, - String process, - String address, - String protocol, - int port) {} - - private L4Checks() {} - - static List check(Platform platform, Map projects) { - String document = platform.eResource().getURI().lastSegment(); - List refusals = new ArrayList<>(); - List entries = new ArrayList<>(); - for (Map.Entry named : projects.entrySet()) { - Project project = named.getKey(); - for (int a = 0; a < project.getApplications().size(); a++) { - Application application = project.getApplications().get(a); - for (L4Exposure exposure : application.getL4Exposure()) { - entries.add(new Entry( - named.getValue(), - Pointer.of(exposure), - named.getValue() + "/" + a, - project.getProject(), - // Every name links before this is asked: an unlinked one refused the document. - exposure.getProcess().getName(), - exposure.getAddress(), - exposure.getProtocol().getLiteral(), - exposure.getPort())); - } - } - } - for (int t = 0; t < platform.getTiers().size(); t++) { - Tier tier = platform.getTiers().get(t); - Application proxy = tier.getTraefik(); - // A tier with no address derives nothing, and a proxy no project file declares is - // E_UNKNOWN_TIER_PROXY's. - if (tier.getAddress() == null || proxy.eIsProxy()) { - continue; - } - Optional answers = proxyProcessOf(proxy, tier.getListener()); - if (answers.isEmpty()) { - refusals.add(new Diagnostic( - TIER_SURFACE_MISSING, - document, - "/tiers/" + t, - "no Process of " + proxy.getId() + " provides every surface the " + tier.getName() - + " tier's listener reaches")); - continue; - } - for (int port : LISTENER_PORTS.get(tier.getListener()).keySet()) { - entries.add(new Entry( - document, - "/tiers/" + t + "/address", - document + "/" + t, - ((Project) proxy.eContainer()).getProject(), - answers.get().getName(), - tier.getAddress(), - "tcp", - port)); - } - } - refusals.addAll(exhausted(platform, document, entries)); - refusals.addAll(taken(platform, entries)); - return refusals; - } - - /** The Process of a proxy that provides every surface the listener reaches, if one does. */ - private static Optional proxyProcessOf(Application proxy, Listener listener) { - return proxy.getProcesses().stream() - .filter(process -> LISTENER_PORTS.get(listener).values().stream() - .allMatch(surface -> process.getProvides().containsKey(surface))) - .findFirst(); - } - - /** Every pool exposed on by more Processes than its range holds addresses. */ - private static List exhausted(Platform platform, String document, List entries) { - List refusals = new ArrayList<>(); - for (Map.Entry address : - platform.getL4Addresses().entrySet()) { - if (address.getValue() instanceof PoolAddress pool) { - Set processes = new LinkedHashSet<>(); - for (Entry entry : entries) { - if (address.getKey().equals(entry.address())) { - processes.add(entry.project() + "/" + entry.process()); - } - } - OptionalLong capacity = held(pool.getRange()); - if (capacity.isEmpty()) { - continue; - } - long held = capacity.getAsLong(); - if (processes.size() > held) { - refusals.add(new Diagnostic( - L4_ADDRESS_EXHAUSTED, - document, - "/l4Addresses/" + address.getKey(), - processes.size() + " Processes are exposed on " + address.getKey() + ", whose range holds " - + held + " addresses")); - } - } - } - return refusals; - } - - /** How many addresses {@code range} holds, by its prefix length; none known when it names none. */ - private static OptionalLong held(String range) { - try { - return OptionalLong.of(1L << (32 - Integer.parseInt(range.substring(range.indexOf('/') + 1)))); - } catch (NumberFormatException e) { - return OptionalLong.empty(); - } - } - - /** Every exposure on a node's own address whose node, protocol and port another owner dials too. */ - private static List taken(Platform platform, List entries) { - Map> owners = new LinkedHashMap<>(); - Map keys = new LinkedHashMap<>(); - for (Entry entry : entries) { - if (platform.getL4Addresses().get(entry.address()) instanceof NodeAddress node) { - String key = node.getNode() + "/" + entry.protocol() + "/" + entry.port(); - keys.put(entry, key); - owners.computeIfAbsent(key, k -> new LinkedHashSet<>()) - .add(entry.owner() + "/" + entry.process() + "/" + entry.address()); - } - } - List refusals = new ArrayList<>(); - keys.forEach((entry, key) -> { - if (owners.get(key).size() > 1) { - refusals.add(new Diagnostic( - NODE_PORT_TAKEN, - entry.document(), - entry.path(), - entry.process() + " dials " + entry.protocol() + " " + entry.port() + " on a node another owner" - + " dials it on too")); - } - }); - return refusals; - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/NodeAgentChecks.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/NodeAgentChecks.java deleted file mode 100644 index 214440d16..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/NodeAgentChecks.java +++ /dev/null @@ -1,61 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.NodeContract; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.NodeAgents; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.PoolAddress; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * What the node contract and a Platform document break together: a Node Agent they derive that the - * Platform document's catalog names no image for (spec/v1/14-platform-intent.md#node-agents). Which - * agents run is a fact of the contract's nodes and the Platform's pools, neither of which an - * invariant over one metamodel can read, and the refusal is written at the catalog entry the - * document lacks, which has no object to point at (docs/adr/emf/0143). - */ -final class NodeAgentChecks { - - static final String NO_NODE_AGENT_POLICY = "E_NO_NODE_AGENT_POLICY"; - - /** The vendor whose cards {@code gpu-device} and {@code gpu-metrics} serve. */ - private static final String GPU_AGENT_VENDOR = "nvidia"; - - private NodeAgentChecks() {} - - /** Every derived agent of {@code contract} and {@code platform} the catalog names nothing for. */ - static List check(Platform platform, NodeContract contract) { - Set sites = - contract.getNodes().stream().map(node -> node.getSite()).collect(Collectors.toSet()); - boolean gpu = contract.getNodes().stream() - .anyMatch(node -> node.getGpus().stream() - .anyMatch(card -> card.getVendor().equals(GPU_AGENT_VENDOR))); - boolean speaker = platform.getL4Addresses().values().stream() - .anyMatch(address -> address instanceof PoolAddress pool && sites.contains(pool.getSite())); - NodeAgents catalog = platform.getNodeAgents(); - // An agent no node needs is not derived, and an agent the catalog names is not refused. - Map unnamed = new LinkedHashMap<>(); - unnamed.put("gpu-device", gpu && (catalog == null || catalog.getGpuDevice() == null)); - unnamed.put("gpu-metrics", gpu && (catalog == null || catalog.getGpuMetrics() == null)); - unnamed.put( - "node-metrics", - !contract.getNodes().isEmpty() && (catalog == null || catalog.getNodeMetrics() == null)); - unnamed.put("l4-speaker", speaker && (catalog == null || catalog.getL4Speaker() == null)); - String document = platform.eResource().getURI().lastSegment(); - List refusals = new ArrayList<>(); - unnamed.forEach((agent, missing) -> { - if (missing) { - refusals.add(new Diagnostic( - NO_NODE_AGENT_POLICY, - document, - "/nodeAgents/" + agent, - agent + " runs on a node of the contract, and the catalog names no image for it")); - } - }); - return refusals; - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/OperatedChecks.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/OperatedChecks.java deleted file mode 100644 index 3982f949f..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/OperatedChecks.java +++ /dev/null @@ -1,99 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Monitoring; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Process; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * The arguments of the monitoring stack's Prometheus and Alertmanager, which the Prometheus operator - * runs (spec/v1/14-platform-intent.md#the-operators-objects): each is a flag, and none sets what the - * operator sets itself. A refusal is placed at the argument's entry of a list of strings, which no - * invariant's path can name, so it is decided here; the rest of what the operator asks of the - * Process is decided in OCL. - */ -final class OperatedChecks { - - static final String OPERATED_PROCESS = "E_OPERATED_PROCESS"; - - /** One or two dashes, a name that opens on neither a dash nor {@code =}, and any value after {@code =}. */ - private static final Pattern FLAG = Pattern.compile("--?([^=-][^=]*)(?:=.*)?", Pattern.DOTALL); - - /** The flags the operator sets on its Prometheus itself. */ - private static final Set PROMETHEUS_OWNED = Set.of( - "config.file", - "storage.tsdb.path", - "web.config.file", - "web.console.libraries", - "web.console.templates", - "web.enable-lifecycle", - "web.external-url", - "web.listen-address", - "web.route-prefix"); - - /** The flags the operator sets on its Alertmanager itself. */ - private static final Set ALERTMANAGER_OWNED = Set.of( - "cluster.listen-address", - "cluster.peer", - "config.file", - "storage.path", - "web.config.file", - "web.external-url", - "web.listen-address", - "web.route-prefix"); - - private OperatedChecks() {} - - static List check(Platform platform, Map projects) { - Monitoring monitoring = platform.getMonitoring(); - List refusals = new ArrayList<>(); - if (monitoring != null) { - refusals.addAll(arguments(monitoring.getPrometheus(), "Prometheus", PROMETHEUS_OWNED, projects)); - refusals.addAll(arguments(monitoring.getAlertmanager(), "Alertmanager", ALERTMANAGER_OWNED, projects)); - } - return refusals; - } - - /** - * Every argument of the role's one Process that is no flag, or a flag the operator sets. A role with - * several Processes is refused at its Application, in OCL, and its arguments are not asked. - */ - private static List arguments( - Application role, String kind, Set owned, Map projects) { - List refusals = new ArrayList<>(); - // A role no project file of the set declares links to nothing, and is refused for that. - if (role.eIsProxy() || role.getProcesses().size() != 1) { - return List.of(); - } - Process process = role.getProcesses().get(0); - String document = projects.get((Project) role.eContainer()); - List args = process.getArgs(); - for (int i = 0; i < args.size(); i++) { - String argument = args.get(i); - Matcher flag = FLAG.matcher(argument); - if (!flag.matches()) { - refusals.add(refusal( - document, - process, - i, - role.getId() + ": " + argument + " is not a flag, and the operator passes its " + kind - + " flags alone")); - } else if (owned.contains(flag.group(1))) { - refusals.add(refusal( - document, process, i, role.getId() + ": the operator sets --" + flag.group(1) + " itself")); - } - } - return refusals; - } - - private static Diagnostic refusal(String document, Process process, int index, String message) { - return new Diagnostic(OPERATED_PROCESS, document, Pointer.of(process) + "/args/" + index, message); - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Outputs.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Outputs.java deleted file mode 100644 index f3e5f5af0..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Outputs.java +++ /dev/null @@ -1,465 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.descriptor.DependencyEdges; -import dev.jorisjonkers.deploykit.emf.metamodel.json.CanonicalJson; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.stream.IntStream; -import java.util.stream.Stream; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; - -/** - * What a run of the pipeline leaves behind: for every case under {@code spec/v1/examples/}, the - * parsed intent or the diagnostics that refused it, in the canonical JSON the oracles are committed - * in, and the exit code the run ended on - * (docs/adr/emf/0080-parity-crosses-the-cli-file-interface.md). - * - *

The output tree mirrors the example tree: a case at {@code auth/} writes {@code auth/}, and a - * refusal whose oracle is {@code refusals/unknown-surface.diagnostics.json} writes {@code - * refusals/unknown-surface/}, so a written file and its oracle are obviously a pair. A case writes - * exactly one of {@link #INTENT} and {@link #DIAGNOSTICS}, beside its {@link #EXIT}. Every case also - * writes the model of each document it reads in XMI, named by {@link Pipeline#xmiName}, which no - * oracle compares. A set's models link to each other, so a refused case opens in Eclipse and fails - * its validation there too. - */ -public final class Outputs { - - /** - * The project files every case composes with: the Applications the Platform document names in a - * privileged role, the sign-in provider among them, and what they depend on. - */ - private static final List FOUNDATION = List.of( - "delivery/delivery.project.yml", - "edge/edge.project.yml", - "observability/observability.project.yml", - "secrets/secrets.project.yml", - "identity/identity.project.yml", - "mail/mail.project.yml", - "utility/utility.project.yml", - "agents/agents.project.yml", - "data/data.project.yml"); - - /** The parsed intent of a case the pipeline accepted. */ - public static final String INTENT = "intent.json"; - - /** The Effective Intent of a case that carries an oracle for it. */ - public static final String EFFECTIVE = "effective.json"; - - /** The diagnostics of a case the pipeline refused. */ - public static final String DIAGNOSTICS = "diagnostics.json"; - - /** The code the run ended on: {@code 0} when the pipeline accepted the case, {@code 1} when not. */ - public static final String EXIT = "exit"; - - /** - * The real estate's documents at the commit the examples under {@code estate/} were taken at: its - * Platform document and pinned inputs, and every Project it composes, so a case under it resolves - * and renders against the union production composed it in. - */ - private static final List ESTATE = List.of( - "estate/platform.intent.yml", - "estate/node-contract.yml", - "estate/images.lock.yml", - "estate/cluster-state.yml", - "estate/arr/arr.project.yml", - "estate/auth/auth.project.yml", - "estate/data/data.project.yml", - "estate/delivery/delivery.project.yml", - "estate/edge/edge.project.yml", - "estate/estate-dashboard/estate-dashboard.project.yml", - "estate/findability-explorer/findability-explorer.project.yml", - "estate/grimoire/grimoire.project.yml", - "estate/hindsight/hindsight.project.yml", - "estate/home-portal/home-portal.project.yml", - "estate/immich/immich.project.yml", - "estate/jellyfin/jellyfin.project.yml", - "estate/jellyseerr/jellyseerr.project.yml", - "estate/karakeep/karakeep.project.yml", - "estate/mail/mail.project.yml", - "estate/n8n/n8n.project.yml", - "estate/observability/observability.project.yml", - "estate/outline/outline.project.yml", - "estate/overleaf/overleaf.project.yml", - "estate/prowlarr/prowlarr.project.yml", - "estate/qbittorrent/qbittorrent.project.yml", - "estate/secrets/secrets.project.yml", - "estate/tribelt/tribelt.project.yml", - "estate/utility/utility.project.yml"); - - /** - * The cases this implementation resolves, each with the project it resolves and the set of - * documents it is read with: the case's own documents, the foundation it composes with, and the - * pinned inputs beside the Platform document (spec/v1/20-resolved-deployment.md#pinned-inputs). - * Every case the production implementation resolves is here; `knowledge`, whose images - * no lock holds, is resolved by neither, and retires with the project it models (JorisJonkers-dev/deploy-kit#272). - */ - public static final Map RESOLVED = Map.ofEntries( - Map.entry("minimal", new Resolving("notes", withFoundation("minimal/notes.project.yml"))), - Map.entry( - "auth", - new Resolving( - "auth", - withFoundation( - "auth/auth.project.yml", "auth/migration-proof.yml", "data/data.project.yml"))), - Map.entry("data", new Resolving("data", withFoundation("data/data.project.yml"))), - Map.entry( - "knowledge-platform", - new Resolving( - "knowledge-platform", - withFoundation( - "knowledge-platform/knowledge-platform.project.yml", "data/data.project.yml"))), - Map.entry("delivery", new Resolving("delivery", withFoundation())), - Map.entry("edge", new Resolving("edge", withFoundation())), - // The metrics stack scrapes notes' Process, which only the union holding notes lists as a peer. - Map.entry("observability", new Resolving("observability", withFoundation("minimal/notes.project.yml"))), - Map.entry("secrets", new Resolving("secrets", withFoundation())), - Map.entry("identity", new Resolving("identity", withFoundation())), - Map.entry("agents", new Resolving("agents", withFoundation())), - Map.entry("mail", new Resolving("mail", withFoundation())), - Map.entry("utility", new Resolving("utility", withFoundation())), - // The Node Agents, which no project file declares: the Platform document and the node - // contract derive them. - Map.entry("node", new Resolving("node", withFoundation())), - // The real estate's Projects, each read with the whole estate it was composed in. - Map.entry("estate/hindsight", new Resolving("hindsight", ESTATE)), - Map.entry("estate/immich", new Resolving("immich", ESTATE)), - Map.entry("estate/observability", new Resolving("observability", ESTATE))); - - /** The Platform document, its pinned inputs and the foundation every case composes with, then {@code own}. */ - private static List withFoundation(String... own) { - List documents = new ArrayList<>(List.of( - "platform/platform.intent.yml", - "platform/node-contract.yml", - "platform/images.lock.yml", - "platform/cluster-state.yml")); - documents.addAll(List.of(own)); - for (String foundation : FOUNDATION) { - if (!documents.contains(foundation)) { - documents.add(foundation); - } - } - return List.copyOf(documents); - } - - /** Where the composed union's rendered tree is written, under the output root. */ - public static final String RENDERED_TREE = "rendered"; - - /** - * The union the rendered trees are written from: every project whose share the production - * implementation renders, read and rendered together, so the estate-scoped share they hold - * between them is written whole. Its tree is the committed {@code minimal/rendered/} and {@code - * data/rendered/} together, and holds nothing estate-scoped. - */ - public static final Union RENDERED_UNION = - new Union(List.of("notes", "data"), withFoundation("minimal/notes.project.yml", "data/data.project.yml")); - - /** - * auth, rendered alone beside the project that holds its database: its tree is the committed {@code - * auth/rendered/}, its own share and the estate-scoped share it alone derives. - */ - public static final Union AUTH_UNION = new Union( - List.of("auth"), - withFoundation("auth/auth.project.yml", "auth/migration-proof.yml", "data/data.project.yml")); - - /** - * The knowledge platform, rendered alone beside the project that holds its database: its tree is the - * committed {@code knowledge-platform/rendered/}, its own share and the estate-scoped share it alone - * derives. - */ - public static final Union KNOWLEDGE_PLATFORM_UNION = new Union( - List.of("knowledge-platform"), - withFoundation("knowledge-platform/knowledge-platform.project.yml", "data/data.project.yml")); - - /** The integrity the worked projections record for the schema package they were rendered against. */ - public static final String INTEGRITY = "sha256:5e6f7a8b5e6f7a8b5e6f7a8b5e6f7a8b5e6f7a8b5e6f7a8b5e6f7a8b5e6f7a8b"; - - /** The project a resolution case resolves, and the documents under the examples it reads. */ - public record Resolving(String project, List documents) {} - - /** The projects one rendering writes together, and the set of documents they are read with. */ - public record Union(List projects, List documents) {} - - /** minimal's rendered tree, whose presence says the examples carry rendered trees at all. */ - private static final String RENDERED_ORACLE = "minimal/rendered"; - - private static final String DEPENDENCIES_ORACLE = "expected/" + DependencyEdges.NAME; - - private static final String INTENT_ORACLE = "expected/intent.json"; - private static final String EFFECTIVE_ORACLE = "expected/effective.json"; - private static final String DIAGNOSTICS_ORACLE = ".diagnostics.json"; - private static final String PROJECT = ".project.yml"; - - /** The directory of the negative fixtures, and the file a reversed reading of one writes. */ - private static final String NEGATIVE = "negative"; - - private static final String REVERSED = "diagnostics.reversed.json"; - private static final String PLATFORM = "platform.intent.yml"; - - /** The images lock a refused set may carry beside its documents. */ - private static final String IMAGES_LOCK = "images.lock.yml"; - - private Outputs() {} - - /** Every case under {@code examples} run through the pipeline, written under {@code out}. */ - public static void write(Path examples, Path out) throws IOException { - for (Path directory : casesWithAnIntentOracle(examples)) { - writeParsed(out.resolve(examples.relativize(directory)), authored(directory)); - } - for (Path directory : casesWith(examples, EFFECTIVE_ORACLE)) { - writeEffective(out.resolve(examples.relativize(directory)), authored(directory)); - } - for (Path directory : casesWith(examples, DEPENDENCIES_ORACLE)) { - Resolving resolving = RESOLVED.get(examples.relativize(directory).toString()); - if (resolving != null) { - writeResolved(out.resolve(examples.relativize(directory)), examples, resolving); - } - } - if (Files.isDirectory(examples.resolve(RENDERED_ORACLE))) { - writeRendered(out.resolve(RENDERED_TREE), examples); - } - writeNegative(examples, out); - for (Path oracle : refusalsWithADiagnosticsOracle(examples)) { - String stem = oracle.getFileName().toString().replace(DIAGNOSTICS_ORACLE, ""); - Path set = oracle.resolveSibling(stem); - Path directory = out.resolve(examples.relativize(set)); - // A directory beside the oracle is a set of documents read together; a file is read alone. - if (Files.isDirectory(set)) { - List documents = documents(set); - // A set's images lock is checked with it, and is no model of its own. - List checked = new ArrayList<>(documents); - if (Files.isRegularFile(set.resolve(IMAGES_LOCK))) { - checked.add(0, set.resolve(IMAGES_LOCK)); - } - writeDiagnostics(directory, Pipeline.check(checked)); - writeModels(directory, documents); - } else { - writeParsed(directory, oracle.resolveSibling(stem + PROJECT)); - } - } - } - - /** - * Every negative fixture's fragments, read beside the foundation and the Platform document they - * compose with, once in the order their paths sort and once in the reverse: composition is - * order-independent, so both write the one set its oracle names - * (spec/v1/40-composition.md#the-composition-run). - */ - private static void writeNegative(Path examples, Path out) throws IOException { - if (!Files.isDirectory(examples.resolve(NEGATIVE))) { - return; - } - List foundation = withFoundation().stream().map(examples::resolve).toList(); - for (Path oracle : negativeOracles(examples)) { - String stem = oracle.getFileName().toString().replace(DIAGNOSTICS_ORACLE, ""); - List fragments; - // Every file below the fixture; check reads the documents among them and no other. - try (Stream tree = Files.walk(oracle.resolveSibling(stem))) { - fragments = tree.sorted().toList(); - } - Path directory = out.resolve(examples.relativize(oracle.resolveSibling(stem))); - List forwards = new ArrayList<>(foundation); - forwards.addAll(fragments); - writeDiagnostics(directory, Pipeline.check(forwards)); - List backwards = IntStream.range(0, forwards.size()) - .mapToObj(i -> forwards.get(forwards.size() - 1 - i)) - .toList(); - Files.writeString( - directory.resolve(REVERSED), - CanonicalJson.write(triples(Pipeline.check(backwards))), - StandardCharsets.UTF_8); - } - } - - /** The diagnostics oracles beside the fixtures under {@code negative/}. */ - private static List negativeOracles(Path examples) throws IOException { - try (Stream tree = Files.list(examples.resolve(NEGATIVE))) { - return tree.filter(path -> path.getFileName().toString().endsWith(DIAGNOSTICS_ORACLE)) - .sorted() - .toList(); - } - } - - /** The case directories carrying an intent oracle: every case the pipeline is expected to accept. */ - private static List casesWithAnIntentOracle(Path examples) throws IOException { - return casesWith(examples, INTENT_ORACLE); - } - - /** The case directories carrying {@code oracle}, a path relative to the case. */ - private static List casesWith(Path examples, String oracle) throws IOException { - try (Stream tree = Files.walk(examples)) { - return tree.filter(path -> path.endsWith(oracle)) - .map(path -> path.getParent().getParent()) - .sorted() - .toList(); - } - } - - /** The diagnostics oracles under {@code refusals/}: every case the pipeline is expected to refuse. */ - private static List refusalsWithADiagnosticsOracle(Path examples) throws IOException { - try (Stream tree = Files.list(examples.resolve("refusals"))) { - return tree.filter(path -> path.getFileName().toString().endsWith(DIAGNOSTICS_ORACLE)) - .sorted() - .toList(); - } - } - - /** The one authored document of a case: its project file, or its Platform document. */ - private static Path authored(Path directory) throws IOException { - return documents(directory).get(0); - } - - /** The authored documents in {@code directory}, sorted; whatever else it holds is not read. */ - private static List documents(Path directory) throws IOException { - try (Stream entries = Files.list(directory)) { - return entries.filter(Outputs::isDocument).sorted().toList(); - } - } - - private static boolean isDocument(Path path) { - String name = path.getFileName().toString(); - return name.endsWith(PROJECT) || name.equals(PLATFORM); - } - - private static void writeParsed(Path directory, Path authored) throws IOException { - Parsed parsed = Pipeline.intent(authored); - if (parsed.ok()) { - write(directory, INTENT, CanonicalJson.write(parsed.intent()), 0); - } else { - writeDiagnostics(directory, parsed.diagnostics()); - } - writeModels(directory, List.of(authored)); - } - - /** - * The Effective Intent of {@code authored}. A case with that oracle is one the pipeline accepts; - * one it refuses leaves an empty object here, beside the diagnostics its intent step wrote. - */ - private static void writeEffective(Path directory, Path authored) throws IOException { - Files.createDirectories(directory); - Files.writeString( - directory.resolve(EFFECTIVE), - CanonicalJson.write(Pipeline.effective(authored).intent()), - StandardCharsets.UTF_8); - } - - /** - * The resolved dependency edges of a resolution case, the half of resolution the parity contract - * compares, and the Resolved Deployment model they were exported from, in XMI, which no oracle - * compares and which is what the templates read. - */ - private static void writeResolved(Path directory, Path examples, Resolving resolving) throws IOException { - Resolved resolved = Pipeline.resolve( - resolving.documents().stream().map(examples::resolve).toList(), resolving.project(), INTEGRITY); - if (!resolved.ok()) { - writeDiagnostics(directory, resolved.diagnostics()); - return; - } - DependencyEdges.write(directory, resolved.deployment()); - // The two extents the transformation read, so a launch in Eclipse runs it on the same models. - // A link to an Application the union does not hold, such as a critical Application the - // Platform document names in another set, lands nowhere in either extent, so it is left out - // rather than written as a reference to a document beside the case. - EcoreUtil.Copier copier = new EcoreUtil.Copier(true, false); - Resource intent = model(directory, INTENT_MODEL); - Resource pinned = model(directory, PINNED_MODEL); - intent.getContents().addAll(copier.copyAll(resolved.intent())); - pinned.getContents().addAll(copier.copyAll(resolved.pinned())); - copier.copyReferences(); - Resource deployment = model(directory, resolving.project() + RESOLVED_MODEL); - deployment.getContents().add(resolved.deployment()); - for (Resource resource : List.of(intent, pinned, deployment)) { - resource.save(null); - } - } - - /** - * The composed union's Deliverable Sets, written by the pipeline's one entry from the documents - * to the tree, or the diagnostics that refused the set in place of the tree. - */ - private static void writeRendered(Path directory, Path examples) throws IOException { - List refusals = Pipeline.render( - RENDERED_UNION.documents().stream().map(examples::resolve).toList(), - RENDERED_UNION.projects(), - INTEGRITY, - directory); - if (!refusals.isEmpty()) { - writeDiagnostics(directory, refusals); - } - } - - /** An XMI resource for {@code name} under {@code directory}, which refers to its objects as {@link ByIndex} does. */ - private static Resource model(Path directory, String name) { - return new ByIndex( - URI.createFileURI(directory.resolve(name).toAbsolutePath().toString())); - } - - /** - * An XMI resource of several roots that refers to its objects by their root's index and their - * containment path, never by ID: an extent holds several projects, and an ID names one object - * only within one of them. - */ - static final class ByIndex extends XMIResourceImpl { - ByIndex(URI uri) { - super(uri); - } - - @Override - public String getURIFragment(EObject object) { - EObject root = EcoreUtil.getRootContainer(object); - String index = "/" + getContents().indexOf(root); - return root == object ? index : index + "/" + EcoreUtil.getRelativeURIFragmentPath(root, object); - } - } - - /** The intent extent a resolution case reads: each authored Project, its lowering, and the Platform document. */ - public static final String INTENT_MODEL = "resolution.intent.xmi"; - - /** The pinned extent a resolution case reads: the node contract, the images lock and the snapshot. */ - public static final String PINNED_MODEL = "resolution.pinned.xmi"; - - /** What the XMI of a resolved project is called, beside the edges exported from it. */ - public static final String RESOLVED_MODEL = ".resolveddeployment"; - - /** The XMI of each of {@code documents} read together; a file that holds no document has none. */ - private static void writeModels(Path directory, List documents) throws IOException { - for (Map.Entry model : Pipeline.xmi(documents).entrySet()) { - Files.writeString( - directory.resolve(Pipeline.xmiName(model.getKey())), model.getValue(), StandardCharsets.UTF_8); - } - } - - private static void writeDiagnostics(Path directory, List diagnostics) throws IOException { - write(directory, DIAGNOSTICS, CanonicalJson.write(triples(diagnostics)), diagnostics.isEmpty() ? 0 : 1); - } - - /** - * The {@code (code, document, path)} triples the parity contract fixes, in an order no run can - * change, so a refusal's file is the set the contract compares rather than one reading of it. - */ - private static List triples(List diagnostics) { - return diagnostics.stream() - .map(diagnostic -> (Object) new TreeMap<>(Map.of( - "code", diagnostic.code(), - "document", diagnostic.document(), - "path", diagnostic.path()))) - .sorted(Comparator.comparing(Object::toString)) - .toList(); - } - - private static void write(Path directory, String name, String json, int exit) throws IOException { - Files.createDirectories(directory); - Files.writeString(directory.resolve(name), json, StandardCharsets.UTF_8); - Files.writeString(directory.resolve(EXIT), Integer.toString(exit), StandardCharsets.UTF_8); - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Parsed.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Parsed.java deleted file mode 100644 index b7a917427..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Parsed.java +++ /dev/null @@ -1,28 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import java.util.List; -import java.util.Map; - -/** - * The outcome of reading one authored document: the parsed intent as a JSON value, or the - * diagnostics that refused it. One of the two is always empty. - */ -public record Parsed(Map intent, List diagnostics) { - - public Parsed { - intent = Map.copyOf(intent); - diagnostics = List.copyOf(diagnostics); - } - - public static Parsed of(Map intent) { - return new Parsed(intent, List.of()); - } - - public static Parsed refused(List diagnostics) { - return new Parsed(Map.of(), diagnostics); - } - - public boolean ok() { - return diagnostics.isEmpty(); - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Pipeline.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Pipeline.java deleted file mode 100644 index 400ef0d65..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Pipeline.java +++ /dev/null @@ -1,793 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import com.google.inject.Injector; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.AssetFile; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.ImagesLock; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.NodeContract; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.PinnedInputsFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.PinnedInputsPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.AlertRules; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Asset; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.AssetDeclaration; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Dashboard; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.SharedIntent; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.Alias; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.StableAddressFile; -import dev.jorisjonkers.deploykit.emf.render.Rendering; -import dev.jorisjonkers.deploykit.emf.resolve.Lowering; -import dev.jorisjonkers.deploykit.emf.resolve.Resolution; -import dev.jorisjonkers.deploykit.emf.syntax.ClusterStateStandaloneSetup; -import dev.jorisjonkers.deploykit.emf.syntax.ImagesLockStandaloneSetup; -import dev.jorisjonkers.deploykit.emf.syntax.MigrationProofStandaloneSetup; -import dev.jorisjonkers.deploykit.emf.syntax.NodeContractStandaloneSetup; -import dev.jorisjonkers.deploykit.emf.syntax.PlatformIntentStandaloneSetup; -import dev.jorisjonkers.deploykit.emf.syntax.ProjectIntentStandaloneSetup; -import dev.jorisjonkers.deploykit.emf.syntax.linking.UnlinkedNames; -import dev.jorisjonkers.deploykit.emf.syntax.schema.Shapes; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.regex.Pattern; -import java.util.stream.Stream; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; -import org.eclipse.xtext.EcoreUtil2; -import org.eclipse.xtext.Grammar; -import org.eclipse.xtext.IGrammarAccess; -import org.eclipse.xtext.linking.impl.XtextLinkingDiagnostic; -import org.eclipse.xtext.resource.IResourceFactory; -import org.eclipse.xtext.resource.XtextResource; -import org.eclipse.xtext.resource.XtextResourceSet; - -/** - * The pipeline entry: authored files in, their parsed intent or the diagnostics that refused them out. - * It is the seam the parity suite runs every case through. - * - *

Which language reads a file is the file name's to say: {@code platform.intent.yml} is a Platform - * document and {@code *.project.yml} a project file. A set handed to {@link #check} also reads any other - * YAML file whose document says {@code kind: Project} as one, as a composition fixture standing in for a - * published fragment does (spec/v1/10-project-intent.md#two-artefacts). A set of files is read into one - * resource set, so a tier's proxy links to an Application another file declares. - */ -public final class Pipeline { - - /** The Complete OCL file the metamodel carries, beside its classes. */ - private static final String CONSTRAINTS = "project-intent.ocl"; - - /** The code an Asset earns whose file is not beside its project file. */ - private static final String ASSET_NOT_FOUND = "E_ASSET_NOT_FOUND"; - - /** The code an env file earns whose scope directory names no level of the project file. */ - private static final String UNKNOWN_ENV_SCOPE = "E_UNKNOWN_ENV_SCOPE"; - - /** - * The codes of what a Process holds across its levels and its env files, and of what the union asks - * of a tier's proxy, asked of a document that holds, as composition asks them. - */ - private static final java.util.Set ACROSS_THE_UNION = java.util.Set.of( - "E_SELF_WITHOUT_VAULT_CLIENT", "E_CLIENT_PLACEHOLDER_WITHOUT_SECRET", "E_NO_API_ACCESS_POLICY"); - - /** The code an image earns that a pod runs as its own user where the lock holds it as root. */ - private static final String IMAGE_RUNS_AS_ROOT = "E_IMAGE_RUNS_AS_ROOT"; - - /** The code an image earns that the images lock holds no entry for. */ - private static final String UNLOCKED_IMAGE = "E_UNLOCKED_IMAGE"; - - /** The code a Project the mesh enrols earns where no project file declares it. */ - private static final String UNKNOWN_ENROLLED_PROJECT = "E_UNKNOWN_ENROLLED_PROJECT"; - - private static final String PLATFORM = "platform.intent.yml"; - private static final String PROJECT = ".project.yml"; - private static final String YAML = ".yml"; - - /** A document's own {@code kind: Project}, at the top level, with an optional comment after it. */ - private static final Pattern DECLARES_PROJECT = Pattern.compile("(?m)^kind:[ \\t]*Project[ \\t]*(#.*)?$"); - - /** The pinned inputs resolution reads beside the intent, each by its own file name. */ - private static final String NODE_CONTRACT = "node-contract.yml"; - - private static final String IMAGES_LOCK = "images.lock.yml"; - private static final String CLUSTER_STATE = "cluster-state.yml"; - private static final String MIGRATION_PROOF = "migration-proof.yml"; - - private Pipeline() {} - - /** The parsed intent of the one authored file at {@code path}, or the diagnostics refusing it. */ - public static Parsed intent(Path path) { - // Checked with the env files beside it, since what a Process reads through them is part of what - // is checked of it; the intent is the authored document alone. - Resource checked = read(List.of(path)).get(0); - withEnv(checked, path); - List refusals = refusals(checked, false); - return refusals.isEmpty() - ? Parsed.of( - IntentJson.of(read(List.of(path)).get(0).getContents().get(0))) - : Parsed.refused(refusals); - } - - /** - * The Effective Intent of the one project file at {@code path}: the file and the env files under - * the {@code env/} directory beside it, lowered onto the Processes that hold them - * (spec/v1/10-project-intent.md#the-effective-intent), or the diagnostics refusing either. - */ - public static Parsed effective(Path path) throws IOException { - Resource resource = read(List.of(path)).get(0); - // What a Process reads through its env files is part of what is checked of it. - withEnv(resource, path); - List refusals = new ArrayList<>(refusals(resource, false)); - EnvFiles.Read env = EnvFiles.read(envBeside(path)); - refusals.addAll(env.diagnostics()); - if (!refusals.isEmpty()) { - return Parsed.refused(refusals); - } - Project project = (Project) resource.getContents().get(0); - for (EnvFiles.Scoped scoped : env.files()) { - if (levelOf(project, scoped.scope()).isEmpty()) { - refusals.add(new Diagnostic( - UNKNOWN_ENV_SCOPE, - scoped.path(), - scoped.path(), - "this scope directory names nothing the project file declares")); - } - } - return refusals.isEmpty() ? Parsed.of(IntentJson.of(Lowering.lower(project))) : Parsed.refused(refusals); - } - - /** - * The Resolved Deployment of {@code project}, from {@code files} read together: the Platform - * document, every project file of the union with the env files beside each, and the pinned inputs - * (spec/v1/20-resolved-deployment.md#pinned-inputs). Every document is checked first, and a set - * the checks refuse is refused here with their diagnostics, before anything is resolved. - */ - public static Resolved resolve(List files, String project, String schemaPackageIntegrity) throws IOException { - Authored authored = authored(files); - if (!authored.ok()) { - return Resolved.refused(authored.diagnostics()); - } - List intent = new ArrayList<>(); - for (EObject root : authored.intent()) { - intent.add(root); - // The authored Project stays in the extent beside its lowering: the Platform document's - // links point into it, and the transformation reads the lowering. - if (root instanceof Project document) { - intent.add(Lowering.lower(document)); - } - } - ResolvedDeployment deployment = Resolution.resolve(intent, authored.pinned(), project, schemaPackageIntegrity); - List unplaceable = Placement.check(deployment, intent); - return unplaceable.isEmpty() - ? Resolved.of(deployment, intent, authored.pinned()) - : Resolved.refused(unplaceable); - } - - /** - * {@code files} read together as the resolution reads them, before any project is lowered: every - * authored Project with the env files beside it on the levels they name, the Platform document, and - * the pinned inputs with the file each Asset names. A set the checks refuse is refused here. - */ - public static Authored authored(List files) throws IOException { - List refusals = new ArrayList<>(check(files)); - if (!refusals.isEmpty()) { - return Authored.refused(refusals); - } - List documents = read(files); - List intent = new ArrayList<>(); - List pinned = new ArrayList<>(); - for (int i = 0; i < files.size(); i++) { - EObject root = documents.get(i).getContents().get(0); - switch (root) { - case Project authored -> { - EnvFiles.Read env = EnvFiles.read(envBeside(files.get(i))); - refusals.addAll(env.diagnostics()); - for (EnvFiles.Scoped scoped : env.files()) { - levelOf(authored, scoped.scope()) - .ifPresent(level -> level.getEnv().add(scoped.file())); - } - intent.add(authored); - pinned.addAll(assetFiles(authored, files.get(i))); - } - case Platform platform -> intent.add(platform); - default -> pinned.add(root); - } - } - return refusals.isEmpty() ? Authored.of(intent, pinned) : Authored.refused(refusals); - } - - /** - * The Deliverable Sets of {@code projects}, from {@code files} read together, written under - * {@code root} in one pass: every document parsed and checked, each project lowered and resolved, - * and the templates run over the Resolved Deployments (spec/v1/30-deliverables.md): lower, then - * resolve, then render. Rendered together, the projects write the estate-scoped share they hold - * between them, which each resolution plans beside its own model. A set the checks - * refuse writes nothing, and its diagnostics are returned. - */ - public static List render( - List files, List projects, String schemaPackageIntegrity, Path root) throws IOException { - List deployments = new ArrayList<>(); - for (String project : projects) { - Resolved resolved = resolve(files, project, schemaPackageIntegrity); - if (!resolved.ok()) { - return resolved.diagnostics(); - } - deployments.add(resolved.deployment()); - } - return renderTogether(deployments, root); - } - - /** - * {@code deployments} rendered together to {@code root}, the estate-scoped share they name written - * whole, unless a path, a Vault name or a ServiceAccount has two owners: then nothing is written, - * and the collisions are returned. - */ - static List renderTogether(List deployments, Path root) { - oneStableAddressFile(deployments); - List planned = Collisions.ofPlan(deployments); - if (!planned.isEmpty()) { - return planned; - } - return Rendering.render(deployments, root, Collisions::ofAccounts); - } - - /** - * The Stable Addresses are the estate's, delivered with the Projects that name them - * (spec/v1/16-dependencies.md#the-stable-address): each Project's resolution plans the file of - * those its own edges name, so a render of several writes one file of every one any of them - * names, once each and in name order. - */ - private static void oneStableAddressFile(List deployments) { - List files = deployments.stream() - .flatMap(deployment -> deployment.getDeliverables().stream()) - .filter(StableAddressFile.class::isInstance) - .map(StableAddressFile.class::cast) - .toList(); - Map named = new TreeMap<>(); - files.forEach(file -> file.getAddresses().forEach(alias -> named.putIfAbsent(alias.getName(), alias))); - List every = List.copyOf(named.values()); - files.forEach(file -> { - file.getAddresses().clear(); - file.getAddresses().addAll(EcoreUtil.copyAll(every)); - }); - } - - /** - * The file each Asset of {@code project} names, read as text from beside its project file - * (spec/v1/10-project-intent.md#assets). Every one is there, or {@link #check} refused the set - * with E_ASSET_NOT_FOUND. - */ - private static List assetFiles(Project project, Path file) throws IOException { - // An Asset, mounted or seeded, and every dashboard and alert rules file the project names - // are read from beside it; only an Asset's absence is refused before resolution. - // An Alert Rules file is also read as the data it holds, its rules, which the monitoring - // stack's rules are written from. - List named = new ArrayList<>(); - List ruleFiles = new ArrayList<>(); - EcoreUtil2.getAllContentsOfType(project, AssetDeclaration.class).forEach(asset -> named.add(asset.getFrom())); - EcoreUtil2.getAllContentsOfType(project, Dashboard.class).forEach(board -> named.add(board.getFrom())); - EcoreUtil2.getAllContentsOfType(project, AlertRules.class).forEach(group -> ruleFiles.add(group.getFrom())); - named.addAll(ruleFiles); - List read = new ArrayList<>(); - for (String from : named) { - Path beside = besideProject(file, from).orElseThrow(); - AssetFile assetFile = PinnedInputsFactory.eINSTANCE.createAssetFile(); - assetFile.setProject(project.getProject()); - assetFile.setFrom(from); - assetFile.setContent(Files.readString(beside, StandardCharsets.UTF_8)); - if (ruleFiles.contains(from)) { - assetFile.setRules(DataFile.read(assetFile.getContent()).orElse(null)); - } - read.add(assetFile); - } - return read; - } - - /** The env files under the {@code env/} directory beside {@code path}, in path order. */ - private static List envBeside(Path path) throws IOException { - Path env = path.toAbsolutePath().resolveSibling("env"); - if (!Files.isDirectory(env)) { - return List.of(); - } - try (Stream tree = Files.walk(env)) { - List sources = new ArrayList<>(); - for (Path file : tree.filter(file -> file.toString().endsWith(".env")) - .sorted() - .toList()) { - sources.add(new EnvFiles.Source(file.toString(), Files.readString(file, StandardCharsets.UTF_8))); - } - return sources; - } - } - - /** The level of {@code project} a scope directory names, or nothing where it names none. */ - private static Optional levelOf(Project project, EnvFiles.Scope scope) { - return switch (scope.level()) { - case PROJECT -> Optional.of(project); - case APPLICATION -> - project.getApplications().stream() - .filter(application -> scope.name().equals(application.getId())) - .map(SharedIntent.class::cast) - .findFirst(); - case PROCESS -> - project.getApplications().stream() - .flatMap(application -> application.getProcesses().stream()) - .filter(process -> scope.name().equals(process.getName())) - .map(SharedIntent.class::cast) - .findFirst(); - }; - } - - /** - * The parsed model of the one authored file at {@code path}, serialised as XMI: the same instance - * of the metamodel the constraints are checked on, in the form Eclipse opens without the grammar. A - * name that links into another document stays a proxy, because the file is read alone, and is - * written relative to the authored file beside it, never as a path on the machine that ran it. - */ - public static String xmi(Path path) throws IOException { - return xmi(List.of(path)).get(path); - } - - /** - * The parsed models of {@code files} read together, each serialised as XMI as if written beside - * its authored file, under the name {@link #xmiName} gives it. A name one file declares and another links to is - * written as a reference from one XMI file to the other, so the set loads in Eclipse as it is read - * here; a name no file declares stays a proxy against the authored file. A document the pipeline - * refuses is written all the same, so its refusal can be reproduced by validating it. A file that - * holds no document has no model and is left out. - */ - public static Map xmi(List files) throws IOException { - List documents = read(files); - EcoreUtil.Copier copier = new EcoreUtil.Copier(); - ResourceSet models = new ResourceSetImpl(); - Map written = new LinkedHashMap<>(); - for (int i = 0; i < files.size(); i++) { - if (documents.get(i).getContents().isEmpty()) { - continue; - } - Path file = files.get(i); - Resource model = new ByPath(URI.createFileURI( - file.toAbsolutePath().resolveSibling(xmiName(file)).toString())); - models.getResources().add(model); - model.getContents().add(copier.copy(documents.get(i).getContents().get(0))); - written.put(file, model); - } - // Only once every root is copied does a link into another document have a copy to point at. - copier.copyReferences(); - Map xmi = new LinkedHashMap<>(); - for (Map.Entry model : written.entrySet()) { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - model.getValue().save(out, null); - xmi.put(model.getKey(), out.toString(StandardCharsets.UTF_8)); - } - return xmi; - } - - /** - * An XMI resource that refers to its objects by containment path, never by ID. An Application's - * {@code id} and a Process's {@code name} are both IDs, and one document may give an Application - * and its Process the same name, so an ID would not name one object once the file is read back. - */ - static final class ByPath extends XMIResourceImpl { - ByPath(URI uri) { - super(uri); - } - - @Override - public String getURIFragment(EObject object) { - EObject root = EcoreUtil.getRootContainer(object); - return root == object ? "/" : "//" + EcoreUtil.getRelativeURIFragmentPath(root, object); - } - } - - /** - * What the XMI of an authored file is called: its own name with {@code .xmi} for {@code .yml}, so - * {@code notes.project.yml} is {@code notes.project.xmi} and the two sort side by side. - */ - public static String xmiName(Path file) { - return file.getFileName().toString().replaceFirst("\\.yml$", "") + ".xmi"; - } - - /** - * The diagnostics refusing {@code files} read together: each file's own first, and only when every - * file holds, what a Platform document and the project files beside it break together. A file that - * is neither document is not read. - * - *

Each file is first read alone, where a constraint across documents holds trivially, and the set - * is read together only once every file holds, where the constraints of one document already do. So - * the second reading refuses exactly what the documents break together, which is nothing when no - * Platform document is among them. - */ - public static List check(List files) { - List documents = files.stream() - .filter(file -> isPlatform(file) || isProject(file)) - .toList(); - List refusals = new ArrayList<>(); - for (Path document : documents) { - Resource alone = read(List.of(document)).get(0); - withEnv(alone, document); - refusals.addAll(refusals(alone, false)); - } - if (!refusals.isEmpty()) { - return refusals; - } - List read = read(documents); - List placed = new ArrayList<>(); - List projects = new ArrayList<>(); - Map named = new LinkedHashMap<>(); - Optional platform = Optional.empty(); - for (int i = 0; i < documents.size(); i++) { - Path file = documents.get(i); - if (read.get(i).getContents().get(0) instanceof Project project) { - // What a Process holds reaches it through the env files beside its project too. - attachEnv(project, file); - refusals.addAll(unreadAssets(project, file)); - refusals.addAll(ShippedFiles.check( - project, file.getFileName().toString(), from -> textBeside(file, from), placed)); - projects.add(project.getProject()); - named.put(project, file.getFileName().toString()); - } else { - // Only a project file and the Platform document are among the documents. - platform = Optional.of((Platform) read.get(i).getContents().get(0)); - } - } - refusals.addAll(ShippedFiles.acrossTheEstate(placed, platform)); - platform.ifPresent(document -> refusals.addAll(unknownEnrolled(document, projects))); - platform.ifPresent(document -> refusals.addAll(L4Checks.check(document, named))); - platform.ifPresent(document -> refusals.addAll(OperatedChecks.check(document, named))); - Optional estate = platform; - files.stream() - .filter(file -> file.getFileName().toString().equals(IMAGES_LOCK)) - .findFirst() - .ifPresent(lock -> { - refusals.addAll(rootImages(lock, named.keySet())); - estate.ifPresent(document -> refusals.addAll(unlockedSeeder(lock, document))); - }); - // Which Node Agents run is decided by the contract beside the Platform document, where the set has one. - files.stream() - .filter(file -> file.getFileName().toString().equals(NODE_CONTRACT)) - .findFirst() - .ifPresent(contract -> estate.ifPresent(document -> refusals.addAll(nodeAgents(contract, document)))); - for (Resource document : read) { - refusals.addAll(refusals(document, true)); - } - return refusals; - } - - /** - * Every Project the mesh enrols that no project file of the set declares - * (spec/v1/14-platform-intent.md#the-mesh). - */ - private static List unknownEnrolled(Platform platform, List projects) { - List unknown = new ArrayList<>(); - if (platform.getMesh() != null) { - List enrolled = platform.getMesh().getEnrolled(); - for (int i = 0; i < enrolled.size(); i++) { - if (!projects.contains(enrolled.get(i))) { - unknown.add(new Diagnostic( - UNKNOWN_ENROLLED_PROJECT, - platform.eResource().getURI().lastSegment(), - Pointer.of(platform.getMesh()) + "/enrolled/" + i, - "no project file declares the Project " + enrolled.get(i) + " the mesh enrols")); - } - } - } - return unknown; - } - - /** - * Every image a pod runs as its own user that the images lock holds with uid 0 - * (spec/v1/10-project-intent.md#the-uid-is-a-pinned-input-and-the-volume-needs-a-group): the - * posture runs every pod as non-root, and the kubelet refuses such a pod. A lock that does not - * parse is refused for its shape, not here. - */ - private static List rootImages(Path lock, Collection projects) { - Resource read = read(List.of(lock)).get(0); - return read.getErrors().isEmpty() - ? read.getContents().stream() - .map(ImagesLock.class::cast) - .findFirst() - .map(images -> { - Map uids = new LinkedHashMap<>(); - images.getImages().forEach(image -> uids.put(image.getAlias(), image.getUid())); - return rootAliases(uids, projects).stream() - .map(alias -> new Diagnostic( - IMAGE_RUNS_AS_ROOT, - lock.getFileName().toString(), - "/images/" + alias, - "the images lock holds " + alias - + " with uid 0, and every pod runs as non-root")) - .toList(); - }) - .orElse(List.of()) - : List.of(); - } - - /** - * The seeder the Platform document names, where the images lock holds no entry for its image - * (spec/v1/14-platform-intent.md#the-seeder): the step runs by digest, and a lock that does not - * parse is refused for its shape, not here. - */ - private static List unlockedSeeder(Path lock, Platform platform) { - Resource read = read(List.of(lock)).get(0); - if (platform.getSeeder() == null || !read.getErrors().isEmpty()) { - return List.of(); - } - boolean held = read.getContents().stream() - .map(ImagesLock.class::cast) - .flatMap(images -> images.getImages().stream()) - .anyMatch(image -> image.getAlias().equals(platform.getSeeder().getImage())); - return held - ? List.of() - : List.of(new Diagnostic( - UNLOCKED_IMAGE, - platform.eResource().getURI().lastSegment(), - "/seeder/image", - "the images lock holds no entry for " - + platform.getSeeder().getImage())); - } - - /** - * The Node Agents the node contract at {@code contract} and {@code platform} derive that the - * catalog names no image for, or the refusals of a contract that does not read. - */ - private static List nodeAgents(Path contract, Platform platform) { - Resource read = read(List.of(contract)).get(0); - if (!read.getErrors().isEmpty()) { - return shape(read, contract.getFileName().toString(), read.getErrors()); - } - return NodeAgentChecks.check(platform, (NodeContract) read.getContents().get(0)); - } - - /** - * The aliases, sorted, of every image a pod of {@code projects} runs as its own user, a Process's - * or a migration's, that {@code uids} holds as root, for each project whose every image, a - * sidecar's too, the lock holds: an alias the lock does not hold is the share's own refusal. - */ - static SortedSet rootAliases(Map uids, Collection projects) { - SortedSet root = new TreeSet<>(); - for (Project project : projects) { - Set aliases = new TreeSet<>(); - Set ownUser = new TreeSet<>(); - for (Application application : project.getApplications()) { - for (dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Process process : - application.getProcesses()) { - ownUser.add(process.getImage()); - process.getSidecars().forEach(sidecar -> aliases.add(sidecar.getImage())); - } - // Only a migration over the platform's runner runs an image of its own. - if (application.getMigration() - instanceof dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ManagedMigration) { - ownUser.add(application.getId() + "-migration"); - } - } - aliases.addAll(ownUser); - if (uids.keySet().containsAll(aliases)) { - ownUser.stream().filter(alias -> uids.get(alias) == 0).forEach(root::add); - } - } - return root; - } - - /** The env files beside {@code file} on the levels they name, where {@code resource} holds a project. */ - private static void withEnv(Resource resource, Path file) { - // A document whose shape breaks is refused for its shape before anything it holds is asked. - if (!resource.getContents().isEmpty() && resource.getContents().get(0) instanceof Project project) { - attachEnv(project, file); - } - } - - /** The text of the file {@code from} names beside {@code file}, if one is there. */ - private static Optional textBeside(Path file, String from) { - return besideProject(file, from).map(path -> { - try { - return Files.readString(path, StandardCharsets.UTF_8); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }); - } - - /** The env files beside {@code file}, each on the level its scope directory names. */ - private static void attachEnv(Project project, Path file) { - try { - for (EnvFiles.Scoped scoped : EnvFiles.read(envBeside(file)).files()) { - levelOf(project, scoped.scope()) - .ifPresent(level -> level.getEnv().add(scoped.file())); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** - * The file {@code from} names below the directory of {@code file}, if one is there: a path that - * leaves that directory, absolute or through {@code ..}, names no file beside the project, exactly - * as the production implementation, which reads only the files of the set, finds none. - */ - private static Optional besideProject(Path file, String from) { - Path directory = file.toAbsolutePath().normalize().getParent(); - Path target = directory.resolve(from).normalize(); - return target.startsWith(directory) && Files.isRegularFile(target) ? Optional.of(target) : Optional.empty(); - } - - /** - * Every Asset of {@code project} whose file is not beside {@code file}: an Asset mounts a file its - * fragment carries (spec/v1/10-project-intent.md#assets). - */ - private static List unreadAssets(Project project, Path file) { - List unread = new ArrayList<>(); - for (Asset asset : EcoreUtil2.getAllContentsOfType(project, Asset.class)) { - if (besideProject(file, asset.getFrom()).isEmpty()) { - unread.add(new Diagnostic( - ASSET_NOT_FOUND, - file.getFileName().toString(), - Pointer.of(asset) + "/from", - "no file " + asset.getFrom() + " is read beside the project file")); - } - } - return unread; - } - - private static boolean isPlatform(Path file) { - return file.getFileName().toString().endsWith(PLATFORM); - } - - /** A project file by its name, or another YAML file, never the Platform document, whose document says it is one. */ - private static boolean isProject(Path file) { - String name = file.getFileName().toString(); - if (name.endsWith(PROJECT)) { - return true; - } - if (!name.endsWith(YAML)) { - return false; - } - try { - return DECLARES_PROJECT - .matcher(Files.readString(file, StandardCharsets.UTF_8)) - .find(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** Every file loaded into one resource set, by the language its name says, then linked. */ - static List read(List files) { - // Outside OSGi nothing registers the metamodels, and the grammars' rules return their classes. - EPackage.Registry.INSTANCE.putIfAbsent(ProjectIntentPackage.eNS_URI, ProjectIntentPackage.eINSTANCE); - EPackage.Registry.INSTANCE.putIfAbsent(PinnedInputsPackage.eNS_URI, PinnedInputsPackage.eINSTANCE); - Injector project = new ProjectIntentStandaloneSetup().createInjectorAndDoEMFRegistration(); - Map languages = Map.of( - PLATFORM, new PlatformIntentStandaloneSetup().createInjectorAndDoEMFRegistration(), - NODE_CONTRACT, new NodeContractStandaloneSetup().createInjectorAndDoEMFRegistration(), - IMAGES_LOCK, new ImagesLockStandaloneSetup().createInjectorAndDoEMFRegistration(), - CLUSTER_STATE, new ClusterStateStandaloneSetup().createInjectorAndDoEMFRegistration(), - MIGRATION_PROOF, new MigrationProofStandaloneSetup().createInjectorAndDoEMFRegistration()); - XtextResourceSet resources = project.getInstance(XtextResourceSet.class); - List documents = new ArrayList<>(); - for (Path file : files) { - String name = file.getFileName().toString(); - Injector language = languages.entrySet().stream() - .filter(named -> name.endsWith(named.getKey())) - .map(Map.Entry::getValue) - .findFirst() - .orElse(project); - Resource document = language.getInstance(IResourceFactory.class) - .createResource(URI.createFileURI(file.toAbsolutePath().toString())); - resources.getResources().add(document); - try { - document.load(resources.getLoadOptions()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - documents.add(document); - } - // Linking is lazy: every reference is resolved once every file is loaded, so a name that links to - // nothing is among the errors and a name another file declares is not. - documents.forEach(EcoreUtil2::resolveAll); - return documents; - } - - /** - * What refuses one document: its shape, then its constraints and its names. A tier's proxy is a name - * only a set of documents can link, so it is read {@code together} and every other name is not. - */ - private static List refusals(Resource resource, boolean together) { - String file = resource.getURI().lastSegment(); - List refusals = new ArrayList<>(); - List syntax = new ArrayList<>(); - for (Resource.Diagnostic error : resource.getErrors()) { - if (!(error instanceof XtextLinkingDiagnostic)) { - syntax.add(error); - } - } - refusals.addAll(shape(resource, file, syntax)); - if (!refusals.isEmpty()) { - return refusals; - } - List constraints = Constraints.check( - resource.getContents().get(0), Constraints.beside(ProjectIntentPackage.class, CONSTRAINTS)); - // What a Process holds across its levels and env files is asked only of a document that holds - // on its own, as the production implementation asks it of the union after each document. - boolean holds = constraints.stream().allMatch(refusal -> ACROSS_THE_UNION.contains(refusal.code())); - refusals.addAll( - holds - ? constraints - : constraints.stream() - .filter(refusal -> !ACROSS_THE_UNION.contains(refusal.code())) - .toList()); - refusals.addAll(unlinked(resource, together)); - return refusals; - } - - /** - * Where a document's shape is wrong, as the schema's refusals say it: one diagnostic for every node - * that is wrong, at its JSON pointer. The parser stops at its first error and cannot say where in - * the document that is, so the grammar's own rules are read against the whole file; what the - * parser said stands only when they find nothing. - */ - private static List shape(Resource resource, String file, List syntax) { - List shape = new ArrayList<>(); - // The parse keeps the whole text it read, so the file is not read a second time. - XtextResource xtext = (XtextResource) resource; - String text = xtext.getParseResult().getRootNode().getText(); - Grammar grammar = - xtext.getResourceServiceProvider().get(IGrammarAccess.class).getGrammar(); - for (Shapes.Issue issue : Shapes.check(text, grammar)) { - shape.add(new Diagnostic(Diagnostic.SCHEMA, file, issue.path(), issue.message())); - } - if (!shape.isEmpty()) { - return shape; - } - List parsed = new ArrayList<>(); - for (Resource.Diagnostic error : syntax) { - parsed.add( - new Diagnostic(Diagnostic.SCHEMA, file, "", "line " + error.getLine() + ": " + error.getMessage())); - } - return parsed; - } - - /** - * The names in {@code resource} that link to nothing: a tier's proxy when {@code together}, and - * every other name when not. Only a document whose shape holds is asked, so every error it carries - * is a link. - */ - private static List unlinked(Resource resource, boolean together) { - List unlinked = new ArrayList<>(); - for (Resource.Diagnostic error : resource.getErrors()) { - XtextLinkingDiagnostic linking = (XtextLinkingDiagnostic) error; - if (UnlinkedNames.ACROSS_DOCUMENTS.contains(linking.getCode()) == together) { - EObject owner = resource.getEObject(linking.getUriToProblem().fragment()); - // A name below its owner carries where it sits as the diagnostic's one datum. - String below = linking.getData().length == 0 ? "" : linking.getData()[0]; - unlinked.add(new Diagnostic( - linking.getCode(), - resource.getURI().lastSegment(), - Pointer.of(owner) + below, - linking.getMessage())); - } - } - return unlinked; - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Placement.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Placement.java deleted file mode 100644 index 06e94ecd8..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Placement.java +++ /dev/null @@ -1,65 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedApplication; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedProcess; -import java.util.ArrayList; -import java.util.List; -import org.eclipse.emf.ecore.EObject; - -/** - * The placement refusals of a resolution: a Process no node of the contract can hold, and replicas - * spread across more nodes than are eligible (spec/v1/20-resolved-deployment.md#layer-2-does-not-assign-a-node). - * The invariants are Complete OCL over the Resolved Deployment ({@code resolved-deployment.ocl}), which - * holds the eligible nodes; this class writes each where the production implementation does, in the - * project file that declares the Process, because the resolution knows no file. - */ -final class Placement { - - /** The Complete OCL file the Resolved Deployment's metamodel carries, beside its classes. */ - private static final String CONSTRAINTS = "resolved-deployment.ocl"; - - private Placement() {} - - /** The refusals of {@code deployment}, written into the authored projects of {@code intent}. */ - static List check(ResolvedDeployment deployment, List intent) { - List refusals = new ArrayList<>(); - for (Constraints.Violation violation : - Constraints.violations(deployment, Constraints.beside(ResolvedDeploymentPackage.class, CONSTRAINTS))) { - ResolvedProcess process = (ResolvedProcess) violation.object(); - ResolvedApplication resolved = (ResolvedApplication) process.eContainer(); - // Every Project the resolution reads is among the intent, authored beside its lowering. - Project project = intent.stream() - .filter(Project.class::isInstance) - .map(Project.class::cast) - .filter(candidate -> candidate.getProject().equals(resolved.getProject())) - .findFirst() - .orElseThrow(); - Application application = project.getApplications().stream() - .filter(candidate -> candidate.getId().equals(resolved.getId())) - .findFirst() - .orElseThrow(); - int a = project.getApplications().indexOf(application); - int p = application.getProcesses().stream() - .map(dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Process::getName) - .toList() - .indexOf(process.getName()); - refusals.add(new Diagnostic( - violation.code(), - project.eResource().getURI().lastSegment(), - "/applications/" + a + "/processes/" + p + "/" + violation.feature(), - message(process, violation.feature()))); - } - return refusals; - } - - private static String message(ResolvedProcess process, String feature) { - return feature.equals("replicas") - ? process.getName() + " keeps " + process.getReplicas() + " replicas on different nodes, and " - + process.getPlacement().getEligibleNodes().size() + " can hold it" - : "no node in the node contract can hold " + process.getName(); - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Pointer.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Pointer.java deleted file mode 100644 index 53adda239..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Pointer.java +++ /dev/null @@ -1,41 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import java.util.List; -import java.util.Map; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EStructuralFeature; - -/** - * The RFC 6901 JSON Pointer of an object inside its document, read off its containment chain: the - * name of the feature that holds it, and its index where the feature holds many, or its key where - * the feature is a map (docs/architecture.md#the-parity-contract). A map entry's value sits at its - * entry's pointer. The root is the empty pointer. - */ -public final class Pointer { - - private Pointer() {} - - /** The pointer of {@code object} in the document it belongs to. */ - public static String of(EObject object) { - EObject owner = object.eContainer(); - if (owner == null) { - return ""; - } - if (owner instanceof Map.Entry) { - return of(owner); - } - EStructuralFeature feature = object.eContainingFeature(); - String step = escape(feature.getName()); - if (object instanceof Map.Entry entry) { - step = step + "/" + escape(String.valueOf(entry.getKey())); - } else if (feature.isMany()) { - step = step + "/" + ((List) owner.eGet(feature)).indexOf(object); - } - return of(owner) + "/" + step; - } - - /** A feature name as a pointer segment: the two characters a pointer spells differently. */ - private static String escape(String name) { - return name.replace("~", "~0").replace("/", "~1"); - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Resolved.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Resolved.java deleted file mode 100644 index 64b5c06dd..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/Resolved.java +++ /dev/null @@ -1,32 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import java.util.List; -import org.eclipse.emf.ecore.EObject; - -/** - * The outcome of resolving one project of a set: its Resolved Deployment and the two extents it was - * resolved from, or the diagnostics that refused the set before resolution ran. A refused set has - * no deployment and no extents. - */ -public record Resolved( - ResolvedDeployment deployment, List intent, List pinned, List diagnostics) { - - public Resolved { - intent = List.copyOf(intent); - pinned = List.copyOf(pinned); - diagnostics = List.copyOf(diagnostics); - } - - public static Resolved of(ResolvedDeployment deployment, List intent, List pinned) { - return new Resolved(deployment, intent, pinned, List.of()); - } - - public static Resolved refused(List diagnostics) { - return new Resolved(null, List.of(), List.of(), diagnostics); - } - - public boolean ok() { - return diagnostics.isEmpty(); - } -} diff --git a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/ShippedFiles.java b/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/ShippedFiles.java deleted file mode 100644 index f3695ccd7..000000000 --- a/emf/bundles/cli/src/main/java/dev/jorisjonkers/deploykit/emf/cli/ShippedFiles.java +++ /dev/null @@ -1,264 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.AlertRules; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Dashboard; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * The files an Application ships beside its project file for the monitoring stack to load: its - * dashboards and its alert-rule groups (spec/v1/10-project-intent.md#observability). Each must be - * there and hold what its loader keys it by, and no two dashboards of the estate share a uid. - */ -final class ShippedFiles { - - static final String DASHBOARD_NOT_FOUND = "E_DASHBOARD_NOT_FOUND"; - static final String DASHBOARD_WITHOUT_UID = "E_DASHBOARD_WITHOUT_UID"; - static final String DUPLICATE_DASHBOARD_UID = "E_DUPLICATE_DASHBOARD_UID"; - static final String NO_DASHBOARD_POLICY = "E_NO_DASHBOARD_POLICY"; - static final String ALERT_RULES_NOT_FOUND = "E_ALERT_RULES_NOT_FOUND"; - static final String ALERT_RULES_WITHOUT_GROUPS = "E_ALERT_RULES_WITHOUT_GROUPS"; - - /** A dashboard of one project whose file holds a uid, by where it is written. */ - record Placed(String document, String path, String uid) {} - - private ShippedFiles() {} - - /** - * Every dashboard and rule-group file {@code project} names that {@code read} does not hold, or - * that holds no uid or no groups; each dashboard that holds a uid is added to {@code placed}. - */ - static List check( - Project project, String document, Function> read, List placed) { - List refusals = new ArrayList<>(); - for (Application application : project.getApplications()) { - for (Dashboard dashboard : application.getDashboards()) { - String path = Pointer.of(dashboard) + "/from"; - Optional content = read.apply(dashboard.getFrom()); - Optional uid = content.flatMap(TopLevel::uid); - if (content.isEmpty()) { - refusals.add(new Diagnostic( - DASHBOARD_NOT_FOUND, - document, - path, - "no file " + dashboard.getFrom() + " is read beside the project file")); - } else if (uid.isEmpty()) { - refusals.add(new Diagnostic( - DASHBOARD_WITHOUT_UID, - document, - path, - dashboard.getFrom() + " names no uid, so Grafana would key it by a value of its own")); - } else { - placed.add(new Placed(document, path, uid.get())); - } - } - for (AlertRules rules : application.getAlertRules()) { - String path = Pointer.of(rules) + "/from"; - Optional content = read.apply(rules.getFrom()); - if (content.isEmpty()) { - refusals.add(new Diagnostic( - ALERT_RULES_NOT_FOUND, - document, - path, - "no file " + rules.getFrom() + " is read beside the project file")); - } else if (DataFile.groups(content.get()).isEmpty()) { - refusals.add(new Diagnostic( - ALERT_RULES_WITHOUT_GROUPS, - document, - path, - rules.getFrom() + " holds no list of rule groups under `groups`")); - } - } - } - return refusals; - } - - /** - * Every dashboard of the estate after the first that carries a uid already carried, and, where a - * Platform document is read and names no Grafana, every dashboard, which would ship nowhere. - */ - static List acrossTheEstate(List placed, Optional platform) { - List refusals = new ArrayList<>(); - Set seen = new HashSet<>(); - for (Placed dashboard : placed) { - if (!seen.add(dashboard.uid())) { - refusals.add(new Diagnostic( - DUPLICATE_DASHBOARD_UID, - dashboard.document(), - dashboard.path(), - "another dashboard of the estate already carries the uid " + dashboard.uid())); - } - } - boolean shipsNowhere = platform.map( - p -> p.getTelemetry() == null || p.getTelemetry().getDashboards() == null) - .orElse(false); - if (shipsNowhere) { - for (Placed dashboard : placed) { - refusals.add(new Diagnostic( - NO_DASHBOARD_POLICY, - dashboard.document(), - dashboard.path(), - "the platform names no Grafana for a dashboard to ship to")); - } - } - return refusals; - } - - /** - * The one top-level string a JSON document carries under a key, read by a parser just large enough - * to tell a top-level key from a nested one and a document from text that is not JSON. - */ - static final class TopLevel { - /** A number, or one of the three words JSON spells a value with. */ - private static final Pattern LITERAL = Pattern.compile("true|false|null|-?\\d+(\\.\\d+)?([eE][-+]?\\d+)?"); - - private final String text; - private int at; - - private TopLevel(String text) { - this.text = text; - } - - /** The non-empty string the document's own `uid` holds, where it is a JSON object that has one. */ - static Optional uid(String content) { - TopLevel json = new TopLevel(content); - try { - json.space(); - if (json.peek() != '{') { - return Optional.empty(); - } - Optional uid = json.object(true); - json.space(); - return json.at == json.text.length() ? uid.filter(value -> !value.isEmpty()) : Optional.empty(); - } catch (IllegalStateException | IndexOutOfBoundsException e) { - return Optional.empty(); - } - } - - private char peek() { - return text.charAt(at); - } - - private void space() { - while (at < text.length() && Character.isWhitespace(text.charAt(at))) { - at++; - } - } - - private void expect(char c) { - space(); - if (text.charAt(at++) != c) { - throw new IllegalStateException("expected " + c); - } - } - - /** An object; at the top level, the string its `uid` holds, if it holds one. */ - private Optional object(boolean top) { - expect('{'); - Optional uid = Optional.empty(); - space(); - if (peek() == '}') { - at++; - return uid; - } - while (true) { - space(); - String key = string(); - expect(':'); - space(); - if (top && key.equals("uid") && peek() == '"') { - uid = Optional.of(string()); - } else { - value(); - } - space(); - char next = text.charAt(at++); - if (next == '}') { - return uid; - } - if (next != ',') { - throw new IllegalStateException("expected , or }"); - } - } - } - - private void value() { - space(); - char c = peek(); - if (c == '{') { - object(false); - } else if (c == '[') { - at++; - space(); - if (peek() == ']') { - at++; - return; - } - while (true) { - value(); - space(); - char next = text.charAt(at++); - if (next == ']') { - return; - } - if (next != ',') { - throw new IllegalStateException("expected , or ]"); - } - } - } else if (c == '"') { - string(); - } else { - Matcher literal = LITERAL.matcher(text).region(at, text.length()); - if (!literal.lookingAt()) { - throw new IllegalStateException("not a value"); - } - at = literal.end(); - } - } - - private String string() { - if (text.charAt(at++) != '"') { - throw new IllegalStateException("expected a string"); - } - StringBuilder out = new StringBuilder(); - while (true) { - char c = text.charAt(at++); - if (c == '"') { - return out.toString(); - } - if (c == '\\') { - char escaped = text.charAt(at++); - if (escaped == 'u') { - try { - out.append((char) Integer.parseInt(text.substring(at, at + 4), 16)); - } catch (NumberFormatException e) { - throw new IllegalStateException("a \\u escape needs four hex digits", e); - } - at += 4; - } else { - out.append( - switch (escaped) { - case 'n' -> '\n'; - case 't' -> '\t'; - case 'r' -> '\r'; - case 'b' -> '\b'; - case 'f' -> '\f'; - default -> escaped; - }); - } - } else { - out.append(c); - } - } - } - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/AtlLowering.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/AtlLowering.java deleted file mode 100644 index ef758f3af..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/AtlLowering.java +++ /dev/null @@ -1,135 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EffectiveProject; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; -import org.eclipse.m2m.atl.emftvm.EmftvmFactory; -import org.eclipse.m2m.atl.emftvm.ExecEnv; -import org.eclipse.m2m.atl.emftvm.Metamodel; -import org.eclipse.m2m.atl.emftvm.Model; -import org.eclipse.m2m.atl.emftvm.Module; -import org.eclipse.m2m.atl.emftvm.compiler.AtlToEmftvmCompiler; -import org.eclipse.m2m.atl.emftvm.impl.resource.EMFTVMResourceFactoryImpl; -import org.eclipse.m2m.atl.emftvm.util.ExecEnvPool; -import org.eclipse.m2m.atl.emftvm.util.ModuleNotFoundException; -import org.eclipse.m2m.atl.emftvm.util.TimingData; - -/** - * The lowering's ATL port, {@code benchmark/lower.atl}, run headless on EMFTVM: the benchmark's - * second lowering, which no bundle ships (docs/benchmarks.md). {@link #prepared()} compiles the - * source once and reuses the module, as {@link QvtoLowering} does the QVTo; {@link #once} compiles it - * for one call, as {@link dev.jorisjonkers.deploykit.emf.resolve.Lowering} parses its QVTo on every - * call. - */ -final class AtlLowering { - - /** The module's name, which is also the ATL file's. */ - static final String MODULE = "lower"; - - private static final String SOURCE = "/benchmark/" + MODULE + ".atl"; - - private final ExecEnvPool pool = new ExecEnvPool(); - - private AtlLowering() { - Metamodel intent = EmftvmFactory.eINSTANCE.createMetamodel(); - intent.setResource(ProjectIntentPackage.eINSTANCE.eResource()); - pool.registerMetaModel("PI", intent); - pool.setModuleResolverFactory(() -> AtlLowering::resolve); - pool.loadModule(MODULE); - // The pool compiles and loads the module for the first environment it hands out. - pool.returnExecEnv(pool.getExecEnv()); - } - - /** A lowering whose module is compiled and loaded once, here, and reused by every run after. */ - static AtlLowering prepared() { - return new AtlLowering(); - } - - /** {@code project} lowered by a module compiled for this call alone: the shipped lowering's shape. */ - static EffectiveProject once(Project project) { - return prepared().lower(project); - } - - /** The one module this lowering loads, compiled; any other name is not one it has. */ - private static Module resolve(String name) throws ModuleNotFoundException { - if (!MODULE.equals(name)) { - throw new ModuleNotFoundException("no module " + name); - } - return compile(); - } - - /** - * The ATL source compiled to an EMFTVM module: the ATL parser and the ATL-to-EMFTVM compiler write - * its bytecode, which is then loaded as a module. A problem the compiler reports as an error fails - * the compilation with every problem it reported. - */ - static Module compile() { - ByteArrayOutputStream bytecode = new ByteArrayOutputStream(); - List errors = new ArrayList<>(); - try (InputStream source = AtlLowering.class.getResourceAsStream(SOURCE)) { - for (EObject problem : new AtlToEmftvmCompiler().compileWithProblemModel(source, bytecode)) { - String severity = String.valueOf(problem.eGet(problem.eClass().getEStructuralFeature("severity"))); - if ("error".equals(severity)) { - errors.add(problem.eGet(problem.eClass().getEStructuralFeature("location")) + " " - + problem.eGet(problem.eClass().getEStructuralFeature("description"))); - } - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - if (!errors.isEmpty()) { - throw new IllegalStateException(SOURCE + " does not compile: " + errors); - } - Resource module = new EMFTVMResourceFactoryImpl().createResource(URI.createURI(MODULE + ".emftvm")); - new ResourceSetImpl().getResources().add(module); - try { - module.load(new ByteArrayInputStream(bytecode.toByteArray()), Map.of()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - return (Module) module.getContents().get(0); - } - - /** {@code project}, lowered; the source is left as it was. */ - EffectiveProject lower(Project project) { - Resource input = project.eResource(); - if (input == null || !input.getContents().equals(List.of(project))) { - // A matched rule lowers every Project its input model holds, so the model holds one. - throw new IllegalArgumentException("a Project alone in its resource is lowered, not " + input); - } - Model in = EmftvmFactory.eINSTANCE.createModel(); - in.setResource(input); - Resource effective = new XMIResourceImpl(URI.createURI("lowered.effective")); - new ResourceSetImpl().getResources().add(effective); - Model out = EmftvmFactory.eINSTANCE.createModel(); - out.setResource(effective); - ExecEnv env = pool.getExecEnv(); - try { - env.registerInputModel("IN", in); - env.registerOutputModel("OUT", out); - env.run(new TimingData()); - } finally { - env.clearModels(); - pool.returnExecEnv(env); - } - List roots = List.copyOf(effective.getContents()); - if (roots.size() != 1 || !(roots.get(0) instanceof EffectiveProject lowered)) { - // Every object a rule creates is contained by the one it belongs to, or it is left a root. - throw new IllegalStateException(project.getProject() + " lowered to " + roots); - } - return lowered; - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Benchmark.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Benchmark.java deleted file mode 100644 index f758bd279..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Benchmark.java +++ /dev/null @@ -1,191 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.UncheckedIOException; -import java.lang.management.GarbageCollectorMXBean; -import java.lang.management.ManagementFactory; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -/** - * The benchmark's switch, its measuring and its report (docs/benchmarks.md). A series runs its task - * {@link #warmup()} times unmeasured, collects the garbage, then runs it {@link #runs()} times measured, each run timed alone with - * {@link System#nanoTime()}, and reports the median and the spread of the measured runs. A cold - * sample is one run in a JVM started for it alone ({@link ColdRun}). - */ -final class Benchmark { - - /** The system property that runs the benchmark: {@code -Demf.benchmark=true}, which {@code -Pbenchmark} sets. */ - static final String PROPERTY = "emf.benchmark"; - - /** Where a run writes its tables, under the cli bundle's build directory. */ - static final Path REPORT = Path.of("target", "benchmark"); - - /** What keeps a task's result reachable, so the JIT cannot drop the work that made it. */ - @SuppressWarnings("unused") - private static volatile Object sink; - - private Benchmark() {} - - static int warmup() { - return Integer.getInteger(PROPERTY + ".warmup", 5); - } - - static int runs() { - return Integer.getInteger(PROPERTY + ".runs", 10); - } - - /** How many fresh JVMs a cold series starts. */ - static int forks() { - return Integer.getInteger(PROPERTY + ".forks", 5); - } - - /** {@code task} run {@link #warmup()} times, then measured {@link #runs()} times. */ - static Series measure(Supplier task) { - return measure(warmup(), runs(), task); - } - - static Series measure(int warmup, int runs, Supplier task) { - for (int i = 0; i < warmup; i++) { - sink = task.get(); - } - // The garbage of what ran before is collected now, not inside a measured run. - System.gc(); - long[] nanos = new long[runs]; - for (int i = 0; i < runs; i++) { - long start = System.nanoTime(); - sink = task.get(); - nanos[i] = System.nanoTime() - start; - } - return new Series(nanos); - } - - /** The measured runs of one series, in nanoseconds. */ - record Series(long[] nanos) { - - Series { - nanos = nanos.clone(); - Arrays.sort(nanos); - } - - double median() { - return quantile(0.5); - } - - /** The value {@code q} of the way up the sorted runs, interpolated between neighbours. */ - double quantile(double q) { - double at = q * (nanos.length - 1); - int below = (int) Math.floor(at); - int above = (int) Math.ceil(at); - return nanos[below] + (nanos[above] - nanos[below]) * (at - below); - } - - double min() { - return nanos[0]; - } - - double max() { - return nanos[nanos.length - 1]; - } - - /** {@code median [p25–p75]} in milliseconds: the median and the interquartile range. */ - String cell() { - return String.format(Locale.ROOT, "%s [%s–%s]", ms(median()), ms(quantile(0.25)), ms(quantile(0.75))); - } - - /** The median in milliseconds alone. */ - String medianCell() { - return ms(median()); - } - - /** {@code min–max} in milliseconds. */ - String range() { - return String.format(Locale.ROOT, "%s–%s", ms(min()), ms(max())); - } - } - - /** {@code nanos} in milliseconds, to three significant figures at most and one decimal at least. */ - static String ms(double nanos) { - double millis = nanos / 1e6; - if (millis >= 100) { - return String.format(Locale.ROOT, "%.0f", millis); - } - if (millis >= 10) { - return String.format(Locale.ROOT, "%.1f", millis); - } - return String.format(Locale.ROOT, "%.2f", millis); - } - - /** A Markdown table: a header row and the rows under it. */ - static String table(List header, List> rows) { - StringBuilder table = new StringBuilder(); - table.append("| ").append(String.join(" | ", header)).append(" |\n"); - table.append("|") - .append(header.stream().map(h -> "---").collect(Collectors.joining("|"))) - .append("|\n"); - for (List row : rows) { - table.append("| ").append(String.join(" | ", row)).append(" |\n"); - } - return table.toString(); - } - - /** {@code text} written to {@code name} under {@link #REPORT}, and printed. */ - static void report(String name, String text) { - try { - Files.createDirectories(REPORT); - Files.writeString(REPORT.resolve(name), text, StandardCharsets.UTF_8); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - System.out.println("=== " + name + "\n" + text); - } - - /** The JVM and the machine a run measured on, and how it measured. */ - static String environment() { - Runtime runtime = Runtime.getRuntime(); - List lines = new ArrayList<>(); - lines.add("- JVM: " + System.getProperty("java.vm.name") + " " + System.getProperty("java.vm.version") + " (" - + System.getProperty("java.vm.vendor") + ")"); - lines.add("- JVM arguments: " - + String.join(" ", ManagementFactory.getRuntimeMXBean().getInputArguments())); - lines.add("- Heap maximum: " + runtime.maxMemory() / (1024 * 1024) + " MiB"); - lines.add("- Collectors: " - + ManagementFactory.getGarbageCollectorMXBeans().stream() - .map(GarbageCollectorMXBean::getName) - .collect(Collectors.joining(", "))); - lines.add("- OS: " + System.getProperty("os.name") + " " + System.getProperty("os.version") + " " - + System.getProperty("os.arch") + ", " + runtime.availableProcessors() + " processors"); - lines.add("- CPU: " + sysctl("machdep.cpu.brand_string")); - lines.add("- Memory: " + sysctl("hw.memsize")); - lines.add("- Warm-up runs: " + warmup() + ", measured runs: " + runs() + ", cold JVMs: " + forks()); - return String.join("\n", lines) + "\n"; - } - - /** A macOS kernel value, or what was asked when there is none to read. */ - private static String sysctl(String name) { - try { - java.lang.Process sysctl = new ProcessBuilder("/usr/sbin/sysctl", "-n", name) - .redirectErrorStream(true) - .start(); - try (BufferedReader out = - new BufferedReader(new InputStreamReader(sysctl.getInputStream(), StandardCharsets.UTF_8))) { - String value = out.lines().collect(Collectors.joining(" ")).trim(); - return sysctl.waitFor() == 0 && !value.isEmpty() ? value : "(no " + name + ")"; - } - } catch (IOException e) { - return "(no " + name + ": " + e.getMessage() + ")"; - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return "(no " + name + ")"; - } - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/BenchmarkInputs.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/BenchmarkInputs.java deleted file mode 100644 index 3f87922fb..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/BenchmarkInputs.java +++ /dev/null @@ -1,132 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import org.eclipse.emf.ecore.EObject; - -/** - * What the benchmark runs on (docs/benchmarks.md): the worked examples this implementation resolves, - * each read with the union {@link Outputs#RESOLVED} names, and every Project those unions lower. - */ -final class BenchmarkInputs { - - /** The real estate's Platform document and pinned inputs, which every estate union reads. */ - private static final List ESTATE_PINNED = List.of( - "estate/platform.intent.yml", - "estate/node-contract.yml", - "estate/images.lock.yml", - "estate/cluster-state.yml"); - - /** - * The estate's 24 Projects, in the order the scaling series adds them. The first twelve are the - * smallest union the checks accept: the Platform document names an Application of each, or another - * of the twelve depends on one. Every prefix from twelve on is accepted, each later Project depending - * only on Projects before it; a prefix shorter than twelve is read and lowered, never checked. - */ - static final List ESTATE_ORDER = List.of( - "arr", - "auth", - "data", - "delivery", - "edge", - "estate-dashboard", - "mail", - "observability", - "prowlarr", - "qbittorrent", - "secrets", - "utility", - "findability-explorer", - "grimoire", - "hindsight", - "home-portal", - "immich", - "jellyfin", - "jellyseerr", - "karakeep", - "n8n", - "outline", - "overleaf", - "tribelt"); - - /** The smallest estate union the checks accept. */ - static final int ESTATE_CORE = 12; - - private BenchmarkInputs() {} - - /** The estate's pinned inputs and its first {@code projects} Projects in {@link #ESTATE_ORDER}. */ - static List estate(int projects) { - List documents = new ArrayList<>(ESTATE_PINNED); - for (String project : ESTATE_ORDER.subList(0, projects)) { - documents.add("estate/" + project + "/" + project + ".project.yml"); - } - return documents; - } - - /** Every case {@link Outputs#RESOLVED} resolves, by name, with the documents it is read with. */ - static Map cases() { - return new TreeMap<>(Outputs.RESOLVED); - } - - /** {@code documents}, relative to the examples, as paths. */ - static List files(List documents) { - return documents.stream().map(Examples::of).toList(); - } - - /** {@code files} read, checked and attached to their env files, as the pipeline reads them before lowering. */ - static Authored authored(List files) { - try { - Authored authored = Pipeline.authored(files); - if (!authored.ok()) { - throw new IllegalStateException("the pipeline refuses " + files + ": " + authored.diagnostics()); - } - return authored; - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** The authored Projects of {@code authored}, in the order they were read. */ - static List projects(Authored authored) { - List projects = new ArrayList<>(); - for (EObject root : authored.intent()) { - if (root instanceof Project project) { - projects.add(project); - } - } - return projects; - } - - /** - * Every Project file any case reads, each once, by its path under the examples, read with the first - * case's union that holds it: the input of every lowering the pipeline runs. - */ - static Map lowered() { - Map projects = new LinkedHashMap<>(); - for (Outputs.Resolving resolving : cases().values()) { - List unread = resolving.documents().stream() - .filter(document -> document.endsWith(".project.yml") && !projects.containsKey(document)) - .toList(); - if (unread.isEmpty()) { - continue; - } - Authored authored = authored(files(resolving.documents())); - for (Project project : projects(authored)) { - String document = Examples.repository() - .resolve("spec/v1/examples") - .relativize(Path.of(project.eResource().getURI().toFileString())) - .toString() - .replace('\\', '/'); - projects.putIfAbsent(document, project); - } - } - return projects; - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ColdRun.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ColdRun.java deleted file mode 100644 index 50c3caa93..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ColdRun.java +++ /dev/null @@ -1,152 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.render.Rendering; -import dev.jorisjonkers.deploykit.emf.resolve.Lowering; -import dev.jorisjonkers.deploykit.emf.resolve.Resolution; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import org.eclipse.emf.ecore.EObject; - -/** - * One cold sample, in a JVM started for it alone (docs/benchmarks.md): every class is loaded, every - * transformation compiled and every method interpreted for the first time inside the timing. It prints - * one {@code COLD name=nanos} line per thing it timed, which {@link #fork} reads back. - */ -final class ColdRun { - - private static final String PREFIX = "COLD "; - - private ColdRun() {} - - /** - * {@code lower qvto|atl}: the estate's Projects read and checked untimed, then the first Project's - * lowering and every Project's lowering timed. {@code pipeline }: each stage of one worked - * example timed once, in the order the pipeline runs them. - */ - public static void main(String[] args) throws IOException { - Map timed = - switch (args[0]) { - case "lower" -> lower(args[1]); - case "pipeline" -> pipeline(args[1]); - default -> throw new IllegalArgumentException("no cold run " + args[0]); - }; - timed.forEach((name, nanos) -> System.out.println(PREFIX + name + "=" + nanos)); - } - - private static Map lower(String engine) { - List projects = BenchmarkInputs.projects(BenchmarkInputs.authored( - BenchmarkInputs.files(BenchmarkInputs.estate(BenchmarkInputs.ESTATE_ORDER.size())))); - Map timed = new LinkedHashMap<>(); - long start = System.nanoTime(); - Function lowering = - switch (engine) { - case "qvto" -> { - QvtoLowering qvto = QvtoLowering.prepared(); - yield project -> qvto.lower(project); - } - case "atl" -> { - AtlLowering atl = AtlLowering.prepared(); - yield project -> atl.lower(project); - } - default -> throw new IllegalArgumentException("no lowering " + engine); - }; - timed.put("load", System.nanoTime() - start); - lowering.apply(projects.get(0)); - timed.put("first", System.nanoTime() - start); - for (Project project : projects.subList(1, projects.size())) { - lowering.apply(project); - } - timed.put("all", System.nanoTime() - start); - return timed; - } - - private static Map pipeline(String example) throws IOException { - Outputs.Resolving resolving = Outputs.RESOLVED.get(example); - List files = BenchmarkInputs.files(resolving.documents()); - Map timed = new LinkedHashMap<>(); - long start = System.nanoTime(); - Pipeline.read(files); - timed.put("read", System.nanoTime() - start); - start = System.nanoTime(); - Authored authored = BenchmarkInputs.authored(files); - timed.put("check", System.nanoTime() - start); - start = System.nanoTime(); - List intent = new ArrayList<>(); - for (EObject root : authored.intent()) { - intent.add(root); - if (root instanceof Project project) { - intent.add(Lowering.lower(project)); - } - } - timed.put("lower", System.nanoTime() - start); - start = System.nanoTime(); - ResolvedDeployment deployment = - Resolution.resolve(intent, authored.pinned(), resolving.project(), Outputs.INTEGRITY); - timed.put("resolve", System.nanoTime() - start); - Path root = Files.createTempDirectory("cold-render"); - start = System.nanoTime(); - Rendering.render(List.of(deployment), root); - timed.put("render", System.nanoTime() - start); - return timed; - } - - /** {@code args} run in {@link Benchmark#forks()} fresh JVMs, each one's timings in nanoseconds by name. */ - static List> fork(String... args) { - List> samples = new ArrayList<>(); - for (int i = 0; i < Benchmark.forks(); i++) { - List command = new ArrayList<>(List.of( - Path.of(System.getProperty("java.home"), "bin", "java").toString(), - "-cp", - System.getProperty("java.class.path"), - ColdRun.class.getName())); - command.addAll(List.of(args)); - samples.add(run(command)); - } - return samples; - } - - private static Map run(List command) { - try { - java.lang.Process child = - new ProcessBuilder(command).redirectErrorStream(true).start(); - Map timed = new LinkedHashMap<>(); - List said = new ArrayList<>(); - try (BufferedReader out = - new BufferedReader(new InputStreamReader(child.getInputStream(), StandardCharsets.UTF_8))) { - for (String line = out.readLine(); line != null; line = out.readLine()) { - if (line.startsWith(PREFIX)) { - String[] pair = line.substring(PREFIX.length()).split("=", 2); - try { - timed.put(pair[0], Long.parseLong(pair[1])); - } catch (NumberFormatException e) { - throw new IllegalStateException("not a timing: " + line, e); - } - } else { - said.add(line); - } - } - } - if (child.waitFor() != 0 || timed.isEmpty()) { - throw new IllegalStateException(command + " failed:\n" + String.join("\n", said)); - } - return timed; - } catch (IOException e) { - throw new UncheckedIOException(e); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new IllegalStateException(e); - } - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/CollisionsTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/CollisionsTest.java deleted file mode 100644 index 6cdab059b..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/CollisionsTest.java +++ /dev/null @@ -1,139 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.AdapterName; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.NamespaceFile; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentFactory; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** One owner per path, Vault name and ServiceAccount (spec/v1/30-deliverables.md#path-allocation). */ -class CollisionsTest { - - /** A deployment planning one file at each of {@code paths}, every one written by {@code adapter}. */ - private static ResolvedDeployment planning(AdapterName adapter, String... paths) { - ResolvedDeployment deployment = ResolvedDeploymentFactory.eINSTANCE.createResolvedDeployment(); - for (String path : paths) { - NamespaceFile file = ResolvedDeploymentFactory.eINSTANCE.createNamespaceFile(); - file.setPath(path); - file.setAdapter(adapter); - deployment.getDeliverables().add(file); - } - return deployment; - } - - private static List messages(List refused) { - assertThat(refused).allSatisfy(diagnostic -> { - assertThat(diagnostic.code()).isEqualTo("E_PATH_COLLISION"); - assertThat(diagnostic.document()).isEmpty(); - assertThat(diagnostic.path()).isEmpty(); - }); - return refused.stream().map(Diagnostic::message).toList(); - } - - @Test - void aPlanWhoseEveryPathHasOneOwnerHoldsNoCollision() { - assertThat(Collisions.ofPlan(List.of( - planning(AdapterName.KUBERNETES, "apps/a/namespace.yaml"), - planning(AdapterName.KUBERNETES, "apps/b/namespace.yaml")))) - .isEmpty(); - } - - @Test - void aPathTwoDeliverablesClaimIsRefusedWithBothOwners() { - assertThat(messages(Collisions.ofPlan(List.of( - planning(AdapterName.KUBERNETES, "apps/a/namespace.yaml"), - planning(AdapterName.TRAEFIK, "apps/a/namespace.yaml"))))) - .containsExactly("apps/a/namespace.yaml is claimed by kubernetes and traefik"); - assertThat(messages( - Collisions.ofPlan(List.of(planning(AdapterName.KUBERNETES, "apps/a/x.yaml", "apps/a/x.yaml"))))) - .containsExactly("apps/a/x.yaml is claimed by kubernetes and kubernetes"); - } - - @Test - void anEstateFileEveryProjectPlansIsOneFileUnlessTwoAdaptersWriteIt() { - String estate = "estate/priority-classes/priorityclasses.yaml"; - assertThat(Collisions.ofPlan( - List.of(planning(AdapterName.KUBERNETES, estate), planning(AdapterName.KUBERNETES, estate)))) - .isEmpty(); - assertThat(messages(Collisions.ofPlan( - List.of(planning(AdapterName.KUBERNETES, estate), planning(AdapterName.VSO, estate))))) - .containsExactly(estate + " is claimed by kubernetes and vso"); - } - - @Test - void aVaultNameTwoDocumentsClaimIsRefusedWithBothPaths() { - assertThat(messages(Collisions.ofPlan(List.of(planning( - AdapterName.VAULT_POLICY, - "apps/a-b/policies/a-b-c.policy.json", - "apps/a/policies/a-b-c.policy.json", - "apps/a/policies/a-b-c.role.json"))))) - .containsExactly("the Vault name a-b-c.policy.json is claimed by apps/a-b/policies/a-b-c.policy.json" - + " and apps/a/policies/a-b-c.policy.json"); - assertThat(Collisions.ofPlan(List.of(planning( - AdapterName.VAULT_POLICY, - "apps/a/policies/x.policy.json", - "apps/a/policies/x.policy.json.bak")))) - .isEmpty(); - } - - @Test - void aServiceAccountTwoFilesHoldIsRefusedWithBothFiles(@TempDir Path root) throws IOException { - write(root, "apps/a/identity.yaml", account("a", "notes-system")); - write(root, "apps/a/backup.yaml", "---\napiVersion: batch/v1\nkind: CronJob\n" + account("a", "notes-system")); - write(root, "apps/b/identity.yaml", account("a", "other-system")); - - assertThat(messages(Collisions.ofAccounts(root))) - .containsExactly("the ServiceAccount notes-system/a is claimed by apps/a/backup.yaml" - + " and apps/a/identity.yaml"); - } - - @Test - void aServiceAccountIsReadAtAnyIndentationAndOnlyFromItsOwnMetadata(@TempDir Path root) throws IOException { - write(root, "apps/a/one.yaml", indented(account("a", "ns")) + "kind: ConfigMap\nmetadata:\n name: a\n"); - write( - root, - "apps/a/two.yaml", - "kind: ServiceAccount\nmetadata:\n labels:\n x: y\n namespace: ns\n name: a\n"); - - assertThat(messages(Collisions.ofAccounts(root))) - .containsExactly("the ServiceAccount ns/a is claimed by apps/a/one.yaml and apps/a/two.yaml"); - } - - @Test - void aServiceAccountWithoutANameOrNamespaceIsKeyedByWhatItHolds(@TempDir Path root) throws IOException { - write(root, "a.yaml", "kind: ServiceAccount\nmetadata:\n labels:\n x: y\n"); - write(root, "b.yaml", "kind: ServiceAccount\nmetadata:\n labels:\n z: w\n"); - - assertThat(messages(Collisions.ofAccounts(root))) - .containsExactly("the ServiceAccount / is claimed by a.yaml and b.yaml"); - } - - @Test - void aTreeThatCannotBeReadIsAnErrorRatherThanARefusal(@TempDir Path root) { - assertThatThrownBy(() -> Collisions.ofAccounts(root.resolve("missing"))) - .isInstanceOf(UncheckedIOException.class); - } - - private static String account(String name, String namespace) { - return "kind: ServiceAccount\nmetadata:\n name: " + name + "\n namespace: " + namespace + "\n"; - } - - private static String indented(String text) { - return text.lines().map(line -> " " + line + "\n").reduce("", String::concat); - } - - private static void write(Path root, String path, String text) throws IOException { - Path file = root.resolve(path); - Files.createDirectories(file.getParent()); - Files.writeString(file, text); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Comparison.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Comparison.java deleted file mode 100644 index b1f7d09cb..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Comparison.java +++ /dev/null @@ -1,397 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.regex.Pattern; -import java.util.stream.Stream; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; -import org.yaml.snakeyaml.LoaderOptions; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.SafeConstructor; - -/** - * The stage harness's one comparator: two files, or two trees of files, compared by what they hold - * first and by their bytes last. JSON is read as a Jackson tree, YAML as every document of a stream - * through SnakeYAML's YAML 1.1 reader on both sides, so a quoted {@code "true"} and a plain {@code - * true} still differ by type, and XMI is loaded into EMF and compared by EMF Compare, keyed by - * each object's natural key (ModelDiff). Every difference is reported, as a path into the file: {@code - * apps/x/workload.yaml#1 .spec.containers[0].env[3].value: expected "x", got "y"}. A file that holds - * the same content in other bytes is one difference, "formatting only", naming the first line that - * differs. - */ -final class Comparison { - - private static final ObjectMapper JSON = - new ObjectMapper().enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS); - - /** A key written bare in a path; any other is written quoted, in brackets. */ - private static final Pattern BARE = Pattern.compile("[A-Za-z0-9_-]+"); - - /** The keys an item of a list is named by, in the order they are tried. */ - private static final List IDENTITIES = List.of("name", "id", "path", "alias", "key"); - - /** A file in a tree that is documentation of the tree rather than part of it. */ - private static final String README = "README.md"; - - private Comparison() {} - - /** Every difference between the tree under {@code expected} and the files of {@code actual}. */ - static List trees(Path expected, Map actual) { - Map committed = read(expected); - List differences = new ArrayList<>(); - TreeSet names = new TreeSet<>(committed.keySet()); - names.addAll(actual.keySet()); - for (String name : names) { - if (!actual.containsKey(name)) { - differences.add(name + ": missing file"); - } else if (!committed.containsKey(name)) { - differences.add(name + ": extra file"); - } else { - URI uri = URI.createFileURI( - expected.resolve(name).toAbsolutePath().toString()); - differences.addAll(files(name, uri, committed.get(name), actual.get(name))); - } - } - return differences; - } - - /** Every file under {@code root} but a README, by its path below it, sorted; nothing when there is no root. */ - static Map read(Path root) { - Map files = new TreeMap<>(); - if (!Files.isDirectory(root)) { - return files; - } - try (Stream tree = Files.walk(root)) { - for (Path file : tree.filter(Files::isRegularFile).toList()) { - String name = root.relativize(file).toString().replace('\\', '/'); - if (!file.getFileName().toString().equals(README)) { - files.put(name, Files.readAllBytes(file)); - } - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - return files; - } - - /** - * Every difference between two versions of the file {@code name}, by the format its extension - * names; {@code uri} is where both are read as being, so an XMI reference resolves the same way - * from either. - */ - static List files(String name, URI uri, byte[] expected, byte[] actual) { - String committed = new String(expected, StandardCharsets.UTF_8); - String written = new String(actual, StandardCharsets.UTF_8); - List differences; - if (name.endsWith(".json")) { - differences = json(name, committed, written); - } else if (name.endsWith(".yaml") || name.endsWith(".yml")) { - differences = yaml(name, committed, written); - } else if (name.endsWith(".xmi") || name.endsWith(".resolveddeployment")) { - differences = xmi(name, uri, expected, actual); - } else { - differences = new ArrayList<>(); - } - if (differences.isEmpty() && !committed.equals(written)) { - differences.add(formattingOnly(name, committed, written)); - } - return differences; - } - - /** Every difference between two JSON documents, by value. */ - static List json(String name, String expected, String actual) { - List differences = new ArrayList<>(); - Object committed; - Object written; - try { - committed = JSON.readValue(expected, Object.class); - written = JSON.readValue(actual, Object.class); - } catch (JsonProcessingException e) { - differences.add(name + ": not JSON: " + e.getOriginalMessage()); - return differences; - } - values(name, "", committed, written, differences); - return differences; - } - - /** Every difference between two YAML streams, document by document, as a YAML 1.1 reader reads them. */ - static List yaml(String name, String expected, String actual) { - List differences = new ArrayList<>(); - List committed; - List written; - try { - committed = documents(expected); - written = documents(actual); - } catch (RuntimeException e) { - differences.add( - name + ": not YAML: " + e.getMessage().lines().findFirst().orElse("")); - return differences; - } - for (int i = 0; i < Math.max(committed.size(), written.size()); i++) { - String document = name + "#" + (i + 1); - if (i >= written.size()) { - differences.add(document + ": missing document"); - } else if (i >= committed.size()) { - differences.add(document + ": extra document"); - } else { - values(document, "", committed.get(i), written.get(i), differences); - } - } - return differences; - } - - private static List documents(String text) { - List documents = new ArrayList<>(); - for (Object document : new Yaml(new SafeConstructor(new LoaderOptions())).loadAll(text)) { - documents.add(document); - } - return documents; - } - - /** - * Every difference between two XMI files, each loaded on its own as if it were at {@code uri}: - * EMF Compare decides whether they differ and says where (ModelDiff). - */ - static List xmi(String name, URI uri, byte[] expected, byte[] actual) { - Resource committed; - Resource written; - try { - committed = load(uri, expected); - written = load(uri, actual); - } catch (IOException | RuntimeException e) { - List differences = new ArrayList<>(); - differences.add(name + ": not XMI: " + e.getMessage()); - return differences; - } - return new ArrayList<>(ModelDiff.differences(name, committed, written)); - } - - /** {@code bytes} read as XMI at {@code uri}, in a resource set of their own. */ - static Resource load(URI uri, byte[] bytes) throws IOException { - ResourceSet resources = new ResourceSetImpl(); - resources - .getResourceFactoryRegistry() - .getExtensionToFactoryMap() - .put(Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl()); - Resource resource = resources.createResource(uri); - resource.load(new ByteArrayInputStream(bytes), null); - return resource; - } - - private static void values(String document, String at, Object expected, Object actual, List out) { - String committed = kind(expected); - String written = kind(actual); - if (!committed.equals(written)) { - out.add(where(document, at) + ": expected " + show(expected) + " (" + committed + "), got " + show(actual) - + " (" + written + ")"); - return; - } - if (expected == null) { - // Two nulls: a YAML key written with no value on both sides. - return; - } - switch (expected) { - case Map map -> { - Map other = (Map) actual; - for (Map.Entry entry : map.entrySet()) { - String path = at + key(entry.getKey()); - if (other.containsKey(entry.getKey())) { - values(document, path, entry.getValue(), other.get(entry.getKey()), out); - } else { - out.add(where(document, path) + ": missing (expected " + show(entry.getValue()) + ")"); - } - } - for (Map.Entry entry : other.entrySet()) { - if (!map.containsKey(entry.getKey())) { - out.add(where(document, at + key(entry.getKey())) + ": extra (got " + show(entry.getValue()) - + ")"); - } - } - } - case List list -> { - List other = (List) actual; - String identity = identity(list, other); - if (identity != null) { - keyed(document, at, identity, list, other, out); - return; - } - for (int i = 0; i < Math.max(list.size(), other.size()); i++) { - String path = at + "[" + i + "]"; - if (i >= other.size()) { - out.add(where(document, path) + ": missing (expected " + show(list.get(i)) + ")"); - } else if (i >= list.size()) { - out.add(where(document, path) + ": extra (got " + show(other.get(i)) + ")"); - } else { - values(document, path, list.get(i), other.get(i), out); - } - } - } - default -> { - if (!same(expected, actual)) { - out.add(where(document, at) + ": expected " + show(expected) + ", got " + show(actual)); - } - } - } - } - - /** - * The key every item of both lists is a map naming uniquely, if there is one: such a list is - * compared item by item by that key, so one inserted item is one difference rather than a shift - * of every item after it, and an order that differs is one more. - */ - private static String identity(List expected, List actual) { - for (String key : IDENTITIES) { - if (named(expected, key) && named(actual, key)) { - return key; - } - } - return null; - } - - private static boolean named(List items, String key) { - Set names = new HashSet<>(); - for (Object item : items) { - if (!(item instanceof Map map) || !(map.get(key) instanceof String name) || !names.add(name)) { - return false; - } - } - return true; - } - - private static void keyed( - String document, String at, String identity, List expected, List actual, List out) { - Map written = new LinkedHashMap<>(); - actual.forEach(item -> written.put(((Map) item).get(identity), item)); - List committedOrder = new ArrayList<>(); - for (Object item : expected) { - Object name = ((Map) item).get(identity); - String path = at + "[" + identity + "=" + quoted((String) name) + "]"; - if (written.containsKey(name)) { - committedOrder.add(name); - values(document, path, item, written.get(name), out); - } else { - out.add(where(document, path) + ": missing (expected " + show(item) + ")"); - } - } - Map committed = new LinkedHashMap<>(); - expected.forEach(item -> committed.put(((Map) item).get(identity), item)); - List writtenOrder = new ArrayList<>(); - for (Map.Entry item : written.entrySet()) { - if (committed.containsKey(item.getKey())) { - writtenOrder.add(item.getKey()); - } else { - out.add(where(document, at + "[" + identity + "=" + quoted((String) item.getKey()) + "]") - + ": extra (got " + show(item.getValue()) + ")"); - } - } - if (!committedOrder.equals(writtenOrder)) { - out.add(where(document, at) + ": order differs by " + identity + ": expected " + committedOrder + ", got " - + writtenOrder); - } - } - - private static boolean same(Object expected, Object actual) { - if (expected instanceof Number committed && actual instanceof Number written) { - return new BigDecimal(committed.toString()).compareTo(new BigDecimal(written.toString())) == 0; - } - return Objects.equals(expected, actual); - } - - /** What a YAML 1.1 or JSON reader made of a value, by the type a consumer would see. */ - private static String kind(Object value) { - if (value == null) { - return "null"; - } - if (value instanceof Map) { - return "map"; - } - if (value instanceof List) { - return "list"; - } - if (value instanceof String) { - return "string"; - } - if (value instanceof Boolean) { - return "boolean"; - } - if (value instanceof BigDecimal || value instanceof Double || value instanceof Float) { - return "float"; - } - if (value instanceof Number) { - return "integer"; - } - if (value instanceof Date) { - return "timestamp"; - } - return value.getClass().getSimpleName(); - } - - private static String show(Object value) { - return switch (value) { - case null -> "null"; - case String text -> quoted(text); - case Map map -> "a map of " + map.size(); - case List list -> "a list of " + list.size(); - default -> String.valueOf(value); - }; - } - - private static String quoted(String text) { - try { - return JSON.writeValueAsString(text); - } catch (JsonProcessingException e) { - throw new IllegalStateException(e); - } - } - - private static String key(Object key) { - String text = String.valueOf(key); - return key instanceof String && BARE.matcher(text).matches() ? "." + text : "[" + show(key) + "]"; - } - - private static String where(String document, String at) { - return at.isEmpty() ? document : document + " " + at; - } - - /** The one difference of two files that hold the same values in other bytes: the first line they part at. */ - static String formattingOnly(String name, String expected, String actual) { - List committed = expected.lines().toList(); - List written = actual.lines().toList(); - int line = 0; - while (line < committed.size() - && line < written.size() - && committed.get(line).equals(written.get(line))) { - line++; - } - String detail = line < committed.size() || line < written.size() - ? "line " + (line + 1) + ": expected " + lineAt(committed, line) + ", got " + lineAt(written, line) - : "line endings or the final line break"; - return name + ": formatting only (quoting, indentation or key order); " + detail; - } - - private static String lineAt(List lines, int index) { - return index < lines.size() ? quoted(lines.get(index)) : "the end of the file"; - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ComparisonTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ComparisonTest.java deleted file mode 100644 index adf786ef7..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ComparisonTest.java +++ /dev/null @@ -1,244 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.AdapterName; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.NamespaceFile; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentFactory; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Map; -import java.util.TreeMap; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** The stage harness's comparator, held to the differences it exists to report (Comparison). */ -class ComparisonTest { - - private static final String WORKLOAD = """ - # GENERATED. Never hand-edit. - --- - apiVersion: apps/v1 - kind: Deployment - spec: - template: - spec: - containers: - - name: api - env: - - name: MODE - value: "true" - - name: LEVEL - value: info - --- - apiVersion: v1 - kind: Service - """; - - @Test - void oneChangedFieldIsReportedAtItsPathWithBothValues() { - assertThat(Comparison.yaml("workload.yaml", WORKLOAD, WORKLOAD.replace("value: info", "value: debug"))) - .containsExactly( - "workload.yaml#1 .spec.template.spec.containers[name=\"api\"].env[name=\"LEVEL\"].value: expected" - + " \"info\", got \"debug\""); - assertThat(Comparison.json("intent.json", "{\"owner\":\"joris\"}", "{\"owner\":\"someone-else\"}")) - .containsExactly("intent.json .owner: expected \"joris\", got \"someone-else\""); - } - - @Test - void anExtraKeyAndAMissingKeyAreEachReported() { - assertThat(Comparison.json("intent.json", "{\"a\":1,\"b\":2}", "{\"a\":1,\"c\":[3],\"d.e\":{}}")) - .containsExactly( - "intent.json .b: missing (expected 2)", - "intent.json .c: extra (got a list of 1)", - "intent.json [\"d.e\"]: extra (got a map of 0)"); - } - - @Test - void aQuotedScalarAndAPlainOneDifferByTypeUnderAYaml11Reader() { - assertThat(Comparison.yaml("workload.yaml", WORKLOAD, WORKLOAD.replace("value: \"true\"", "value: true"))) - .containsExactly( - "workload.yaml#1 .spec.template.spec.containers[name=\"api\"].env[name=\"MODE\"].value: expected \"true\"" - + " (string), got true (boolean)"); - // YAML 1.1 reads `on` as a boolean and `0755` as an octal integer: neither is a string. - assertThat(Comparison.yaml("x.yaml", "a: \"on\"\nb: \"0755\"\n", "a: on\nb: 0755\n")) - .containsExactly( - "x.yaml#1 .a: expected \"on\" (string), got true (boolean)", - "x.yaml#1 .b: expected \"0755\" (string), got 493 (integer)"); - } - - @Test - void aReorderedKeyPassesByContentAndFailsByBytesAsFormattingOnly() { - String reordered = WORKLOAD.replace("apiVersion: v1\nkind: Service", "kind: Service\napiVersion: v1"); - - assertThat(Comparison.yaml("workload.yaml", WORKLOAD, reordered)).isEmpty(); - assertThat(Comparison.files("workload.yaml", URI.createURI("workload.yaml"), utf8(WORKLOAD), utf8(reordered))) - .containsExactly("workload.yaml: formatting only (quoting, indentation or key order); line 16:" - + " expected \"apiVersion: v1\", got \"kind: Service\""); - assertThat(Comparison.files("x.json", URI.createURI("x.json"), utf8("{\"a\":1}"), utf8("{\"a\":1}\n"))) - .containsExactly("x.json: formatting only (quoting, indentation or key order); line endings or the" - + " final line break"); - assertThat(Comparison.files("x.json", URI.createURI("x.json"), utf8("{\"a\":1}"), utf8("{\n\"a\":1}"))) - .containsExactly("x.json: formatting only (quoting, indentation or key order); line 1: expected" - + " \"{\\\"a\\\":1}\", got \"{\""); - } - - @Test - void everyDifferenceIsReportedNotOnlyTheFirst() { - String changed = WORKLOAD.replace("name: api", "name: web") - .replace("value: info", "value: debug") - .replace("kind: Service", "kind: Service\nmetadata: {}"); - - assertThat(Comparison.yaml("workload.yaml", WORKLOAD, changed)).hasSize(3); - } - - @Test - void aMissingOrExtraDocumentOrListItemIsReported() { - String one = "---\na: [1, 2]\n"; - String two = "---\na: [1]\n---\nb: 1\n"; - - assertThat(Comparison.yaml("x.yaml", one, two)) - .containsExactly("x.yaml#1 .a[1]: missing (expected 2)", "x.yaml#2: extra document"); - assertThat(Comparison.yaml("x.yaml", two, one)) - .containsExactly("x.yaml#1 .a[1]: extra (got 2)", "x.yaml#2: missing document"); - assertThat(Comparison.yaml("x.yaml", "a: 1.0\n", "a: 1\n")) - .containsExactly("x.yaml#1 .a: expected 1.0 (float), got 1 (integer)"); - assertThat(Comparison.json("x.json", "{\"a\":1}", "{\"a\":1.0}")) - .containsExactly("x.json .a: expected 1 (integer), got 1.0 (float)"); - assertThat(Comparison.yaml("x.yaml", "true: 1\n", "\"true\": 1\n")) - .containsExactly("x.yaml#1 [true]: missing (expected 1)", "x.yaml#1 .true: extra (got 1)"); - } - - @Test - void aListOfNamedItemsIsComparedByNameSoOneInsertionIsOneDifference() { - String expected = "{\"env\":[{\"name\":\"A\",\"value\":\"1\"},{\"name\":\"B\",\"value\":\"2\"}]}"; - - assertThat(Comparison.json("x.json", expected, expected.replace("[{", "[{\"name\":\"N\"},{"))) - .containsExactly("x.json .env[name=\"N\"]: extra (got a map of 1)"); - assertThat(Comparison.json( - "x.json", - expected, - "{\"env\":[{\"name\":\"B\",\"value\":\"3\"},{\"name\":\"C\",\"value\":\"1\"}]}")) - .containsExactly( - "x.json .env[name=\"A\"]: missing (expected a map of 2)", - "x.json .env[name=\"B\"].value: expected \"2\", got \"3\"", - "x.json .env[name=\"C\"]: extra (got a map of 2)"); - assertThat(Comparison.json( - "x.json", - expected, - "{\"env\":[{\"name\":\"B\",\"value\":\"2\"},{\"name\":\"A\",\"value\":\"1\"}]}")) - .containsExactly("x.json .env: order differs by name: expected [A, B], got [B, A]"); - // A name two items share names neither, so the list is compared by position. - assertThat(Comparison.json("x.json", "[{\"name\":\"A\"},{\"name\":\"A\"}]", "[{\"name\":\"A\"}]")) - .containsExactly("x.json [1]: missing (expected a map of 1)"); - } - - @Test - void aFileThatDoesNotParseIsOneDifference() { - assertThat(Comparison.json("x.json", "{", "{}")) - .singleElement() - .asString() - .startsWith("x.json: not JSON: "); - assertThat(Comparison.yaml("x.yaml", "a: [", "a: 1")) - .singleElement() - .asString() - .startsWith("x.yaml: not YAML"); - assertThat(Comparison.xmi("x.xmi", URI.createURI("x.xmi"), utf8("<"), utf8("<"))) - .singleElement() - .asString() - .startsWith("x.xmi: not XMI"); - } - - @Test - void aFileOfAnotherFormatIsComparedByItsBytesAlone() { - assertThat(Comparison.files("a.conf", URI.createURI("a.conf"), utf8("x\n"), utf8("x\n"))) - .isEmpty(); - assertThat(Comparison.files("a.conf", URI.createURI("a.conf"), utf8("x\n"), utf8("y\n"))) - .containsExactly( - "a.conf: formatting only (quoting, indentation or key order); line 1: expected \"x\", got \"y\""); - } - - @Test - void aMissingOrExtraFileInATreeIsReported(@TempDir Path expected) throws IOException { - Files.writeString(expected.resolve("kept.yaml"), "a: 1\n"); - Files.writeString(expected.resolve("gone.yaml"), "a: 1\n"); - Files.writeString(expected.resolve("README.md"), "not part of the tree"); - Map written = new TreeMap<>(); - written.put("kept.yaml", utf8("a: 2\n")); - written.put("new.yaml", utf8("a: 1\n")); - - assertThat(Comparison.trees(expected, written)) - .containsExactly( - "gone.yaml: missing file", "kept.yaml#1 .a: expected 1, got 2", "new.yaml: extra file"); - assertThat(Comparison.read(expected.resolve("absent"))).isEmpty(); - } - - @Test - void anXmiModelIsComparedByEmfCompareAtKeyedPaths() throws IOException { - URI uri = URI.createURI("file:/stages/render/x/expected/notes.resolveddeployment"); - byte[] expected = xmi(uri, deployment("notes-system", 1)); - byte[] renamed = xmi(uri, deployment("other-system", 1)); - byte[] longer = xmi(uri, deployment("notes-system", 2)); - - assertThat(Comparison.xmi("m.xmi", uri, expected, xmi(uri, deployment("notes-system", 1)))) - .isEmpty(); - assertThat(Comparison.xmi("m.xmi", uri, expected, renamed)) - .containsExactly("m.xmi#1 .deliverables[path=\"apps/notes/namespace.yaml\"].namespace: expected" - + " \"notes-system\", got \"other-system\""); - // Two deliverables at one path share a key, so neither is keyed by it. - assertThat(Comparison.xmi("m.xmi", uri, expected, longer)) - .containsExactly("m.xmi#1 .deliverables[1]: extra (got a NamespaceFile)" + ModelDiff.SIMILARITY); - assertThat(Comparison.xmi("m.xmi", uri, longer, expected)) - .containsExactly("m.xmi#1 .deliverables[1]: missing (expected a NamespaceFile)" + ModelDiff.SIMILARITY); - } - - @Test - void anXmiFeatureSetOnOneSideOnlyAndAMissingRootAreReported() throws IOException { - URI uri = URI.createURI("file:/stages/x.xmi"); - ResolvedDeployment unset = deployment("notes-system", 1); - ((NamespaceFile) unset.getDeliverables().get(0)).setNamespace(null); - ResolvedDeployment other = ResolvedDeploymentFactory.eINSTANCE.createResolvedDeployment(); - - assertThat(Comparison.xmi("m.xmi", uri, xmi(uri, deployment("notes-system", 1)), xmi(uri, unset))) - .containsExactly("m.xmi#1 .deliverables[path=\"apps/notes/namespace.yaml\"].namespace: expected" - + " \"notes-system\", got null"); - assertThat(Comparison.xmi("m.xmi", uri, xmi(uri, other, other), xmi(uri, other))) - .containsExactly("m.xmi#2: missing root (expected a ResolvedDeployment)"); - assertThat(Comparison.xmi("m.xmi", uri, xmi(uri, other), xmi(uri, other, other))) - .containsExactly("m.xmi#2: extra root (got a ResolvedDeployment)"); - } - - private static ResolvedDeployment deployment(String namespace, int files) { - ResolvedDeploymentFactory model = ResolvedDeploymentFactory.eINSTANCE; - ResolvedDeployment deployment = model.createResolvedDeployment(); - for (int i = 0; i < files; i++) { - NamespaceFile file = model.createNamespaceFile(); - file.setPath("apps/notes/namespace.yaml"); - file.setAdapter(AdapterName.KUBERNETES); - file.setNamespace(namespace); - deployment.getDeliverables().add(file); - } - return deployment; - } - - private static byte[] xmi(URI uri, ResolvedDeployment... roots) throws IOException { - Resource resource = Stages.resources().createResource(uri); - for (ResolvedDeployment root : roots) { - resource.getContents().add(EcoreUtil.copy(root)); - } - ByteArrayOutputStream out = new ByteArrayOutputStream(); - resource.save(out, null); - return out.toByteArray(); - } - - private static byte[] utf8(String text) { - return text.getBytes(StandardCharsets.UTF_8); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ConstraintsTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ConstraintsTest.java deleted file mode 100644 index 52215e601..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ConstraintsTest.java +++ /dev/null @@ -1,132 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** The constraints a parsed document answers, and the diagnostics a violation becomes. */ -class ConstraintsTest { - - private static final String REFUSED = """ - apiVersion: intent.jorisjonkers.dev/v1 - kind: Project - schemaVersion: 1.0.0 - project: refusals - owner: joris - applications: - - id: unwired - processes: - - name: unwired-worker - lifecycle: scheduled - image: unwired-worker - runtime: node - placement: - memory: 128Mi - cpu: 25m - """; - - private static Path file(Path directory, String text) throws IOException { - Path file = directory.resolve("unwired.project.yml"); - Files.writeString(file, text); - return file; - } - - @Test - void aViolationCarriesTheInvariantsNameAndThePointerOfWhatItRefused(@TempDir Path directory) throws IOException { - Parsed parsed = Pipeline.intent(file(directory, REFUSED)); - - assertThat(parsed.ok()).isFalse(); - assertThat(parsed.intent()).isEmpty(); - assertThat(parsed.diagnostics()).singleElement().satisfies(diagnostic -> { - assertThat(diagnostic.code()).isEqualTo("E_SCHEDULE_MISSING"); - assertThat(diagnostic.document()).isEqualTo("unwired.project.yml"); - assertThat(diagnostic.path()).isEqualTo("/applications/0/processes/0"); - assertThat(diagnostic.message()).contains("E_SCHEDULE_MISSING"); - }); - } - - private static final String ACCEPTED = """ - apiVersion: intent.jorisjonkers.dev/v1 - kind: Project - schemaVersion: 1.0.0 - project: refusals - owner: joris - applications: - - id: wired - observability: - scrape: - process: wired-worker - surface: http - path: /metrics - processes: - - name: wired-worker - lifecycle: application - image: wired-worker - runtime: node - provides: - http: 8080 - placement: - memory: 128Mi - cpu: 25m - cutover: continuous - """; - - @Test - void aDocumentThatBreaksNoConstraintCarriesNoDiagnostic(@TempDir Path directory) throws IOException { - Parsed parsed = Pipeline.intent(file(directory, ACCEPTED)); - - assertThat(parsed.diagnostics()).isEmpty(); - assertThat(parsed.intent()).containsKey("applications"); - } - - @Test - void theConstraintsAreTheFileTheMetamodelCarries() { - assertThat(Constraints.beside(ProjectIntentPackage.class, "project-intent.ocl") - .toString()) - .endsWith("project-intent.ocl"); - } - - @Test - void aPostgresOnAVolumeThatDerivesNoBackupDeclaresItsEngine() { - // Its consumers' database catalog derives from the engine, so the engine is not decoration - // (docs/adr/model/0019-engine-is-process-vocabulary.md). - assertThat(Pipeline.intent(Examples.of("refusals/engine-owns-databases.project.yml")) - .diagnostics()) - .isEmpty(); - assertThat(Pipeline.intent(Examples.of("refusals/engine-without-durability.project.yml")) - .diagnostics()) - .extracting(Diagnostic::code) - .containsExactly("E_ENGINE_WITHOUT_DURABILITY"); - } - - @Test - void aClaimIsTheProjectsAloneBackupClaimIncluded() { - // A project's Processes share one namespace, and a claim is named as written - // (spec/v1/10-project-intent.md#storage-and-durability). - assertThat(Pipeline.intent(Examples.of("refusals/duplicate-claim.project.yml")) - .diagnostics()) - .extracting(Diagnostic::code, Diagnostic::path) - .containsExactly(tuple("E_DUPLICATE_CLAIM", "/applications/0/processes/1/volumes/0")); - assertThat(Pipeline.intent(Examples.of("refusals/duplicate-backup-claim.project.yml")) - .diagnostics()) - .extracting(Diagnostic::code, Diagnostic::path) - .containsExactly(tuple("E_DUPLICATE_CLAIM", "/applications/0/processes/1/volumes/0")); - } - - @Test - void aGeneratedKeyAdoptsOnlyAValueItsProjectAlreadyReads() { - assertThat(Pipeline.intent(Examples.of("refusals/generated-key-adopts-granted.project.yml")) - .diagnostics()) - .isEmpty(); - assertThat(Pipeline.intent(Examples.of("refusals/generated-key-adopts-ungranted.project.yml")) - .diagnostics()) - .extracting(Diagnostic::code) - .containsExactly("E_GENERATED_KEY_ADOPTS_UNGRANTED"); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/DataFileTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/DataFileTest.java deleted file mode 100644 index 7a50393b2..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/DataFileTest.java +++ /dev/null @@ -1,159 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.Datum; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.DatumKind; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.DatumList; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.DatumMap; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.DatumScalar; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.junit.jupiter.params.provider.ValueSource; - -/** A data file read as YAML reads it, into the data it holds, or into nothing where it is not that YAML. */ -class DataFileTest { - - /** The data as JSON, a string's text quoted and every other scalar as its own text. */ - private static String json(Datum datum) { - if (datum instanceof DatumMap map) { - return map.getEntries().stream() - .map(entry -> "\"" + entry.getKey() + "\":" + json(entry.getValue())) - .collect(Collectors.joining(",", "{", "}")); - } - if (datum instanceof DatumList list) { - return list.getItems().stream().map(DataFileTest::json).collect(Collectors.joining(",", "[", "]")); - } - return quoted((DatumScalar) datum); - } - - private static String quoted(DatumScalar scalar) { - return scalar.getKind() == DatumKind.STRING ? "\"" + scalar.getText() + "\"" : scalar.getText(); - } - - private static String read(String text) { - return DataFile.read(text).map(DataFileTest::json).orElse("nothing"); - } - - static Stream documents() { - return Stream.of( - // Block collections, nested, and a sequence as a mapping's value at the key's own column. - Arguments.of( - "a: 1\nb:\n c: x\n d:\n - y\n - z: w\n v: u\n", - "{\"a\":1,\"b\":{\"c\":\"x\",\"d\":[\"y\",{\"z\":\"w\",\"v\":\"u\"}]}}"), - Arguments.of("- a\n-\n - b\n-\n- # nothing\n", "[\"a\",[\"b\"],null,null]"), - Arguments.of(" a: 1\n b: 2\n", "{\"a\":1,\"b\":2}"), - Arguments.of("a:\nb: # empty\n", "{\"a\":null,\"b\":null}"), - // Comments, a document marker, and a file of nothing. - Arguments.of("# head\n---\na: b # tail\n\n# end\n", "{\"a\":\"b\"}"), - Arguments.of("--- [a]\n", "[\"a\"]"), - Arguments.of("", "null"), - Arguments.of("# only\n", "null"), - Arguments.of("a: x\r\nb: y\r\n", "{\"a\":\"x\",\"b\":\"y\"}"), - // A quoted key may have spaces before its colon; a # inside a plain key opens no comment. - Arguments.of("\"a\" : 1\n", "{\"a\":1}"), - Arguments.of("a# b: c\n", "{\"a# b\":\"c\"}"), - // Quoted keys and scalars, and their escapes. - Arguments.of( - "\"a b\": 'it''s'\n'c': \"\\\"\\\\\\/\\n\\t\\r\\b\\f\\0\\ \\u0041\"\n", - "{\"a b\":\"it's\",\"c\":\"\"\\/\n\t\r\b\f\0 A\"}"), - Arguments.of("a: x#y\nb: 'q' # c\n", "{\"a\":\"x#y\",\"b\":\"q\"}"), - // Plain scalars over several lines fold: a line break is a space, a blank line a break. - Arguments.of("a: one\n two\n\n three\nb: c\n", "{\"a\":\"one two\nthree\",\"b\":\"c\"}"), - Arguments.of("- one\n two\n # comment\n- three\n", "[\"one two\",\"three\"]"), - Arguments.of("root scalar\nover lines\n", "\"root scalar over lines\""), - // Literal and folded block scalars, and how each keeps its trailing line breaks. - Arguments.of("a: |\n x\n\n y\n z\nb: 1\n", "{\"a\":\"x\n\n y\nz\n\",\"b\":1}"), - Arguments.of("a: |-\n x\n y\n", "{\"a\":\"x\ny\"}"), - Arguments.of("a: |+\n x\n\n\nb: 1\n", "{\"a\":\"x\n\n\n\",\"b\":1}"), - Arguments.of("a: >\n\n x\n y\n\n z\n more\n w\n", "{\"a\":\"\nx y\nz\n more\nw\n\"}"), - Arguments.of("a: >-\n x\n\n\n y", "{\"a\":\"x\n\ny\"}"), - Arguments.of("a: |\nb: 1\n", "{\"a\":\"\",\"b\":1}"), - Arguments.of("a: |+\n\n", "{\"a\":\"\n\"}"), - // Flow collections, over lines, with comments, empty values and JSON among them. - Arguments.of( - "{\"g\": [\n {\"n\": \"x\", \"r\": [1, 2.50, true]}, # one\n {}\n], k: , m: [ ], o: {p: q r,\n s: t}}\n", - "{\"g\":[{\"n\":\"x\",\"r\":[1,2.5,true]},{}],\"k\":null,\"m\":[],\"o\":{\"p\":\"q r\",\"s\":\"t\"}}"), - Arguments.of("[a:b, http://x, 'q', [c]]\n", "[\"a:b\",\"http://x\",\"q\",[\"c\"]]"), - Arguments.of("[a\n b, c]\n", "[\"a b\",\"c\"]"), - Arguments.of("{a: b}\n", "{\"a\":\"b\"}"), - Arguments.of("{'a': , b: }\n", "{\"a\":null,\"b\":null}"), - Arguments.of("[a#b, c #d\n]\n", "[\"a#b\",\"c\"]"), - // Keys as YAML writes them: after a marker's look-alike, with a colon or a hash inside, - // with a tab after, and empty. - Arguments.of("---x: 1\n", "{\"---x\":1}"), - Arguments.of("a:b: 1\na#b:\t2\n", "{\"a:b\":1,\"a#b\":2}"), - Arguments.of(": 1\n", "{\"\":1}"), - Arguments.of("x #c\n", "\"x\""), - Arguments.of("-5\n", "-5"), - Arguments.of("a:\n- x\nb: y\n", "{\"a\":[\"x\"],\"b\":\"y\"}"), - Arguments.of("a: x\n ", "{\"a\":\"x\"}"), - Arguments.of("a: |\n x\n \ty\n", "{\"a\":\"x\n\ty\n\"}"), - Arguments.of("a: 'x\\y'\n", "{\"a\":\"x\\y\"}"), - Arguments.of("{a: 1 b}\n", "{\"a\":\"1 b\"}"), - Arguments.of("- a\n - b\n", "[\"a - b\"]"), - // A plain scalar is typed as the core schema types it. - Arguments.of( - "[~, null, Null, NULL, true, False, 007, -3, +4, 0o17, 0x1F, 1.50, .5, 1e3, -0.0, 1.2.3, 0b1, yes]\n", - "[null,null,null,null,true,false,7,-3,4,15,31,1.5,0.5,1000,0,\"1.2.3\",\"0b1\",\"yes\"]")); - } - - @ParameterizedTest - @MethodSource("documents") - void aDocumentHoldsWhatYamlReadsItAs(String text, String expected) { - assertThat(read(text)).isEqualTo(expected); - } - - @ParameterizedTest - @ValueSource( - strings = { - "a: 1\na: 2\n", - "{a: 1, a: 2}\n", - "a: 1\n b: 2\n", - "a: [1]\n b\n", - "- [a]\n b\n", - "a: 1\nb\n", - "a: [1] x\n", - "a: 'x' y\n", - "a: 'x\n", - "a: \"x\n", - "a: \"\\q\"\n", - "a: \"\\u00G1\"\n", - "a: \"\\u0", - "a: &x 1\n", - "a: *x\n", - "a: !x 1\n", - "a: |2\n x\n", - "&x a: 1\n", - "{a 1}\n", - "{a: 1 b: 2}\n", - "[&x]\n", - "{: 1}\n", - "[a, b\n", - "--- a\n--- b\n", - "a: 1\n...\n", - "%YAML 1.2\n", - "a: 1\n- b\n", - "a: |\n x\n y\n", - "\"a\":b\n", - "\"a\" b\n" - }) - void textThatIsNotTheYamlItReadsHoldsNothing(String text) { - assertThat(DataFile.read(text)).isEmpty(); - } - - @Test - void aFilesGroupsAreTheListItsTopLevelMappingHoldsUnderGroups() { - assertThat(DataFile.groups("x: 1\ngroups:\n - name: a\n").map(DataFileTest::json)) - .contains("[{\"name\":\"a\"}]"); - assertThat(DataFile.groups("- groups: [a]\n")).isEmpty(); - assertThat(DataFile.groups("groups: a\n")).isEmpty(); - assertThat(DataFile.groups("groups: []\n")).isEmpty(); - assertThat(DataFile.groups("rules: [a]\n")).isEmpty(); - assertThat(DataFile.groups("groups: [a\n")).isEmpty(); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/DiagnosticTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/DiagnosticTest.java deleted file mode 100644 index 3e5cbb464..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/DiagnosticTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.List; -import org.junit.jupiter.api.Test; - -/** What a refusal carries: the code, the document and the path the parity contract compares, and a message. */ -class DiagnosticTest { - - @Test - void aDiagnosticCarriesItsCodeDocumentPathAndMessage() { - Diagnostic diagnostic = new Diagnostic( - Diagnostic.SCHEMA, "notes.project.yml", "/applications/0/processes/0/runtime", "refused"); - - assertThat(diagnostic.code()).isEqualTo("schema"); - assertThat(diagnostic.document()).isEqualTo("notes.project.yml"); - assertThat(diagnostic.path()).isEqualTo("/applications/0/processes/0/runtime"); - assertThat(diagnostic.message()).isEqualTo("refused"); - } - - @Test - void aParsedDocumentIsEitherAnIntentOrRefusals() { - Diagnostic diagnostic = new Diagnostic(Diagnostic.SCHEMA, "notes.project.yml", "", "refused"); - - assertThat(Parsed.refused(List.of(diagnostic)).ok()).isFalse(); - assertThat(Parsed.refused(List.of(diagnostic)).intent()).isEmpty(); - assertThat(Parsed.of(java.util.Map.of("project", "notes")).ok()).isTrue(); - assertThat(Parsed.of(java.util.Map.of("project", "notes")).diagnostics()) - .isEmpty(); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/EnvFilesTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/EnvFilesTest.java deleted file mode 100644 index fc868daf5..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/EnvFilesTest.java +++ /dev/null @@ -1,136 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.cli.EnvFiles.Scope; -import dev.jorisjonkers.deploykit.emf.cli.EnvFiles.Source; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EnvLiteral; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EnvVariable; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Placeholder; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.PlaceholderKind; -import java.util.List; -import java.util.Optional; -import org.junit.jupiter.api.Test; - -/** REQ-037: the dotenv subset chapter 10 fixes, read into the model. */ -class EnvFilesTest { - - private static EnvFiles.Read read(String text) { - return EnvFiles.read(List.of(new Source("env/w/base.env", text))); - } - - private static List names(EnvFiles.Read read) { - return read.files().get(0).file().getEntries().stream() - .map(EnvVariable::getName) - .toList(); - } - - @Test - void readsALiteralAPlaceholderCommentsAndBlankLines() { - EnvFiles.Read read = read("# a comment\n\nMODE=lite\nDB_HOST=${dependency:platform-postgres.host}\n"); - - assertThat(read.ok()).as(read.diagnostics().toString()).isTrue(); - assertThat(names(read)).containsExactly("MODE", "DB_HOST"); - List entries = read.files().get(0).file().getEntries(); - assertThat(((EnvLiteral) entries.get(0).getValue()).getText()).isEqualTo("lite"); - Placeholder host = (Placeholder) entries.get(1).getValue(); - assertThat(host.getKind()).isEqualTo(PlaceholderKind.DEPENDENCY); - assertThat(host.getSource()).isEqualTo("platform-postgres.host"); - } - - @Test - void keepsTheLiteralTextAfterAPlaceholderThatIsNoSecret() { - EnvFiles.Read read = read("LOGIN=${exposure:auth.public#url}/login\nHOST=${exposure:auth.public#host}\n"); - - assertThat(read.ok()).as(read.diagnostics().toString()).isTrue(); - List entries = read.files().get(0).file().getEntries(); - Placeholder login = (Placeholder) entries.get(0).getValue(); - assertThat(login.getSource()).isEqualTo("auth.public#url"); - assertThat(login.getSuffix()).isEqualTo("/login"); - assertThat(((Placeholder) entries.get(1).getValue()).isSetSuffix()).isFalse(); - } - - @Test - void refusesEveryLineOutsideTheSubset() { - assertThat(read("MODE\n").ok()).isFalse(); - assertThat(read("=lite\n").ok()).isFalse(); - assertThat(read("9LIVES=yes\n").ok()).isFalse(); - assertThat(read("DSN=${secret:secret/data/p#u}/db\n").ok()).isFalse(); - assertThat(read("DSN=${unknown:x}\n").ok()).isFalse(); - assertThat(read("DSN=${secret}\n").ok()).isFalse(); - assertThat(read("DSN=${:x}\n").ok()).isFalse(); - assertThat(read("DSN=${secret:a}b}\n").ok()).isFalse(); - assertThat(read("DSN=prefix-${secret:x}\n").ok()).isFalse(); - assertThat(read("DSN=${secret:}\n").ok()).isFalse(); - assertThat(read("DSN=\n").ok()).isFalse(); - assertThat(read("TOKEN=a#b\n").ok()).isFalse(); - assertThat(read("URL=${exposure:a.b#url\n").ok()).isFalse(); - assertThat(read("URL=${exposure:a.b#url}#x\n").ok()).isFalse(); - assertThat(read("URL=${exposure:a.b#url}${exposure:a.b#host}\n").ok()).isFalse(); - } - - @Test - void namesTheLineAndTheFileEveryRefusalConcerns() { - EnvFiles.Read read = read("A=1\n# a comment\nMODE\n"); - - assertThat(read.diagnostics()).singleElement().satisfies(refusal -> { - assertThat(refusal.document()).isEqualTo("env/w/base.env"); - assertThat(refusal.path()).isEqualTo("env/w/base.env:3"); - }); - } - - @Test - void carriesEachFileWithThePathAndTheScopeItWasReadUnder() { - EnvFiles.Scoped scoped = EnvFiles.read( - List.of(new Source("platform/env/_applications/knowledge/base.env", "A=1\n"))) - .files() - .get(0); - - assertThat(scoped.path()).isEqualTo("platform/env/_applications/knowledge/base.env"); - assertThat(scoped.scope().level()).isEqualTo(Scope.Level.APPLICATION); - assertThat(scoped.scope().name()).isEqualTo("knowledge"); - } - - @Test - void keepsAnEqualsInsideAValueAndRefusesOneVariableSetTwice() { - EnvFiles.Read dsn = read("DSN=host=db;port=5432\n"); - - assertThat(((EnvLiteral) dsn.files().get(0).file().getEntries().get(0).getValue()).getText()) - .isEqualTo("host=db;port=5432"); - EnvFiles.Read twice = read("MODE=lite\nMODE=full\n"); - assertThat(twice.diagnostics()).extracting(Diagnostic::code).containsExactly("E_SHARED_DECLARATION_DUPLICATED"); - } - - @Test - void refusesAFileOtherThanTheScopesOneBaseFileBecauseNoFileVariesByCluster() { - EnvFiles.Read overlay = EnvFiles.read(List.of(new Source("env/w/production.env", "A=1\n"))); - - assertThat(overlay.files()).isEmpty(); - assertThat(overlay.diagnostics()).singleElement().satisfies(refusal -> { - assertThat(refusal.code()).isEqualTo(Diagnostic.SCHEMA); - assertThat(refusal.message()).isEqualTo("a scope's one env file is base.env"); - }); - } - - @Test - void scopesAFileByTheDirectoryThatHoldsIt() { - assertThat(EnvFiles.scopeOf("platform/env/_project/base.env")) - .contains(new Scope(Scope.Level.PROJECT, "_project")); - assertThat(EnvFiles.scopeOf("platform/env/_applications/knowledge/base.env")) - .contains(new Scope(Scope.Level.APPLICATION, "knowledge")); - assertThat(EnvFiles.scopeOf("platform/env/knowledge-api/base.env")) - .get() - .satisfies(scope -> { - assertThat(scope.level()).isEqualTo(Scope.Level.PROCESS); - assertThat(scope.name()).isEqualTo("knowledge-api"); - }); - // A scope is a directory, so a file sitting directly in env/ names none, - // and the Application scope has to say which Application. - assertThat(EnvFiles.scopeOf("platform/knowledge.project.yml")).isEqualTo(Optional.empty()); - assertThat(EnvFiles.scopeOf("platform/env/w/base.yml")).isEqualTo(Optional.empty()); - assertThat(EnvFiles.scopeOf("platform/env/base.env")).isEqualTo(Optional.empty()); - assertThat(EnvFiles.scopeOf("platform/env/_applications/base.env")).isEqualTo(Optional.empty()); - assertThat(EnvFiles.scopeOf("platform/env/w/deep/base.env")).isEqualTo(Optional.empty()); - assertThat(EnvFiles.read(List.of(new Source("notes.yml", ""))).ok()).isFalse(); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Examples.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Examples.java deleted file mode 100644 index 5f4248061..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Examples.java +++ /dev/null @@ -1,42 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; - -/** The worked examples under {@code spec/v1/examples/}, and scratch copies of them with one change. */ -final class Examples { - - private Examples() {} - - static Path of(String relative) { - return repository().resolve("spec/v1/examples").resolve(relative); - } - - /** The working copy's root: the directory holding {@code emf/pom.xml}. */ - static Path repository() { - Path dir = Path.of("").toAbsolutePath(); - while (!Files.isRegularFile(dir.resolve("emf/pom.xml"))) { - dir = dir.getParent(); - } - return dir; - } - - static String read(String relative) { - try { - return Files.readString(of(relative)); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** {@code text} written to {@code name} in {@code directory}. */ - static Path write(Path directory, String name, String text) { - try { - return Files.writeString(directory.resolve(name), text); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/FieldCoverage.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/FieldCoverage.java deleted file mode 100644 index ed9fcb872..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/FieldCoverage.java +++ /dev/null @@ -1,432 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.PinnedInputsPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentPackage; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; -import java.util.Deque; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import org.eclipse.emf.common.util.Enumerator; -import org.eclipse.emf.ecore.EAttribute; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EClassifier; -import org.eclipse.emf.ecore.EEnum; -import org.eclipse.emf.ecore.EEnumLiteral; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.yaml.snakeyaml.LoaderOptions; -import org.yaml.snakeyaml.Yaml; -import org.yaml.snakeyaml.constructor.SafeConstructor; - -/** - * What the stage cases never exercise, one line per gap, each a sentence naming what is missing: - * {@code ResolvedProcess.servingLabel is never set by a resolve case}. A stage's gaps are every - * feature of every concrete class its documents can hold that no case's input sets, every enum - * literal none uses, and the same of what {@code lower} and {@code resolve} write; for {@code parse}, - * every property path of the two intent schemas no input carries; for {@code render}, every type - * {@code render.mtl} dispatches on that no input instantiates. FieldCoverageTest holds the gaps to a - * committed baseline that may only shrink. - */ -final class FieldCoverage { - - /** The three metamodels a stage's documents are instances of. */ - static final List PACKAGES = - List.of(ProjectIntentPackage.eINSTANCE, PinnedInputsPackage.eINSTANCE, ResolvedDeploymentPackage.eINSTANCE); - - private static final ObjectMapper JSON = new ObjectMapper(); - - /** A template the polymorphic dispatch of {@code render.mtl} chooses by the Deliverable's type. */ - private static final Pattern DISPATCH = - Pattern.compile("\\[template private (?:objects|json)\\(d : resolveddeployment::(\\w+)\\)\\]"); - - private FieldCoverage() {} - - // ------------------------------------------------------------------------------------ stages - - /** Every gap of {@code stage} over its committed cases, sorted. */ - static List gaps(String stage) throws IOException { - TreeSet gaps = new TreeSet<>(); - // A given case is hand-written input, which says nothing of what its own stage writes. - List cases = Stages.produced(stage); - switch (stage) { - case "parse" -> { - List input = models(cases, "parse", Stages.INTENT_MODEL, "parse", Stages.PINNED_MODEL); - Set classes = containable(intentRoots(true)); - String phrase = "in a parse case's input"; - gaps.addAll(features(classes, input, phrase)); - gaps.addAll(literals(classes, input, phrase)); - Path schemas = Examples.repository().resolve("spec/v1/schemas"); - gaps.addAll(schemaPaths( - schemas.resolve("project-intent.schema.json"), authored(cases, true), "a parse case's input")); - gaps.addAll(schemaPaths( - schemas.resolve("platform-intent.schema.json"), - authored(cases, false), - "a parse case's input")); - } - case "lower" -> { - List input = models(cases, "parse", Stages.INTENT_MODEL); - Set inputs = containable(List.of(ProjectIntentPackage.eINSTANCE.getProject())); - gaps.addAll(features(inputs, input, "in a lower case's input")); - gaps.addAll(literals(inputs, input, "in a lower case's input")); - List output = models(cases, "lower", Stages.EFFECTIVE_MODEL); - Set outputs = containable(List.of(ProjectIntentPackage.eINSTANCE.getEffectiveProject())); - gaps.addAll(features(outputs, output, "by a lower case")); - gaps.addAll(literals(outputs, output, "by a lower case")); - } - case "resolve" -> { - List input = models( - cases, - "parse", - Stages.INTENT_MODEL, - "parse", - Stages.PINNED_MODEL, - "lower", - Stages.EFFECTIVE_MODEL); - Set inputs = containable(intentRoots(false)); - gaps.addAll(features(inputs, input, "in a resolve case's input")); - gaps.addAll(literals(inputs, input, "in a resolve case's input")); - List output = deployments(cases); - Set outputs = containable(List.of(ResolvedDeploymentPackage.eINSTANCE.getResolvedDeployment())); - gaps.addAll(features(outputs, output, "by a resolve case")); - gaps.addAll(literals(outputs, output, "by a resolve case")); - } - case "render" -> { - List input = deployments(cases); - Set inputs = containable(List.of(ResolvedDeploymentPackage.eINSTANCE.getResolvedDeployment())); - gaps.addAll(features(inputs, input, "in a render case's input")); - gaps.addAll(literals(inputs, input, "in a render case's input")); - gaps.addAll(dispatch( - Examples.repository().resolve("emf/bundles/render/model/render.mtl"), - input, - "in a render case's input")); - } - default -> throw new IllegalArgumentException("no stage " + stage); - } - return List.copyOf(gaps); - } - - /** - * The classes a document of the intent and pinned metamodels opens on: every concrete class no - * containment holds. The Effective Intent is what the lowering writes, so an authored set holds - * none of it. - */ - private static List intentRoots(boolean authored) { - Set contained = new HashSet<>(); - List classes = new ArrayList<>(); - for (EPackage metamodel : List.of(ProjectIntentPackage.eINSTANCE, PinnedInputsPackage.eINSTANCE)) { - for (EClassifier classifier : metamodel.getEClassifiers()) { - if (classifier instanceof EClass type) { - classes.add(type); - for (EReference reference : type.getEAllContainments()) { - contained.addAll(concrete(reference.getEReferenceType())); - } - } - } - } - return classes.stream() - .filter(type -> !type.isAbstract() && !type.isInterface() && !contained.contains(type)) - .filter(type -> !authored || type != ProjectIntentPackage.eINSTANCE.getEffectiveProject()) - .toList(); - } - - /** The roots of {@code file} of every case, read in pairs of (stage, file), each case in one resource set. */ - private static List models(List cases, String... stagesAndFiles) { - List roots = new ArrayList<>(); - for (String name : cases) { - var resources = Stages.resources(); - for (int i = 0; i + 1 < stagesAndFiles.length; i += 2) { - roots.addAll(Stages.load( - resources, Stages.expected(stagesAndFiles[i], name).resolve(stagesAndFiles[i + 1]))); - } - } - return roots; - } - - /** Every Resolved Deployment the resolve cases of {@code cases} wrote. */ - private static List deployments(List cases) throws IOException { - List roots = new ArrayList<>(); - for (String name : cases) { - for (String project : Stages.projects(name)) { - roots.addAll(Stages.load( - Stages.resources(), Stages.expected("resolve", name).resolve(project + Stages.RESOLVED_MODEL))); - } - } - return roots; - } - - /** The authored documents of the parse cases, read as YAML: the project files, or the Platform documents. */ - private static List authored(List cases, boolean projects) throws IOException { - List documents = new ArrayList<>(); - for (String name : cases) { - for (Path document : Stages.documents( - Stages.root().resolve("parse").resolve(name).resolve(Stages.INPUT))) { - String file = document.getFileName().toString(); - if (projects ? file.endsWith(".project.yml") : file.equals("platform.intent.yml")) { - documents.add(new Yaml(new SafeConstructor(new LoaderOptions())).load(Files.readString(document))); - } - } - } - return documents; - } - - // ------------------------------------------------------------------------------- metamodels - - /** The concrete classes a document opening on one of {@code roots} can hold, the roots among them. */ - static Set containable(Collection roots) { - Set reached = new LinkedHashSet<>(); - Deque next = new ArrayDeque<>(roots); - while (!next.isEmpty()) { - EClass type = next.pop(); - if (reached.add(type)) { - for (EReference reference : type.getEAllContainments()) { - next.addAll(concrete(reference.getEReferenceType())); - } - } - } - return reached; - } - - /** {@code type} and every class of the three metamodels below it, the concrete ones only. */ - private static List concrete(EClass type) { - Set found = new LinkedHashSet<>(); - if (!type.isAbstract() && !type.isInterface()) { - found.add(type); - } - for (EPackage metamodel : PACKAGES) { - for (EClassifier classifier : metamodel.getEClassifiers()) { - if (classifier instanceof EClass candidate - && !candidate.isAbstract() - && !candidate.isInterface() - && type.isSuperTypeOf(candidate)) { - found.add(candidate); - } - } - } - return List.copyOf(found); - } - - /** Whether a feature is one a document carries: neither derived, nor transient, nor the way back to a container. */ - private static boolean carried(EStructuralFeature feature) { - return !feature.isDerived() - && !feature.isTransient() - && !(feature instanceof EReference reference && reference.isContainer()); - } - - /** - * Every class of {@code classes} no object of {@code models} is an instance of, and every feature - * of every class none of its instances sets. A required single value is set wherever its object is. - */ - static List features(Set classes, Collection models, String phrase) { - Map> instances = instances(models); - List gaps = new ArrayList<>(); - for (EClass type : sorted(classes)) { - List objects = instances.getOrDefault(type, List.of()); - if (objects.isEmpty()) { - gaps.add(type.getName() + " is never instantiated " + phrase); - } - for (EStructuralFeature feature : type.getEAllStructuralFeatures()) { - if (carried(feature) - && objects.stream() - .noneMatch(object -> - object.eIsSet(feature) || (feature.isRequired() && !feature.isMany()))) { - gaps.add(type.getName() + "." + feature.getName() + " is never set " + phrase); - } - } - } - return gaps; - } - - /** Every literal of every enum a feature of {@code classes} is typed by that no object of {@code models} holds. */ - static List literals(Set classes, Collection models, String phrase) { - Set enums = new LinkedHashSet<>(); - for (EClass type : classes) { - for (EAttribute attribute : type.getEAllAttributes()) { - if (carried(attribute) && attribute.getEAttributeType() instanceof EEnum vocabulary) { - enums.add(vocabulary); - } - } - } - Set used = new HashSet<>(); - for (Iterator all = EcoreUtil.getAllContents(models, false); all.hasNext(); ) { - EObject object = all.next(); - for (EAttribute attribute : object.eClass().getEAllAttributes()) { - if (attribute.getEAttributeType() instanceof EEnum vocabulary - && (object.eIsSet(attribute) || attribute.isRequired())) { - for (Object value : values(object, attribute)) { - used.add(vocabulary.getName() + "." + ((Enumerator) value).getName()); - } - } - } - } - List gaps = new ArrayList<>(); - for (EEnum vocabulary : - enums.stream().sorted(Comparator.comparing(EEnum::getName)).toList()) { - // A literal with no spelling is the model's way of saying "unset", which no document writes. - for (EEnumLiteral literal : vocabulary.getELiterals().stream() - .filter(literal -> !literal.getLiteral().isEmpty()) - .toList()) { - String name = vocabulary.getName() + "." + literal.getName(); - if (!used.contains(name)) { - gaps.add(name + " is never used " + phrase); - } - } - } - return gaps; - } - - /** Every type a template of {@code mtl} dispatches on that no object of {@code models} is an instance of. */ - static List dispatch(Path mtl, Collection models, String phrase) throws IOException { - Set instantiated = new HashSet<>(); - for (Iterator all = EcoreUtil.getAllContents(models, false); all.hasNext(); ) { - EClass type = all.next().eClass(); - instantiated.add(type.getName()); - type.getEAllSuperTypes().forEach(supertype -> instantiated.add(supertype.getName())); - } - TreeSet gaps = new TreeSet<>(); - Matcher templates = DISPATCH.matcher(Files.readString(mtl)); - while (templates.find()) { - if (!instantiated.contains(templates.group(1))) { - gaps.add(templates.group(1) + " is never instantiated " + phrase + " (render.mtl dispatches on it)"); - } - } - return List.copyOf(gaps); - } - - private static Map> instances(Collection models) { - Map> instances = new HashMap<>(); - for (Iterator all = EcoreUtil.getAllContents(models, false); all.hasNext(); ) { - EObject object = all.next(); - instances - .computeIfAbsent(object.eClass(), type -> new ArrayList<>()) - .add(object); - } - return instances; - } - - private static List values(EObject object, EStructuralFeature feature) { - Object value = object.eGet(feature); - return feature.isMany() ? (List) value : value == null ? List.of() : List.of(value); - } - - private static List sorted(Set classes) { - return classes.stream().sorted(Comparator.comparing(EClass::getName)).toList(); - } - - // ---------------------------------------------------------------------------------- schemas - - /** Every property path of the JSON schema at {@code schema} that none of {@code documents} carries. */ - static List schemaPaths(Path schema, List documents, String where) { - JsonNode root; - try { - root = JSON.readTree(schema.toFile()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - Set declared = new TreeSet<>(); - declared(root, root, "", declared, new HashSet<>()); - Set present = new HashSet<>(); - for (Object document : documents) { - present(root, root, document, "", present, new HashSet<>()); - } - String name = schema.getFileName().toString(); - return declared.stream() - .filter(path -> !present.contains(path)) - .map(path -> name + " " + path + " is never present in " + where) - .toList(); - } - - /** Every property path below {@code node}: a property by its name, a map's value as {@code *}, an item as {@code []}. */ - private static void declared(JsonNode root, JsonNode node, String at, Set paths, Set following) { - if (node.has("$ref")) { - String ref = node.get("$ref").asText(); - if (following.add(ref)) { - declared(root, target(root, ref), at, paths, following); - following.remove(ref); - } - } - for (String combinator : List.of("anyOf", "oneOf", "allOf")) { - for (JsonNode branch : node.path(combinator)) { - declared(root, branch, at, paths, following); - } - } - for (Map.Entry property : node.path("properties").properties()) { - String path = at + "/" + property.getKey(); - paths.add(path); - declared(root, property.getValue(), path, paths, following); - } - if (node.path("additionalProperties").isObject()) { - String path = at + "/*"; - paths.add(path); - declared(root, node.get("additionalProperties"), path, paths, following); - } - if (node.path("items").isObject()) { - declared(root, node.get("items"), at + "[]", paths, following); - } - } - - /** Every property path of {@code node} that {@code value} carries, in the notation {@link #declared} writes. */ - private static void present( - JsonNode root, JsonNode node, Object value, String at, Set paths, Set following) { - if (node.has("$ref")) { - String ref = node.get("$ref").asText(); - if (following.add(ref)) { - present(root, target(root, ref), value, at, paths, following); - following.remove(ref); - } - } - for (String combinator : List.of("anyOf", "oneOf", "allOf")) { - for (JsonNode branch : node.path(combinator)) { - present(root, branch, value, at, paths, following); - } - } - if (value instanceof Map map) { - for (Map.Entry entry : map.entrySet()) { - String key = String.valueOf(entry.getKey()); - JsonNode property = node.path("properties").path(key); - if (property.isObject()) { - paths.add(at + "/" + key); - present(root, property, entry.getValue(), at + "/" + key, paths, new HashSet<>()); - } else if (node.path("additionalProperties").isObject()) { - paths.add(at + "/*"); - present( - root, - node.get("additionalProperties"), - entry.getValue(), - at + "/*", - paths, - new HashSet<>()); - } - } - } - if (value instanceof List list && node.path("items").isObject()) { - for (Object item : list) { - present(root, node.get("items"), item, at + "[]", paths, new HashSet<>()); - } - } - } - - private static JsonNode target(JsonNode root, String ref) { - return root.at(ref.substring(1)); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/FieldCoverageTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/FieldCoverageTest.java deleted file mode 100644 index 3bd18ea6b..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/FieldCoverageTest.java +++ /dev/null @@ -1,142 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Cutover; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Process; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentFactory; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeSet; -import org.eclipse.emf.ecore.EClass; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -/** - * Field coverage is a ratchet: every gap a stage's cases leave (FieldCoverage) is either in the - * stage's committed {@code gaps.txt} or fails the build, and an entry the cases now cover fails it - * too, until it is removed, so the baseline only shrinks. {@code -Dgolden.update=true} removes the - * covered entries; a new gap is never added by an update, only by hand. - */ -class FieldCoverageTest { - - private static final String BASELINE = "gaps.txt"; - - static List stages() { - return Stages.ORDER; - } - - @ParameterizedTest(name = "{0}") - @MethodSource("stages") - void aStagesGapsAreExactlyItsBaseline(String stage) throws IOException { - List gaps = FieldCoverage.gaps(stage); - Path file = Stages.root().resolve(stage).resolve(BASELINE); - List baseline = Files.isRegularFile(file) ? Files.readAllLines(file) : List.of(); - - if (Stages.updating()) { - Set kept = new TreeSet<>(gaps); - if (Files.isRegularFile(file)) { - kept.retainAll(baseline); - } - Files.createDirectories(file.getParent()); - Files.write(file, kept); - return; - } - List uncovered = new ArrayList<>(gaps); - uncovered.removeAll(baseline); - List covered = new ArrayList<>(baseline); - covered.removeAll(gaps); - assertThat(uncovered) - .withFailMessage( - "%s: %d gaps no case covers and %s does not excuse; add a case that covers each:%n%s", - stage, uncovered.size(), BASELINE, String.join("\n", uncovered)) - .isEmpty(); - assertThat(covered) - .withFailMessage( - "%s: %d entries of %s are covered now; remove each (the ratchet only shrinks):%n%s", - stage, covered.size(), BASELINE, String.join("\n", covered)) - .isEmpty(); - } - - @Test - void aFeatureNoInstanceSetsAndAClassNothingInstantiatesAreGaps() { - ProjectIntentPackage model = ProjectIntentPackage.eINSTANCE; - Process process = ProjectIntentFactory.eINSTANCE.createProcess(); - process.setName("api"); - Set classes = Set.of(model.getProcess(), model.getPlacement()); - - List gaps = FieldCoverage.features(classes, List.of(process), "in a test"); - - assertThat(gaps) - .contains("Process.cutover is never set in a test", "Placement is never instantiated in a test") - .doesNotContain("Process.name is never set in a test"); - process.setCutover(Cutover.INTERRUPTED); - assertThat(FieldCoverage.features(classes, List.of(process), "in a test")) - .doesNotContain("Process.cutover is never set in a test"); - } - - @Test - void anEnumLiteralNoObjectHoldsIsAGap() { - Process process = ProjectIntentFactory.eINSTANCE.createProcess(); - process.setCutover(Cutover.INTERRUPTED); - Set classes = Set.of(ProjectIntentPackage.eINSTANCE.getProcess()); - - assertThat(FieldCoverage.literals(classes, List.of(process), "in a test")) - .contains("Cutover.continuous is never used in a test") - .doesNotContain("Cutover.interrupted is never used in a test"); - } - - @Test - void aClassIsContainableThroughAnAbstractReferenceTypeByEveryConcreteSubtype() { - Set reached = FieldCoverage.containable(List.of(ProjectIntentPackage.eINSTANCE.getProject())); - - assertThat(reached) - .contains(ProjectIntentPackage.eINSTANCE.getProcess(), ProjectIntentPackage.eINSTANCE.getKvGrant()); - assertThat(reached).doesNotContain(ProjectIntentPackage.eINSTANCE.getEffectiveProject()); - } - - @Test - void aSchemaPathNoDocumentCarriesIsAGap(@TempDir Path directory) throws IOException { - Path schema = Files.writeString(directory.resolve("x.schema.json"), """ - {"$ref": "#/$defs/Doc", "$defs": { - "Doc": {"type": "object", "properties": { - "name": {"type": "string"}, - "items": {"type": "array", "items": {"anyOf": [{"$ref": "#/$defs/Item"}]}}, - "labels": {"type": "object", "additionalProperties": {"type": "string"}}, - "self": {"$ref": "#/$defs/Doc"}}}, - "Item": {"type": "object", "properties": {"id": {"type": "string"}, "port": {"type": "integer"}}}}} - """); - Map document = Map.of("name", "x", "items", List.of(Map.of("id", "a")), "other", 1); - - assertThat(FieldCoverage.schemaPaths(schema, List.of(document), "a test")) - .containsExactly( - "x.schema.json /items[]/port is never present in a test", - "x.schema.json /labels is never present in a test", - "x.schema.json /labels/* is never present in a test", - "x.schema.json /self is never present in a test"); - } - - @Test - void aTypeTheTemplatesDispatchOnThatNoModelInstantiatesIsAGap(@TempDir Path directory) throws IOException { - Path mtl = Files.writeString(directory.resolve("x.mtl"), """ - [template private objects(d : resolveddeployment::NamespaceFile)] - [/template] - [template private json(d : resolveddeployment::VaultRoleFile)] - [/template] - """); - var deployment = ResolvedDeploymentFactory.eINSTANCE.createResolvedDeployment(); - deployment.getDeliverables().add(ResolvedDeploymentFactory.eINSTANCE.createNamespaceFile()); - - assertThat(FieldCoverage.dispatch(mtl, List.of(deployment), "in a test")) - .containsExactly("VaultRoleFile is never instantiated in a test (render.mtl dispatches on it)"); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/IntentJsonTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/IntentJsonTest.java deleted file mode 100644 index 269561198..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/IntentJsonTest.java +++ /dev/null @@ -1,147 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.AnalysisPolicy; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.DeliveryPolicy; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Generate; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.GeneratedKey; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.HttpProbe; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.KeyEncoding; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.KvGrant; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Lifecycle; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Match; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Placement; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.PlainKey; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Probes; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Process; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Route; -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.Test; - -/** What the intent of a parsed model holds: the authored keys, and nothing the document left out. */ -class IntentJsonTest { - - private static final ProjectIntentFactory MODEL = ProjectIntentFactory.eINSTANCE; - - private static Process process() { - Process process = MODEL.createProcess(); - process.setName("notes-api"); - process.setLifecycle(Lifecycle.APPLICATION); - process.setImage("notes-api"); - Placement placement = MODEL.createPlacement(); - placement.setMemory("256Mi"); - placement.setCpu("50m"); - process.setPlacement(placement); - return process; - } - - @Test - void aRequiredFeatureIsWrittenEvenWhenItHoldsItsDefault() { - Map intent = IntentJson.of(process()); - - assertThat(intent).contains(entry("name", "notes-api"), entry("image", "notes-api")); - // `runtime` is required and holds `jvm`, its first literal, which nothing set. - assertThat(intent).containsKey("runtime"); - } - - @Test - void anEnumerationIsWrittenAsItsLiteral() { - assertThat(IntentJson.of(process())).contains(entry("lifecycle", "application")); - } - - @Test - void anOptionalFeatureTheDocumentLeftOutIsAbsent() { - // `cutover` is among them since it became Shared Intent (docs/adr/model/0124). - assertThat(IntentJson.of(process())).doesNotContainKeys("startupBudget", "probes", "provides", "cutover"); - } - - @Test - void aListOfLinkedNamesIsWrittenAsTheIdentifiersTheyLinkTo() { - // The delivery machinery, linked across the documents read together. - DeliveryPolicy delivery = MODEL.createDeliveryPolicy(); - AnalysisPolicy analysis = MODEL.createAnalysisPolicy(); - analysis.setInterval("30s"); - analysis.setIterations(4); - analysis.setThreshold(3); - analysis.setErrorRate("1%"); - analysis.setLatency("500ms"); - delivery.setAnalysis(analysis); - for (String id : new String[] {"flagger", "release-gate"}) { - Application application = MODEL.createApplication(); - application.setId(id); - delivery.getMachinery().add(application); - } - delivery.setGate(delivery.getMachinery().get(1)); - - assertThat(IntentJson.of(delivery)) - .contains(entry("machinery", List.of("flagger", "release-gate")), entry("gate", "release-gate")); - } - - @Test - void anOptionalFeatureTheDocumentSetIsWritten() { - Process process = process(); - process.setStartupBudget("20s"); - Probes probes = MODEL.createProbes(); - HttpProbe readiness = MODEL.createHttpProbe(); - readiness.setPath("/healthz/ready"); - readiness.setPort(8080); - probes.setReadiness(readiness); - process.setProbes(probes); - - assertThat(IntentJson.of(process())) - .doesNotContainKey("startupBudget"); // the sample above is a different object - assertThat(IntentJson.of(process)) - .contains( - entry("startupBudget", "20s"), - entry("probes", Map.of("readiness", Map.of("path", "/healthz/ready", "port", 8080)))); - } - - @Test - void aReferenceIsWrittenAsTheNameItLinked() { - Process process = process(); - process.getProvides().put("http", 8080); - Route route = MODEL.createRoute(); - route.setPath("/"); - route.setMatch(Match.PREFIX); - route.setProcess(process); - route.setSurface(process.getProvides().get(0)); - - assertThat(IntentJson.of(route)) - .contains(entry("process", "notes-api"), entry("surface", "http"), entry("match", "prefix")); - } - - @Test - void aMapEntryIsWrittenAsAnObjectAndAListAsAList() { - Process process = process(); - process.getProvides().put("http", 8080); - - assertThat(IntentJson.of(process())).doesNotContainKey("provides"); - assertThat(IntentJson.of(process())).doesNotContainKey("applications"); - assertThat(IntentJson.of(process)).contains(entry("provides", Map.of("http", 8080))); - } - - @Test - void aPlainKeyIsWrittenAsItsNameAndAGeneratedKeyAsABlock() { - KvGrant grant = MODEL.createKvGrant(); - grant.setPath("secret/data/notes-system/app"); - grant.setRotation(MODEL.createRotation()); - PlainKey plain = MODEL.createPlainKey(); - plain.setName("password"); - GeneratedKey generated = MODEL.createGeneratedKey(); - generated.setName("session_key"); - Generate generate = MODEL.createGenerate(); - generate.setEncoding(KeyEncoding.BASE64); - generated.setGenerate(generate); - grant.getKeys().addAll(List.of(plain, generated)); - - assertThat(IntentJson.of(grant)) - .contains(entry( - "keys", - List.of("password", Map.of("name", "session_key", "generate", Map.of("encoding", "base64"))))); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/IntentSetTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/IntentSetTest.java deleted file mode 100644 index 3bed891cf..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/IntentSetTest.java +++ /dev/null @@ -1,412 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.groups.Tuple.tuple; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.PosixFilePermissions; -import java.util.List; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** - * REQ-031 (docs/requirements.md): the Platform document and the project files read beside it are - * refused where a reference one makes into the other does not resolve, or a policy one asks for the - * other does not offer. - */ -class IntentSetTest { - - private static final List WORKED = List.of( - Examples.of("platform/platform.intent.yml"), - Examples.of("auth/auth.project.yml"), - Examples.of("data/data.project.yml"), - Examples.of("delivery/delivery.project.yml"), - Examples.of("edge/edge.project.yml"), - Examples.of("knowledge/knowledge.project.yml"), - Examples.of("minimal/notes.project.yml"), - Examples.of("observability/observability.project.yml"), - Examples.of("secrets/secrets.project.yml"), - Examples.of("identity/identity.project.yml"), - Examples.of("mail/mail.project.yml"), - Examples.of("utility/utility.project.yml"), - Examples.of("agents/agents.project.yml")); - - /** The worked Platform document's telemetry block, which a variant composed with fewer projects drops. */ - private static final String TELEMETRY = "\ntelemetry:\n( .*\n)+"; - - /** Its sign-in block, whose provider a variant without the identity project does not compose. */ - private static final String SIGN_IN = "\nsignIn:\n( .*\n)+"; - - /** Its API access block, which names Applications a variant may not compose. */ - private static final String API_ACCESS = "\napiAccess:\n( .*\n)+"; - - @Test - void theWorkedEstateIsRefusedNowhere() { - // The foundation is declared and secrets are encrypted at rest. - assertThat(Pipeline.check(WORKED)).isEmpty(); - } - - @Test - void aYamlFileThatSaysItIsAProjectIsReadAsOneWhateverItsName(@TempDir Path directory) { - String broken = Examples.read("minimal/notes.project.yml").replace("runtime: node", "runtime: rust"); - - assertThat(Pipeline.check(List.of(Examples.write(directory, "notes.yml", broken)))) - .extracting(Diagnostic::document) - .containsOnly("notes.yml"); - assertThat(Pipeline.check(List.of( - Examples.write(directory, "asset.yml", broken.replace("kind: Project", "kind: Asset")), - Examples.write(directory, "notes.txt", broken)))) - .isEmpty(); - } - - @Test - void aYamlFileThatCannotBeReadIsAnErrorRatherThanAProjectOrNot(@TempDir Path directory) { - assertThatThrownBy(() -> Pipeline.check(List.of(directory.resolve("missing.yml")))) - .isInstanceOf(UncheckedIOException.class); - } - - @Test - void theEnvFilesBesideAProjectFileReachTheProcessesTheyName() { - assertThat(Pipeline.check(List.of( - Examples.of("refusals/unbound-secret-grant/platform.intent.yml"), - Examples.of("refusals/unbound-secret-grant/refusals.project.yml")))) - .extracting(Diagnostic::code, Diagnostic::path) - .containsExactly(tuple("E_UNBOUND_SECRET_GRANT", "/applications/0/processes/0")); - } - - @Test - void anAssetIsReadOnlyFromBelowItsProjectsDirectory(@TempDir Path directory) throws IOException { - Path project = Files.createDirectories(directory.resolve("project")); - Files.writeString(directory.resolve("outside.conf"), "a = 1\n"); - String notes = Examples.read("minimal/notes.project.yml") - .replace( - " cutover: continuous", - " assets:\n - { from: FROM, mountAt: /etc/a.conf }\n cutover: continuous"); - - for (String from : - List.of("../outside.conf", directory.resolve("outside.conf").toString())) { - assertThat(Pipeline.check( - List.of(Examples.write(project, "notes.project.yml", notes.replace("FROM", from))))) - .as(from) - .extracting(Diagnostic::code) - .containsExactly("E_ASSET_NOT_FOUND"); - } - } - - @Test - void anEnvFileThatCannotBeReadIsAnErrorRatherThanARefusal(@TempDir Path directory) throws IOException { - Path project = Examples.write(directory, "notes.project.yml", Examples.read("minimal/notes.project.yml")); - Path env = Files.createDirectories(directory.resolve("env/notes-api")); - Path unreadable = Files.writeString(env.resolve("base.env"), "A=1\n"); - Files.setPosixFilePermissions(unreadable, PosixFilePermissions.fromString("---------")); - - assertThatThrownBy(() -> Pipeline.check(List.of(project))).isInstanceOf(UncheckedIOException.class); - } - - @Test - void everyEnvAndFileGrantIsRefusedWhereSecretsAreNotEncryptedAtRest(@TempDir Path directory) { - Path platform = Examples.write( - directory, - "platform.intent.yml", - Examples.read("platform/platform.intent.yml") - .replace("secretsEncryption: true", "secretsEncryption: false")); - List unencrypted = new java.util.ArrayList<>(WORKED.subList(1, WORKED.size())); - unencrypted.add(0, platform); - - assertThat(Pipeline.check(unencrypted)) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path) - .containsExactlyInAnyOrder( - tuple( - "E_SECRETS_AT_REST_REQUIRED", - "data.project.yml", - "/applications/0/processes/0/secrets/0"), - tuple("E_SECRETS_AT_REST_REQUIRED", "knowledge.project.yml", "/secrets/0"), - tuple("E_SECRETS_AT_REST_REQUIRED", "knowledge.project.yml", "/secrets/1"), - tuple( - "E_SECRETS_AT_REST_REQUIRED", - "knowledge.project.yml", - "/applications/0/processes/0/secrets/0"), - tuple( - "E_SECRETS_AT_REST_REQUIRED", - "knowledge.project.yml", - "/applications/1/processes/0/secrets/0"), - tuple( - "E_SECRETS_AT_REST_REQUIRED", - "data.project.yml", - "/applications/4/processes/0/secrets/0"), - tuple( - "E_SECRETS_AT_REST_REQUIRED", - "data.project.yml", - "/applications/5/processes/0/secrets/0"), - tuple( - "E_SECRETS_AT_REST_REQUIRED", - "agents.project.yml", - "/applications/0/processes/0/secrets/0")); - } - - @Test - void projectFilesReadWithoutAPlatformDocumentAnswerNoRuleAcrossDocuments() { - assertThat(Pipeline.check(WORKED.subList(1, WORKED.size()))).isEmpty(); - } - - @Test - void aSetThatBreaksNothingIsNotRefused(@TempDir Path directory) { - Path platform = Examples.write( - directory, - "platform.intent.yml", - Examples.read("platform/platform.intent.yml") - .replace("secretsEncryption: false", "secretsEncryption: true") - // notes provides no `web` surface, so its tiers name no address its proxy answers on. - .replaceAll("\\n *address: (edge-frankfurt|lan-edge)[^\\n]*", "") - .replace("traefik: edge/traefik-public", "traefik: notes/notes") - .replace("traefik: edge/traefik-lan", "traefik: notes/notes") - .replace( - "machinery: [edge/traefik-public, edge/traefik-lan, delivery/flagger, delivery/release-gate]", - "machinery: [notes/notes]") - .replace("gate: delivery/release-gate", "gate: notes/notes") - .replace("reporter: delivery/reporter", "reporter: notes/notes") - .replace("secretStore: secrets/vault", "secretStore: notes/notes") - .replace("ingressClass: traefik-lan", "ingressClass: traefik-public") - .replaceFirst(SIGN_IN, "\n") - .replaceFirst(TELEMETRY, "\n") - .replaceFirst(API_ACCESS, "\n")); - - assertThat(Pipeline.check(List.of(platform, Examples.of("minimal/notes.project.yml")))) - .isEmpty(); - } - - @Test - void noRuleAcrossDocumentsRunsUntilEveryFileHolds(@TempDir Path directory) { - Path broken = Examples.write(directory, "broken.project.yml", "kind: Project\n"); - - assertThat(Pipeline.check(List.of(WORKED.get(0), WORKED.get(2), broken))) - .extracting(Diagnostic::document) - .containsOnly("broken.project.yml") - .isNotEmpty(); - } - - @Test - void aFileThatIsNeitherDocumentIsNotRead(@TempDir Path directory) { - Path environment = Examples.write(directory, "notes.env", "NODE_ENV=production\n"); - - assertThat(Pipeline.check(List.of(environment))).isEmpty(); - } - - @Test - void aRouteWhoseOwnAudienceNoTierCarriesIsRefusedAtTheRoute(@TempDir Path directory) { - Path platform = Examples.write( - directory, - "platform.intent.yml", - Examples.read("platform/platform.intent.yml") - .replace("audiences: [anonymous, authenticated]", "audiences: [lan]") - .replaceFirst("\n\\s+forwardAuth: [^\n]*", "") - .replace("secretsEncryption: false", "secretsEncryption: true") - .replace("traefik: edge/traefik-public", "traefik: knowledge/knowledge") - .replace("traefik: edge/traefik-lan", "traefik: knowledge/knowledge") - .replace( - "machinery: [edge/traefik-public, edge/traefik-lan, delivery/flagger, delivery/release-gate]", - "machinery: [knowledge/knowledge]") - .replace("gate: delivery/release-gate", "gate: knowledge/knowledge") - .replace("reporter: delivery/reporter", "reporter: knowledge/knowledge") - .replace("secretStore: secrets/vault", "secretStore: knowledge/knowledge") - .replaceFirst(TELEMETRY, "\n") - .replaceFirst(API_ACCESS, "\n")); - Path knowledge = Examples.write( - directory, - "knowledge.project.yml", - Examples.read("knowledge/knowledge.project.yml").replace("audience: authenticated", "audience: lan")); - - // knowledge stands in for the machinery here, and a changelog on the machinery is its own refusal. - assertThat(Pipeline.check(List.of(platform, knowledge)).stream() - .filter(refusal -> refusal.code().equals("E_NO_TIER_FOR_AUDIENCE"))) - .extracting(Diagnostic::code, Diagnostic::path) - .containsExactly( - tuple("E_NO_TIER_FOR_AUDIENCE", "/applications/0/exposure/0/routes/0"), - tuple("E_NO_TIER_FOR_AUDIENCE", "/applications/0/exposure/0/routes/1"), - tuple("E_NO_TIER_FOR_AUDIENCE", "/applications/0/exposure/0/routes/2"), - tuple("E_NO_TIER_FOR_AUDIENCE", "/applications/0/exposure/0/routes/3")); - } - - @Test - void aHolderOfApiAccessIsRefusedWhereNoProjectFileDeclaresIt(@TempDir Path directory) { - Path platform = Examples.write( - directory, - "platform.intent.yml", - Examples.read("platform/platform.intent.yml") - .replace( - "holders: [delivery/flagger, delivery/release-gate, delivery/collector, delivery/reporter,", - "holders: [delivery/flagger, delivery/gone,")); - List admitted = new java.util.ArrayList<>(WORKED.subList(1, WORKED.size())); - admitted.add(0, platform); - - // `gone` is declared nowhere, and the Release Gate, the Collector and the Reporter declare - // access the platform no longer admits. - assertThat(Pipeline.check(admitted)) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path) - .containsExactlyInAnyOrder( - tuple("E_UNKNOWN_API_HOLDER", "platform.intent.yml", "/apiAccess"), - tuple("E_PROCESS_RBAC_GRANT", "delivery.project.yml", "/applications/1/processes/0/api"), - tuple("E_PROCESS_RBAC_GRANT", "delivery.project.yml", "/applications/2/processes/0/api"), - tuple("E_PROCESS_RBAC_GRANT", "delivery.project.yml", "/applications/3/processes/0/api")); - } - - @Test - void anIdTwoApplicationsCarryAdmitsNeitherToHoldApiAccess(@TempDir Path directory) { - Path impostor = Examples.write( - directory, - "impostor.project.yml", - Examples.read("refusals/process-rbac-grant/refusals.project.yml") - .replace("id: edge-proxy", "id: flagger")); - List doubled = new java.util.ArrayList<>(WORKED); - doubled.add(impostor); - - // The platform admits `flagger` by id, and nothing says which of the two it meant. - assertThat(Pipeline.check(doubled).stream() - .filter(refusal -> refusal.code().equals("E_PROCESS_RBAC_GRANT"))) - .extracting(Diagnostic::document, Diagnostic::path) - .containsExactlyInAnyOrder( - tuple("delivery.project.yml", "/applications/0/processes/0/api"), - tuple("impostor.project.yml", "/applications/0/processes/0/api")); - } - - @Test - void theFoundationsNamesAreRefusedWhereNoProjectFileDeclaresThem() { - assertThat(Pipeline.check(WORKED.stream() - .filter(path -> !path.toString().contains("/edge/") - && !path.toString().contains("/observability/")) - .toList())) - .extracting(Diagnostic::code, Diagnostic::path) - .contains( - tuple("E_UNKNOWN_TIER_PROXY", "/tiers/0"), - tuple("E_UNKNOWN_TIER_PROXY", "/tiers/1"), - tuple("E_UNKNOWN_MACHINERY", "/delivery"), - tuple("E_UNKNOWN_TELEMETRY_COLLECTOR", "/telemetry"), - tuple("E_UNKNOWN_METRICS_STACK", "/telemetry")); - } - - @Test - void anAttachmentToAVpnThePlatformDoesNotRunIsRefusedAndOneItRunsIsNot(@TempDir Path directory) { - String fixture = "refusals/no-vpn-policy/"; - String platform = Examples.read(fixture + "platform.intent.yml"); - Path project = Examples.of(fixture + "refusals.project.yml"); - - assertThat(Pipeline.check(List.of(Examples.of(fixture + "platform.intent.yml"), project))) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path) - .containsExactly(tuple("E_NO_VPN_POLICY", "refusals.project.yml", "/applications/0/processes/0/vpn")); - assertThat(Pipeline.check(List.of( - Examples.write( - directory, - "platform.intent.yml", - platform - + "vpn:\n image: gluetun\n credential: secret/data/platform/vpn\n" - + " memory: 128Mi\n cpu: 50m\n"), - project))) - .isEmpty(); - } - - @Test - void aVpnSettingTheRenderDerivesIsASchemaRefusal(@TempDir Path directory) { - String platform = Examples.read("refusals/no-vpn-policy/platform.intent.yml") - + "vpn:\n image: gluetun\n credential: secret/data/platform/vpn\n" - + " memory: 128Mi\n cpu: 50m\n settings:\n VPN_PORT_FORWARDING: \"on\"\n"; - - assertThat(Pipeline.check(List.of(Examples.write(directory, "platform.intent.yml", platform)))) - .extracting(Diagnostic::code, Diagnostic::path) - .containsExactly(tuple("schema", "/vpn")); - } - - /** The library-not-granted fixture, its Platform document's grant written as {@code grant}. */ - private static List granting(Path directory, String grant, String mount) { - String fixture = "refusals/library-not-granted/"; - return List.of( - Examples.write( - directory, - "platform.intent.yml", - Examples.read(fixture + "platform.intent.yml").replace("refusals: read", grant)), - Examples.write( - directory, - "refusals.project.yml", - Examples.read(fixture + "refusals.project.yml").replace("access: write", mount))); - } - - @Test - void aLibraryIsMountedOnlyForWhatItGrantsTheProject(@TempDir Path directory) { - String at = "/applications/0/processes/0/libraries/0"; - - assertThat(Pipeline.check(granting(directory, "refusals: write", "access: write"))) - .isEmpty(); - assertThat(Pipeline.check(granting(directory, "refusals: read", "access: read"))) - .isEmpty(); - assertThat(Pipeline.check(granting(directory, "jellyfin: write", "access: read"))) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path) - .containsExactly(tuple("E_LIBRARY_NOT_GRANTED", "refusals.project.yml", at)); - } - - @Test - void aLibraryOutsideAnAbsoluteDirectoryOrAMountClimbingOutOfOneIsASchemaRefusal(@TempDir Path directory) { - String platform = Examples.read("refusals/library-not-granted/platform.intent.yml"); - String project = Examples.read("refusals/library-not-granted/refusals.project.yml"); - - assertThat(Pipeline.check(List.of(Examples.write( - directory, "platform.intent.yml", platform.replace("path: /srv/media", "path: /srv/../etc"))))) - .extracting(Diagnostic::code, Diagnostic::path) - .containsExactly(tuple("schema", "/libraries/media")); - assertThat(Pipeline.check(List.of( - Examples.write(directory, "platform.intent.yml", platform.replace("gid: 3001", "gid: 0"))))) - .extracting(Diagnostic::code, Diagnostic::path) - .containsExactly(tuple("schema", "/libraries/media")); - assertThat(Pipeline.check(List.of(Examples.write( - directory, "refusals.project.yml", project.replace("subPath: Photos", "subPath: ../Photos"))))) - .extracting(Diagnostic::code, Diagnostic::path) - .containsExactly(tuple("schema", "/applications/0/processes/0/libraries/0")); - } - - /** - * Projects whose units wait on each other are refused, each at its first Application that follows - * a unit on the cycle, rather than rendered as a deadlock: notes declares the public tier's proxy, - * so every Project routed on that tier follows it, and notes reaches the metrics stack's collector - * (spec/v1/20-resolved-deployment.md#the-reconcile-unit). - */ - @Test - void projectsWhoseUnitsWaitOnEachOtherAreRefusedAtTheApplicationThatClosesTheCycle(@TempDir Path directory) { - Path platform = Examples.write( - directory, - "platform.intent.yml", - Examples.read("platform/platform.intent.yml") - .replaceAll("\\n *address: edge-frankfurt[^\\n]*", "") - .replace("traefik: edge/traefik-public", "traefik: notes/notes")); - Path notes = Examples.write( - directory, - "notes.project.yml", - Examples.read("minimal/notes.project.yml").replace(ResolutionTest.REACHES, ResolutionTest.REACHED)); - List files = WORKED.stream() - .map(file -> file.equals(WORKED.get(0)) - ? platform - : file.endsWith("minimal/notes.project.yml") ? notes : file) - .toList(); - - assertThat(Pipeline.check(files)) - .filteredOn(diagnostic -> diagnostic.code().equals("E_RECONCILE_CYCLE")) - .extracting(Diagnostic::document, Diagnostic::path) - .containsExactlyInAnyOrder( - tuple("observability.project.yml", "/applications/5"), - tuple("notes.project.yml", "/applications/0")); - // Optional, the edge orders nothing, and no unit waits on itself. - Path optional = Examples.write( - directory, - "notes.project.yml", - Examples.read("minimal/notes.project.yml") - .replace( - ResolutionTest.REACHES, - ResolutionTest.REACHED.replace("surface: otlp }", "surface: otlp, required: false }"))); - assertThat(Pipeline.check(files.stream() - .map(file -> file.endsWith("notes.project.yml") ? optional : file) - .toList())) - .extracting(Diagnostic::code) - .doesNotContain("E_RECONCILE_CYCLE"); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/L4ChecksTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/L4ChecksTest.java deleted file mode 100644 index c7818af1b..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/L4ChecksTest.java +++ /dev/null @@ -1,219 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.L4Exposure; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.L4Protocol; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Listener; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.NodeAddress; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.PoolAddress; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Process; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Tier; -import java.util.LinkedHashMap; -import java.util.Map; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.InternalEObject; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; -import org.junit.jupiter.api.Test; - -/** What a Platform document's L4 Addresses and tiers and the project files beside it break together. */ -class L4ChecksTest { - - private static final ProjectIntentFactory MODEL = ProjectIntentFactory.eINSTANCE; - - /** A Platform document read from `platform.intent.yml`, declaring a node's address and a pool. */ - private static Platform platform(String range) { - Platform platform = MODEL.createPlatform(); - NodeAddress node = MODEL.createNodeAddress(); - node.setNode("edge-1"); - NodeAddress again = MODEL.createNodeAddress(); - again.setNode("edge-1"); - PoolAddress pool = MODEL.createPoolAddress(); - pool.setSite("enschede"); - pool.setRange(range); - platform.getL4Addresses().put("edge-node", node); - platform.getL4Addresses().put("edge-node-2", again); - platform.getL4Addresses().put("lan-mqtt", pool); - new XMIResourceImpl(URI.createURI("platform.intent.yml")).getContents().add(platform); - return platform; - } - - private static Project project(String name, String... processes) { - Project project = MODEL.createProject(); - project.setProject(name); - Application application = MODEL.createApplication(); - application.setId(name + "-app"); - for (String named : processes) { - Process process = MODEL.createProcess(); - process.setName(named); - application.getProcesses().add(process); - } - project.getApplications().add(application); - return project; - } - - private static void expose(Project project, String process, String address, L4Protocol protocol, int port) { - Application application = project.getApplications().get(0); - L4Exposure exposure = MODEL.createL4Exposure(); - exposure.setProcess(application.getProcesses().stream() - .filter(p -> p.getName().equals(process)) - .findFirst() - .orElseThrow()); - exposure.setAddress(address); - exposure.setProtocol(protocol); - exposure.setPort(port); - application.getL4Exposure().add(exposure); - } - - private static Tier tier(Platform platform, String name, Listener listener, String address, Application proxy) { - Tier tier = MODEL.createTier(); - tier.setName(name); - tier.setListener(listener); - tier.setAddress(address); - tier.setTraefik(proxy); - platform.getTiers().add(tier); - return tier; - } - - private static Map named(Project... projects) { - Map named = new LinkedHashMap<>(); - for (Project project : projects) { - named.put(project, project.getProject() + ".project.yml"); - } - return named; - } - - @Test - void aTierThatNamesAnAddressNeedsAProxyProcessThatAnswersEveryPortItsListenerDerives() { - Platform platform = platform("192.168.0.97/32"); - Project edge = project("edge", "proxy"); - Process proxy = edge.getApplications().get(0).getProcesses().get(0); - proxy.getProvides().put("web", 8000); - Application app = edge.getApplications().get(0); - tier(platform, "public", Listener.TLS, "edge-node", app); - tier(platform, "lan", Listener.PLAIN, "lan-mqtt", app); - tier(platform, "internal", Listener.TLS, null, app); - - assertThat(L4Checks.check(platform, named(edge))) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path, Diagnostic::message) - .containsExactly(tuple( - L4Checks.TIER_SURFACE_MISSING, - "platform.intent.yml", - "/tiers/0", - "no Process of edge-app provides every surface the public tier's listener reaches")); - proxy.getProvides().put("websecure", 8443); - assertThat(L4Checks.check(platform, named(edge))).isEmpty(); - } - - @Test - void aProxyNoProjectFileDeclaresIsNotThisChecksToRefuse() { - Platform platform = platform("192.168.0.97/32"); - Application unlinked = MODEL.createApplication(); - ((InternalEObject) unlinked).eSetProxyURI(URI.createURI("edge.project.yml#//@applications.0")); - tier(platform, "public", Listener.TLS, "edge-node", unlinked); - - assertThat(L4Checks.check(platform, named())).isEmpty(); - } - - @Test - void aNodesPortTwoOwnersDialIsRefusedAtEachAndATiersPortIsTheTiersOwn() { - Platform platform = platform("192.168.0.97/32"); - Project edge = project("edge", "proxy"); - edge.getApplications().get(0).getProcesses().get(0).getProvides().put("web", 8000); - tier( - platform, - "lan", - Listener.PLAIN, - "edge-node", - edge.getApplications().get(0)); - Project mail = project("mail", "smtp", "other"); - expose(mail, "smtp", "edge-node", L4Protocol.TCP, 80); - expose(mail, "smtp", "edge-node", L4Protocol.TCP, 25); - expose(mail, "smtp", "edge-node", L4Protocol.TCP, 25); - expose(mail, "smtp", "edge-node", L4Protocol.UDP, 53); - expose(mail, "other", "edge-node", L4Protocol.TCP, 53); - expose(mail, "smtp", "lan-mqtt", L4Protocol.TCP, 80); - - assertThat(L4Checks.check(platform, named(edge, mail))) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path, Diagnostic::message) - .containsExactly( - tuple( - L4Checks.NODE_PORT_TAKEN, - "mail.project.yml", - "/applications/0/l4Exposure/0", - "smtp dials tcp 80 on a node another owner dials it on too"), - tuple( - L4Checks.NODE_PORT_TAKEN, - "platform.intent.yml", - "/tiers/0/address", - "proxy dials tcp 80 on a node another owner dials it on too")); - } - - @Test - void twoProjectsProcessesOfOneNameAreTwoOwners() { - Platform platform = platform("192.168.0.97/32"); - Project data = project("data", "dns"); - expose(data, "dns", "edge-node", L4Protocol.UDP, 53); - Project utility = project("utility", "dns"); - expose(utility, "dns", "edge-node", L4Protocol.UDP, 53); - - assertThat(L4Checks.check(platform, named(data, utility))) - .extracting(Diagnostic::document) - .containsExactly("data.project.yml", "utility.project.yml"); - } - - @Test - void oneProcessOnTwoOfANodesAddressesDialsItsPortTwice() { - Platform platform = platform("192.168.0.97/32"); - Project mail = project("mail", "smtp"); - expose(mail, "smtp", "edge-node", L4Protocol.TCP, 25); - expose(mail, "smtp", "edge-node-2", L4Protocol.TCP, 25); - - assertThat(L4Checks.check(platform, named(mail))) - .extracting(Diagnostic::path) - .containsExactly("/applications/0/l4Exposure/0", "/applications/0/l4Exposure/1"); - } - - @Test - void aPoolHoldsAsManyProcessesAsItsRangeHoldsAddresses() { - Project data = project("data", "mqtt", "other"); - expose(data, "mqtt", "lan-mqtt", L4Protocol.TCP, 1883); - expose(data, "mqtt", "lan-mqtt", L4Protocol.TCP, 8883); - expose(data, "other", "edge-node", L4Protocol.TCP, 1883); - Project mail = project("mail", "mqtt"); - expose(mail, "mqtt", "lan-mqtt", L4Protocol.TCP, 1883); - - assertThat(L4Checks.check(platform("192.168.0.97/31"), named(data, mail))) - .isEmpty(); - assertThat(L4Checks.check(platform("192.168.0.97"), named(data, mail))) - .as("a range naming no prefix length holds no count to exceed") - .isEmpty(); - assertThat(L4Checks.check(platform("192.168.0.97/32"), named(data, mail))) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path, Diagnostic::message) - .containsExactly(tuple( - L4Checks.L4_ADDRESS_EXHAUSTED, - "platform.intent.yml", - "/l4Addresses/lan-mqtt", - "2 Processes are exposed on lan-mqtt, whose range holds 1 addresses")); - } - - @Test - void aTiersDerivedPortTakesAnAddressOfItsPool() { - Platform platform = platform("192.168.0.97/32"); - Project edge = project("edge", "proxy"); - edge.getApplications().get(0).getProcesses().get(0).getProvides().put("web", 8000); - tier(platform, "lan", Listener.PLAIN, "lan-mqtt", edge.getApplications().get(0)); - Project data = project("data", "mqtt"); - expose(data, "mqtt", "lan-mqtt", L4Protocol.TCP, 1883); - - assertThat(L4Checks.check(platform, named(edge, data))) - .extracting(Diagnostic::code) - .containsExactly(L4Checks.L4_ADDRESS_EXHAUSTED); - assertThat(L4Checks.check(platform, named(edge))).isEmpty(); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/LoweringBenchmarkTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/LoweringBenchmarkTest.java deleted file mode 100644 index b6dad3bbb..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/LoweringBenchmarkTest.java +++ /dev/null @@ -1,255 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.resolve.Lowering; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.function.Function; -import java.util.regex.Pattern; -import org.eclipse.emf.common.util.TreeIterator; -import org.eclipse.emf.ecore.EObject; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledIfSystemProperty; - -/** - * The QVT-Operational lowering and its ATL port, head to head on the same inputs - * (docs/benchmarks.md#qvto-against-atl): warm, with each transformation loaded once and reused, and - * loaded for every Project; the cost of loading alone; cold, in a fresh JVM; - * and the size of each source. {@link LoweringEquivalenceTest} holds the two outputs equal first. - * Opt-in: {@code -Pbenchmark}. - */ -@EnabledIfSystemProperty(named = Benchmark.PROPERTY, matches = "true") -class LoweringBenchmarkTest { - - private static final List SIZES = List.of(1, 4, 8, 12, 16, 20, 24); - - /** How many times each lowering runs over every Project before a series is measured. */ - private static final int WARM_ROUNDS = 40; - - @Test - void perProjectWarm() { - QvtoLowering qvto = QvtoLowering.prepared(); - AtlLowering atl = AtlLowering.prepared(); - Map lowered = BenchmarkInputs.lowered(); - warm(List.copyOf(lowered.values()), qvto, atl); - List> rows = new ArrayList<>(); - double qvtoTotal = 0; - double atlTotal = 0; - for (Map.Entry entry : lowered.entrySet()) { - Project project = entry.getValue(); - Benchmark.Series byQvto = Benchmark.measure(() -> qvto.lower(project)); - Benchmark.Series byAtl = Benchmark.measure(() -> atl.lower(project)); - qvtoTotal += byQvto.median(); - atlTotal += byAtl.median(); - rows.add(List.of( - entry.getKey(), - String.valueOf(objects(project)), - byQvto.cell(), - byAtl.cell(), - ratio(byAtl.median(), byQvto.median()))); - } - rows.add(List.of( - "**sum of medians**", "", Benchmark.ms(qvtoTotal), Benchmark.ms(atlTotal), ratio(atlTotal, qvtoTotal))); - Benchmark.report( - "lowering-per-project.md", - Benchmark.environment() - + "\n" - + Benchmark.table(List.of("Project", "objects", "QVTo ms", "ATL ms", "ATL / QVTo"), rows)); - assertThat(rows).hasSizeGreaterThan(30); - } - - @Test - void theEstateAtGrowingSizes() { - QvtoLowering qvto = QvtoLowering.prepared(); - AtlLowering atl = AtlLowering.prepared(); - List estate = BenchmarkInputs.projects(BenchmarkInputs.authored( - BenchmarkInputs.files(BenchmarkInputs.estate(BenchmarkInputs.ESTATE_ORDER.size())))); - warm(estate, qvto, atl); - // Every loaded-once series first, so none runs on the garbage a load per call leaves behind. - List> rows = new ArrayList<>(); - for (int size : SIZES) { - List projects = estate.subList(0, size); - Benchmark.Series byQvto = Benchmark.measure(() -> all(projects, project -> qvto.lower(project))); - Benchmark.Series byAtl = Benchmark.measure(() -> all(projects, project -> atl.lower(project))); - rows.add(new ArrayList<>(List.of( - String.valueOf(size), - String.valueOf(projects.stream() - .mapToInt(LoweringBenchmarkTest::objects) - .sum()), - byQvto.cell(), - byAtl.cell(), - ratio(byAtl.median(), byQvto.median())))); - } - for (int i = 0; i < SIZES.size(); i++) { - List projects = estate.subList(0, SIZES.get(i)); - // Each side loaded for every Project, whatever Lowering.lower does, so the pair stays a - // like-for-like comparison of loading and running together. - Benchmark.Series loaded = Benchmark.measure( - () -> all(projects, project -> QvtoLowering.prepared().lower(project))); - Benchmark.Series compiled = Benchmark.measure(() -> all(projects, project -> AtlLowering.once(project))); - String loadedCell = loaded.cell(); - String compiledCell = compiled.cell(); - String compiledRatio = ratio(compiled.median(), loaded.median()); - rows.get(i).addAll(List.of(loadedCell, compiledCell, compiledRatio)); - } - Benchmark.report( - "lowering-estate-scaling.md", - Benchmark.environment() - + "\n" - + Benchmark.table( - List.of( - "Projects", - "objects", - "QVTo ms (loaded once)", - "ATL ms (compiled once)", - "ATL / QVTo", - "QVTo ms (loaded per Project)", - "ATL ms (compiled per Project)", - "ATL / QVTo"), - rows)); - assertThat(rows).hasSize(SIZES.size()); - } - - @Test - void loadingAloneAndCold() { - Benchmark.Series loadQvto = Benchmark.measure(QvtoLowering::prepared); - Benchmark.Series loadAtl = Benchmark.measure(AtlLowering::prepared); - List> rows = new ArrayList<>(); - rows.add(List.of( - "load, warm JVM (parse, compile, load the transformation)", - loadQvto.cell(), - loadAtl.cell(), - ratio(loadAtl.median(), loadQvto.median()))); - List> coldQvto = ColdRun.fork("lower", "qvto"); - List> coldAtl = ColdRun.fork("lower", "atl"); - for (String timed : List.of("load", "first", "all")) { - Benchmark.Series byQvto = series(coldQvto, timed); - Benchmark.Series byAtl = series(coldAtl, timed); - rows.add(List.of( - switch (timed) { - case "load" -> "cold JVM: load"; - case "first" -> "cold JVM: load and lower the first estate Project"; - default -> "cold JVM: load and lower all 24 estate Projects"; - }, - byQvto.cell(), - byAtl.cell(), - ratio(byAtl.median(), byQvto.median()))); - } - Benchmark.report( - "lowering-load-and-cold.md", - Benchmark.environment() - + "\n" - + Benchmark.table(List.of("what is timed", "QVTo ms", "ATL ms", "ATL / QVTo"), rows)); - assertThat(rows).hasSize(4); - } - - @Test - void thePipelineCold() { - List> rows = new ArrayList<>(); - for (String example : List.of("minimal", "estate/hindsight")) { - List> samples = ColdRun.fork("pipeline", example); - List row = new ArrayList<>(List.of(example)); - for (String stage : List.of("read", "check", "lower", "resolve", "render")) { - row.add(series(samples, stage).cell()); - } - rows.add(row); - } - Benchmark.report( - "stages-cold.md", - Benchmark.environment() - + "\n" - + Benchmark.table( - List.of("example", "read ms", "check ms", "lower ms", "resolve ms", "render ms"), - rows)); - assertThat(rows).hasSize(2); - } - - @Test - void theSources() throws IOException { - String qvto = source(Lowering.class.getResourceAsStream("/lower.qvto")); - String atl = source(AtlLowering.class.getResourceAsStream("/benchmark/lower.atl")); - List> rows = List.of( - List.of( - "lines", - String.valueOf(qvto.lines().count()), - String.valueOf(atl.lines().count())), - List.of( - "lines of code (not blank, not a comment)", - String.valueOf(code(qvto)), - String.valueOf(code(atl))), - List.of( - "mappings / rules", - String.valueOf(count(qvto, "^mapping ")), - count(atl, "^rule ") + " matched, " + count(atl, "^lazy rule ") + " lazy"), - List.of( - "of which only dispatch to a subtype (`disjuncts`)", - String.valueOf(count(qvto, "\\bdisjuncts\\b")), - "–"), - List.of( - "queries / helpers", - String.valueOf(count(qvto, "^query ")), - String.valueOf(count(atl, "^helper ")))); - Benchmark.report("lowering-sources.md", Benchmark.table(List.of("", "lower.qvto", "lower.atl"), rows)); - assertThat(code(atl)).isPositive(); - } - - /** - * Both lowerings run over {@code projects} {@link #WARM_ROUNDS} times before anything is measured: a - * lowering takes well under a millisecond, and the JIT settles only after some hundreds of them. - */ - private static void warm(List projects, QvtoLowering qvto, AtlLowering atl) { - for (int i = 0; i < WARM_ROUNDS; i++) { - all(projects, project -> qvto.lower(project)); - all(projects, project -> atl.lower(project)); - } - } - - private static List all(List projects, Function lowering) { - return projects.stream().map(lowering).toList(); - } - - private static Benchmark.Series series(List> samples, String timed) { - return new Benchmark.Series( - samples.stream().mapToLong(sample -> sample.get(timed)).toArray()); - } - - private static String ratio(double numerator, double denominator) { - return String.format(Locale.ROOT, "%.2f×", numerator / denominator); - } - - /** How many objects {@code project} holds, itself among them. */ - static int objects(EObject project) { - int count = 1; - for (TreeIterator contents = project.eAllContents(); contents.hasNext(); contents.next()) { - count++; - } - return count; - } - - private static String source(InputStream in) throws IOException { - try (in) { - return new String(in.readAllBytes(), StandardCharsets.UTF_8); - } - } - - private static long code(String source) { - return source.lines() - .map(String::strip) - .filter(line -> !line.isEmpty() && !line.startsWith("--")) - .count(); - } - - private static long count(String source, String regex) { - return Pattern.compile(regex, Pattern.MULTILINE) - .matcher(source) - .results() - .count(); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/LoweringEquivalenceTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/LoweringEquivalenceTest.java deleted file mode 100644 index 0a594e8a7..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/LoweringEquivalenceTest.java +++ /dev/null @@ -1,84 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EffectiveProject; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.resolve.Lowering; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.TreeMap; -import java.util.regex.Pattern; -import org.eclipse.emf.common.util.TreeIterator; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledIfSystemProperty; - -/** - * The ATL port of the lowering writes what the QVT-Operational lowering writes, on every Project the - * worked examples lower: EMF Compare finds no difference between the two Effective Intents - * (docs/benchmarks.md#equivalence). Opt-in with the benchmark, {@code -Demf.benchmark=true}: the port - * ships in no bundle, so the default build does not hold it. - */ -@EnabledIfSystemProperty(named = Benchmark.PROPERTY, matches = "true") -class LoweringEquivalenceTest { - - @Test - void theAtlPortLowersEveryExampleAsTheQvtoLoweringDoes() throws IOException { - Map projects = BenchmarkInputs.lowered(); - AtlLowering atl = AtlLowering.prepared(); - QvtoLowering reused = QvtoLowering.prepared(); - List differences = new ArrayList<>(); - for (Map.Entry entry : projects.entrySet()) { - Project project = entry.getValue(); - Project before = EcoreUtil.copy(project); - EffectiveProject qvto = Lowering.lower(project); - EffectiveProject ported = atl.lower(project); - differences.addAll(ModelDiff.differences(entry.getKey(), List.of(qvto), List.of(ported))); - // The benchmark's QVTo lowering, loaded once, is the shipped one. - differences.addAll( - ModelDiff.differences(entry.getKey() + " (reused)", List.of(qvto), List.of(reused.lower(project)))); - // Neither lowering writes to its source. - differences.addAll(ModelDiff.differences(entry.getKey() + " (source)", List.of(before), List.of(project))); - } - // Every Project file a resolved example reads: the twelve worked ones and the estate's 24. - assertThat(projects).hasSize(36); - assertThat(differences).isEmpty(); - Benchmark.report("equivalence.md", exercised(projects.values())); - } - - /** - * Which of the port's rules the examples exercise: a rule is exercised where the inputs hold an - * object of the class it matches, and equivalence says nothing of a rule they never reach. - */ - private static String exercised(Collection projects) throws IOException { - Map held = new TreeMap<>(); - for (Project project : projects) { - held.merge(project.eClass().getName(), 1, Integer::sum); - for (TreeIterator contents = project.eAllContents(); contents.hasNext(); ) { - held.merge(contents.next().eClass().getName(), 1, Integer::sum); - } - } - String atl; - try (InputStream source = AtlLowering.class.getResourceAsStream("/benchmark/lower.atl")) { - atl = new String(source.readAllBytes(), StandardCharsets.UTF_8); - } - List rules = Pattern.compile("^(?:lazy )?rule (\\w+) \\{\\R\\tfrom s : PI!(\\w+)", Pattern.MULTILINE) - .matcher(atl) - .results() - .map(rule -> rule.group(1) + " (" + rule.group(2) + "): " + held.getOrDefault(rule.group(2), 0)) - .toList(); - List unreached = - rules.stream().filter(rule -> rule.endsWith(": 0")).toList(); - return projects.size() + " Projects lowered by both, " - + held.values().stream().mapToInt(Integer::intValue).sum() + " objects; " - + (rules.size() - unreached.size()) + " of " + rules.size() + " rules exercised.\n\n" - + "Objects each rule matches, over every input:\n\n- " + String.join("\n- ", rules) + "\n"; - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelDiff.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelDiff.java deleted file mode 100644 index 32ea14d55..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelDiff.java +++ /dev/null @@ -1,566 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.eclipse.emf.common.util.TreeIterator; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.compare.AttributeChange; -import org.eclipse.emf.compare.Comparison; -import org.eclipse.emf.compare.Diff; -import org.eclipse.emf.compare.EMFCompare; -import org.eclipse.emf.compare.Match; -import org.eclipse.emf.compare.ReferenceChange; -import org.eclipse.emf.compare.ResourceAttachmentChange; -import org.eclipse.emf.compare.match.DefaultComparisonFactory; -import org.eclipse.emf.compare.match.DefaultEqualityHelperFactory; -import org.eclipse.emf.compare.match.DefaultMatchEngine; -import org.eclipse.emf.compare.match.IMatchEngine; -import org.eclipse.emf.compare.match.eobject.IdentifierEObjectMatcher; -import org.eclipse.emf.compare.match.impl.MatchEngineFactoryRegistryImpl; -import org.eclipse.emf.compare.scope.DefaultComparisonScope; -import org.eclipse.emf.compare.scope.IComparisonScope; -import org.eclipse.emf.compare.utils.UseIdentifiers; -import org.eclipse.emf.ecore.EAttribute; -import org.eclipse.emf.ecore.EEnum; -import org.eclipse.emf.ecore.EEnumLiteral; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.InternalEObject; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.impl.ResourceImpl; -import org.eclipse.emf.ecore.util.EcoreUtil; - -/** - * The tests' one comparison of two models (docs/adr/emf/0152-emf-compare-decides-and-explains-every-model-comparison.md): - * EMF Compare decides whether they differ and says where, and two models are equal only when it - * reports no difference. Objects are paired by their natural key, a path from the root naming each - * list item by a key unique among its siblings, and by similarity only where no key exists. Every - * difference is one line in {@link dev.jorisjonkers.deploykit.emf.cli.Comparison}'s format: {@code - * notes.resolveddeployment#1 .applications[id="notes"].processes[name="api"].memory: expected - * "256Mi", got "512Mi"}. - * - *

A list item's key is, in this order, the first of - * {@link #IDENTITIES} unique among its siblings; else one of them together with a qualifier that - * makes the pair unique, another of them or an enumeration-typed attribute, in declaration order ({@code [input="cluster-state", - * name="production"]}); else a single-valued reference to an object that is itself keyed ({@code - * [process=.applications[id="notes"].processes[name="api"]]}). A root is keyed the same way among - * the roots of its resource, and by its position among them when it has none. Two objects pair by - * key only when both sides key them alike; the rest, and every item with no key, are paired by - * similarity, and a line about an item with no key writes it by its index and says it was {@link - * #SIMILARITY paired by similarity}. - */ -final class ModelDiff { - - /** What a line about an object with no natural key ends with. */ - static final String SIMILARITY = " (no natural key; paired by similarity)"; - - /** The attributes a list item is named by, in the order they are tried. */ - static final List IDENTITIES = List.of("name", "id", "path", "alias", "key", "project", "from"); - - /** How many references deep a key may follow before it gives up. */ - private static final int DEPTH = 3; - - private static final ObjectMapper JSON = new ObjectMapper(); - - private final String name; - /** The keys EMF Compare pairs objects by: each object's own, where the other side holds the same key. */ - private final Map keys = new IdentityHashMap<>(); - - /** The objects that have a natural key of their own, whether or not the other side shares it. */ - private final Set named = Collections.newSetFromMap(new IdentityHashMap<>()); - - private final Map identities = new IdentityHashMap<>(); - private final Set unnamed = Collections.newSetFromMap(new IdentityHashMap<>()); - private Comparison comparison; - - private ModelDiff(String name) { - this.name = name; - } - - /** - * Every difference between the models whose roots are {@code expected} and {@code actual}, - * reported under the file {@code name}; none when they are equal. Roots that are not exactly the - * contents of one resource are compared as copies, so neither model is moved. - */ - static List differences(String name, List expected, List actual) { - return differences(name, resource(expected), resource(actual)); - } - - /** Every difference between the two resources' models, reported under the file {@code name}. */ - static List differences(String name, Resource expected, Resource actual) { - ModelDiff diff = new ModelDiff(name); - diff.key(diff.key(expected), diff.key(actual)); - diff.comparison = compare(expected, actual, diff.keys); - return diff.report(); - } - - private static Resource resource(List roots) { - Resource holder = roots.isEmpty() ? null : roots.get(0).eResource(); - if (holder != null && holder.getContents().equals(roots)) { - return holder; - } - Resource copy = new ResourceImpl(URI.createURI("model")); - copy.getContents().addAll(EcoreUtil.copyAll(roots)); - return copy; - } - - /** EMF Compare's two-way comparison: {@code actual} is the left side, {@code expected} the right. */ - private static Comparison compare(Resource expected, Resource actual, Map keys) { - IMatchEngine engine = new DefaultMatchEngine( - new IdentifierEObjectMatcher( - DefaultMatchEngine.createDefaultEObjectMatcher(UseIdentifiers.NEVER), keys::get), - new DefaultComparisonFactory(new DefaultEqualityHelperFactory())); - IMatchEngine.Factory.Registry registry = MatchEngineFactoryRegistryImpl.createStandaloneInstance(); - registry.add(new IMatchEngine.Factory() { - @Override - public IMatchEngine getMatchEngine() { - return engine; - } - - @Override - public int getRanking() { - return Integer.MAX_VALUE; - } - - @Override - public void setRanking(int ranking) { - throw new UnsupportedOperationException("the one engine ranks first"); - } - - @Override - public boolean isMatchEngineFactoryFor(IComparisonScope scope) { - return true; - } - }); - return EMFCompare.builder() - .setMatchEngineFactoryRegistry(registry) - .build() - .compare(new DefaultComparisonScope(actual, expected, null)); - } - - // -------------------------------------------------------------------------------------- keys - - /** Every object of {@code resource} by its natural key; a key two objects of it share keys neither. */ - private Map key(Resource resource) { - Map seen = new HashMap<>(); - Set shared = new HashSet<>(); - for (TreeIterator objects = resource.getAllContents(); objects.hasNext(); ) { - EObject object = objects.next(); - String path = path(object, 0, false); - if (path != null) { - String key = object.eClass().getName() + path; - if (seen.put(key, object) != null) { - shared.add(key); - } - } - } - Map keyed = new IdentityHashMap<>(); - seen.forEach((key, object) -> { - if (!shared.contains(key)) { - keyed.put(object, key); - } - }); - return keyed; - } - - /** - * Pairs by key only what both sides key alike: an object whose key the other side lacks, because - * it was added, removed or re-keyed, is left to similarity, which pairs it with what it most - * resembles or reports it added or removed. - */ - private void key(Map expected, Map actual) { - Set expectedKeys = new HashSet<>(expected.values()); - Set actualKeys = new HashSet<>(actual.values()); - named.addAll(expected.keySet()); - named.addAll(actual.keySet()); - expected.forEach((object, key) -> { - if (actualKeys.contains(key)) { - keys.put(object, key); - } - }); - actual.forEach((object, key) -> { - if (expectedKeys.contains(key)) { - keys.put(object, key); - } - }); - } - - /** - * {@code object}'s path from its root: in a key ({@code byIndex} false) the root's own key first - * and null when an item on the way has no key, in a report each unkeyed item by its index. - */ - private String path(EObject object, int depth, boolean byIndex) { - StringBuilder path = new StringBuilder(); - EObject at = object; - for (; at.eContainer() != null; at = at.eContainer()) { - EStructuralFeature feature = at.eContainingFeature(); - String step = "." + feature.getName(); - if (feature.isMany()) { - String identity = identity(at, (List) at.eContainer().eGet(feature, false), depth); - if (identity == null && !byIndex) { - return null; - } - step += identity == null ? "[" + index(at) + "]" : identity; - } - path.insert(0, step); - } - if (!byIndex) { - String root = root(at, depth); - if (root == null) { - return null; - } - path.insert(0, root); - } - return path.toString(); - } - - /** A root's key among its resource's roots: its natural key, else its position. */ - private String root(EObject root, int depth) { - if (root.eResource() == null) { - return "/"; - } - List roots = root.eResource().getContents(); - String identity = identity(root, roots, depth); - return "/" + (identity == null ? "#" + (roots.indexOf(root) + 1) : identity); - } - - /** {@code item}'s key among {@code siblings}, by the rules the class comment states; null when it has none. */ - private String identity(EObject item, List siblings, int depth) { - if (depth == 0 && identities.containsKey(item)) { - return identities.get(item); - } - if (depth == 0 && unnamed.contains(item)) { - return null; - } - String identity = computeIdentity(item, siblings, depth); - if (depth == 0) { - if (identity == null) { - unnamed.add(item); - } else { - identities.put(item, identity); - } - } - return identity; - } - - private String computeIdentity(EObject item, List siblings, int depth) { - List candidates = new ArrayList<>(); - for (String key : IDENTITIES) { - if (item.eClass().getEStructuralFeature(key) instanceof EAttribute attribute - && !attribute.isMany() - && item.eIsSet(attribute)) { - candidates.add(attribute); - } - } - for (EAttribute candidate : candidates) { - if (unique(siblings, List.of(candidate.getName()))) { - return "[" + candidate.getName() + "=" + show(item.eGet(candidate)) + "]"; - } - } - for (EAttribute candidate : candidates) { - List partners = new ArrayList<>(candidates); - item.eClass().getEAllAttributes().stream() - .filter(attribute -> attribute.getEType() instanceof EEnum) - .forEach(partners::add); - for (EAttribute other : partners) { - if (other != candidate - && !other.isMany() - && !other.isDerived() - && item.eIsSet(other) - && unique(siblings, List.of(candidate.getName(), other.getName()))) { - List pair = item.eClass().getEAllAttributes().indexOf(other) - < item.eClass().getEAllAttributes().indexOf(candidate) - ? List.of(other, candidate) - : List.of(candidate, other); - return "[" + pair.get(0).getName() + "=" + show(item.eGet(pair.get(0))) + "," - + pair.get(1).getName() + "=" + show(item.eGet(pair.get(1))) + "]"; - } - } - } - if (depth < DEPTH) { - for (EReference reference : item.eClass().getEAllReferences()) { - if (reference.isContainment() - || reference.isContainer() - || reference.isMany() - || reference.isDerived() - || !item.eIsSet(reference) - || !unique(siblings, List.of(reference.getName()))) { - continue; - } - EObject target = (EObject) item.eGet(reference, false); - String path = target.eIsProxy() ? null : path(target, depth + 1, false); - if (path != null) { - // A target in a file of one root is written without the root's position. - String shown = target.eResource() != null - && target.eResource().getContents().size() == 1 - && path.startsWith("/#1") - ? path.substring(3) - : path.substring(1); - return "[" + reference.getName() + "=" + shown + "]"; - } - } - } - return null; - } - - /** - * Whether no two of {@code siblings} that set every feature named in {@code features} share one - * value of them. - */ - private static boolean unique(List siblings, List features) { - Set> seen = new HashSet<>(); - for (Object sibling : siblings) { - EObject other = (EObject) sibling; - List values = new ArrayList<>(); - for (String feature : features) { - EStructuralFeature same = other.eClass().getEStructuralFeature(feature); - if (same == null || same.isMany() || !other.eIsSet(same)) { - break; - } - values.add(other.eGet(same, false)); - } - if (values.size() == features.size() && !seen.add(values)) { - return false; - } - } - return true; - } - - // ------------------------------------------------------------------------------------ report - - /** One line a difference, match by match in the tree's order; a feature set on one side only counts too. */ - private List report() { - List lines = new ArrayList<>(); - List matches = new ArrayList<>(comparison.getMatches()); - for (int i = 0; i < matches.size(); i++) { - Match match = matches.get(i); - matches.addAll(i + 1, match.getSubmatches()); - for (Diff diff : match.getDifferences()) { - String line = line(diff); - if (line != null) { - lines.add(line); - } - } - lines.addAll(setOnOneSide(match)); - } - if (lines.isEmpty() && !comparison.getDifferences().isEmpty()) { - lines.add(name + ": " + comparison.getDifferences().size() - + " differences EMF Compare reports, none of them inside a reported one"); - } - return lines; - } - - private String line(Diff diff) { - Match match = diff.getMatch(); - if (!(diff instanceof ResourceAttachmentChange) && (match.getLeft() == null || match.getRight() == null)) { - // The owner is itself added or removed, and that line says how much it holds. - return null; - } - EObject owner = match.getRight() != null ? match.getRight() : match.getLeft(); - return switch (diff) { - case ResourceAttachmentChange root -> root(root, owner); - case ReferenceChange change -> - change.getReference().isContainment() ? containment(change) : reference(change, owner); - case AttributeChange change -> attribute(change, owner); - default -> - where(owner, "") + ": " + diff.getKind() + " " + diff.eClass().getName() + similarity(owner); - }; - } - - private String root(ResourceAttachmentChange change, EObject root) { - Match match = change.getMatch(); - return switch (change.getKind()) { - case ADD -> where(root, "") + ": extra root (got " + subtree(root) + ")" + similarity(root); - case DELETE -> where(root, "") + ": missing root (expected " + subtree(root) + ")" + similarity(root); - default -> - where(root, "") + ": root moved from index " + index(match.getRight()) + " to " + index(match.getLeft()) - + similarity(root); - }; - } - - private String containment(ReferenceChange change) { - Match valueMatch = comparison.getMatch(change.getValue()); - EObject expected = valueMatch.getRight(); - EObject actual = valueMatch.getLeft(); - return switch (change.getKind()) { - case ADD -> where(actual, "") + ": extra (got " + subtree(actual) + ")" + similarity(actual); - case DELETE -> - where(expected, "") + ": missing (expected " + subtree(expected) + ")" + similarity(expected); - default -> { - Match parent = comparison.getMatch(expected.eContainer()); - boolean moved = parent == null - || parent.getLeft() != actual.eContainer() - || expected.eContainingFeature() != actual.eContainingFeature(); - yield where(expected, "") + ": moved from index " + index(expected) + " to " + index(actual) - + (moved ? " under " + target(actual.eContainer()) : "") + similarity(expected); - } - }; - } - - private String reference(ReferenceChange change, EObject owner) { - EReference reference = change.getReference(); - Match match = change.getMatch(); - String at = where(owner, "." + reference.getName()) + ": "; - if (!reference.isMany()) { - return at + "expected " + target(value(match.getRight(), reference)) + ", got " - + target(value(match.getLeft(), reference)) + similarity(owner); - } - EObject value = change.getValue(); - return at - + switch (change.getKind()) { - case ADD -> "extra " + target(value); - case DELETE -> "missing " + target(value); - default -> { - Match moved = comparison.getMatch(value); - yield target(value) + " moved from index " - + list(match.getRight(), reference).indexOf(moved == null ? value : moved.getRight()) - + " to " + list(match.getLeft(), reference).indexOf(value); - } - } - + similarity(owner); - } - - private String attribute(AttributeChange change, EObject owner) { - EAttribute attribute = change.getAttribute(); - Match match = change.getMatch(); - String at = where(owner, "." + attribute.getName()) + ": "; - if (!attribute.isMany()) { - return at + "expected " + show(value(match.getRight(), attribute)) + ", got " - + show(value(match.getLeft(), attribute)) + similarity(owner); - } - Object value = change.getValue(); - return at - + switch (change.getKind()) { - case ADD -> "extra " + show(value); - case DELETE -> "missing " + show(value); - default -> - show(value) + " moved from index " - + list(match.getRight(), attribute).indexOf(value) + " to " - + list(match.getLeft(), attribute).indexOf(value); - } - + similarity(owner); - } - - /** - * A feature EMF Compare finds no difference in, but which one side sets and the other does not: - * an unsettable feature unset beside one set to its default, which an XMI file tells apart. - */ - private List setOnOneSide(Match match) { - List lines = new ArrayList<>(); - EObject expected = match.getRight(); - EObject actual = match.getLeft(); - if (expected == null || actual == null) { - return lines; - } - Set reported = new HashSet<>(); - for (Diff diff : match.getDifferences()) { - if (diff instanceof AttributeChange change) { - reported.add(change.getAttribute()); - } else if (diff instanceof ReferenceChange change) { - reported.add(change.getReference()); - } - } - for (EStructuralFeature feature : expected.eClass().getEAllStructuralFeatures()) { - if (feature.isDerived() - || feature.isTransient() - || (feature instanceof EReference reference && reference.isContainer()) - || reported.contains(feature) - || expected.eIsSet(feature) == actual.eIsSet(feature)) { - continue; - } - lines.add(where(expected, "." + feature.getName()) + ": expected " + set(expected, feature) + ", got " - + set(actual, feature) + similarity(expected)); - } - return lines; - } - - private String set(EObject owner, EStructuralFeature feature) { - Object value = owner.eGet(feature, false); - return (owner.eIsSet(feature) ? "set " : "unset ") - + (feature instanceof EReference ? target(value) : show(value)); - } - - // ----------------------------------------------------------------------------------- helpers - - /** The marker a line about an object with no natural key ends with; nothing for a keyed one. */ - private String similarity(EObject object) { - return object == null || named.contains(object) ? "" : SIMILARITY; - } - - private static Object value(EObject owner, EStructuralFeature feature) { - return owner == null || !owner.eIsSet(feature) ? null : owner.eGet(feature, false); - } - - private static List list(EObject owner, EStructuralFeature feature) { - return owner == null ? List.of() : (List) owner.eGet(feature, false); - } - - private static int index(EObject object) { - if (object.eContainer() == null) { - return object.eResource().getContents().indexOf(object); - } - return object.eContainingFeature().isMany() - ? ((List) object.eContainer().eGet(object.eContainingFeature(), false)).indexOf(object) - : 0; - } - - /** {@code # }, as {@link dev.jorisjonkers.deploykit.emf.cli.Comparison} writes it. */ - private String where(EObject object, String feature) { - EObject root = EcoreUtil.getRootContainer(object); - String at = path(object, 0, true) + feature; - String file = name + "#" + (root.eResource().getContents().indexOf(root) + 1); - return at.isEmpty() ? file : file + " " + at; - } - - /** An added or removed object as a line shows it: its class, and how many objects its subtree holds. */ - private static String subtree(EObject object) { - int size = 0; - for (TreeIterator contents = object.eAllContents(); contents.hasNext(); contents.next()) { - size++; - } - return "a " + object.eClass().getName() + (size == 0 ? "" : " holding " + size + " objects"); - } - - /** A referenced object as a line shows it: by its keyed path, its root's index first in a file of several. */ - private String target(Object value) { - if (!(value instanceof EObject object)) { - return "null"; - } - if (object.eIsProxy()) { - return "-> " + ((InternalEObject) object).eProxyURI(); - } - EObject root = EcoreUtil.getRootContainer(object); - String file = root.eResource() == null || root.eResource().getContents().size() == 1 - ? "" - : "#" + (root.eResource().getContents().indexOf(root) + 1) + " "; - String path = path(object, 0, true); - return object.eClass().getName() + " -> " + (file + path).strip(); - } - - private static String show(Object value) { - return switch (value) { - case null -> "null"; - case String text -> quoted(text); - case EEnumLiteral literal -> literal.getName(); - case List list -> "(" + list.size() + " values)"; - default -> String.valueOf(value); - }; - } - - private static String quoted(String text) { - try { - return JSON.writeValueAsString(text); - } catch (JsonProcessingException e) { - throw new IllegalStateException(e); - } - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelDiffTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelDiffTest.java deleted file mode 100644 index ac6a4bbff..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelDiffTest.java +++ /dev/null @@ -1,520 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.Cutover; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.EnvEntry; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.GateMember; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.InputDigest; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.PinnedInput; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.Provenance; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ReconcileUnit; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ReleaseGate; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedApplication; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedPlacement; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedProbe; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedProcess; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedVolume; -import java.io.IOException; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.Consumer; -import java.util.stream.Stream; -import org.eclipse.emf.common.util.EList; -import org.eclipse.emf.common.util.Enumerator; -import org.eclipse.emf.common.util.TreeIterator; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EAttribute; -import org.eclipse.emf.ecore.EEnum; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.junit.jupiter.api.Test; - -/** - * The tests' model comparison (ModelDiff), held to what it decides and how it says it: each kind of - * difference is reported once, by its keyed path, and no real difference ever compares equal. - */ -class ModelDiffTest { - - private static final ResolvedDeploymentFactory MODEL = ResolvedDeploymentFactory.eINSTANCE; - - private static final String FILE = "m.resolveddeployment"; - - @Test - void twoModelsThatHoldTheSameAreEqual() { - assertThat(differences(deployment(), deployment())).isEmpty(); - assertThat(ModelDiff.differences(FILE, List.of(), List.of())).isEmpty(); - } - - @Test - void aChangedAttributeIsOneLineAtItsKeyedPath() { - assertThat(differences( - deployment(), edited(d -> process(d, "notes", "api").setMemory("512Mi")))) - .containsExactly( - FILE + "#1 .applications[id=\"notes\"].processes[name=\"api\"].memory: expected \"256Mi\", got" - + " \"512Mi\""); - } - - @Test - void anUnsettableFeatureSetToItsDefaultDiffersFromOneUnset() { - ResolvedDeployment set = edited(d -> process(d, "notes", "api").setCutover(Cutover.CONTINUOUS)); - - assertThat(differences(set, deployment())) - .containsExactly(FILE + "#1 .applications[id=\"notes\"].processes[name=\"api\"].cutover: expected set " - + Cutover.CONTINUOUS + ", got unset " + Cutover.CONTINUOUS); - } - - @Test - void anAddedChildIsOneLineNamingIt() { - ResolvedDeployment added = - edited(d -> process(d, "notes", "api").getEnvironment().add(1, env("DEBUG", "1"))); - - assertThat(differences(deployment(), added)) - .containsExactly(FILE + "#1 .applications[id=\"notes\"].processes[name=\"api\"].environment" - + "[name=\"DEBUG\"]: extra (got a EnvEntry)"); - } - - @Test - void aRemovedSubtreeIsOneLineSayingHowMuchItHeld() { - ResolvedDeployment removed = edited(d -> EcoreUtil.delete(process(d, "notes", "worker"), true)); - - assertThat(differences(deployment(), removed)) - .containsExactly(FILE + "#1 .applications[id=\"notes\"].processes[name=\"worker\"]: missing (expected" - + " a ResolvedProcess holding 2 objects)"); - } - - @Test - void aReorderedListIsOneMoveNotAShiftOfEveryItemAfterIt() { - ResolvedDeployment moved = - edited(d -> process(d, "notes", "api").getEnvironment().move(2, 0)); - - assertThat(differences(deployment(), moved)) - .containsExactly(FILE + "#1 .applications[id=\"notes\"].processes[name=\"api\"].environment" - + "[name=\"A\"]: moved from index 0 to 2"); - } - - @Test - void aChangedReferenceNamesBothTargetsByKeyNotByIndex() { - ResolvedDeployment retargeted = edited(d -> d.getApplications() - .get(0) - .setReconcileUnit(d.getReconcileUnits().get(1))); - - assertThat(differences(deployment(), retargeted)) - .containsExactly(FILE + "#1 .applications[id=\"notes\"].reconcileUnit: expected ReconcileUnit ->" - + " .reconcileUnits[name=\"apps\"], got ReconcileUnit -> .reconcileUnits[name=\"data\"]"); - } - - @Test - void aManyValuedAttributeOrReferenceReportsEachValue() { - ResolvedDeployment edited = edited(d -> { - EList nodes = process(d, "notes", "api").getPlacement().getEligibleNodes(); - nodes.add("node-c"); - nodes.remove("node-a"); - d.getReconcileUnits().get(0).getAfter().clear(); - }); - - assertThat(differences(deployment(), edited)) - .containsExactly( - FILE + "#1 .applications[id=\"notes\"].processes[name=\"api\"].placement.eligibleNodes: extra" - + " \"node-c\"", - FILE + "#1 .applications[id=\"notes\"].processes[name=\"api\"].placement.eligibleNodes:" - + " missing \"node-a\"", - FILE + "#1 .reconcileUnits[name=\"apps\"].after: missing ReconcileUnit -> .reconcileUnits" - + "[name=\"data\"]"); - assertThat(differences( - deployment(), - edited(d -> process(d, "notes", "api") - .getPlacement() - .getEligibleNodes() - .move(1, 0)))) - .containsExactly( - FILE + "#1 .applications[id=\"notes\"].processes[name=\"api\"].placement.eligibleNodes:" - + " \"node-a\" moved from index 0 to 1"); - } - - /** Two input digests share the name production; the pinned input they digest tells them apart. */ - @Test - void aKeyOneFieldCannotMakeUniqueIsMadeOfTwo() { - ResolvedDeployment changed = - edited(d -> d.getProvenance().getInputDigests().get(1).setDigest("sha256:22")); - - assertThat(differences(deployment(), changed)) - .containsExactly(FILE + "#1 .provenance.inputDigests[input=" + PinnedInput.CLUSTER_STATE - + ",name=\"production\"].digest: expected \"sha256:2\", got \"sha256:22\""); - } - - @Test - void anItemWithNoKeyIsNamedByAReferenceToAKeyedObject() { - ResolvedDeployment edited = edited(d -> d.getApplications() - .get(0) - .getReleaseGate() - .getMembers() - .get(0) - .getChecks() - .clear()); - - assertThat(differences(deployment(), edited)) - .singleElement() - .asString() - .startsWith(FILE + "#1 .applications[id=\"notes\"].releaseGate.members[process=.applications" - + "[id=\"notes\"].processes[name=\"api\"]].checks: missing "); - } - - @Test - void anItemWithNoKeyAtAllIsPairedBySimilarityAndSaysSo() { - ResolvedDeployment resized = - edited(d -> process(d, "notes", "api").getVolumes().get(1).setSize("20Gi")); - - assertThat(differences(deployment(), resized)) - .containsExactly(FILE + "#1 .applications[id=\"notes\"].processes[name=\"api\"].volumes[1].size:" - + " expected \"2Gi\", got \"20Gi\"" + ModelDiff.SIMILARITY); - } - - @Test - void twoItemsSharingAKeyAreBothPairedBySimilarity() { - ResolvedDeployment twice = edited(d -> { - EList environment = process(d, "notes", "api").getEnvironment(); - environment.add(env("A", "other")); - }); - ResolvedDeployment changed = EcoreUtil.copy(twice); - process(changed, "notes", "api").getEnvironment().get(3).setValue("changed"); - - assertThat(differences(twice, changed)) - .containsExactly(FILE + "#1 .applications[id=\"notes\"].processes[name=\"api\"].environment[3].value:" - + " expected \"other\", got \"changed\"" + ModelDiff.SIMILARITY); - } - - @Test - void anObjectOfAnotherClassUnderTheSameKeyIsRemovedAndAdded() { - ResolvedDeployment tcp = - edited(d -> process(d, "notes", "api").getReadiness().setTarget(MODEL.createTcpTarget())); - - assertThat(differences(deployment(), tcp)) - .containsExactlyInAnyOrder( - FILE + "#1 .applications[id=\"notes\"].processes[name=\"api\"].readiness.target: missing" - + " (expected a HttpTarget)", - FILE + "#1 .applications[id=\"notes\"].processes[name=\"api\"].readiness.target: extra (got a" - + " TcpTarget)"); - } - - @Test - void aRootAddedRemovedOrMovedIsReportedByItsIndex() { - ResolvedDeployment other = MODEL.createResolvedDeployment(); - other.setApiVersion("other"); - - assertThat(ModelDiff.differences(FILE, List.of(deployment()), List.of(deployment(), other))) - .containsExactly(FILE + "#2: extra root (got a ResolvedDeployment)"); - assertThat(ModelDiff.differences(FILE, List.of(deployment(), other), List.of(deployment()))) - .containsExactly(FILE + "#2: missing root (expected a ResolvedDeployment)"); - } - - @Test - void aReferenceIntoAnotherRootNamesThatRoot() { - ResolvedDeployment first = deployment(); - ResolvedDeployment second = deployment(); - second.getApplications().get(0).setId("other"); - Resource expected = resource(EcoreUtil.copyAll(List.of(first, second))); - Resource actual = resource(EcoreUtil.copyAll(List.of(first, second))); - ((ResolvedDeployment) actual.getContents().get(0)) - .getApplications() - .get(0) - .setReconcileUnit(((ResolvedDeployment) actual.getContents().get(1)) - .getReconcileUnits() - .get(0)); - - assertThat(ModelDiff.differences(FILE, expected, actual)) - .singleElement() - .asString() - .isEqualTo(FILE + "#1 .applications[id=\"notes\"].reconcileUnit: expected ReconcileUnit -> #1" - + " .reconcileUnits[name=\"apps\"], got ReconcileUnit -> #2 .reconcileUnits[name=\"apps\"]"); - } - - /** The same pair, freshly built and compared five times, reports the same lines in the same order. */ - @Test - void theReportIsTheSameEveryRun() throws IOException { - Path golden = Stages.expected("resolve", "knowledge-platform").resolve("knowledge-platform.resolveddeployment"); - URI uri = URI.createFileURI(golden.toAbsolutePath().toString()); - byte[] bytes = Files.readAllBytes(golden); - List> runs = new ArrayList<>(); - for (int i = 0; i < 5; i++) { - Resource actual = Comparison.load(uri, bytes); - ResolvedDeployment root = (ResolvedDeployment) actual.getContents().get(0); - root.getApplications().move(0, 1); - EcoreUtil.delete(root.getApplications().get(0).getProcesses().get(0), true); - root.getProvenance().getInputDigests().get(0).setDigest("x"); - runs.add(ModelDiff.differences("k", Comparison.load(uri, bytes), actual)); - } - assertThat(runs.get(0)).isNotEmpty(); - assertThat(runs).allSatisfy(run -> assertThat(run).isEqualTo(runs.get(0))); - } - - /** - * No real difference compares equal: over every model the stage goldens hold, each attribute of - * each class changed and unset, each list emptied of an item and reordered, and each reference - * moved to another target or unset, each one at a time, is reported. - */ - @Test - void noRealDifferenceEverComparesEqual() throws IOException { - List goldens; - try (Stream tree = Files.walk(Stages.root())) { - goldens = tree.filter(path -> - path.toString().endsWith(".xmi") || path.toString().endsWith(Stages.RESOLVED_MODEL)) - .sorted(Comparator.comparingLong(ModelDiffTest::size).thenComparing(Path::toString)) - .toList(); - } - Stages.resources(); - Set tried = new HashSet<>(); - List passed = new ArrayList<>(); - for (Path golden : goldens) { - URI uri = URI.createFileURI(golden.toAbsolutePath().toString()); - byte[] bytes = Files.readAllBytes(golden); - Resource expected = Comparison.load(uri, bytes); - Resource actual = Comparison.load(uri, bytes); - for (TreeIterator objects = expected.getAllContents(); objects.hasNext(); ) { - EObject object = objects.next(); - for (EStructuralFeature feature : object.eClass().getEAllStructuralFeatures()) { - if (feature.isDerived() || feature.isTransient()) { - continue; - } - for (Mutation mutation : Mutation.values()) { - String kind = object.eClass().getName() + "." + feature.getName() + " " + mutation; - if (tried.contains(kind)) { - continue; - } - // A mutation that does not apply leaves the copy as it was, so only an - // applied one costs a fresh load. - if (mutation.apply(twin(expected, actual, object), feature)) { - tried.add(kind); - if (ModelDiff.differences(golden.getFileName().toString(), expected, actual) - .isEmpty()) { - passed.add(kind + " in " + golden.getFileName()); - } - actual = Comparison.load(uri, bytes); - } - } - } - } - } - assertThat(passed).as("differences that compared equal").isEmpty(); - assertThat(tried).as("the kinds of difference tried").hasSizeGreaterThan(1500); - } - - /** One way to change one feature of one object; {@link #apply} says whether it applied. */ - private enum Mutation { - CHANGE, - UNSET, - REMOVE, - REORDER, - RETARGET; - - boolean apply(EObject object, EStructuralFeature feature) { - boolean set = object.eIsSet(feature); - return switch (this) { - case CHANGE -> - set && !feature.isMany() && feature instanceof EAttribute attribute && change(object, attribute); - case UNSET -> set && !feature.isMany() && unset(object, feature); - case REMOVE -> set && feature.isMany() && remove(object, feature); - case REORDER -> set && feature.isMany() && reorder(object, feature); - case RETARGET -> - set - && !feature.isMany() - && feature instanceof EReference reference - && !reference.isContainment() - && retarget(object, reference); - }; - } - - private static boolean change(EObject object, EAttribute attribute) { - Object value = object.eGet(attribute); - Object changed = - switch (value) { - case String text -> text + "~"; - case Integer number -> number + 1; - case Long number -> number + 1; - case Boolean flag -> !flag; - case BigDecimal number -> number.add(BigDecimal.ONE); - case BigInteger number -> number.add(BigInteger.ONE); - case Enumerator literal - when attribute.getEType() instanceof EEnum type -> - type.getELiterals().size() < 2 - ? null - : type.getELiterals() - .get( - (literal.getValue() - == type.getELiterals() - .get(0) - .getValue()) - ? 1 - : 0) - .getInstance(); - default -> null; - }; - if (changed == null) { - return false; - } - object.eSet(attribute, changed); - return true; - } - - private static boolean unset(EObject object, EStructuralFeature feature) { - object.eUnset(feature); - return true; - } - - private static boolean remove(EObject object, EStructuralFeature feature) { - ((List) object.eGet(feature)).remove(0); - return true; - } - - private static boolean reorder(EObject object, EStructuralFeature feature) { - EList values = (EList) object.eGet(feature); - if (values.size() < 2 || values.get(0).equals(values.get(values.size() - 1))) { - return false; - } - values.move(values.size() - 1, 0); - return true; - } - - private static boolean retarget(EObject object, EReference reference) { - Object current = object.eGet(reference); - for (TreeIterator all = object.eResource().getAllContents(); all.hasNext(); ) { - EObject other = all.next(); - if (other != current && reference.getEReferenceType().isInstance(other)) { - object.eSet(reference, other); - return true; - } - } - return false; - } - } - - // ------------------------------------------------------------------------------------ model - - /** - * One Application with two processes, two reconcile units the second follows the first in, a - * provenance whose two digests share a name, and a release gate whose member names a process. - */ - private static ResolvedDeployment deployment() { - ResolvedDeployment deployment = MODEL.createResolvedDeployment(); - Provenance provenance = MODEL.createProvenance(); - provenance.getInputDigests().add(digest(PinnedInput.NODE_CONTRACT, "production", "sha256:1")); - provenance.getInputDigests().add(digest(PinnedInput.CLUSTER_STATE, "production", "sha256:2")); - deployment.setProvenance(provenance); - ReconcileUnit apps = MODEL.createReconcileUnit(); - apps.setName("apps"); - ReconcileUnit data = MODEL.createReconcileUnit(); - data.setName("data"); - apps.getAfter().add(data); - deployment.getReconcileUnits().add(apps); - deployment.getReconcileUnits().add(data); - - ResolvedApplication application = MODEL.createResolvedApplication(); - application.setId("notes"); - application.setReconcileUnit(apps); - ResolvedProcess api = MODEL.createResolvedProcess(); - api.setName("api"); - api.setMemory("256Mi"); - api.getEnvironment().add(env("A", "1")); - api.getEnvironment().add(env("B", "2")); - api.getEnvironment().add(env("C", "3")); - api.getVolumes().add(volume("data", "1Gi")); - api.getVolumes().add(volume("cache", "2Gi")); - ResolvedPlacement placement = MODEL.createResolvedPlacement(); - placement.getEligibleNodes().add("node-a"); - placement.getEligibleNodes().add("node-b"); - api.setPlacement(placement); - ResolvedProbe readiness = MODEL.createResolvedProbe(); - readiness.setTarget(MODEL.createHttpTarget()); - api.setReadiness(readiness); - ResolvedProcess worker = MODEL.createResolvedProcess(); - worker.setName("worker"); - worker.getEnvironment().add(env("QUEUE", "jobs")); - worker.getEnvironment().add(env("THREADS", "4")); - application.getProcesses().add(api); - application.getProcesses().add(worker); - ReleaseGate gate = MODEL.createReleaseGate(); - GateMember member = MODEL.createGateMember(); - member.setProcess(api); - member.getChecks().add(dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.AnalysisCheck.ERROR_RATE); - gate.getMembers().add(member); - application.setReleaseGate(gate); - deployment.getApplications().add(application); - return deployment; - } - - private static ResolvedDeployment edited(Consumer edit) { - ResolvedDeployment deployment = deployment(); - edit.accept(deployment); - return deployment; - } - - private static List differences(ResolvedDeployment expected, ResolvedDeployment actual) { - return ModelDiff.differences(FILE, resource(List.of(expected)), resource(List.of(actual))); - } - - private static Resource resource(java.util.Collection roots) { - Resource resource = Stages.resources().createResource(URI.createURI("file:/m.resolveddeployment")); - resource.getContents().addAll(roots); - return resource; - } - - private static ResolvedProcess process(ResolvedDeployment deployment, String application, String process) { - return deployment.getApplications().stream() - .filter(candidate -> candidate.getId().equals(application)) - .flatMap(candidate -> candidate.getProcesses().stream()) - .filter(candidate -> candidate.getName().equals(process)) - .findFirst() - .orElseThrow(); - } - - private static EnvEntry env(String name, String value) { - EnvEntry entry = MODEL.createEnvEntry(); - entry.setName(name); - entry.setValue(value); - return entry; - } - - private static ResolvedVolume volume(String claim, String size) { - ResolvedVolume volume = MODEL.createResolvedVolume(); - volume.setClaim(claim); - volume.setSize(size); - return volume; - } - - private static InputDigest digest(PinnedInput input, String name, String digest) { - InputDigest entry = MODEL.createInputDigest(); - entry.setInput(input); - entry.setName(name); - entry.setDigest(digest); - return entry; - } - - /** The object of {@code actual} at {@code object}'s position in {@code expected}: two loads of one file. */ - private static EObject twin(Resource expected, Resource actual, EObject object) { - EObject root = EcoreUtil.getRootContainer(object); - EObject twinRoot = actual.getContents().get(expected.getContents().indexOf(root)); - return root == object - ? twinRoot - : EcoreUtil.getEObject(twinRoot, EcoreUtil.getRelativeURIFragmentPath(root, object)); - } - - private static long size(Path path) { - try { - return Files.size(path); - } catch (IOException e) { - throw new java.io.UncheckedIOException(e); - } - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelWitnessesTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelWitnessesTest.java deleted file mode 100644 index 807dcacc4..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelWitnessesTest.java +++ /dev/null @@ -1,1605 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** - * The model behaviours of the behaviour ledger that landed in the production implementation after - * the Task 3 hand-in (docs/witnesses.md): each test renders or checks the worked examples, or one - * with a single edit, and asserts the one behaviour its name states, in the rendered file or the - * refusal the production implementation's test asserts too. - */ -class ModelWitnessesTest { - - /** The renders every test below reads, one per example, in a directory that outlives the tests. */ - @TempDir - static Path shared; - - private static final Map TREES = new HashMap<>(); - - /** One change to a worked example: {@code from} becomes {@code to} in {@code file}. */ - private record Edit(String file, String from, String to) {} - - /** - * The render of {@code example}, or, named {@code :}, of another project its set - * reads, such as the datastore's own project that applies a catalog. - */ - private static Path tree(String example) { - return TREES.computeIfAbsent(example, name -> { - try { - String[] named = name.split(":", 2); - Outputs.Resolving resolving = Outputs.RESOLVED.get(named[0]); - List files = - resolving.documents().stream().map(Examples::of).toList(); - Path out = shared.resolve(name.replace(':', '-')); - String project = named.length == 1 ? resolving.project() : named[1]; - assertThat(Pipeline.render(files, List.of(project), Outputs.INTEGRITY, out)) - .isEmpty(); - return out; - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }); - } - - /** What the render of {@code example} wrote at {@code path} below the tree. */ - private static String rendered(String example, String path) { - try { - return Files.readString(tree(example).resolve(path)); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** The documents of {@code example} with {@code edits} made to copies of the directories they sit in. */ - private static List edited(String example, Path work, Edit... edits) throws IOException { - List copied = new ArrayList<>(); - for (Edit edit : edits) { - String top = edit.file().substring(0, edit.file().indexOf('/')); - if (!copied.contains(top)) { - copied.add(top); - copy(Examples.of(top), work.resolve(top)); - } - Path target = work.resolve(edit.file()); - String text = Files.readString(target); - assertThat(text) - .as("the text %s edits in %s", edit.from(), edit.file()) - .contains(edit.from()); - Files.writeString(target, text.replace(edit.from(), edit.to())); - } - return Outputs.RESOLVED.get(example).documents().stream() - .map(file -> - copied.contains(file.substring(0, file.indexOf('/'))) ? work.resolve(file) : Examples.of(file)) - .toList(); - } - - private static void copy(Path from, Path to) throws IOException { - try (Stream walk = Files.walk(from)) { - for (Path source : walk.toList()) { - Path target = to.resolve(from.relativize(source).toString()); - if (Files.isDirectory(source)) { - Files.createDirectories(target); - } else { - Files.copy(source, target); - } - } - } - } - - /** The render of {@code example} with {@code edits}, written below {@code work}. */ - private static Path renderedWith(String example, Path work, Edit... edits) throws IOException { - List files = edited(example, work.resolve("in"), edits); - Path out = work.resolve("out"); - assertThat(Pipeline.render(files, List.of(Outputs.RESOLVED.get(example).project()), Outputs.INTEGRITY, out)) - .isEmpty(); - return out; - } - - /** The diagnostics, as {@code code path}, of the fixture {@code name} below {@code directory}. */ - private static List refusal(String directory, String name) throws IOException { - Path set = Examples.of(directory + "/" + name); - List diagnostics; - if (Files.isDirectory(set)) { - try (Stream entries = Files.list(set)) { - diagnostics = - Pipeline.check(entries.filter(file -> file.toString().endsWith(".yml")) - .sorted() - .toList()); - } - } else { - diagnostics = Pipeline.intent(Examples.of(directory + "/" + name + ".project.yml")) - .diagnostics(); - } - return diagnostics.stream() - .map(diagnostic -> diagnostic.code() + " " + diagnostic.path()) - .toList(); - } - - private static List refusal(String name) throws IOException { - return refusal("refusals", name); - } - - /** The one object of kind {@code kind} and name {@code name} in a multi-document YAML text. */ - private static String object(String text, String kind, String name) { - List found = Stream.of(text.split("\n---\n")) - .filter(document -> - document.contains("\nkind: " + kind + "\n") && document.contains("\n name: " + name + "\n")) - .toList(); - assertThat(found).as("%s %s", kind, name).hasSize(1); - return found.get(0); - } - - /** The capabilities a Vault policy JSON grants on {@code path}. */ - private static List capabilities(String policy, String path) { - Matcher found = Pattern.compile("\"" + Pattern.quote(path) + "\": \\{\\s*\"capabilities\": \\[([^\\]]*)\\]") - .matcher(policy); - assertThat(found.find()).as(path).isTrue(); - return Stream.of(found.group(1).split(",")) - .map(word -> word.replace("\"", "").trim()) - .toList(); - } - - @Test - void aLowPortKeepsNetBindServiceAloneAndAHighPortAddsNothing() { - String workloads = rendered("auth", "apps/auth/auth/workload.yaml"); - - String ui = object(workloads, "Deployment", "auth-ui"); - assertThat(ui) - .contains("containerPort: 80\n") - .contains("add:\n - NET_BIND_SERVICE\n drop:\n - ALL"); - String api = object(workloads, "Deployment", "auth-api"); - assertThat(api).contains("containerPort: 8080\n").doesNotContain("NET_BIND_SERVICE"); - assertThat(workloads).doesNotContain("sysctl"); - } - - @Test - void aTransitGrantThatReadsCoversTheKeyAndUpdatesEachOtherOperationsOnePath() { - String policy = rendered("auth", "apps/auth/vault-policy/policies/auth-system-auth-api.policy.json"); - - assertThat(capabilities(policy, "transit/keys/auth-api-jwt")).containsExactly("read"); - assertThat(capabilities(policy, "transit/sign/auth-api-jwt")).containsExactly("update"); - assertThat(capabilities(policy, "transit/keys/auth-api-jwt/rotate")).containsExactly("update"); - } - - @Test - void aMongoIsDumpedByThePlatformsMethodOwnsNoDatabaseAndIsRefusedWithoutADurableVolume() throws IOException { - String backup = rendered("data", "apps/data/platform-mongo/backup.yaml"); - - assertThat(backup) - .contains("platform/mongo-backup@sha256:") - .contains("schedule: 45 2 * * *\n") - .contains("- name: BACKUP_HOST\n value: mongo.data-system.svc.cluster.local") - .contains("- name: BACKUP_PORT\n value: \"27017\""); - try (Stream files = Files.list(tree("data").resolve("apps/data/platform-mongo"))) { - assertThat(files.map(file -> file.getFileName().toString()).toList()) - .noneMatch(name -> name.contains("catalog")); - } - assertThat(refusal("mongo-credentials-without-database")) - .containsExactly("E_CREDENTIALS_WITHOUT_DATABASE /applications/2/processes/0/dependsOn/0/credentials"); - assertThat(refusal("mongo-without-durability")) - .containsExactly("E_ENGINE_WITHOUT_DURABILITY /applications/0/processes/0"); - } - - @Test - void aScheduledProcessIsACronJobThatNeverRunsTwiceAndSkipsALateRun() throws IOException { - String cron = object(rendered("data", "apps/data/asset-sync/workload.yaml"), "CronJob", "asset-sync"); - - assertThat(cron) - .contains("schedule: \"*/15 * * * *\"\n") - .contains("concurrencyPolicy: Forbid\n") - .contains("startingDeadlineSeconds: 300\n"); - assertThat(refusal("schedule-missing")).containsExactly("E_SCHEDULE_MISSING /applications/0/processes/0"); - assertThat(refusal("schedule-unscheduled")) - .containsExactly("E_SCHEDULE_UNSCHEDULED /applications/0/processes/0/schedule"); - assertThat(refusal("scheduled-process-serves")) - .containsExactly("E_SCHEDULED_PROCESS_SERVES /applications/0/processes/0"); - assertThat(refusal("schema-refusals", "schedule-malformed")) - .containsExactly("schema /applications/0/processes/0/schedule"); - } - - @Test - void eachHumanGrantIsOneClusterRoleBindingInEveryCompositionAndADuplicateIsRefused() throws IOException { - String binding = object( - rendered("auth", "estate/human-grants/clusterrolebindings.yaml"), - "ClusterRoleBinding", - "human:oidc:k8s-admin:cluster-admin"); - - assertThat(binding) - .contains("kind: ClusterRole\n name: cluster-admin\n") - .contains("kind: Group\n name: oidc:k8s-admin\n"); - assertThat(rendered("mail", "estate/human-grants/clusterrolebindings.yaml")) - .isEqualTo(rendered("auth", "estate/human-grants/clusterrolebindings.yaml")); - assertThat(refusal("duplicate-human-grant")).containsExactly("E_DUPLICATE_HUMAN_GRANT /humanGrants/1"); - assertThat(refusal("schema-refusals", "human-grant-to-a-user")).contains("schema /humanGrants/0/user"); - assertThat(refusal("schema-refusals", "human-grant-in-a-namespace")) - .contains("schema /humanGrants/0/namespace"); - assertThat(refusal("schema-refusals", "human-grant-role-outside-vocabulary")) - .contains("schema /humanGrants/0/clusterRole"); - assertThat(refusal("schema-refusals", "human-grant-without-reason")).contains("schema /humanGrants/0/reason"); - } - - @Test - void theSameHostOnOneTierIsRefusedAndOnTwoTiersRendersOneRoutePerProxy() throws IOException { - assertThat(refusalOfNegative("duplicate-host")) - .containsExactly( - "E_DUPLICATE_HOST /applications/0/exposure/0", "E_DUPLICATE_HOST /applications/0/exposure/0"); - - String host = "Host(`hermes.jorisjonkers.dev`)"; - assertThat(rendered("agents", "apps/agents/hermes/route-public.yaml")) - .contains(host) - .contains("kubernetes.io/ingress.class: traefik-public\n"); - assertThat(rendered("agents", "apps/agents/hermes/route-lan.yaml")) - .contains(host) - .contains("kubernetes.io/ingress.class: traefik-lan\n"); - } - - /** The diagnostics of a negative fixture, composed with the foundation, as {@code code path}. */ - private static List refusalOfNegative(String name) throws IOException { - List files = new ArrayList<>(Outputs.RESOLVED.get("delivery").documents().stream() - .map(Examples::of) - .toList()); - try (Stream tree = Files.walk(Examples.of("negative/" + name))) { - files.addAll(tree.filter(file -> file.toString().endsWith(".yml")) - .sorted() - .toList()); - } - return Pipeline.check(files).stream() - .map(diagnostic -> diagnostic.code() + " " + diagnostic.path()) - .toList(); - } - - @Test - void everyRouteCarriesItsTiersIngressClassAndATierThatNamesNoneIsRefused() throws IOException { - assertThat(rendered("auth", "apps/auth/auth/route-public.yaml")) - .contains(" kubernetes.io/ingress.class: traefik-public\n"); - assertThat(rendered("data", "apps/data/platform-rabbitmq/route-lan.yaml")) - .contains(" kubernetes.io/ingress.class: traefik-lan\n"); - assertThat(refusal("tier-without-ingress-class")) - .containsExactly("E_TIER_WITHOUT_INGRESS_CLASS /applications/0/exposure/0"); - } - - @Test - void theProjectThatDeclaresAProxyRendersTheSharedMiddlewaresOncePerNamespace() throws IOException { - String middlewares = rendered("edge", "apps/edge/traefik-lan/middlewares.yaml"); - - for (String name : List.of( - "forward-auth", - "security-headers", - "security-headers-strict", - "security-headers-admin", - "security-headers-workflow")) { - assertThat(object(middlewares, "Middleware", name)).contains("namespace: edge-system\n"); - } - assertThat(tree("edge").resolve("apps/edge/traefik-public/middlewares.yaml")) - .doesNotExist(); - try (Stream files = Files.walk(tree("edge"))) { - assertThat(files.filter(file -> file.toString().endsWith(".yaml")) - .filter(file -> read(file).contains(" name: security-headers\n"))) - .hasSize(1); - } - } - - private static String read(Path file) { - try { - return Files.readString(file); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Test - void aForwardAuthNamesAProviderSurfaceAndPathAndAnUnknownProviderIsRefused() throws IOException { - assertThat(object(rendered("edge", "apps/edge/traefik-lan/middlewares.yaml"), "Middleware", "forward-auth")) - .contains("address: http://identity-http.estate-system.svc.cluster.local:") - .contains("/gate/forward\n"); - assertThat(refusal("unknown-forward-auth-provider")) - .contains("E_UNKNOWN_FORWARD_AUTH_PROVIDER /tiers/0/forwardAuth"); - } - - @Test - void aTiersProxyIsConfiguredByItsSurfacesAndTheCrdProviderFilteredOnItsClass() throws IOException { - String publicProxy = rendered("edge", "apps/edge/traefik-public/workload.yaml"); - - assertThat(publicProxy) - .contains("- --entryPoints.web.address=:8000/tcp\n") - .contains("- --entryPoints.websecure.address=:8443/tcp\n") - .contains("- --entryPoints.websecure.http.tls=true\n") - .contains("- --entryPoints.traefik.address=:8080/tcp\n") - .contains("- --providers.kubernetescrd=true\n") - .contains("- --providers.kubernetescrd.ingressClass=traefik-public\n"); - String lanProxy = rendered("edge", "apps/edge/traefik-lan/workload.yaml"); - assertThat(lanProxy) - .contains("- --providers.kubernetescrd.ingressClass=traefik-lan\n") - .doesNotContain("websecure"); - assertThat(refusal("tier-class-unfiltered")).containsExactly("E_TIER_CLASS_UNFILTERED /tiers/1/ingressClass"); - } - - @Test - void eachDashboardFileIsOneGrafanaDashboardInItsFolderAndAnUnusableOneIsRefused() throws IOException { - String dashboard = rendered("data", "apps/data/platform-rabbitmq/dashboards.yaml"); - - assertThat(dashboard) - .contains("kind: GrafanaDashboard\n") - .contains("namespace: data-system\n") - .contains("instanceSelector:\n matchLabels:\n dashboards: grafana\n") - .contains("folder: data\n") - .contains("\"uid\": \"rabbitmq\"") - .contains("- inputName: DS_PROMETHEUS\n datasourceName: prometheus\n"); - assertThat(refusal("dashboard-not-found")) - .containsExactly("E_DASHBOARD_NOT_FOUND /applications/0/dashboards/0/from"); - assertThat(refusal("dashboard-without-uid")) - .containsExactly("E_DASHBOARD_WITHOUT_UID /applications/0/dashboards/0/from"); - assertThat(refusal("duplicate-dashboard-uid")) - .containsExactly("E_DUPLICATE_DASHBOARD_UID /applications/1/dashboards/0/from"); - assertThat(refusal("no-dashboard-policy")).contains("E_NO_DASHBOARD_POLICY /applications/0/dashboards/0/from"); - } - - @Test - void aRouteOnATierThatDeclaresDnsCarriesTheExternalDnsAnnotationsAndOneOnATierWithoutCarriesNone() { - assertThat(rendered("auth", "apps/auth/auth/route-public.yaml")) - .contains(" external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev\n") - .contains(" external-dns.alpha.kubernetes.io/cloudflare-proxied: \"true\"\n"); - assertThat(rendered("data", "apps/data/platform-rabbitmq/route-lan.yaml")) - .doesNotContain("external-dns"); - } - - @Test - void aParkedProcessKeepsWhatItOwnsRunsNoPodAndAParkedScheduleStartsNoRun(@TempDir Path work) throws IOException { - Path parked = tree("agents").resolve("apps/agents/agents-api"); - - assertThat(read(parked.resolve("workload.yaml"))).contains(" replicas: 0\n"); - assertThat(parked.resolve("service.yaml")).isRegularFile(); - assertThat(parked.resolve("networkpolicy.yaml")).isRegularFile(); - assertThat(parked.resolve("serviceaccount.yaml")).isRegularFile(); - assertThat(parked.resolve("canary.yaml")).doesNotExist(); - - Path suspended = renderedWith( - "data", - work, - new Edit( - "data/data.project.yml", - " lifecycle: scheduled\n", - " lifecycle: scheduled\n parked: { reason: Stopped while the bucket is moved. }\n")); - assertThat(Files.readString(suspended.resolve("apps/data/asset-sync/workload.yaml"))) - .contains("suspend: true\n"); - } - - @Test - void aDatastoreRunsAtTheDataClassACriticalApplicationAtTheCriticalClassAndAnyOtherAtNone() throws IOException { - assertThat(rendered("data", "apps/data/platform-postgres/workload.yaml")) - .contains("priorityClassName: platform-data\n"); - assertThat(rendered("data", "apps/data/asset-sync/workload.yaml")).doesNotContain("priorityClassName"); - assertThat(rendered("data", "apps/data/platform-valkey/workload.yaml")).doesNotContain("priorityClassName"); - assertThat(rendered("auth", "apps/auth/auth/workload.yaml")) - .contains("priorityClassName: platform-critical-app\n"); - String classes = rendered("auth", "estate/priority-classes/priorityclasses.yaml"); - assertThat(object(classes, "PriorityClass", "platform-data")).contains("value: 1000000\n"); - assertThat(object(classes, "PriorityClass", "platform-critical-app")).contains("value: 100000\n"); - assertThat(refusal("unknown-critical-application")) - .contains("E_UNKNOWN_CRITICAL_APPLICATION /priority/criticalApplications/0"); - } - - @Test - void aNodeAddressExposureIsAHostPortOnTheProcessHoldsItToTheNodeAndRendersNoLoadBalancer() throws IOException { - String workload = rendered("mail", "apps/mail/stalwart/workload.yaml"); - - assertThat(workload) - .contains("- name: smtp\n containerPort: 25\n hostPort: 25\n") - .contains("- name: imaps\n containerPort: 993\n hostPort: 993\n") - .contains("kubernetes.io/hostname") - .contains("- frankfurt-contabo-1\n"); - assertThat(rendered("mail", "apps/mail/stalwart/service.yaml")).doesNotContain("LoadBalancer"); - assertThat(refusal("node-port-taken")) - .containsExactly( - "E_NODE_PORT_TAKEN /applications/0/l4Exposure/0", - "E_NODE_PORT_TAKEN /applications/1/l4Exposure/0"); - assertThat(refusal("node-address-replicated")) - .containsExactly("E_NODE_ADDRESS_REPLICATED /applications/0/processes/0/replicas"); - assertThat(refusal("node-address-continuous")) - .containsExactly("E_CUTOVER_UNHONOURABLE /applications/0/processes/0"); - } - - @Test - void aTiersAddressExposesItsProxyOnTheListenersPortsAndAnAcmeTierGetsAResolverWithItsOwnState() throws IOException { - String publicProxy = rendered("edge", "apps/edge/traefik-public/workload.yaml"); - - assertThat(publicProxy) - .contains("- name: web\n containerPort: 8000\n hostPort: 80\n") - .contains("- name: websecure\n containerPort: 8443\n hostPort: 443\n") - .doesNotContain("- name: tcp-80\n") - .contains("- --certificatesresolvers.public-frankfurt.acme.email=hostmaster@jorisjonkers.dev\n") - .contains("- --certificatesresolvers.public-frankfurt.acme.storage=/acme/public-frankfurt.json\n") - .contains("- --certificatesresolvers.public-frankfurt.acme.dnschallenge.provider=cloudflare\n") - .contains("secretKeyRef:\n name: traefik-public-platform-cloudflare\n") - .contains("key: CF_DNS_API_TOKEN\n"); - assertThat(rendered("edge", "apps/edge/traefik-public/pvc.yaml")).contains(" name: traefik-public-acme\n"); - assertThat(rendered("edge", "apps/edge/traefik-lan/service.yaml")) - .contains("metallb.io/address-pool: lan-edge\n") - .contains("- name: tcp-80\n port: 80\n protocol: TCP\n targetPort: 8000\n"); - assertThat(refusal("unknown-l4-address")).containsExactly("E_UNKNOWN_L4_ADDRESS /applications/0/l4Exposure/0"); - assertThat(refusal("tier-surface-missing")).containsExactly("E_TIER_SURFACE_MISSING /tiers/0"); - } - - @Test - void aRoutesTlsFollowsItsTierAnAcmeTierNamesItsResolverAPlainTierRendersNoneAndATlsTierThatIssuesNoneAnEmptyBlock( - @TempDir Path work) throws IOException { - assertThat(rendered("auth", "apps/auth/auth/route-public.yaml")) - .contains(" tls:\n certResolver: public-frankfurt\n"); - assertThat(rendered("data", "apps/data/platform-rabbitmq/route-lan.yaml")) - .doesNotContain("tls:") - .doesNotContain("certResolver"); - - Path terminating = renderedWith( - "data", - work, - new Edit( - "platform/platform.intent.yml", - " listener: plain\n certificates: none\n", - " listener: tls\n certificates: none\n"), - new Edit( - "edge/edge.project.yml", - " web: 8000\n admin: 8080\n", - " web: 8000\n websecure: 8443\n admin: 8080\n")); - assertThat(Files.readString(terminating.resolve("apps/data/platform-rabbitmq/route-lan.yaml"))) - .contains(" tls: {}\n"); - } - - @Test - void aProcessAnsweringOnPort53ResolvesThroughThePlatformsUpstreamNameserversAndIsRefusedWithoutThem() - throws IOException { - String workload = rendered("utility", "apps/utility/adguard/workload.yaml"); - - assertThat(workload) - .contains("dnsPolicy: None\n") - .contains("nameservers:\n - 9.9.9.10\n - 149.112.112.10\n"); - assertThat(rendered("utility", "apps/utility/adguard/networkpolicy.yaml")) - .contains( - "- ipBlock:\n cidr: 9.9.9.10/32\n - ipBlock:\n cidr: 149.112.112.10/32\n" - + " ports:\n - protocol: UDP\n port: 53\n - protocol: TCP\n port: 53\n"); - assertThat(refusal("no-upstream-nameservers")) - .containsExactly("E_NO_UPSTREAM_NAMESERVERS /applications/0/l4Exposure/0"); - } - - @Test - void aProcessThatSpawnsCreatesPodsFromItsTemplateAlone() { - String rules = rendered("agents", "apps/agents/agents-api/rbac.yaml"); - assertThat(rules) - .contains( - " - pods\n verbs:\n - get\n - list\n - watch\n - create\n - delete\n"); - - String workload = rendered("agents", "apps/agents/agents-api/workload.yaml"); - assertThat(workload) - .contains( - "- name: SPAWN_RUNNER_IMAGE\n value: ghcr.io/jorisjonkers-dev/agents/agent-runner@sha256:") - .contains( - "- name: SPAWN_RUNNER_LABELS\n value: deploy-kit.jorisjonkers.dev/spawned-from=agents-api-runner," - + "consumes.deploy-kit.jorisjonkers.dev/agents-api.http=true\n"); - assertThat(rendered("agents", "apps/agents/agents-api/networkpolicy.yaml")) - .contains("deploy-kit.jorisjonkers.dev/spawned-from: agents-api-runner\n"); - } - - @Test - void anAdmittedApiBlockWithNoRulesRendersNoRoleAndNoBindingBesideItsMountedToken() { - Path headlamp = tree("utility").resolve("apps/utility/headlamp"); - - assertThat(headlamp.resolve("rbac.yaml")).doesNotExist(); - assertThat(read(headlamp.resolve("kustomization.yaml"))).doesNotContain("rbac.yaml"); - assertThat(read(headlamp.resolve("workload.yaml"))).contains("automountServiceAccountToken: true\n"); - assertThat(read(headlamp.resolve("networkpolicy.yaml"))).contains("cidr: 10.43.0.1/32\n"); - } - - @Test - void anEdgeIntoAnObjectStoreThatNamesBucketsDerivesItsCatalogAndHandsTheConsumerItsKey() throws IOException { - String catalog = rendered("knowledge-platform:data", "apps/data/platform-garage/garage-catalog.yaml"); - - assertThat(catalog) - // Applied with the derived admin token, from the store's own Project. - .contains("{\"admin\":{\"path\":\"secret/data/data/garage/catalog\",\"token\":\"token\"}") - .contains("\"keys\":[{\"buckets\":[\"knowledge-platform-assets\"],\"name\":\"knowledge-platform\"," - + "\"path\":\"secret/data/knowledge-platform/garage/s3\"}]"); - assertThat(rendered("knowledge-platform", "apps/knowledge-platform/karakeep/vso.yaml")) - .contains("path: knowledge-platform/garage/s3\n"); - assertThat(refusal("buckets-without-object-store")) - .containsExactly("E_BUCKETS_WITHOUT_OBJECT_STORE /applications/1/processes/0/dependsOn/0/buckets"); - } - - @Test - void everyStableAddressIsOneExternalNameKeptCurrentByFluxAndAConsumersAliasNamesItAlone() { - String stable = object( - rendered("auth", "estate/stable-addresses/services.yaml"), "Service", "platform-postgres-postgres"); - // Kept current: nothing asks Flux to create it once and leave it. - assertThat(stable) - .contains("namespace: estate-system\n") - .doesNotContain("kustomize.toolkit.fluxcd.io/ssa") - .contains("type: ExternalName\n externalName: postgres.data-system.svc.cluster.local"); - - assertThat(object(rendered("auth", "apps/auth/aliases.yaml"), "Service", "platform-postgres")) - .contains("type: ExternalName\n") - .contains("externalName: platform-postgres-postgres.estate-system.svc.cluster.local"); - assertThat(rendered("edge", "apps/edge/traefik-lan/middlewares.yaml")) - .contains(".estate-system.svc.cluster.local:"); - } - - @Test - void everyCanaryAsksTheReleaseGateAFourthQuestionRollback() { - String canary = rendered("auth", "apps/auth/auth/canary.yaml"); - - for (String process : List.of("auth-api", "auth-ui")) { - assertThat(object(canary, "Canary", process)) - .contains(" - name: rollback\n type: rollback\n" - + " url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback\n") - .contains(" process: " + process + "\n"); - } - } - - @Test - void aSeededAssetIsTheFirstInitContainerThatWritesItAtMode0600AndTheProcessNeverMountsIt() { - String workload = rendered("utility", "apps/utility/adguard/workload.yaml"); - int init = workload.indexOf(" initContainers:\n - name: seed\n"); - int main = workload.indexOf(" containers:\n - name: adguard\n"); - - assertThat(init).isPositive().isLessThan(main); - String seed = workload.substring(init, main); - assertThat(seed) - .contains("- /bin/sh\n - -c\n") - .contains("mkdir -p '/opt/adguardhome/conf'") - .contains( - "cp -p '/opt/adguardhome/conf/AdGuardHome.yaml' '/opt/adguardhome/conf/AdGuardHome.yaml.superseded'") - .contains("chmod 0600 '/opt/adguardhome/conf/AdGuardHome.yaml.seeding'") - .contains( - "mv '/opt/adguardhome/conf/AdGuardHome.yaml.seeding' '/opt/adguardhome/conf/AdGuardHome.yaml'") - .contains("readOnlyRootFilesystem: true\n") - .contains("mountPath: /seed/adguard-adguardhome-yaml-85a1bf27a7\n readOnly: true\n"); - assertThat(workload.substring(main)).doesNotContain("/seed/"); - } - - @Test - void aContainerThatMountsAWritableTmpGetsHomeAfterItsOwnVariablesAndOneWithoutGetsNone(@TempDir Path work) - throws IOException { - String auth = rendered("auth", "apps/auth/auth/workload.yaml"); - assertThat(object(auth, "Deployment", "auth-api")) - .contains("- name: HOME\n value: /tmp\n") - .contains("mountPath: /tmp\n"); - assertThat(rendered("auth", "apps/auth/auth/migration.yaml")) - .contains("- name: HOME\n value: /tmp\n"); - assertThat(rendered("utility", "apps/utility/adguard/workload.yaml")).doesNotContain("name: HOME"); - assertThat(rendered("minimal", "apps/notes/notes/workload.yaml")).doesNotContain("name: HOME"); - - Path authored = renderedWith( - "auth", - work, - new Edit( - "auth/env/auth-api/base.env", - "SESSION_COOKIE_SECURE=true\n", - "SESSION_COOKIE_SECURE=true\nHOME=/work\n")); - String api = - object(Files.readString(authored.resolve("apps/auth/auth/workload.yaml")), "Deployment", "auth-api"); - assertThat(api).contains("- name: HOME\n value: /work\n").doesNotContain("value: /tmp\n"); - } - - @Test - void everyNamespaceTheRenderWritesIsNeverPruned() { - for (String[] namespace : new String[][] { - {"minimal", "apps/notes/namespace.yaml"}, - {"node", "apps/node/namespace.yaml"}, - {"auth", "estate/stable-addresses/namespace.yaml"} - }) { - assertThat(rendered(namespace[0], namespace[1])) - .as(namespace[1]) - .contains("kind: Namespace") - .contains(" annotations:\n kustomize.toolkit.fluxcd.io/prune: disabled\n"); - } - } - - void everyMonitorCarriesThePlatformsSelectorLabelsBesideItsOwnAndTheMonitorsOwnValueWins(@TempDir Path work) - throws IOException { - String monitor = rendered("minimal", "apps/notes/notes/podmonitor.yaml"); - assertThat(monitor) - .contains(" labels:\n release: metrics-stack\n app.kubernetes.io/name: notes-api\n") - .containsOnlyOnce("app.kubernetes.io/managed-by:"); - - String labels = " labels:\n release: metrics-stack\n"; - Edit collision = new Edit( - "platform/platform.intent.yml", labels, labels + " app.kubernetes.io/managed-by: someone-else\n"); - for (String[] where : new String[][] { - {"minimal", "apps/notes/notes/podmonitor.yaml"}, - {"observability", "apps/observability/prometheus/flux-podmonitor.yaml"} - }) { - Path collided = renderedWith(where[0], work.resolve("collided-" + where[0]), collision); - assertThat(Files.readString(collided.resolve(where[1]))) - .containsOnlyOnce("app.kubernetes.io/managed-by:") - .contains("app.kubernetes.io/managed-by: deploy-kit\n"); - } - - Path bare = renderedWith("minimal", work.resolve("bare"), new Edit("platform/platform.intent.yml", labels, "")); - assertThat(Files.readString(bare.resolve("apps/notes/notes/podmonitor.yaml"))) - .doesNotContain("release:") - .contains(" labels:\n app.kubernetes.io/name: notes-api\n"); - } - - @Test - void anUnproxiedHostPointsAtTheTiersDirectAddressAndItsRoutesCountAClientByItsConnection(@TempDir Path work) - throws IOException { - String limit = " - { path: /, match: prefix, process: notes-api, surface: http }"; - Edit limited = new Edit( - "minimal/notes.project.yml", - limit, - limit.replace("surface: http }", "surface: http, rateLimit: { requests: 10, per: 1m } }")); - Edit unproxied = new Edit( - "minimal/notes.project.yml", - " contentPolicy: strict\n", - " contentPolicy: strict\n proxied: false\n"); - - String off = Files.readString(renderedWith("minimal", work.resolve("off"), limited, unproxied) - .resolve("apps/notes/notes/route-public.yaml")); - assertThat(off) - .contains("external-dns.alpha.kubernetes.io/target: 167.86.79.203\n") - .contains("external-dns.alpha.kubernetes.io/cloudflare-proxied: \"false\"\n") - .contains(" rateLimit:\n average: 10\n period: 1m\n burst: 10\n") - .doesNotContain("CF-Connecting-IP"); - - String on = Files.readString( - renderedWith("minimal", work.resolve("on"), limited).resolve("apps/notes/notes/route-public.yaml")); - assertThat(on) - .contains("external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev\n") - .contains("requestHeaderName: CF-Connecting-IP\n"); - - assertThat(refusal("no-direct-target")) - .containsExactly("E_NO_DIRECT_TARGET /applications/0/exposure/0/proxied"); - } - - @Test - void theMetricsStackRendersRuleGroupsAndRoutesEachSeverityToItsReceiverAndNoRuleGroupsRenderElsewhere() { - assertThat(rendered("observability", "apps/observability/prometheus/alertrules.yaml")) - .contains("kind: PrometheusRule\n") - .contains(" name: prometheus-platform\n") - .contains(" - name: platform\n"); - String config = rendered("observability", "apps/observability/alertmanager/alertmanagerconfig.yaml"); - assertThat(config) - .contains("kind: AlertmanagerConfig\n") - .contains(" - name: severity\n value: critical\n receiver: discord\n") - .contains(" repeatInterval: 4h\n") - .contains(" - name: severity\n value: warning\n receiver: discord\n") - .contains( - " name: alertmanager-platform-alertmanager-discord\n key: webhook-url\n"); - assertThat(rendered("observability", "apps/observability/alertmanager/vso.yaml")) - .contains("alertmanager-platform-alertmanager-discord"); - } - - @Test - void theLogCollectorReadsEveryPodsLogThroughTheApiAsOneCopyAndNoTreeHoldsAWebhookHookOrAggregatedRole() - throws IOException { - String rbac = rendered("observability", "apps/observability/alloy/rbac.yaml"); - assertThat(rbac).contains("kind: ClusterRole\n").contains(" - pods/log\n"); - String workload = rendered("observability", "apps/observability/alloy/workload.yaml"); - assertThat(workload) - .contains("kind: Deployment\n") - .doesNotContain("DaemonSet") - .doesNotContain("hostNetwork"); - assertThat(workload).doesNotContain("hostPID").doesNotContain("hostPath"); - for (String example : Outputs.RESOLVED.keySet()) { - try (Stream files = Files.walk(tree(example))) { - assertThat(files.filter(file -> file.toString().endsWith(".yaml")) - .map(ModelWitnessesTest::read) - .filter(text -> text.contains("kind: MutatingWebhookConfiguration") - || text.contains("kind: ValidatingWebhookConfiguration") - || text.contains("helm.sh/hook") - || text.contains("aggregate-to-"))) - .as(example) - .isEmpty(); - } - } - } - - @Test - void theMetricsStackScrapesFluxsControllersWhereThePlatformRecordsTheirMetricsAndNowhereElse(@TempDir Path work) - throws IOException { - String monitor = rendered("observability", "apps/observability/prometheus/flux-podmonitor.yaml"); - assertThat(monitor) - .contains(" name: flux-controllers\n namespace: observability-system\n") - .contains(" release: metrics-stack\n") - .contains(" app.kubernetes.io/part-of: flux\n") - .contains(" - flux-system\n") - .contains( - " - portNumber: 8080\n path: /metrics\n interval: 30s\n scrapeTimeout: 10s\n"); - assertThat(rendered("observability", "apps/observability/prometheus/networkpolicy.yaml")) - .contains("kubernetes.io/metadata.name: flux-system"); - - Path unrecorded = renderedWith( - "observability", - work, - new Edit("platform/platform.intent.yml", " metrics: {port: 8080, path: /metrics}\n", "")); - assertThat(unrecorded.resolve("apps/observability/prometheus/flux-podmonitor.yaml")) - .doesNotExist(); - assertThat(Files.readString(unrecorded.resolve("apps/observability/prometheus/networkpolicy.yaml"))) - .doesNotContain("flux-system"); - } - - /** A diagnostic as {@code code document path}. */ - private static String described(Diagnostic diagnostic) { - return diagnostic.code() + " " + diagnostic.document() + " " + diagnostic.path(); - } - - /** What rendering {@code example} with {@code edits} refuses, as {@code code document path}. */ - private static List renderRefusals(String example, Path work, Edit... edits) throws IOException { - List files = edited(example, work.resolve("in"), edits); - return Pipeline.render( - files, List.of(Outputs.RESOLVED.get(example).project()), Outputs.INTEGRITY, work.resolve("out")) - .stream() - .map(ModelWitnessesTest::described) - .toList(); - } - - /** What checking the documents of {@code example} with {@code edits} refuses, as {@code code document path}. */ - private static List checkRefusals(String example, Path work, Edit... edits) throws IOException { - return Pipeline.check(edited(example, work.resolve("in"), edits)).stream() - .map(ModelWitnessesTest::described) - .toList(); - } - - private static final String UTILITY = "utility/utility.project.yml"; - private static final String PLATFORM_DOCUMENT = "platform/platform.intent.yml"; - - @Test - void aProcessExposedOnAPoolIsHeldToThePoolsSiteAndAPlacementThatContradictsItIsRefused(@TempDir Path work) - throws IOException { - assertThat(rendered("utility", "apps/utility/adguard/service.yaml")) - .contains("metallb.io/address-pool: lan-dns\n") - .contains("type: LoadBalancer\n") - .contains("externalTrafficPolicy: Local\n") - .contains(" protocol: TCP\n targetPort: 5353\n") - .contains(" protocol: UDP\n targetPort: 5353\n"); - - assertThat(rendered("utility", "apps/utility/adguard/workload.yaml")).contains("enschede"); - Edit elsewhere = new Edit( - PLATFORM_DOCUMENT, - " lan-dns:\n kind: pool\n site: enschede\n", - " lan-dns:\n kind: pool\n site: frankfurt\n"); - assertThat(renderRefusals("utility", work, elsewhere)) - .containsExactly("E_PLACEMENT_UNSATISFIABLE utility.project.yml /applications/0/processes/0/placement"); - } - - @Test - void replicasSpreadAcrossNodesRepelEachOtherWithinOneRevisionAndNeedANodeEach(@TempDir Path work) - throws IOException { - assertThat(rendered("utility", "apps/utility/adguard/workload.yaml")) - .contains("podAntiAffinity:\n") - .contains("requiredDuringSchedulingIgnoredDuringExecution:") - .contains("- pod-template-hash\n") - .contains("topologyKey: kubernetes.io/hostname\n"); - - Edit forty = new Edit(UTILITY, " count: 2\n", " count: 40\n"); - assertThat(renderRefusals("utility", work.resolve("spread"), forty)) - .containsExactly("E_PLACEMENT_UNSATISFIABLE utility.project.yml /applications/0/processes/0/replicas"); - Path unspread = renderedWith( - "utility", work.resolve("unspread"), forty, new Edit(UTILITY, " across: node\n", "")); - assertThat(Files.readString(unspread.resolve("apps/utility/adguard/workload.yaml"))) - .doesNotContain("podAntiAffinity"); - } - - @Test - void aWritablePathsSizeIsAddedToTheProcessesMemoryAndAPathNoNodeCanHoldBesideItIsRefused(@TempDir Path work) - throws IOException { - String workload = rendered("utility", "apps/utility/adguard/workload.yaml"); - assertThat(workload) - .contains("medium: Memory\n sizeLimit: 128Mi\n") - .contains("sizeLimit: 64Mi\n") - .contains("memory: 256Mi\n"); - - assertThat(renderRefusals( - "utility", - work.resolve("held"), - new Edit( - UTILITY, - "{ path: /opt/adguardhome/work, memory: 128Mi }", - "{ path: /opt/adguardhome/work, memory: 64Gi }"))) - .containsExactly("E_PLACEMENT_UNSATISFIABLE utility.project.yml /applications/0/processes/0/placement"); - // The same path above the Process, in either form, is declared twice. - assertThat(checkRefusals( - "utility", - work.resolve("twice"), - new Edit( - UTILITY, - " processes:\n - name: adguard\n", - " writablePaths: [/opt/adguardhome/conf]\n processes:\n - name: adguard\n"))) - .containsExactly("E_SHARED_DECLARATION_DUPLICATED utility.project.yml /applications/0/processes/0"); - assertThat( - checkRefusals( - "utility", - work.resolve("memory"), - new Edit( - UTILITY, - " processes:\n - name: adguard\n", - " writablePaths: [{ path: /opt/adguardhome/work, memory: 128Mi }]\n processes:\n - name: adguard\n"))) - .containsExactly("E_SHARED_DECLARATION_DUPLICATED utility.project.yml /applications/0/processes/0"); - } - - @Test - void theNodeAgentsAreDerivedAndACatalogThatNamesNoImageForOneIsRefusedAtTheEntry(@TempDir Path work) - throws IOException { - assertThat(checkRefusals("node", work.resolve("whole"))).isEmpty(); - - String speaker = " l4-speaker:\n image: metallb-speaker\n memory: 64Mi\n cpu: 20m\n" - + " controller: { image: metallb-controller, memory: 64Mi, cpu: 10m }\n"; - String platform = "platform.intent.yml"; - assertThat(checkRefusals("node", work.resolve("speaker"), new Edit(PLATFORM_DOCUMENT, speaker, ""))) - .containsExactly("E_NO_NODE_AGENT_POLICY " + platform + " /nodeAgents/l4-speaker"); - assertThat(checkRefusals( - "node", - work.resolve("catalog"), - new Edit( - PLATFORM_DOCUMENT, - "nodeAgents:\n gpu-device: { image: nvidia-device-plugin, memory: 64Mi, cpu: 10m }\n" - + " gpu-metrics: { image: dcgm-exporter, memory: 256Mi, cpu: 50m }\n" - + " node-metrics: { image: node-exporter, memory: 64Mi, cpu: 20m }\n" - + speaker, - ""))) - .containsExactly( - "E_NO_NODE_AGENT_POLICY " + platform + " /nodeAgents/gpu-device", - "E_NO_NODE_AGENT_POLICY " + platform + " /nodeAgents/gpu-metrics", - "E_NO_NODE_AGENT_POLICY " + platform + " /nodeAgents/node-metrics", - "E_NO_NODE_AGENT_POLICY " + platform + " /nodeAgents/l4-speaker"); - } - - @Test - void aSetWithoutTheNodeContractDerivesNoAgentAndAPoolOnASiteWithNoNodeDerivesNoAnnouncer(@TempDir Path work) - throws IOException { - String speaker = " l4-speaker:\n image: metallb-speaker\n memory: 64Mi\n cpu: 20m\n" - + " controller: { image: metallb-controller, memory: 64Mi, cpu: 10m }\n"; - Edit unnamed = new Edit(PLATFORM_DOCUMENT, speaker, ""); - List without = edited("node", work.resolve("without"), unnamed).stream() - .filter(file -> !file.getFileName().toString().equals("node-contract.yml")) - .toList(); - assertThat(Pipeline.check(without)).isEmpty(); - - List nowhere = new ArrayList<>(List.of(unnamed)); - for (String pool : List.of("lan-dns", "lan-edge", "lan-mqtt")) { - nowhere.add(new Edit( - PLATFORM_DOCUMENT, - " " + pool + ":\n kind: pool\n site: enschede\n", - " " + pool + ":\n kind: pool\n site: nowhere\n")); - } - assertThat(checkRefusals("node", work.resolve("nowhere"), nowhere.toArray(Edit[]::new))) - .isEmpty(); - } - - @Test - void aNodeContractThatDoesNotReadIsRefusedAtTheContract(@TempDir Path work) throws IOException { - assertThat(checkRefusals( - "node", - work, - new Edit("platform/node-contract.yml", "labelPrefix: platform.jorisjonkers.dev\n", ""))) - .containsExactly("schema node-contract.yml /labelPrefix"); - } - - @Test - void anOffClusterCopyNamesAnAgePublicKeyAndOneThatIsNoneIsRefusedWithThePlatformDocument(@TempDir Path work) - throws IOException { - assertThat(rendered("data", "apps/data/platform-postgres/backup.yaml")) - .contains("- name: BACKUP_OFF_CLUSTER_RECIPIENT\n") - .contains("age1s6v5qrx3mgcgk37gscv8y6z43rssksdct5lx3xk5xrtptjndqvhsnhj7h8"); - String key = " recipient: age1s6v5qrx3mgcgk37gscv8y6z43rssksdct5lx3xk5xrtptjndqvhsnhj7h8\n"; - String at = "schema platform.intent.yml /durability/irreplaceable/offCluster/recipient"; - assertThat(checkRefusals("data", work.resolve("none"), new Edit(PLATFORM_DOCUMENT, key, ""))) - .containsExactly(at); - assertThat(checkRefusals( - "data", - work.resolve("ssh"), - new Edit(PLATFORM_DOCUMENT, key, " recipient: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI\n"))) - .containsExactly(at); - assertThat(checkRefusals( - "data", - work.resolve("alphabet"), - new Edit(PLATFORM_DOCUMENT, "recipient: age1s6v5qrx3", "recipient: age1b6v5qrx3"))) - .containsExactly(at); - } - - @Test - void aProcessAndASidecarCarryTheCommandAndArgumentsTheyNameAsWrittenAndNamingNoneCarriesNone(@TempDir Path work) - throws IOException { - Path run = renderedWith( - "mail", - work.resolve("named"), - new Edit( - "mail/mail.project.yml", - " sidecars:\n - name: stalwart-apply\n image: stalwart-provisioner\n", - " command: [/usr/bin/stalwart]\n args: [serve, --port=8080, \"\"]\n" - + " sidecars:\n - name: stalwart-apply\n image: stalwart-provisioner\n" - + " command: [/bin/apply]\n args: [--verbose]\n")); - String workload = Files.readString(run.resolve("apps/mail/stalwart/workload.yaml")); - assertThat(workload) - .contains(" command:\n - /usr/bin/stalwart\n args:\n - serve\n" - + " - --port=8080\n - \"\"\n") - .contains(" command:\n - /bin/apply\n args:\n - --verbose\n"); - assertThat(rendered("mail", "apps/mail/stalwart/workload.yaml")) - .doesNotContain("command:") - .doesNotContain("args:"); - int attempt = 0; - for (String empty : List.of("command: []", "command: [\"\"]", "args: []")) { - assertThat(checkRefusals( - "mail", - work.resolve("empty" + attempt++), - new Edit( - "mail/mail.project.yml", - " sidecars:\n - name: stalwart-apply\n", - " " + empty + "\n sidecars:\n - name: stalwart-apply\n"))) - .hasSize(1) - .allMatch(refusal -> refusal.startsWith("schema mail.project.yml /applications/")); - } - } - - @Test - void aDescriptionRendersNothingAndOneOverOneHundredAndSixtyCharactersOrEmptyIsASchemaRefusal(@TempDir Path work) - throws IOException { - Edit application = new Edit( - "minimal/notes.project.yml", - "applications:\n - id: notes\n", - "applications:\n - id: notes\n description: What notes does.\n"); - Edit process = new Edit( - "minimal/notes.project.yml", - " - name: notes-api\n", - " - name: notes-api\n description: Serves the notes.\n"); - Path described = renderedWith("minimal", work.resolve("described"), application, process); - try (Stream files = Files.walk(tree("minimal"))) { - for (Path file : files.filter(Files::isRegularFile).toList()) { - assertThat(Files.readString(described.resolve(tree("minimal").relativize(file)))) - .as(file.toString()) - .isEqualTo(Files.readString(file)); - } - } - for (Edit edit : List.of(application, process)) { - String sentence = edit.to() - .substring(edit.to().indexOf("description: ") + "description: ".length()) - .stripTrailing(); - String path = - edit == application ? "/applications/0/description" : "/applications/0/processes/0/description"; - assertThat(checkRefusals( - "minimal", - work.resolve("long" + (edit == application)), - new Edit(edit.file(), edit.from(), edit.to().replace(sentence, "x".repeat(161))))) - .containsExactly("schema notes.project.yml " + path); - assertThat(checkRefusals( - "minimal", - work.resolve("empty" + (edit == application)), - new Edit(edit.file(), edit.from(), edit.to().replace(sentence, "\"\"")))) - .containsExactly("schema notes.project.yml " + path); - } - } - - @Test - void anOptionalKeyMakesEveryReferenceToItOptionalAndOptionalFalseIsRefused(@TempDir Path work) throws IOException { - String optional = "key: github-pat\n optional: true\n"; - assertThat(rendered("agents", "apps/agents/hermes/workload.yaml")).contains(optional); - - Path required = renderedWith( - "agents", - work.resolve("required"), - new Edit("agents/agents.project.yml", "- { name: github-pat, optional: true }", "- github-pat")); - assertThat(Files.readString(required.resolve("apps/agents/hermes/workload.yaml"))) - .contains("key: github-pat\n") - .doesNotContain(optional); - assertThat(checkRefusals( - "agents", - work.resolve("false"), - new Edit( - "agents/agents.project.yml", - "- { name: github-pat, optional: true }", - "- { name: github-pat, optional: false }"))) - .containsExactly("schema agents.project.yml /applications/0/processes/0/secrets/0/keys/2/optional"); - } - - @Test - void aSeededAssetIsRefusedWhereThePlatformNamesNoSeederAndWhereItLandsBelowNoVolumeOrWritablePath( - @TempDir Path work) throws IOException { - String seeded = "utility.project.yml /applications/0/processes/0/assets/0/seedAt"; - assertThat(checkRefusals("utility", work.resolve("whole"))).isEmpty(); - assertThat(checkRefusals( - "utility", - work.resolve("unnamed"), - new Edit(PLATFORM_DOCUMENT, "seeder:\n image: busybox\n memory: 16Mi\n cpu: 10m\n", ""))) - // Hermes, in the foundation, seeds its config too. - .containsExactlyInAnyOrder( - "E_NO_SEEDER " + seeded, - "E_NO_SEEDER agents.project.yml /applications/0/processes/0/assets/0/seedAt"); - assertThat(checkRefusals( - "utility", - work.resolve("retired"), - new Edit("platform/images.lock.yml", " busybox:\n", " busybox-retired:\n"))) - .containsExactly("E_UNLOCKED_IMAGE platform.intent.yml /seeder/image"); - // A lock that does not read is refused for its shape, never for the seeder it cannot be asked about. - assertThat(checkRefusals( - "utility", - work.resolve("unreadable"), - new Edit("platform/images.lock.yml", " busybox:\n", " busybox: 5\n"))) - .noneMatch(refusal -> refusal.startsWith("E_UNLOCKED_IMAGE")); - for (String outside : List.of( - "/etc/AdGuardHome.yaml", - "/opt/adguardhome/conf", - "/opt/adguardhome/conf/", - "/opt/adguardhome/conf/../AdGuardHome.yaml", - "/opt/adguardhome/conf/./AdGuardHome.yaml", - "/opt/adguardhome/conf-other/AdGuardHome.yaml")) { - assertThat(checkRefusals( - "utility", - work.resolve("outside" + outside.hashCode()), - new Edit(UTILITY, "seedAt: /opt/adguardhome/conf/AdGuardHome.yaml", "seedAt: " + outside))) - .as(outside) - .containsExactly("E_SEED_OUTSIDE_VOLUME " + seeded); - } - // A file below a path a level above declares, or deeper below one, is where a seed may land. - assertThat(checkRefusals( - "utility", - work.resolve("deeper"), - new Edit( - UTILITY, - "seedAt: /opt/adguardhome/conf/AdGuardHome.yaml", - "seedAt: /opt/adguardhome/conf/more/AdGuardHome.yaml"))) - .isEmpty(); - // The seeder is held beside the Process: a seeder no node can hold beside it leaves it nowhere to go. - assertThat(renderRefusals( - "utility", - work.resolve("heavy"), - new Edit(PLATFORM_DOCUMENT, " memory: 16Mi\n cpu: 10m\n", " memory: 40Gi\n cpu: 10m\n"))) - .containsExactly("E_PLACEMENT_UNSATISFIABLE utility.project.yml /applications/0/processes/0/placement"); - } - - @Test - void aSidecarMountsOnlyAnAssetItsProcessHoldsAndAnotherIsRefused(@TempDir Path work) throws IOException { - assertThat(rendered("mail", "apps/mail/stalwart/workload.yaml")) - .contains("mountPath: /etc/stalwart-provisioner/manifest.json\n") - .contains("readOnly: true\n"); - assertThat(checkRefusals( - "mail", - work.resolve("unknown"), - new Edit( - "mail/mail.project.yml", - " assets:\n - { from: config/manifest.json,", - " assets:\n - { from: config/other.json,"))) - .containsExactly( - "E_UNKNOWN_SIDECAR_ASSET mail.project.yml /applications/0/processes/0/sidecars/0/assets/0"); - // An Asset a level above shares down to the Process is the Process's, and one a lower level - // replaced at its path is not. - Edit shared = new Edit( - "mail/mail.project.yml", - " assets:\n - from: config/manifest.json\n mountAt: /etc/stalwart-provisioner/manifest.json\n", - ""); - Edit above = new Edit( - "mail/mail.project.yml", - " processes:\n", - " assets:\n - { from: config/manifest.json, mountAt: /etc/stalwart-provisioner/manifest.json }\n processes:\n"); - assertThat(checkRefusals("mail", work.resolve("shared"), shared, above)).isEmpty(); - // A lower level that holds the path replaces what the level above shares at it. - Edit replacing = new Edit( - "mail/mail.project.yml", - " - from: config/manifest.json\n mountAt: /etc/stalwart-provisioner/manifest.json\n", - " - from: config/other.json\n mountAt: /etc/stalwart-provisioner/manifest.json\n"); - List files = edited("mail", work.resolve("replaced"), replacing, above); - Files.writeString(work.resolve("replaced/mail/config/other.json"), "{}\n"); - assertThat(Pipeline.check(files).stream().map(ModelWitnessesTest::described)) - .containsExactly( - "E_UNKNOWN_SIDECAR_ASSET mail.project.yml /applications/0/processes/0/sidecars/0/assets/0"); - } - - @Test - void aClientTakesTheFieldsItsSignInModeTakesAndRequiresWhatItNeedsAndTheLogoutPathIsANativeClientsAlone( - @TempDir Path work) throws IOException { - Edit logout = new Edit( - "identity/identity.project.yml", - " redirectPaths: [/callback, /silent-renew]\n", - " redirectPaths: [/callback, /silent-renew]\n backChannelLogoutPath: /logout/backchannel\n"); - Path native_ = renderedWith("identity", work.resolve("native"), logout); - String client = Files.readString(native_.resolve("apps/identity/portal/client.yaml")); - assertThat(client) - .contains( - " - https://home.jorisjonkers.dev/silent-renew\n" - + " backChannelLogoutUri: https://home.jorisjonkers.dev/logout/backchannel\n credential: pkce\n"); - assertThat(rendered("identity", "apps/identity/portal/client.yaml")).doesNotContain("backChannelLogoutUri"); - - String gated = "identity.project.yml /applications/2/client/"; - assertThat(checkRefusals( - "identity", - work.resolve("gated"), - new Edit( - "identity/identity.project.yml", - " iconPath: /favicon.ico\n", - " iconPath: /favicon.ico\n backChannelLogoutPath: /logout\n credential: pkce\n" - + " redirectPaths: [/callback]\n protectedPath: /api\n"))) - .containsExactlyInAnyOrder( - "E_CLIENT_FIELD_FOR_MODE " + gated + "redirectPaths", - "E_CLIENT_FIELD_FOR_MODE " + gated + "protectedPath", - "E_CLIENT_FIELD_FOR_MODE " + gated + "backChannelLogoutPath", - "E_CLIENT_FIELD_FOR_MODE " + gated + "credential"); - assertThat(checkRefusals( - "identity", - work.resolve("missing"), - new Edit("identity/identity.project.yml", " label: Who am I\n", ""))) - .containsExactly("E_CLIENT_FIELD_FOR_MODE " + gated.substring(0, gated.length() - 1)); - assertThat(checkRefusals( - "identity", - work.resolve("nativeless"), - new Edit("identity/identity.project.yml", " credential: pkce\n", ""))) - .containsExactly("E_CLIENT_FIELD_FOR_MODE identity.project.yml /applications/1/client"); - assertThat( - checkRefusals( - "identity", - work.resolve("token"), - new Edit( - "identity/identity.project.yml", - " signIn: gated\n label: Who am I\n iconPath: /favicon.ico\n", - " signIn: token\n label: Who am I\n description: d\n iconPath: /favicon.ico\n launchPath: /\n"))) - .contains( - "E_CLIENT_FIELD_FOR_MODE " + gated + "label", - "E_CLIENT_FIELD_FOR_MODE " + gated + "description", - "E_CLIENT_FIELD_FOR_MODE " + gated + "iconPath", - "E_CLIENT_FIELD_FOR_MODE " + gated + "launchPath"); - } - - @Test - void theL4SpeakerStartsOnMetalLbZeroFifteenThreeReadingSecretsInItsOwnNamespaceAlone() { - String speaker = rendered("node", "apps/node/l4-speaker/workload.yaml"); - assertThat(speaker) - .contains("- name: METALLB_POD_NAME\n valueFrom:\n fieldRef:\n" - + " fieldPath: metadata.name\n"); - - String rbac = rendered("node", "apps/node/l4-speaker/rbac.yaml"); - assertThat(object(rbac, "ClusterRole", "node:l4-speaker")) - .contains(" - configurationstates\n - configurationstates/status\n") - .doesNotContain("secrets"); - assertThat(object(rbac, "ClusterRole", "node:l4-controller")) - .contains(" - services\n - namespaces\n - nodes\n") - .contains(" - configurationstates\n") - .doesNotContain("secrets"); - String speakerRole = object(rbac, "Role", "l4-speaker"); - assertThat(speakerRole) - .contains(" namespace: node-system\n") - .contains(" - secrets\n - configmaps\n") - .contains(" - servicebgpstatuses\n"); - assertThat(object(rbac, "Role", "l4-controller")) - .contains(" - secrets\n - configmaps\n") - .doesNotContain("servicebgpstatuses"); - assertThat(object(rbac, "RoleBinding", "l4-speaker")) - .contains(" kind: Role\n name: l4-speaker\n") - .contains(" name: l4-speaker\n namespace: node-system"); - } - - @Test - void theGpuDeviceHandsOutEachCardByItsIndex() { - assertThat(rendered("node", "apps/node/gpu-device/workload.yaml")) - .contains("- name: DEVICE_ID_STRATEGY\n value: index\n"); - } - - @Test - void theL4SpeakerRunsMemberlistKeyedByTheNodeProjectsOwnGeneratedKeyAndWithoutAPolicyJobNone(@TempDir Path work) - throws IOException { - assertThat(rendered("node", "apps/node/l4-speaker/workload.yaml")) - .contains("- name: METALLB_ML_BIND_ADDR\n valueFrom:\n fieldRef:\n" - + " fieldPath: status.podIP\n") - .contains("- name: METALLB_ML_LABELS\n value: app.kubernetes.io/name=l4-speaker\n") - .contains("- name: METALLB_ML_BIND_PORT\n value: \"7946\"\n") - .contains("- name: METALLB_ML_SECRET_KEY_PATH\n value: /etc/ml_secret_key\n") - .contains(" - name: memberlist\n mountPath: /etc/ml_secret_key\n") - .contains("secretName: l4-speaker-memberlist\n"); - String synced = - object(rendered("node", "apps/node/l4-speaker/vso.yaml"), "VaultStaticSecret", "l4-speaker-memberlist"); - assertThat(synced) - .contains(" vaultAuthRef: l4-speaker\n") - .contains(" path: node-system/l4-speaker\n") - .contains(" - kind: DaemonSet\n name: l4-speaker\n"); - String policies = "apps/node/vault-policy/policies/"; - assertThat(capabilities( - rendered("node", policies + "node-system-l4-speaker.policy.json"), - "secret/data/node-system/l4-speaker")) - .containsExactly("read"); - assertThat(rendered("node", policies + "node-system.generated.json")) - .contains("\"path\": \"secret/data/node-system/l4-speaker\"") - .contains("\"key\": \"secretkey\""); - assertThat(rendered("node", "apps/node/kustomization.yaml")) - .contains(" - vault-policy\n - vaultconnection.yaml\n"); - - Path unkeyed = renderedWith( - "node", - work, - new Edit( - PLATFORM_DOCUMENT, - "policyJob:\n image: vault-policy\n role: policy-admin\n memory: 64Mi\n cpu: 10m\n" - + " deadline: 120s\n", - "")); - assertThat(Files.readString(unkeyed.resolve("apps/node/l4-speaker/workload.yaml"))) - .contains("METALLB_POD_NAME") - .doesNotContain("METALLB_ML_") - .doesNotContain("memberlist"); - assertThat(unkeyed.resolve("apps/node/l4-speaker/vso.yaml")).doesNotExist(); - assertThat(unkeyed.resolve("apps/node/vault-policy")).doesNotExist(); - assertThat(unkeyed.resolve("apps/node/vaultconnection.yaml")).doesNotExist(); - } - - @Test - void aMongoResolvesItsOwnServiceNameToItselfAndAProcessOfAnyOtherEngineToNothing() { - assertThat(rendered("data", "apps/data/platform-mongo/workload.yaml")) - .contains(" hostAliases:\n - ip: 127.0.0.1\n hostnames:\n" - + " - mongo.data-system.svc.cluster.local\n"); - assertThat(rendered("data", "apps/data/platform-postgres/workload.yaml")) - .doesNotContain("hostAliases"); - assertThat(rendered("auth", "apps/auth/auth/workload.yaml")).doesNotContain("hostAliases"); - } - - @Test - void anHourlyPolicyOrCatalogRunGivesUpWithinTheHourAndTheOneShotJobRetriesUntilItSucceeds() { - for (String[] hourly : new String[][] { - {"auth", "apps/auth/vault-policy/cronjob.yaml"}, - {"knowledge-platform:data", "apps/data/platform-postgres/postgres-catalog.yaml"} - }) { - assertThat(object( - rendered(hourly[0], hourly[1]), - "CronJob", - hourly[1].contains("catalog") ? "postgres-catalog" : "vault-policy")) - .as(hourly[1]) - .contains(" backoffLimit: 6\n activeDeadlineSeconds: 3000\n"); - } - // The one-shot Job's pod keeps the attempt deadline every pod of it has; the Job itself none. - assertThat(rendered("auth", "apps/auth/vault-policy/job.yaml")) - .contains("spec:\n backoffLimit: 2147483647\n template:\n"); - } - - @Test - void theMonitoringStacksPrometheusAndAlertmanagerRenderAsTheOperatorsObjectsAndAProcessItCannotRunIsRefused( - @TempDir Path work) throws IOException { - String prometheus = rendered("observability", "apps/observability/prometheus/workload.yaml"); - assertThat(prometheus) - .contains("kind: Prometheus\n") - .contains(" portName: http\n") - .contains(" - name: prometheus\n") - .contains(" serviceMonitorSelector:\n matchLabels:\n release: metrics-stack\n") - .contains(" ruleSelector:\n matchLabels:\n app.kubernetes.io/managed-by: deploy-kit\n") - .contains(" - namespace: observability-system\n name: alertmanager\n port: http\n") - .doesNotContain("app.kubernetes.io/instance: prometheus\n app.kubernetes.io/part-of: prometheus\n" - + " app.kubernetes.io/managed-by"); - assertThat(rendered("observability", "apps/observability/alertmanager/workload.yaml")) - .contains("kind: Alertmanager\n") - .contains(" alertmanagerConfigSelector:\n matchLabels:\n") - .contains(" alertmanagerConfigMatcherStrategy:\n type: None\n"); - - Path flagged = renderedWith( - "observability", - work, - new Edit( - "observability/observability.project.yml", - " writablePaths: [/prometheus]\n", - " writablePaths: [/prometheus]\n args: [--storage.tsdb.retention.time=7d," - + " --storage.tsdb.retention.time=15d, --enable-feature=exemplar-storage," - + " --web.enable-remote-write-receiver, --log.level=debug, --query.max-concurrency]\n"), - new Edit( - "observability/observability.project.yml", - " writablePaths: [/alertmanager]\n", - " writablePaths: [/alertmanager]\n secrets:\n" - + " - path: secret/data/platform/alertmanager/extra\n" - + " keys: [token]\n access: read\n delivery: env\n" - + " rotation: {tolerates: restart}\n")); - assertThat(Files.readString(flagged.resolve("apps/observability/prometheus/workload.yaml"))) - .contains(" additionalArgs:\n - name: log.level\n value: debug\n" - + " - name: query.max-concurrency\n") - .contains(" retention: 15d\n") - .contains(" enableRemoteWriteReceiver: true\n") - .contains(" enableFeatures:\n - exemplar-storage\n") - .doesNotContain("7d"); - assertThat(Files.readString(flagged.resolve("apps/observability/alertmanager/vso.yaml"))) - .contains(" rolloutRestartTargets:\n - kind: StatefulSet\n name: alertmanager-alertmanager\n"); - - assertThat(refusal("operated-process")) - .containsExactlyInAnyOrder( - "E_OPERATED_PROCESS /applications/0/processes/0/args/0", - "E_OPERATED_PROCESS /applications/0/processes/0/cutover", - "E_OPERATED_PROCESS /applications/1/processes/0/provides"); - } - - @Test - void everyProcessThatAnswersATierHoldsTheApiAccessItsProxyReadsRoutesWithAndNoApiAccessBlockIsRefused() - throws IOException { - String rbac = rendered("edge", "apps/edge/traefik-public/rbac.yaml"); - assertThat(object(rbac, "ClusterRole", "edge-system-traefik-public")) - .contains(" - services\n - secrets\n - nodes\n - configmaps\n - namespaces\n") - .contains(" - traefik.io\n") - .contains(" - ingressroutes\n") - .contains(" - tlsstores\n"); - assertThat(rendered("edge", "apps/edge/traefik-lan/workload.yaml")) - .contains("automountServiceAccountToken: true\n"); - assertThat(rendered("edge", "apps/edge/traefik-lan/networkpolicy.yaml")).contains("cidr: 10.43.0.1/32\n"); - assertThat(refusal("no-api-access-policy")) - .containsExactly("E_NO_API_ACCESS_POLICY /applications/0/processes/0"); - } - - @Test - void aTlsTierThatIssuesNoCertificateServesTheOneItReadsFromTheSecretStoreAndElsewhereItIsRefused(@TempDir Path work) - throws IOException { - String from = "secret/data/platform/tls/wildcard"; - Edit tls = new Edit( - PLATFORM_DOCUMENT, - "listener: plain\n certificates: none\n", - "listener: tls\n certificates: none\n certificateFrom: " + from + "\n"); - Path held = renderedWith( - "edge", - work.resolve("held"), - tls, - new Edit( - "edge/edge.project.yml", - " web: 8000\n admin: 8080\n", - " web: 8000\n websecure: 8443\n admin: 8080\n")); - assertThat(Files.readString(held.resolve("apps/edge/traefik-lan/tlsstore.yaml"))) - .contains("kind: TLSStore\nmetadata:\n name: default\n namespace: edge-system\n") - .contains(" app.kubernetes.io/part-of: traefik-lan\n") - .contains(" defaultCertificate:\n secretName: traefik-lan-platform-tls-wildcard\n"); - assertThat(Files.readString(held.resolve("apps/edge/traefik-lan/kustomization.yaml"))) - .contains(" - tlsstore.yaml\n"); - String synced = object( - Files.readString(held.resolve("apps/edge/traefik-lan/vso.yaml")), - "VaultStaticSecret", - "traefik-lan-platform-tls-wildcard"); - assertThat(synced) - .contains(" vaultAuthRef: traefik-lan\n") - .contains(" path: platform/tls/wildcard\n") - .doesNotContain("rolloutRestartTargets"); - assertThat(Files.readString(held.resolve("apps/edge/traefik-lan/workload.yaml"))) - .doesNotContain("traefik-lan-platform-tls-wildcard"); - assertThat(held.resolve("apps/edge/traefik-public/tlsstore.yaml")).doesNotExist(); - - assertThat(refusal("certificate-from-unserved")) - .containsExactly("E_CERTIFICATE_FROM_UNSERVED /tiers/0/certificateFrom"); - assertThat(refusal("certificate-from-repeated")) - .containsExactly("E_CERTIFICATE_FROM_REPEATED /tiers/1/certificateFrom"); - Path platform = work.resolve("storeless/platform.intent.yml"); - Files.createDirectories(platform.getParent()); - Files.writeString( - platform, - Examples.read(PLATFORM_DOCUMENT) - .replace( - "listener: plain\n certificates: none\n", - "listener: tls\n certificates: none\n certificateFrom: " + from + "\n") - .replace("secretStore: secrets/vault\n", "")); - assertThat(Pipeline.check(List.of(platform)).stream().map(ModelWitnessesTest::described)) - .contains("E_NO_SECRET_STORE platform.intent.yml /tiers/1/certificateFrom"); - } - - /** - * A generated key that adopts a value keeps the location it adopts from through the lowering, so - * the Vault policy job is handed that path and key beside the key's defaults. The adopting key and - * the expected document are the production implementation's render test's; the grant is - * delivered as a file here, since a {@code self} grant needs an env file that wires a Vault client. - */ - @Test - void aGeneratedKeyThatAdoptsAValueHandsTheVaultPolicyJobTheLocationItAdoptsFrom(@TempDir Path work) - throws IOException { - Path adopting = renderedWith( - "data", - work, - new Edit( - "data/data.project.yml", - " - path: secret/data/platform/postgres/exporter\n" - + " keys: [datasource]\n", - " - path: secret/data/data-system/exporter\n" - + " keys: [{ name: datasource, generate: { adopt: " - + "\"secret/data/platform/postgres/exporter#datasource\" } }]\n" - + " access: read\n" - + " delivery: file\n" - + " mountAt: /run/secrets/exporter\n" - + " fileMode: \"0400\"\n" - + " rotation: {tolerates: restart}\n" - + " - path: secret/data/platform/postgres/exporter\n" - + " keys: [datasource]\n")); - - assertThat(Files.readString(adopting.resolve("apps/data/vault-policy/policies/data-system.generated.json"))) - .isEqualTo("{\n \"keys\": [\n {\n" - + " \"path\": \"secret/data/data-system/exporter\",\n" - + " \"key\": \"datasource\",\n" - + " \"bytes\": 32,\n" - + " \"encoding\": \"hex\",\n" - + " \"adopt\": {\n" - + " \"path\": \"secret/data/platform/postgres/exporter\",\n" - + " \"key\": \"datasource\"\n" - + " }\n" - + " }\n ]\n}\n"); - } - - @Test - void theMonitoringStacksGrafanaRendersItsInstanceReadsOneGeneratedAdminAndDerivesItsDataSources(@TempDir Path work) - throws IOException { - assertThat(rendered("observability", "apps/observability/grafana/grafana.yaml")) - .contains("kind: Grafana\n") - .contains(" dashboards: grafana\n") - .contains(" url: http://grafana.observability-system:3000\n") - .contains(" adminUser:\n name: grafana-observability-system-grafana-admin\n key: user\n") - .contains(" adminPassword:\n name: grafana-observability-system-grafana-admin\n" - + " key: password\n"); - assertThat(rendered("observability", "apps/observability/grafana/workload.yaml")) - .contains("- name: GF_SECURITY_ADMIN_PASSWORD\n") - .contains("- name: GF_SECURITY_ADMIN_USER\n"); - assertThat(rendered( - "observability", - "apps/observability/vault-policy/policies/observability-system.generated.json")) - .contains("\"path\": \"secret/data/observability-system/grafana-admin\""); - - Path sourced = renderedWith( - "observability", - work.resolve("sourced"), - new Edit( - "observability/observability.project.yml", - " writablePaths: [/var/lib/grafana]\n", - " writablePaths: [/var/lib/grafana]\n dependsOn:\n" - + " - {application: prometheus, surface: http}\n" - + " - {application: tempo, surface: http}\n")); - String configMap = Files.readString(sourced.resolve("apps/observability/grafana/configmap.yaml")); - assertThat(configMap) - .contains("datasources.yaml") - .contains("\"uid\": \"prometheus\"") - .contains("\"uid\": \"tempo\"") - .contains("\"isDefault\": true") - .contains("\"datasourceUid\": \"tempo\"") - .doesNotContain("\"uid\": \"loki\""); - assertThat(Files.readString(sourced.resolve("apps/observability/grafana/workload.yaml"))) - .contains("mountPath: /etc/grafana/provisioning/datasources/datasources.yaml\n"); - - assertThat(checkRefusals( - "observability", - work.resolve("unknown"), - new Edit( - PLATFORM_DOCUMENT, - " loki: observability/loki\n", - " loki: observability/nowhere\n"))) - .contains("E_UNKNOWN_MONITORING_APPLICATION platform.intent.yml /monitoring/stores/loki"); - assertThat(checkRefusals( - "observability", - work.resolve("rules"), - new Edit( - "observability/observability.project.yml", - " - id: loki\n", - " - id: loki\n alertRules:\n - {from: rules/platform.yaml}\n"))) - .contains("E_ALERT_RULES_OUTSIDE_MONITORING observability.project.yml /applications/6/alertRules"); - } - - @Test - void theMetricsStackScrapesK3sWhereTheBootstrapSetRecordsItAndAComponentItDoesNotRecordIsNotScraped( - @TempDir Path work) throws IOException { - String monitors = rendered("observability", "apps/observability/prometheus/k3s-monitors.yaml"); - assertThat(object(monitors, "Secret", "prometheus-token")) - .contains(" kubernetes.io/service-account.name: prometheus\n"); - assertThat(object(monitors, "ClusterRole", "observability-system-prometheus-k3s")) - .contains(" - nodes/metrics\n") - .contains(" - nonResourceURLs:\n - /metrics\n"); - assertThat(object(monitors, "ScrapeConfig", "kubelet-cadvisor")) - .contains(" metricsPath: /metrics/cadvisor\n") - .contains(" replacement: $1:10250\n") - .contains(" release: metrics-stack\n"); - assertThat(object(monitors, "ServiceMonitor", "apiserver")) - .contains(" - default\n") - .contains(" - port: https\n"); - assertThat(object(monitors, "PodMonitor", "coredns")) - .contains(" - kube-system\n") - .contains(" - portNumber: 9153\n"); - assertThat(rendered("observability", "apps/observability/prometheus/workload.yaml")) - .contains( - " scrapeConfigSelector:\n matchLabels:\n app.kubernetes.io/managed-by: deploy-kit\n"); - - Path dnsless = renderedWith( - "observability", - work.resolve("dnsless"), - new Edit(PLATFORM_DOCUMENT, " coreDns: {port: 9153}\n", "")); - assertThat(Files.readString(dnsless.resolve("apps/observability/prometheus/k3s-monitors.yaml"))) - .contains("kind: ServiceMonitor\n") - .doesNotContain("kind: PodMonitor\n"); - Path unrecorded = renderedWith( - "observability", - work.resolve("unrecorded"), - new Edit( - PLATFORM_DOCUMENT, - " k3s:\n metrics:\n kubelet: {port: 10250}\n" - + " apiServer: {service: default/kubernetes, port: https}\n" - + " coreDns: {port: 9153}\n", - "")); - assertThat(unrecorded.resolve("apps/observability/prometheus/k3s-monitors.yaml")) - .doesNotExist(); - } - - /** - * An exporter whose series describe other objects keeps their labels where its scrape says so, and - * only there (spec/v1/10-project-intent.md#observability); and an API rule may name {@code - * deletecollection}, which an operator that empties its own cache on start needs (deploy-kit#781). - */ - @Test - void aScrapeKeepsItsTargetsLabelsOnlyWhereItSaysSoAndAnApiRuleMayNameDeletecollection(@TempDir Path work) - throws IOException { - assertThat(rendered("minimal", "apps/notes/notes/podmonitor.yaml")).doesNotContain("honorLabels"); - Path honoring = renderedWith( - "minimal", - work.resolve("honoring"), - new Edit( - "minimal/notes.project.yml", - " path: /metrics\n", - " path: /metrics\n honorLabels: true\n")); - assertThat(Files.readString(honoring.resolve("apps/notes/notes/podmonitor.yaml"))) - .contains(" scrapeTimeout: 10s\n honorLabels: true\n"); - - Path clearing = renderedWith( - "secrets", - work.resolve("clearing"), - new Edit( - "secrets/secrets.project.yml", - "vaultconnections/status]\n verbs: [get, list, watch, create, update, patch, delete]\n", - "vaultconnections/status]\n" - + " verbs: [get, list, watch, create, update, patch, delete, deletecollection]\n")); - assertThat(Files.readString(clearing.resolve("apps/secrets/vault-secrets-operator/rbac.yaml"))) - .contains(" - delete\n - deletecollection\n"); - } - - @Test - void anAcmeTiersClaimIsNamedForItsProxysProcessAndAVolumeUnderItIsRefused(@TempDir Path work) throws IOException { - assertThat(rendered("edge", "apps/edge/traefik-public/pvc.yaml")).contains(" name: traefik-public-acme\n"); - - // Two acme tiers' proxies in one Project hold two claims. - Path both = renderedWith( - "edge", - work.resolve("both"), - new Edit( - "platform/platform.intent.yml", - " listener: plain\n certificates: none\n traefik: edge/traefik-lan", - " listener: tls\n certificates: acme\n traefik: edge/traefik-lan"), - new Edit( - "edge/edge.project.yml", - " web: 8000\n admin: 8080\n", - " web: 8000\n websecure: 8443\n admin: 8080\n")); - assertThat(Files.readString(both.resolve("apps/edge/traefik-public/pvc.yaml"))) - .contains(" name: traefik-public-acme\n"); - assertThat(Files.readString(both.resolve("apps/edge/traefik-lan/pvc.yaml"))) - .contains(" name: traefik-lan-acme\n"); - - assertThat(claiming(work.resolve("acme"), "edge-proxy-acme", "certificates: acme")) - .containsExactly("/applications/0/processes/0/volumes/0"); - assertThat(claiming(work.resolve("other"), "edge-proxy-data", "certificates: acme")) - .isEmpty(); - assertThat(claiming(work.resolve("none"), "edge-proxy-acme", "certificates: none")) - .isEmpty(); - } - - /** - * The paths {@code E_DUPLICATE_CLAIM} refuses in the acme proxy fixture, its proxy given a volume - * under {@code claim} and its tier issuing {@code certificates}. - */ - private static List claiming(Path work, String claim, String certificates) throws IOException { - copy(Examples.of("refusals/acme-proxy-replicated"), work); - Path platform = work.resolve("platform.intent.yml"); - Files.writeString(platform, Files.readString(platform).replace("certificates: acme", certificates)); - Path project = work.resolve("refusals.project.yml"); - Files.writeString( - project, - Files.readString(project) - .replace( - " cutover: continuous\n", - " cutover: interrupted\n volumes:\n - { claim: " + claim - + ", mountAt: /data, size: 1Gi, durability: reconstructible }\n")); - return Pipeline.check(List.of(platform, project)).stream() - .filter(diagnostic -> diagnostic.code().equals("E_DUPLICATE_CLAIM")) - .map(Diagnostic::path) - .toList(); - } - - @Test - void anAcmeProxysPodReownsItsVolumeOnlyWhileItsRootDoesNotMatchAndNoOtherPodSaysSo() { - assertThat(rendered("edge", "apps/edge/traefik-public/workload.yaml")) - .contains(" fsGroup: 65532\n fsGroupChangePolicy: OnRootMismatch\n"); - assertThat(rendered("edge", "apps/edge/traefik-lan/workload.yaml")).doesNotContain("fsGroupChangePolicy"); - assertThat(rendered("data", "apps/data/platform-postgres/workload.yaml")) - .contains("fsGroup: ") - .doesNotContain("fsGroupChangePolicy"); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/NodeAgentChecksTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/NodeAgentChecksTest.java deleted file mode 100644 index 13ed20c57..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/NodeAgentChecksTest.java +++ /dev/null @@ -1,124 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.Gpu; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.Node; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.NodeContract; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.PinnedInputsFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.NodeAddress; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.NodeAgentPolicy; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.NodeAgents; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.PoolAddress; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import java.util.List; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; -import org.junit.jupiter.api.Test; - -/** Which Node Agents the node contract and the Platform document derive, and which the catalog names no image for. */ -class NodeAgentChecksTest { - - private static final ProjectIntentFactory INTENT = ProjectIntentFactory.eINSTANCE; - - private static Node node(String name, String site, String... vendors) { - Node node = PinnedInputsFactory.eINSTANCE.createNode(); - node.setName(name); - node.setSite(site); - for (String vendor : vendors) { - Gpu card = PinnedInputsFactory.eINSTANCE.createGpu(); - card.setVendor(vendor); - node.getGpus().add(card); - } - return node; - } - - private static NodeContract contract(Node... nodes) { - NodeContract contract = PinnedInputsFactory.eINSTANCE.createNodeContract(); - contract.getNodes().addAll(List.of(nodes)); - return contract; - } - - /** A Platform document with a pool at {@code site} when given one, and a catalog of the named agents. */ - private static Platform platform( - String site, boolean gpuDevice, boolean gpuMetrics, boolean nodeMetrics, boolean speaker) { - Platform platform = INTENT.createPlatform(); - new XMIResourceImpl(URI.createURI("platform.intent.yml")).getContents().add(platform); - if (site != null) { - PoolAddress pool = INTENT.createPoolAddress(); - pool.setSite(site); - platform.getL4Addresses().put("pool", pool); - } - // A node's own address derives nothing to announce. - platform.getL4Addresses().put("own", INTENT.createNodeAddress()); - NodeAgents catalog = INTENT.createNodeAgents(); - if (gpuDevice) { - catalog.setGpuDevice(policy()); - } - if (gpuMetrics) { - catalog.setGpuMetrics(policy()); - } - if (nodeMetrics) { - catalog.setNodeMetrics(policy()); - } - if (speaker) { - catalog.setL4Speaker(INTENT.createSpeakerPolicy()); - } - platform.setNodeAgents(catalog); - return platform; - } - - private static NodeAgentPolicy policy() { - return INTENT.createNodeAgentPolicy(); - } - - private static List paths(Platform platform, NodeContract contract) { - return NodeAgentChecks.check(platform, contract).stream() - .map(Diagnostic::path) - .toList(); - } - - @Test - void everyAgentTheFactsDeriveWhoseCatalogEntryIsMissingIsRefusedAtThatEntry() { - NodeContract everything = contract(node("a", "s", "nvidia")); - - assertThat(paths(platform("s", false, false, false, false), everything)) - .containsExactly( - "/nodeAgents/gpu-device", - "/nodeAgents/gpu-metrics", - "/nodeAgents/node-metrics", - "/nodeAgents/l4-speaker"); - assertThat(paths(platform("s", true, true, true, true), everything)).isEmpty(); - assertThat(paths(platform("s", false, true, true, true), everything)).containsExactly("/nodeAgents/gpu-device"); - assertThat(paths(platform("s", true, false, true, true), everything)) - .containsExactly("/nodeAgents/gpu-metrics"); - assertThat(paths(platform("s", true, true, false, true), everything)) - .containsExactly("/nodeAgents/node-metrics"); - assertThat(paths(platform("s", true, true, true, false), everything)).containsExactly("/nodeAgents/l4-speaker"); - } - - @Test - void anAgentNoNodeNeedsIsNotDerivedAndSoNeverRefused() { - assertThat(paths(platform("s", false, false, false, false), contract(node("a", "s", "amd")))) - .containsExactly("/nodeAgents/node-metrics", "/nodeAgents/l4-speaker"); - assertThat(paths(platform("elsewhere", false, false, true, false), contract(node("a", "s")))) - .isEmpty(); - assertThat(paths(platform(null, false, false, false, false), contract())) - .isEmpty(); - } - - @Test - void aPlatformWithNoCatalogAtAllIsRefusedForEveryAgentItDerives() { - Platform bare = platform("s", false, false, false, false); - bare.setNodeAgents(null); - - assertThat(paths(bare, contract(node("a", "s", "nvidia")))).hasSize(4); - assertThat(bare.getL4Addresses().values()).anyMatch(NodeAddress.class::isInstance); - assertThat(NodeAgentChecks.check(bare, contract(node("a", "s")))) - .extracting(Diagnostic::code, Diagnostic::document) - .containsExactly( - org.assertj.core.groups.Tuple.tuple("E_NO_NODE_AGENT_POLICY", "platform.intent.yml"), - org.assertj.core.groups.Tuple.tuple("E_NO_NODE_AGENT_POLICY", "platform.intent.yml")); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OperatedChecksTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OperatedChecksTest.java deleted file mode 100644 index 4911c9674..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OperatedChecksTest.java +++ /dev/null @@ -1,116 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Monitoring; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Process; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import java.util.List; -import java.util.Map; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.InternalEObject; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; -import org.junit.jupiter.api.Test; - -/** The arguments of the monitoring stack's Prometheus and Alertmanager, which the operator runs. */ -class OperatedChecksTest { - - private static final ProjectIntentFactory MODEL = ProjectIntentFactory.eINSTANCE; - - /** A project file `observability.project.yml` declaring a Prometheus and an Alertmanager. */ - private final Project project = project(); - - private final Application prometheus = project.getApplications().get(0); - private final Application alertmanager = project.getApplications().get(1); - - private static Project project() { - Project project = MODEL.createProject(); - project.setProject("observability"); - for (String id : List.of("prometheus", "alertmanager")) { - Application application = MODEL.createApplication(); - application.setId(id); - Process process = MODEL.createProcess(); - process.setName(id); - application.getProcesses().add(process); - project.getApplications().add(application); - } - new XMIResourceImpl(URI.createURI("observability.project.yml")) - .getContents() - .add(project); - return project; - } - - private static Platform platform(Application prometheus, Application alertmanager) { - Platform platform = MODEL.createPlatform(); - Monitoring monitoring = MODEL.createMonitoring(); - monitoring.setPrometheus(prometheus); - monitoring.setAlertmanager(alertmanager); - platform.setMonitoring(monitoring); - return platform; - } - - private List check(Platform platform) { - return OperatedChecks.check(platform, Map.of(project, "observability.project.yml")); - } - - private static void argue(Application application, String... args) { - application.getProcesses().get(0).getArgs().addAll(List.of(args)); - } - - @Test - void aFlagTheOperatorPassesOnIsNotRefused() { - argue(prometheus, "--log.level=debug", "-query.max-concurrency", "--storage.tsdb.retention.time=15d"); - argue(alertmanager, "--data.retention=120h"); - - assertThat(check(platform(prometheus, alertmanager))).isEmpty(); - } - - @Test - void anArgumentThatIsNoFlagOrSetsWhatTheOperatorSetsIsRefusedAtItsEntry() { - argue(prometheus, "--log.level=debug", "serve", "--config.file=/etc/prometheus.yml", "---triple", "--=x"); - argue(alertmanager, "--cluster.peer=elsewhere:9094", "--storage.path", "-config.file=a"); - - assertThat(check(platform(prometheus, alertmanager))) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path) - .containsExactly( - tuple("E_OPERATED_PROCESS", "observability.project.yml", "/applications/0/processes/0/args/1"), - tuple("E_OPERATED_PROCESS", "observability.project.yml", "/applications/0/processes/0/args/2"), - tuple("E_OPERATED_PROCESS", "observability.project.yml", "/applications/0/processes/0/args/3"), - tuple("E_OPERATED_PROCESS", "observability.project.yml", "/applications/0/processes/0/args/4"), - tuple("E_OPERATED_PROCESS", "observability.project.yml", "/applications/1/processes/0/args/0"), - tuple("E_OPERATED_PROCESS", "observability.project.yml", "/applications/1/processes/0/args/1"), - tuple("E_OPERATED_PROCESS", "observability.project.yml", "/applications/1/processes/0/args/2")); - assertThat(check(platform(prometheus, alertmanager))) - .extracting(Diagnostic::message) - .contains( - "prometheus: serve is not a flag, and the operator passes its Prometheus flags alone", - "prometheus: the operator sets --config.file itself", - "alertmanager: the operator sets --cluster.peer itself"); - } - - /** Each kind keeps its own list: a flag one kind's operator sets is the other's to pass on. */ - @Test - void eachKindIsHeldToTheFlagsItsOwnOperatorSets() { - argue(prometheus, "--cluster.peer=x", "--storage.path=/data"); - argue(alertmanager, "--storage.tsdb.path=/data", "--web.enable-lifecycle"); - - assertThat(check(platform(prometheus, alertmanager))).isEmpty(); - } - - @Test - void aRoleOfSeveralProcessesOrNoneDeclaredOrNoMonitoringBlockAsksNoArgument() { - argue(prometheus, "serve"); - Process second = MODEL.createProcess(); - second.setName("second"); - prometheus.getProcesses().add(second); - Application undeclared = MODEL.createApplication(); - ((InternalEObject) undeclared).eSetProxyURI(URI.createURI("observability.project.yml#nowhere")); - - assertThat(check(platform(prometheus, undeclared))).isEmpty(); - assertThat(check(MODEL.createPlatform())).isEmpty(); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OracleDistanceTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OracleDistanceTest.java deleted file mode 100644 index 77c579fac..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OracleDistanceTest.java +++ /dev/null @@ -1,516 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.fasterxml.jackson.databind.ObjectMapper; -import dev.jorisjonkers.deploykit.emf.metamodel.descriptor.DependencyEdges; -import dev.jorisjonkers.deploykit.emf.metamodel.descriptor.DescriptorFile; -import dev.jorisjonkers.deploykit.emf.metamodel.json.CanonicalJson; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.eclipse.emf.common.util.URI; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** - * How far this implementation is from the production implementation's oracles under {@code - * spec/v1/examples/}, which move on before each catch-up. Every oracle is compared through the stage - * harness's comparator; the cases in {@link #PASSING} must match it exactly, and every other case - * prints one line saying how many differences it is from passing. A case that passes and is not - * listed fails too, so the list grows with each catch-up slice and never lags behind it. - */ -class OracleDistanceTest { - - /** The oracle comparisons expected to pass, as {@code }. Each catch-up slice adds to it. */ - static final Set PASSING = Set.of( - "dependencies auth", - "dependencies data", - "dependencies delivery", - "dependencies edge", - "dependencies estate/hindsight", - "dependencies estate/immich", - "dependencies estate/observability", - "dependencies identity", - "dependencies knowledge-platform", - "dependencies minimal", - "dependencies observability", - "dependencies secrets", - "descriptor expected", - "effective auth", - "effective data", - "effective identity", - "effective knowledge-platform", - "effective minimal", - "intent agents", - "intent auth", - "intent data", - "intent delivery", - "intent edge", - "intent estate/hindsight", - "intent estate/immich", - "intent estate/observability", - "intent identity", - "intent knowledge", - "intent knowledge-platform", - "intent mail", - "intent minimal", - "intent observability", - "intent platform", - "intent secrets", - "intent utility", - "refusal acme-proxy-replicated", - "refusal alert-rules-not-found", - "refusal alert-rules-outside-monitoring", - "refusal alert-rules-without-groups", - "refusal asset-not-found", - "refusal backup-surface-not-provided", - "refusal buckets-without-object-store", - "refusal catalog-surface-not-provided", - "refusal certificate-from-repeated", - "refusal certificate-from-unserved", - "refusal client-crd-not-bootstrapped", - "refusal client-path-unrouted", - "refusal client-placeholder-without-secret", - "refusal credentials-without-database", - "refusal cutover-continuous-over-rwo", - "refusal cutover-missing", - "refusal cutover-mixed", - "refusal dashboard-not-found", - "refusal dashboard-without-uid", - "refusal duplicate-backup-claim", - "refusal duplicate-claim", - "refusal duplicate-dashboard-uid", - "refusal duplicate-human-grant", - "refusal duplicate-l4-port", - "refusal duplicate-route-match", - "refusal durability-policy-incomplete", - "refusal durability-without-engine", - "refusal engine-without-durability", - "refusal env-cannot-reload", - "refusal generated-key-adopts-ungranted", - "refusal generated-key-outside-project", - "refusal generated-key-twice", - "refusal generated-key-written-elsewhere", - "refusal illegal-delivery-for-access", - "refusal image-runs-as-root", - "refusal l4-address-exhausted", - "refusal library-not-granted", - "refusal migration-owner-duplicated", - "refusal migration-undeclared", - "refusal migration-ungated", - "refusal migration-without-database", - "refusal mongo-credentials-without-database", - "refusal mongo-without-durability", - "refusal no-acme-policy", - "refusal no-api-access-policy", - "refusal no-dashboard-policy", - "refusal no-delivery-policy", - "refusal no-direct-target", - "refusal no-durability-policy", - "refusal no-engine-policy", - "refusal no-forward-auth-endpoint", - "refusal no-migration-policy", - "refusal no-secret-store", - "refusal no-sign-in-provider", - "refusal no-tier-for-audience", - "refusal no-upstream-nameservers", - "refusal no-vpn-policy", - "refusal node-address-continuous", - "refusal node-address-replicated", - "refusal node-port-taken", - "refusal non-kv-delivery", - "refusal operated-process", - "refusal owner-role-granted", - "refusal placement-incomplete", - "refusal prepare-process-serves", - "refusal process-rbac-grant", - "refusal profile-key-authored", - "refusal redirect-loop", - "refusal release-unit-no-readiness", - "refusal schedule-missing", - "refusal schedule-unscheduled", - "refusal scheduled-process-serves", - "refusal scrape-unknown-process", - "refusal secrets-at-rest-required", - "refusal secrets-at-rest-required-at-header", - "refusal self-without-vault-client", - "refusal shared-declaration-duplicated", - "refusal shared-quantity", - "refusal surface-label-invalid", - "refusal tier-class-unfiltered", - "refusal tier-surface-missing", - "refusal tier-without-ingress-class", - "refusal unauthorised-secret-reference", - "refusal unbound-secret-grant", - "refusal unknown-api-holder", - "refusal unknown-critical-application", - "refusal unknown-enrolled-project", - "refusal unknown-forward-auth-provider", - "refusal unknown-l4-address", - "refusal unknown-library", - "refusal unknown-machinery", - "refusal unknown-monitoring-application", - "refusal unknown-receiver", - "refusal unknown-surface", - "refusal unknown-telemetry-collector", - "refusal unknown-tier-proxy", - "refusal unresolved-placeholder", - "rendered agents", - "rendered auth", - "rendered data", - "rendered delivery", - "rendered edge", - "rendered estate/hindsight", - "rendered estate/immich", - "rendered estate/observability", - "rendered identity", - "rendered knowledge-platform", - "rendered mail", - "rendered minimal", - "rendered node", - "rendered observability", - "rendered platform", - "rendered secrets", - "rendered utility", - "resolved agents", - "resolved auth", - "resolved data-main", - "resolved delivery", - "resolved edge", - "resolved identity", - "resolved knowledge-platform", - "resolved mail", - "resolved minimal-main", - "resolved node", - "resolved observability", - "resolved utility", - "schema-refusal credentials-file-at-root", - "schema-refusal credentials-file-without-mount", - "schema-refusal egress-outside-vocabulary", - "schema-refusal egress-with-range", - "schema-refusal egress-without-reason", - "schema-refusal every-offending-value", - "schema-refusal grant-file-outside-a-directory", - "schema-refusal grant-file-several-keys", - "schema-refusal grant-file-without-mode", - "schema-refusal human-grant-in-a-namespace", - "schema-refusal human-grant-role-outside-vocabulary", - "schema-refusal human-grant-to-a-user", - "schema-refusal human-grant-without-reason", - "schema-refusal missing-field", - "schema-refusal no-shape-matches", - "schema-refusal outside-yaml-subset", - "schema-refusal platform-unknown-field", - "schema-refusal rate-limit-of-no-requests", - "schema-refusal rate-limit-period-in-milliseconds", - "schema-refusal rate-limit-without-period", - "schema-refusal schedule-malformed", - "schema-refusal two-documents", - "schema-refusal unknown-field", - "schema-refusal wrong-type"); - - @Test - void theListedOraclesMatchAndEveryOtherSaysHowFarItIs(@TempDir Path scratch) throws IOException { - Map> distances = distances(scratch); - List summary = new ArrayList<>(); - List failing = new ArrayList<>(); - List unlisted = new ArrayList<>(); - distances.forEach((comparison, differences) -> { - boolean listed = PASSING.contains(comparison); - if (listed && !differences.isEmpty()) { - failing.add( - comparison + ": " + differences.size() + " differences\n " + String.join("\n ", differences)); - } else if (!listed && differences.isEmpty()) { - unlisted.add(comparison); - } else if (!listed) { - summary.add(comparison + ": " + differences.size() + " differences; first: " + differences.get(0)); - } - }); - // Every difference of every comparison, for the reader of one case's distance. - Files.writeString( - Path.of("target", "oracle-distance.txt"), - distances.entrySet().stream() - .map(entry -> entry.getKey() + ": " + entry.getValue().size() + "\n " - + String.join("\n ", entry.getValue())) - .collect(Collectors.joining("\n"))); - System.out.println("Oracle distance, " + (distances.size() - summary.size()) + " of " + distances.size() - + " passing:\n " + String.join("\n ", summary)); - - assertThat(failing) - .withFailMessage("listed as passing, and not:%n%s", String.join("\n", failing)) - .isEmpty(); - assertThat(unlisted) - .withFailMessage("passing, and not listed: add each to PASSING:%n%s", String.join("\n", unlisted)) - .isEmpty(); - assertThat(distances.keySet()).containsAll(PASSING); - } - - /** Every oracle comparison, by {@code }, with every difference it finds. */ - static Map> distances(Path scratch) throws IOException { - Map> distances = new TreeMap<>(); - Path examples = Examples.of(""); - distances.put( - "descriptor expected", - compare( - examples.resolve("expected").resolve(DescriptorFile.NAME), - Files.readAllBytes(DescriptorFile.write(scratch.resolve("descriptor"))))); - for (Path directory : casesWith(examples, "expected/intent.json")) { - distances.put("intent " + name(examples, directory), attempt(() -> { - Parsed parsed = Pipeline.intent(authored(directory)); - return parsed.ok() - ? compare(directory.resolve("expected/intent.json"), json(parsed.intent())) - : refused(parsed.diagnostics()); - })); - } - for (Path directory : casesWith(examples, "expected/effective.json")) { - distances.put("effective " + name(examples, directory), attempt(() -> { - Parsed parsed = Pipeline.effective(authored(directory)); - return parsed.ok() - ? compare(directory.resolve("expected/effective.json"), json(parsed.intent())) - : refused(parsed.diagnostics()); - })); - } - for (Path directory : casesWith(examples, "expected/" + DependencyEdges.NAME)) { - Outputs.Resolving resolving = Outputs.RESOLVED.get(name(examples, directory)); - distances.put( - "dependencies " + name(examples, directory), - resolving == null - ? List.of("no union this implementation resolves") - : attempt(() -> { - Resolved resolved = Pipeline.resolve( - resolving.documents().stream() - .map(Examples::of) - .toList(), - resolving.project(), - Outputs.INTEGRITY); - return resolved.ok() - ? compare( - directory.resolve("expected/" + DependencyEdges.NAME), - json(DependencyEdges.of(resolved.deployment()))) - : refused(resolved.diagnostics()); - })); - } - for (Path directory : casesWith(examples, "rendered")) { - Path rendered = directory.resolve("rendered"); - // The platform's tree is the estate-scoped share every render holds, which a render of - // notes, naming nothing estate-scoped of its own, holds alone. - Outputs.Resolving resolving = Outputs.RESOLVED.get( - name(examples, directory).equals(PLATFORM) ? "minimal" : name(examples, directory)); - Path out = scratch.resolve("rendered").resolve(name(examples, directory)); - distances.put( - "rendered " + name(examples, directory), - resolving == null - ? List.of("no union this implementation renders; " - + Comparison.read(rendered).size() + " files") - : attempt(() -> { - List refusals = Pipeline.render( - resolving.documents().stream() - .map(Examples::of) - .toList(), - List.of(resolving.project()), - Outputs.INTEGRITY, - out); - return refusals.isEmpty() - ? share(examples, rendered, Comparison.read(out)) - : refused(refusals); - })); - } - // A given resolve case is the Resolved Deployment main's rendered tree needs, written by hand. - for (String name : Stages.cases("resolve")) { - String example = name.replaceFirst("-main$", ""); - Outputs.Resolving resolving = Outputs.RESOLVED.get(example); - if (!Stages.given("resolve", name)) { - continue; - } - for (String project : Stages.projects(name)) { - Path given = Stages.expected("resolve", name).resolve(project + Stages.RESOLVED_MODEL); - distances.put( - "resolved " + name, - resolving == null - ? List.of("no union this implementation resolves") - : attempt(() -> { - Resolved resolved = Pipeline.resolve( - resolving.documents().stream() - .map(Examples::of) - .toList(), - project, - Outputs.INTEGRITY); - if (resolved.ok() && regiven(name)) { - Files.write(given, Stages.xmi(given, resolved.deployment())); - } - return resolved.ok() - ? Comparison.files( - given.getFileName().toString(), - URI.createFileURI(given.toString()), - Files.readAllBytes(given), - Stages.xmi(given, resolved.deployment())) - : refused(resolved.diagnostics()); - })); - } - } - for (String kind : List.of("refusals", "schema-refusals")) { - for (Path oracle : diagnosticsOracles(examples.resolve(kind))) { - String stem = oracle.getFileName().toString().replace(DIAGNOSTICS, ""); - Path set = oracle.resolveSibling(stem); - distances.put( - kind.replaceFirst("s$", "") + " " + stem, - attempt(() -> Comparison.json( - oracle.getFileName().toString(), - sorted(JSON.readValue(oracle.toFile(), List.class)), - sorted(Stages.diagnostics( - Files.isDirectory(set) - ? Pipeline.check(documentsIn(set)) - : Pipeline.intent(oracle.resolveSibling(stem + ".project.yml")) - .diagnostics()))))); - } - } - return distances; - } - - private static final String DIAGNOSTICS = ".diagnostics.json"; - - private static final ObjectMapper JSON = new ObjectMapper(); - - /** A list of diagnostics as canonical JSON, in an order neither implementation's run decides. */ - private static String sorted(List diagnostics) { - return CanonicalJson.write(diagnostics.stream() - .map(diagnostic -> (Object) new TreeMap<>((Map) diagnostic)) - .sorted(Comparator.comparing(Object::toString)) - .toList()); - } - - private static List diagnosticsOracles(Path directory) throws IOException { - try (Stream files = Files.list(directory)) { - return files.filter(file -> file.getFileName().toString().endsWith(DIAGNOSTICS)) - .sorted() - .toList(); - } - } - - /** The documents of a refused set: its project files, its Platform document and its images lock, sorted. */ - private static List documentsIn(Path set) throws IOException { - try (Stream files = Files.list(set)) { - return files.filter(file -> { - String name = file.getFileName().toString(); - return name.endsWith(".project.yml") - || name.equals("platform.intent.yml") - || name.equals("images.lock.yml"); - }) - .sorted() - .toList(); - } - } - - /** A step that fails outright, such as a resolution that does not complete, is one difference. */ - private static List attempt(Step step) { - try { - return step.differences(); - } catch (IOException | RuntimeException e) { - return List.of("did not complete: " - + String.valueOf(e.getMessage()).lines().findFirst().orElse("")); - } - } - - @FunctionalInterface - private interface Step { - List differences() throws IOException; - } - - private static List compare(Path oracle, byte[] written) throws IOException { - String name = oracle.getFileName().toString(); - return Comparison.files(name, URI.createFileURI(oracle.toString()), Files.readAllBytes(oracle), written); - } - - /** - * The distance of a rendering from the share a committed tree holds. The production - * implementation commits a Project's own artifact under {@code apps/}, the estate-scoped - * artifact under {@code estate/} and the pinned sources under {@code projects/}, each only in - * the trees that hold its directory, so a rendering is compared on the directories its tree - * holds. A Project's tree that holds the estate-scoped share holds it beside the platform's own - * share, which the platform's tree holds for every render. - */ - private static List share(Path examples, Path committed, Map rendered) { - Set held = Comparison.read(committed).keySet().stream() - .map(name -> name.substring(0, name.indexOf('/') + 1)) - .collect(Collectors.toSet()); - rendered.keySet().removeIf(name -> !held.contains(name.substring(0, name.indexOf('/') + 1))); - Path platform = examples.resolve(PLATFORM).resolve("rendered"); - if (!held.contains(ESTATE + "/") - || committed - .toAbsolutePath() - .normalize() - .equals(platform.toAbsolutePath().normalize())) { - return Comparison.trees(committed, rendered); - } - Set everyRenders = Comparison.read(platform).keySet(); - Map own = new TreeMap<>(rendered); - own.keySet().removeAll(everyRenders); - Map platformShare = new TreeMap<>(rendered); - platformShare.keySet().retainAll(everyRenders); - List distance = new ArrayList<>(Comparison.trees(committed, own)); - distance.addAll(Comparison.trees(platform, platformShare)); - return distance; - } - - private static final String PLATFORM = "platform"; - - /** - * The property naming the given resolve cases a run rewrites from what this implementation - * resolves, comma-separated: a hand-written case is replaced once the rendered tree it drives - * equals main's, so it stops standing in for a resolution that now exists. - */ - static final String REGIVEN = "given.update"; - - private static boolean regiven(String name) { - return List.of(System.getProperty(REGIVEN, "").split(",")).contains(name); - } - - private static final String ESTATE = "estate"; - - private static List refused(List diagnostics) { - return diagnostics.stream() - .map(diagnostic -> "refused: " + diagnostic.code() + " " + diagnostic.document() + " " - + diagnostic.path() + " (" + diagnostic.message() + ")") - .toList(); - } - - private static byte[] json(Object value) { - return CanonicalJson.write(value).getBytes(StandardCharsets.UTF_8); - } - - private static String name(Path examples, Path directory) { - return examples.relativize(directory).toString().replace('\\', '/'); - } - - /** The one authored document of a case: the first project file, or its Platform document. */ - private static Path authored(Path directory) throws IOException { - try (Stream entries = Files.list(directory)) { - return entries.filter(path -> { - String file = path.getFileName().toString(); - return file.endsWith(".project.yml") || file.equals("platform.intent.yml"); - }) - .min(Comparator.naturalOrder()) - .orElseThrow(); - } - } - - /** The case directories under {@code examples} carrying {@code oracle}, a path relative to the case. */ - private static List casesWith(Path examples, String oracle) throws IOException { - try (Stream tree = Files.walk(examples)) { - return tree.filter(path -> path.endsWith(oracle)) - .map(path -> oracle.contains("/") ? path.getParent().getParent() : path.getParent()) - .sorted() - .toList(); - } - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OutputsTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OutputsTest.java deleted file mode 100644 index 039350135..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OutputsTest.java +++ /dev/null @@ -1,426 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assumptions.assumeFalse; - -import java.io.File; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Comparator; -import java.util.List; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** - * What a run of the pipeline leaves behind: the files every parity case is decided from, under this - * module's build output, one directory per case. - */ -class OutputsTest { - - /** Where a run of this module leaves what the parity contract compares, under its build output. */ - private static final Path OUTPUT = Path.of("target", "parity"); - - /** Set by the mutation gate, whose every run of this test is of a mutant (emf/pom.xml). */ - private static final String MUTATING = "emf.mutation"; - - /** - * The cases whose committed rendered trees the composed union writes between them: minimal's - * and data's own, and the platform's estate-scoped share every render holds. - */ - private static final java.util.Set RENDERED_CASES = java.util.Set.of("minimal", "data", "platform"); - - @Test - void aRunLeavesEveryCaseUnderTheModulesBuildOutput() throws IOException { - // The parity module reads what this run leaves, so it is the build's - // own run. Under the mutation gate every run is a mutant's, writing the - // whole corpus once per mutant: the tests beside it, on smaller - // corpora in their own directories, cover what it covers. - assumeFalse(Boolean.getBoolean(MUTATING), "the mutation gate writes no parity outputs"); - Path examples = Examples.of(""); - deleteTree(OUTPUT); - - Outputs.write(examples, OUTPUT); - - assertThat(files(OUTPUT)).containsExactlyElementsOf(everyCasesPairedFile(examples)); - } - - @Test - void anEffectiveCaseAndANegativeFixtureLeaveTheirFiles(@TempDir Path root) throws IOException { - Path examples = root.resolve("examples"); - Path out = root.resolve("out"); - accepted(examples, "minimal"); - touch(examples.resolve("minimal").resolve("expected").resolve("effective.json")); - for (String document : Outputs.RESOLVED.get("minimal").documents()) { - if (!document.startsWith("minimal/")) { - withWhatItReads(examples, document, text -> text); - } - } - copy( - Examples.of("negative/dependency-cycle/intent/notes.yml"), - examples.resolve("negative/dependency-cycle/intent/notes.yml")); - touch(examples.resolve("negative/dependency-cycle.diagnostics.json")); - // A file beside the oracles that is no oracle names no fixture. - touch(examples.resolve("negative/README.md")); - Files.createDirectories(examples.resolve("refusals")); - - Outputs.write(examples, out); - - assertThat(read(out.resolve("minimal/effective.json"))).startsWith("{").endsWith("}"); - Path cycle = out.resolve("negative/dependency-cycle"); - assertThat(files(out.resolve("negative"))) - .containsExactly( - "dependency-cycle/diagnostics.json", - "dependency-cycle/diagnostics.reversed.json", - "dependency-cycle/exit"); - assertThat(read(cycle.resolve("diagnostics.json"))) - .contains("E_DEPENDENCY_CYCLE") - .isEqualTo(read(cycle.resolve("diagnostics.reversed.json"))); - } - - @Test - void everyShapeOfCaseLeavesTheFileItsOracleIsPairedWith(@TempDir Path root) throws IOException { - Path examples = root.resolve("examples"); - Path out = root.resolve("out"); - accepted(examples, "minimal"); - refused(examples, "unknown-surface"); - refused(examples, "no-tier-for-audience"); - - Outputs.write(examples, out); - - assertThat(files(out)) - .containsExactly( - "minimal/exit", - "minimal/intent.json", - "minimal/notes.project.xmi", - "refusals/no-tier-for-audience/diagnostics.json", - "refusals/no-tier-for-audience/exit", - "refusals/no-tier-for-audience/platform.intent.xmi", - "refusals/no-tier-for-audience/refusals.project.xmi", - "refusals/unknown-surface/diagnostics.json", - "refusals/unknown-surface/exit", - "refusals/unknown-surface/unknown-surface.project.xmi"); - assertThat(read(out.resolve("minimal/exit"))).isEqualTo("0"); - assertThat(read(out.resolve("minimal/intent.json"))).startsWith("{").endsWith("}"); - // The same model as an instance of the metamodel, which loads back without the grammar. - assertThat(read(out.resolve("minimal/notes.project.xmi"))) - .contains("projectintent:Project") - .contains("project=\"notes\""); - assertThat(read(out.resolve("refusals/unknown-surface/exit"))).isEqualTo("1"); - assertThat(read(out.resolve("refusals/unknown-surface/diagnostics.json"))) - .contains("E_UNKNOWN_SURFACE"); - assertThat(read(out.resolve("refusals/no-tier-for-audience/exit"))).isEqualTo("1"); - assertThat(read(out.resolve("refusals/no-tier-for-audience/diagnostics.json"))) - .contains("E_NO_TIER_FOR_AUDIENCE"); - // A refused model is written too, and a set's documents link to each other's XMI. - assertThat(read(out.resolve("refusals/unknown-surface/unknown-surface.project.xmi"))) - .contains("projectintent:Project"); - assertThat(read(out.resolve("refusals/no-tier-for-audience/platform.intent.xmi"))) - .contains("projectintent:Platform") - .contains("href=\"refusals.project.xmi#"); - } - - @Test - void aRefusedSetIsCheckedWithItsImagesLock(@TempDir Path root) throws IOException { - Path examples = root.resolve("examples"); - Path out = root.resolve("out"); - refused(examples, "image-runs-as-root"); - - Outputs.write(examples, out); - - // Only the lock says the image runs as root, so the refusal needs the lock read with the set. - assertThat(read(out.resolve("refusals/image-runs-as-root/diagnostics.json"))) - .contains("E_IMAGE_RUNS_AS_ROOT"); - } - - @Test - void aResolutionCaseLeavesItsEdgesItsModelAndTheExtentsItWasResolvedFrom(@TempDir Path root) throws IOException { - Path examples = root.resolve("examples"); - Path out = root.resolve("out"); - resolving(examples, text -> text); - - Outputs.write(examples, out); - - Path minimal = out.resolve("minimal"); - assertThat(read(minimal.resolve("dependencies.json"))) - .isEqualTo(Examples.read("minimal/expected/dependencies.json")); - assertThat(read(minimal.resolve("notes" + Outputs.RESOLVED_MODEL))) - .contains("resolveddeployment:ResolvedDeployment"); - // Every link of the intent extent lands inside it, by root index and path rather than by ID, - // so the extent loads in Eclipse on its own. - String intent = read(minimal.resolve(Outputs.INTENT_MODEL)); - assertThat(intent).doesNotContain("href=").containsPattern("traefik=\"/\\d+/@applications\\.\\d+\""); - assertThat(read(minimal.resolve(Outputs.PINNED_MODEL))).contains("pinnedinputs:NodeContract"); - } - - @Test - void anExtentNamesARootByItsIndexAndAnythingBelowItByItsPathUnderThatRoot() { - Outputs.ByIndex extent = new Outputs.ByIndex(org.eclipse.emf.common.util.URI.createURI("extent.xmi")); - var model = dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory.eINSTANCE; - var first = model.createProject(); - var second = model.createProject(); - var application = model.createApplication(); - application.setId("notes"); - second.getApplications().add(application); - extent.getContents().add(first); - extent.getContents().add(second); - - assertThat(extent.getURIFragment(second)).isEqualTo("/1"); - assertThat(extent.getURIFragment(application)).isEqualTo("/1/@applications.0"); - assertThat(extent.getEObject("/1/@applications.0")).isSameAs(application); - } - - @Test - void aResolutionCaseTheChecksRefuseLeavesItsDiagnostics(@TempDir Path root) throws IOException { - Path examples = root.resolve("examples"); - Path out = root.resolve("out"); - resolving(examples, text -> text.replace("surface: http }", "surface: grpc }")); - - Outputs.write(examples, out); - - assertThat(read(out.resolve("minimal/exit"))).isEqualTo("1"); - assertThat(read(out.resolve("minimal/diagnostics.json"))).contains("E_UNKNOWN_SURFACE"); - assertThat(out.resolve("minimal/dependencies.json")).doesNotExist(); - } - - @Test - void aRenderedUnionTheChecksRefuseLeavesItsDiagnosticsInPlaceOfTheTree(@TempDir Path root) throws IOException { - Path examples = root.resolve("examples"); - Path out = root.resolve("out"); - for (String document : Outputs.RENDERED_UNION.documents()) { - Path target = examples.resolve(document); - Files.createDirectories(target.getParent()); - String text = Examples.read(document); - Files.writeString( - target, - document.equals("minimal/notes.project.yml") - ? text.replace("surface: http }", "surface: grpc }") - : text); - } - Files.createDirectories(examples.resolve("minimal/rendered")); - Files.createDirectories(examples.resolve("refusals")); - - Outputs.write(examples, out); - - assertThat(files(out.resolve(Outputs.RENDERED_TREE))).containsExactly("diagnostics.json", "exit"); - assertThat(read(out.resolve("rendered/diagnostics.json"))).contains("E_UNKNOWN_SURFACE"); - } - - /** minimal's resolution set, copied out of the real examples, its project file passed through {@code edit}. */ - private static void resolving(Path examples, java.util.function.UnaryOperator edit) throws IOException { - for (String document : Outputs.RESOLVED.get("minimal").documents()) { - withWhatItReads(examples, document, document.equals("minimal/notes.project.yml") ? edit : text -> text); - } - touch(examples.resolve("minimal/expected/dependencies.json")); - Files.createDirectories(examples.resolve("refusals")); - } - - @Test - void aRefusedFileThatHoldsNoDocumentLeavesNoModel(@TempDir Path root) throws IOException { - Path examples = root.resolve("examples"); - Path out = root.resolve("out"); - touch(examples.resolve("refusals/empty.project.yml")); - touch(examples.resolve("refusals/empty.diagnostics.json")); - - Outputs.write(examples, out); - - assertThat(files(out)).containsExactly("refusals/empty/diagnostics.json", "refusals/empty/exit"); - } - - @Test - void aSetTheRunAcceptsLeavesAnEmptyRefusalAndExitZero(@TempDir Path root) throws IOException { - Path examples = root.resolve("examples"); - Path out = root.resolve("out"); - copy(Examples.of("minimal/notes.project.yml"), examples.resolve("refusals/holds/notes.project.yml")); - touch(examples.resolve("refusals/holds.diagnostics.json")); - - Outputs.write(examples, out); - - assertThat(read(out.resolve("refusals/holds/diagnostics.json"))).isEqualTo("[]"); - assertThat(read(out.resolve("refusals/holds/exit"))).isEqualTo("0"); - } - - /** - * The file every oracle under {@code examples} is paired with, and the exit code beside it, read - * from the oracles rather than from the run, so a case the run skipped is a missing file here. - */ - private static List everyCasesPairedFile(Path examples) throws IOException { - try (Stream tree = Files.walk(examples)) { - return tree.flatMap(oracle -> pairedFiles(examples, oracle)) - .sorted() - .toList(); - } - } - - private static Stream pairedFiles(Path examples, Path oracle) { - String name = oracle.getFileName().toString(); - Path relative = examples.relativize(oracle); - // A committed rendered tree the composed union writes, file for file, under one tree. - if (relative.getNameCount() > 2 - && relative.getName(1).toString().equals(Outputs.RENDERED_TREE) - && RENDERED_CASES.contains(relative.getName(0).toString()) - && Files.isRegularFile(oracle) - && !name.equals("README.md")) { - return Stream.of(Outputs.RENDERED_TREE + "/" + relative.subpath(2, relative.getNameCount())); - } - if (oracle.endsWith("expected/intent.json")) { - String directory = relative(examples, oracle.getParent().getParent()); - Stream models = documents(oracle.getParent().getParent()) - .limit(1) - .map(document -> directory + "/" + model(document)); - return Stream.concat(Stream.of(directory + "/exit", directory + "/intent.json"), models); - } - if (oracle.endsWith("expected/dependencies.json")) { - String directory = relative(examples, oracle.getParent().getParent()); - Outputs.Resolving resolving = Outputs.RESOLVED.get(directory); - return resolving == null - ? Stream.empty() - : Stream.of( - directory + "/dependencies.json", - directory + "/" + resolving.project() + Outputs.RESOLVED_MODEL, - directory + "/" + Outputs.INTENT_MODEL, - directory + "/" + Outputs.PINNED_MODEL); - } - if (oracle.endsWith("expected/effective.json")) { - return Stream.of(relative(examples, oracle.getParent().getParent()) + "/effective.json"); - } - // A negative fixture is read in both orders of its fragments. - if (name.endsWith(".diagnostics.json") - && oracle.getParent().getFileName().toString().equals("negative")) { - String directory = "negative/" + name.replace(".diagnostics.json", ""); - return Stream.of( - directory + "/diagnostics.json", directory + "/diagnostics.reversed.json", directory + "/exit"); - } - // Only a refusal under refusals/ binds this implementation; a schema refusal binds the - // production implementation alone (docs/architecture.md#the-parity-contract). - if (name.endsWith(".diagnostics.json") - && oracle.getParent().getFileName().toString().equals("refusals")) { - String stem = name.replace(".diagnostics.json", ""); - String directory = "refusals/" + stem; - Path set = oracle.resolveSibling(stem); - Stream models = Files.isDirectory(set) - ? documents(set).map(document -> directory + "/" + model(document)) - : Stream.of(directory + "/" + stem + ".project.xmi"); - return Stream.concat(Stream.of(directory + "/diagnostics.json", directory + "/exit"), models); - } - return Stream.empty(); - } - - /** What the XMI of the authored document named {@code document} is called. */ - private static String model(String document) { - return document.replaceFirst("\\.yml$", ".xmi"); - } - - /** The file names of the authored documents in {@code set}, sorted. */ - private static Stream documents(Path set) { - try (Stream entries = Files.list(set)) { - return entries - .map(path -> path.getFileName().toString()) - .filter(name -> name.endsWith(".project.yml") || name.equals("platform.intent.yml")) - .sorted() - .toList() - .stream(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** A case the pipeline accepts, copied out of the real examples with an oracle beside it. */ - private static void accepted(Path examples, String name) throws IOException { - copyDocuments(Examples.of(name), examples.resolve(name)); - touch(examples.resolve(name).resolve("expected").resolve("intent.json")); - } - - /** A case the pipeline refuses, whether its input is one file or a set, with an oracle beside it. */ - private static void refused(Path examples, String stem) throws IOException { - Path source = Examples.of("refusals/" + stem); - Path refusals = examples.resolve("refusals"); - if (Files.isDirectory(source)) { - copyDocuments(source, refusals.resolve(stem)); - } else { - copy(Examples.of("refusals/" + stem + ".project.yml"), refusals.resolve(stem + ".project.yml")); - } - touch(refusals.resolve(stem + ".diagnostics.json")); - } - - /** - * {@code document}, edited, with every file it reads beside it (its env files, its Assets and its - * dashboards), and none of its directory's oracles, so the copy is no case of its own. - */ - private static void withWhatItReads(Path examples, String document, java.util.function.UnaryOperator edit) - throws IOException { - Path target = examples.resolve(document); - Files.createDirectories(target.getParent()); - Files.writeString(target, edit.apply(Examples.read(document))); - Path source = Examples.of(document).getParent(); - try (Stream tree = Files.walk(source)) { - for (Path file : tree.filter(Files::isRegularFile) - .filter(file -> source.relativize(file).getNameCount() > 1) - .filter(file -> !List.of("expected", "rendered") - .contains(source.relativize(file).getName(0).toString())) - .toList()) { - Path copied = target.getParent().resolve(source.relativize(file).toString()); - if (!Files.exists(copied)) { - copy(file, copied); - } - } - } - } - - /** Every authored document of {@code source}, and nothing else a case's directory happens to hold. */ - private static void copyDocuments(Path source, Path directory) throws IOException { - try (Stream tree = Files.list(source)) { - for (Path document : tree.filter( - path -> path.getFileName().toString().endsWith(".yml")) - .toList()) { - copy(document, directory.resolve(document.getFileName())); - } - } - } - - private static void copy(Path source, Path target) throws IOException { - Files.createDirectories(target.getParent()); - Files.copy(source, target); - } - - private static void touch(Path file) throws IOException { - Files.createDirectories(file.getParent()); - Files.writeString(file, ""); - } - - /** Every file under {@code root}, relative to it, sorted, with {@code /} between segments. */ - private static List files(Path root) throws IOException { - try (Stream tree = Files.walk(root)) { - return tree.filter(Files::isRegularFile) - .map(file -> relative(root, file)) - .sorted() - .toList(); - } - } - - private static String relative(Path root, Path file) { - return root.relativize(file).toString().replace(File.separatorChar, '/'); - } - - private static String read(Path file) { - try { - return Files.readString(file, StandardCharsets.UTF_8); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private static void deleteTree(Path root) throws IOException { - if (!Files.exists(root)) { - return; - } - try (Stream tree = Files.walk(root)) { - for (Path path : tree.sorted(Comparator.reverseOrder()).toList()) { - Files.delete(path); - } - } - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PinnedInputsTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PinnedInputsTest.java deleted file mode 100644 index 106acd282..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PinnedInputsTest.java +++ /dev/null @@ -1,103 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; - -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.ClusterState; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.Disk; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.ImagesLock; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.Node; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.NodeContract; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Media; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import org.eclipse.emf.ecore.resource.Resource; -import org.junit.jupiter.api.Test; - -/** The pinned inputs beside the Platform document, each read by the language its file name says. */ -class PinnedInputsTest { - - private static Resource read(String relative) { - Resource resource = Pipeline.read(List.of(Examples.of(relative))).get(0); - assertThat(resource.getErrors()).isEmpty(); - return resource; - } - - @Test - void theNodeContractListsEveryNodeInItsOwnOrderWithWhatEachCanHold() { - NodeContract contract = - (NodeContract) read("platform/node-contract.yml").getContents().get(0); - - assertThat(contract.getCluster()).isEqualTo("production"); - assertThat(contract.getNodes()).extracting(Node::getName).hasSize(7).startsWith("enschede-t1000-1"); - Node first = contract.getNodes().get(0); - assertThat(first.getAllocatable().getMemory()).isEqualTo("31488Mi"); - assertThat(first.getCapabilities()).containsExactly("nvidia", "samba", "lan-ingress", "adguard"); - assertThat(first.getGpus().get(0).getMemoryMib()).isEqualTo(4096); - assertThat(first.getDisks()).hasSize(3); - } - - /** REQ-034: the seven nodes, the capability counts chapter 60 states, and a medium no Process may ask for. */ - @Test - void theNodeContractPublishesTheSevenNodesTheirCapabilitiesAndAMediumNoProcessMayAskFor() { - NodeContract contract = - (NodeContract) read("platform/node-contract.yml").getContents().get(0); - - assertThat(contract.getNodes()) - .extracting(Node::getName, Node::getSite) - .containsExactly( - tuple("enschede-t1000-1", "enschede"), - tuple("enschede-rx7900xtx-1", "enschede"), - tuple("enschede-gtx-960m-1", "enschede"), - tuple("enschede-pi-1", "enschede"), - tuple("enschede-pi-2", "enschede"), - tuple("enschede-pi-3", "enschede"), - tuple("frankfurt-contabo-1", "frankfurt")); - Map counts = contract.getNodes().stream() - .flatMap(node -> node.getCapabilities().stream()) - .collect(Collectors.groupingBy(capability -> capability, Collectors.counting())); - assertThat(counts) - .containsExactlyInAnyOrderEntriesOf(Map.of( - "adguard", 5L, - "lan-ingress", 3L, - "nvidia", 2L, - "samba", 1L, - "public-ingress", 1L, - "llm-host", 1L, - "backup-store", 1L, - "amd-gpu", 1L)); - // The contract's media are the wider vocabulary: the Pis boot from SD cards, which no - // Process's `placement.disk.media` may name. - assertThat(contract.getNodes().stream().flatMap(node -> node.getDisks().stream())) - .extracting(Disk::getMedia) - .contains("sdcard"); - assertThat(Media.VALUES).extracting(Media::getLiteral).doesNotContain("sdcard"); - } - - @Test - void theImagesLockFilesEachImageUnderItsAlias() { - ImagesLock lock = - (ImagesLock) read("platform/images.lock.yml").getContents().get(0); - - assertThat(lock.getName()).isEqualTo("estate"); - assertThat(lock.getImages()) - .filteredOn(image -> image.getAlias().equals("notes-api")) - .singleElement() - .satisfies(image -> { - assertThat(image.getRepository()).isEqualTo("ghcr.io/jorisjonkers-dev/notes/notes-api"); - assertThat(image.getDigest()).startsWith("sha256:9c1e5a4b"); - assertThat(image.getUid()).isEqualTo(1000); - }); - } - - @Test - void anEmptySnapshotHoldsNoBindingAndNoPlacement() { - ClusterState state = - (ClusterState) read("platform/cluster-state.yml").getContents().get(0); - - assertThat(state.getCapturedAt()).isEqualTo("2026-09-30T00:00:00Z"); - assertThat(state.getBindings()).isEmpty(); - assertThat(state.getPlacements()).isEmpty(); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineBenchmarkTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineBenchmarkTest.java deleted file mode 100644 index f8c9be1ff..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineBenchmarkTest.java +++ /dev/null @@ -1,284 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.render.Rendering; -import dev.jorisjonkers.deploykit.emf.resolve.Lowering; -import dev.jorisjonkers.deploykit.emf.resolve.Resolution; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryMXBean; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.resource.Resource; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.condition.EnabledIfSystemProperty; -import org.junit.jupiter.api.io.TempDir; - -/** - * Every stage of the pipeline timed alone, per worked example and over the real estate's union at - * growing sizes (docs/benchmarks.md). Each stage is timed on the output of the stage before it, which - * is built once outside the timing: - * - *
    - *
  • read: every document of the union parsed by its Xtext language and linked, {@link - * Pipeline#read}; - *
  • check: the same documents read, checked against the constraints, the names and the - * pinned inputs, and joined to their env files, {@link Pipeline#authored}: what the pipeline does - * before lowering; - *
  • lower: every Project of the union lowered, {@link Lowering#lower} as shipped; - *
  • resolve: one Project resolved against the union by {@code resolution.qvto}, loaded - * once ({@link QvtoResolution}), as {@link Resolution#resolve} loads it once per JVM; the load - * is timed apart, in {@link #loadingEachTransformation}; - *
  • render: the Resolved Deployments rendered to files, {@link Rendering#render}, which - * parses the templates on every call, as shipped. - *
- * - * Opt-in: {@code -Pbenchmark}, which also leaves JaCoCo's agent and the JVM's assertions out. - */ -@EnabledIfSystemProperty(named = Benchmark.PROPERTY, matches = "true") -class PipelineBenchmarkTest { - - /** The estate union sizes the read and lower series run at; from {@link BenchmarkInputs#ESTATE_CORE} on, every stage. */ - private static final List SIZES = List.of(1, 4, 8, 12, 16, 20, 24); - - /** The shipped resolutions {@link #theHeapASeriesOfShippedResolutionsKeeps} runs. */ - private static final int SERIES = 40; - - /** The most full collections {@link #reachable} asks for before it takes the heap as settled. */ - private static final int COLLECTIONS = 10; - - /** The resolution every series runs, loaded on first use and then reused. */ - private static QvtoResolution resolution; - - @TempDir - Path out; - - @Test - void loadingEachTransformation() { - Benchmark.Series lower = Benchmark.measure(QvtoLowering::prepared); - Prepared minimal = Prepared.of( - BenchmarkInputs.files(Outputs.RESOLVED.get("minimal").documents())); - minimal.resolve("notes"); - // Each load of the resolution stays reachable, so this series is kept short. - Benchmark.Series resolve = Benchmark.measure(QvtoResolution::load); - Benchmark.report( - "stages-load.md", - Benchmark.environment() - + "\n" - + Benchmark.table( - List.of("transformation", "lines", "load ms (parse, compile)"), - List.of( - List.of("lower.qvto", lines("/lower.qvto"), lower.cell()), - List.of("resolution.qvto", lines("/resolution.qvto"), resolve.cell())))); - assertThat(resolve.median()).isPositive(); - } - - /** - * The heap a series of shipped resolutions leaves reachable: {@code minimal}'s {@code notes} - * resolved by {@link Resolution#resolve} {@link #SERIES} times in one JVM, the heap in use after a - * full collection read before and after, and the difference spread over the calls. - */ - @Test - void theHeapASeriesOfShippedResolutionsKeeps() { - Prepared minimal = Prepared.of( - BenchmarkInputs.files(Outputs.RESOLVED.get("minimal").documents())); - Resolution.resolve(minimal.intent(), minimal.authored().pinned(), "notes", Outputs.INTEGRITY); - long before = reachable(); - for (int i = 0; i < SERIES; i++) { - Resolution.resolve(minimal.intent(), minimal.authored().pinned(), "notes", Outputs.INTEGRITY); - } - long after = reachable(); - double mib = 1024.0 * 1024.0; - Benchmark.report( - "resolution-heap.md", - Benchmark.environment() - + "\n" - + Benchmark.table( - List.of( - "shipped resolutions", - "heap reachable before (MiB)", - "heap reachable after (MiB)", - "kept per call (MiB)"), - List.of(List.of( - String.valueOf(SERIES), - String.format(Locale.ROOT, "%.1f", before / mib), - String.format(Locale.ROOT, "%.1f", after / mib), - String.format(Locale.ROOT, "%.2f", (after - before) / mib / SERIES))))); - assertThat(after).isPositive(); - } - - /** The heap in use once collections stop freeing anything: what is still reachable. */ - private static long reachable() { - MemoryMXBean memory = ManagementFactory.getMemoryMXBean(); - long used = Long.MAX_VALUE; - for (int i = 0; i < COLLECTIONS; i++) { - System.gc(); - long now = memory.getHeapMemoryUsage().getUsed(); - if (now >= used) { - return now; - } - used = now; - } - return used; - } - - @Test - void everyStagePerWorkedExample() throws IOException { - List> rows = new ArrayList<>(); - for (Map.Entry entry : - BenchmarkInputs.cases().entrySet()) { - Outputs.Resolving resolving = entry.getValue(); - Prepared prepared = Prepared.of(BenchmarkInputs.files(resolving.documents())); - ResolvedDeployment deployment = prepared.resolve(resolving.project()); - // The loaded-once resolution is the shipped one. - assertThat(ModelDiff.differences( - entry.getKey(), - List.of(Resolution.resolve( - prepared.intent(), - prepared.authored().pinned(), - resolving.project(), - Outputs.INTEGRITY)), - List.of(deployment))) - .isEmpty(); - Path root = Files.createDirectories(out.resolve(entry.getKey())); - Benchmark.Series read = Benchmark.measure(() -> Pipeline.read(prepared.files())); - Benchmark.Series check = Benchmark.measure(() -> BenchmarkInputs.authored(prepared.files())); - Benchmark.Series lower = Benchmark.measure(prepared::lowerAll); - Benchmark.Series resolve = Benchmark.measure(() -> prepared.resolve(resolving.project())); - Benchmark.Series render = Benchmark.measure(() -> { - Rendering.render(List.of(deployment), root); - return root; - }); - rows.add(List.of( - entry.getKey(), - String.valueOf(prepared.files().size()), - String.valueOf(prepared.projects().size()), - read.cell(), - check.cell(), - lower.cell(), - resolve.cell(), - render.cell())); - } - Benchmark.report( - "stages-per-example.md", - Benchmark.environment() - + "\n" - + Benchmark.table( - List.of( - "example", - "documents", - "Projects", - "read ms", - "check ms", - "lower ms (all Projects)", - "resolve ms (one Project, loaded once)", - "render ms (one Project)"), - rows)); - assertThat(rows).hasSize(BenchmarkInputs.cases().size()); - } - - @Test - void everyStageOverTheEstateAtGrowingSizes() throws IOException { - List> rows = new ArrayList<>(); - for (int size : SIZES) { - List files = BenchmarkInputs.files(BenchmarkInputs.estate(size)); - Benchmark.Series read = Benchmark.measure(() -> Pipeline.read(files)); - List row = - new ArrayList<>(List.of(String.valueOf(size), String.valueOf(files.size()), read.cell())); - if (size < BenchmarkInputs.ESTATE_CORE) { - // Too few Projects for the checks to accept: lowered as read, never checked or resolved. - List projects = new ArrayList<>(); - for (Resource document : Pipeline.read(files)) { - if (document.getContents().get(0) instanceof Project project) { - projects.add(project); - } - } - Benchmark.Series lower = Benchmark.measure( - () -> projects.stream().map(Lowering::lower).toList()); - row.addAll(List.of("–", lower.cell(), "–", "–")); - } else { - Prepared prepared = Prepared.of(files); - List names = - prepared.projects().stream().map(Project::getProject).toList(); - List deployments = - names.stream().map(prepared::resolve).toList(); - Path root = Files.createDirectories(out.resolve("estate-" + size)); - Benchmark.Series check = Benchmark.measure(() -> BenchmarkInputs.authored(files)); - Benchmark.Series lower = Benchmark.measure(prepared::lowerAll); - Benchmark.Series resolve = Benchmark.measure( - () -> names.stream().map(prepared::resolve).toList()); - Benchmark.Series render = Benchmark.measure(() -> { - Rendering.render(deployments, root); - return root; - }); - row.addAll(List.of(check.cell(), lower.cell(), resolve.cell(), render.cell())); - } - rows.add(row); - } - Benchmark.report( - "stages-estate-scaling.md", - Benchmark.environment() - + "\n" - + Benchmark.table( - List.of( - "Projects", - "documents", - "read ms", - "check ms", - "lower ms (all Projects)", - "resolve ms (every Project, loaded once)", - "render ms (every Project)"), - rows)); - assertThat(rows).hasSize(SIZES.size()); - } - - private static String lines(String transformation) { - try (InputStream source = Resolution.class.getResourceAsStream(transformation)) { - return String.valueOf(new String(source.readAllBytes(), StandardCharsets.UTF_8) - .lines() - .count()); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** A union read, checked and lowered once, so a later stage is timed on what the stage before it made. */ - record Prepared(List files, Authored authored, List projects, List intent) { - - static Prepared of(List files) { - Authored authored = BenchmarkInputs.authored(files); - List projects = BenchmarkInputs.projects(authored); - List intent = new ArrayList<>(); - for (EObject root : authored.intent()) { - intent.add(root); - // The authored Project stays beside its lowering, as the pipeline reads them. - if (root instanceof Project project) { - intent.add(Lowering.lower(project)); - } - } - return new Prepared(files, authored, projects, intent); - } - - List lowerAll() { - return projects.stream().map(Lowering::lower).toList(); - } - - ResolvedDeployment resolve(String project) { - if (resolution == null) { - resolution = QvtoResolution.prepared(intent, authored.pinned(), project); - } - return resolution.resolve(intent, authored.pinned(), project); - } - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineRefusalsTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineRefusalsTest.java deleted file mode 100644 index 52d072ee1..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineRefusalsTest.java +++ /dev/null @@ -1,231 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.assertj.core.api.Assertions.tuple; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Sidecar; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** - * Where the pipeline decides what its constraints cannot see: a Process's env files reach it before it - * is checked, what a Process holds across the union is asked only of a document that holds on its own, - * and the mesh's Projects and the images lock are read beside the documents. - */ -class PipelineRefusalsTest { - - /** A Process holding a `self` grant, which it can read only through its own Vault client. */ - private static final String SELF = """ - apiVersion: intent.jorisjonkers.dev/v1 - kind: Project - schemaVersion: 1.0.0 - project: refusals - owner: joris - applications: - - id: reader - processes: - - name: reader-api - lifecycle: application - image: reader-api - runtime: node - placement: { memory: 128Mi, cpu: 25m } - probes: none - cutover: interrupted - secrets: - - path: secret/data/refusals-system/token - keys: [token] - access: read - delivery: self - rotation: { tolerates: restart } - """; - - private static Path project(Path directory, boolean wired) throws IOException { - Files.createDirectories(directory); - Path file = Examples.write(directory, "refusals.project.yml", SELF); - if (wired) { - Files.createDirectories(directory.resolve("env/reader-api")); - Files.writeString(directory.resolve("env/reader-api/base.env"), "VAULT_ROLE=${identity:vaultRole}\n"); - } - return file; - } - - private static List codes(List diagnostics) { - return diagnostics.stream().map(Diagnostic::code).toList(); - } - - @Test - void aProcessIsCheckedWithTheEnvFilesBesideItsProjectFile(@TempDir Path directory) throws IOException { - Path unwired = project(directory.resolve("unwired"), false); - Path wired = project(directory.resolve("wired"), true); - - assertThat(Pipeline.intent(unwired).diagnostics()) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path) - .containsExactly( - tuple("E_SELF_WITHOUT_VAULT_CLIENT", "refusals.project.yml", "/applications/0/processes/0")); - assertThat(codes(Pipeline.effective(unwired).diagnostics())).containsExactly("E_SELF_WITHOUT_VAULT_CLIENT"); - assertThat(codes(Pipeline.check(List.of(unwired)))).containsExactly("E_SELF_WITHOUT_VAULT_CLIENT"); - assertThat(Pipeline.intent(wired).ok()).isTrue(); - assertThat(Pipeline.effective(wired).ok()).isTrue(); - assertThat(Pipeline.check(List.of(wired))).isEmpty(); - } - - @Test - void anEnvScopeThatNamesNothingIsRefusedOnlyOfADocumentThatHolds(@TempDir Path directory) throws IOException { - Path file = project(directory, true); - Files.createDirectories(directory.resolve("env/ghost")); - Files.writeString(directory.resolve("env/ghost/base.env"), "A=b\n"); - - List refusals = Pipeline.effective(file).diagnostics(); - assertThat(codes(refusals)).containsExactly("E_UNKNOWN_ENV_SCOPE"); - assertThat(refusals.get(0).path()).endsWith("env/ghost/base.env"); - Files.writeString(file, SELF.replace("delivery: self", "delivery: self\n colour: red")); - assertThat(codes(Pipeline.effective(file).diagnostics())).doesNotContain("E_UNKNOWN_ENV_SCOPE"); - } - - @Test - void aDocumentWithNoContentIsRefusedForItsShape(@TempDir Path directory) { - Path empty = Examples.write(directory, "refusals.project.yml", ""); - - assertThat(codes(Pipeline.intent(empty).diagnostics())).containsExactly(Diagnostic.SCHEMA); - Path comment = Examples.write(directory, "comment.project.yml", "# a project file that declares nothing\n"); - assertThat(codes(Pipeline.intent(comment).diagnostics())).containsExactly(Diagnostic.SCHEMA); - } - - @Test - void theFilesAProjectShipsAreReadBesideIt(@TempDir Path directory) throws IOException { - Path file = Examples.write( - directory, - "refusals.project.yml", - SELF.replace("delivery: self", "delivery: env") - .replace( - " processes:", - " dashboards:\n - from: board.json\n - from: absent.json\n processes:")); - Examples.write(directory, "board.json", "{\"uid\": \"board\"}"); - - assertThat(Pipeline.check(List.of(file))) - .extracting(Diagnostic::code, Diagnostic::path) - .containsExactly(tuple(ShippedFiles.DASHBOARD_NOT_FOUND, "/applications/0/dashboards/1/from")); - } - - @Test - void aShippedFileThatCannotBeReadFailsTheCheckRatherThanReadingAsAbsent(@TempDir Path directory) - throws IOException { - Path file = Examples.write( - directory, - "refusals.project.yml", - SELF.replace("delivery: self", "delivery: env") - .replace(" processes:", " dashboards:\n - from: board.json\n processes:")); - Path board = Examples.write(directory, "board.json", "{\"uid\": \"board\"}"); - Files.setPosixFilePermissions(board, java.util.Set.of()); - try { - assertThatThrownBy(() -> Pipeline.check(List.of(file))) - .isInstanceOf(UncheckedIOException.class) - .hasStackTraceContaining("textBeside"); - } finally { - Files.setPosixFilePermissions(board, java.nio.file.attribute.PosixFilePermissions.fromString("rw-------")); - } - } - - @Test - void whatAProcessHoldsAcrossTheUnionIsAskedOnlyOfADocumentThatHolds() { - // The owner role's `self` grant is wired by no Vault client, and is refused for the owner role alone. - assertThat(Pipeline.intent(Examples.of("refusals/owner-role-granted.project.yml")) - .diagnostics()) - .extracting(Diagnostic::code, Diagnostic::path) - .containsExactly(tuple("E_OWNER_ROLE_GRANTED", "/applications/0/processes/0/secrets/0")); - } - - @Test - void aProjectTheMeshEnrolsIsOneAProjectFileDeclares() { - Path set = Examples.of("refusals/unknown-enrolled-project"); - - assertThat(Pipeline.check(List.of(set.resolve("platform.intent.yml"), set.resolve("refusals.project.yml")))) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path, Diagnostic::message) - .containsExactly(tuple( - "E_UNKNOWN_ENROLLED_PROJECT", - "platform.intent.yml", - "/mesh/enrolled/1", - "no project file declares the Project notes the mesh enrols")); - Path meshless = Examples.of("refusals/asset-not-found"); - assertThat(codes(Pipeline.check(List.of(meshless.resolve("platform.intent.yml"))))) - .doesNotContain("E_UNKNOWN_ENROLLED_PROJECT"); - } - - @Test - void theL4AddressesAndTiersAreCheckedAgainstTheProjectFilesBesideThem() { - Path set = Examples.of("refusals/tier-surface-missing"); - - assertThat(Pipeline.check(List.of(set.resolve("platform.intent.yml"), set.resolve("refusals.project.yml")))) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path) - .containsExactly(tuple("E_TIER_SURFACE_MISSING", "platform.intent.yml", "/tiers/0")); - } - - @Test - void anImageTheLockHoldsAsRootIsRefusedAtTheLock(@TempDir Path directory) throws IOException { - Path set = Examples.of("refusals/image-runs-as-root"); - Path project = set.resolve("refusals.project.yml"); - Path lock = set.resolve("images.lock.yml"); - - assertThat(Pipeline.check(List.of(lock, project))) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path, Diagnostic::message) - .containsExactly(tuple( - "E_IMAGE_RUNS_AS_ROOT", - "images.lock.yml", - "/images/api", - "the images lock holds api with uid 0, and every pod runs as non-root")); - String text = Files.readString(lock); - Path copy = Examples.write(directory, "refusals.project.yml", Files.readString(project)); - Examples.write(directory, "images.lock.yml", text.replace("uid: 0", "uid: 1000")); - assertThat(Pipeline.check(List.of(directory.resolve("images.lock.yml"), copy))) - .isEmpty(); - Examples.write(directory, "images.lock.yml", text + "\nimages: ["); - assertThat(Pipeline.check(List.of(directory.resolve("images.lock.yml"), copy))) - .isEmpty(); - Examples.write(directory, "images.lock.yml", ""); - assertThat(Pipeline.check(List.of(directory.resolve("images.lock.yml"), copy))) - .isEmpty(); - Examples.write(directory, "images.lock.yml", "# a lock that locks nothing\n"); - assertThat(Pipeline.check(List.of(directory.resolve("images.lock.yml"), copy))) - .isEmpty(); - } - - @Test - void anImageRunsAsItsOwnUserForAProcessOrAMigrationAndASidecarsIsLockedButNotAsked() { - ProjectIntentFactory model = ProjectIntentFactory.eINSTANCE; - Project project = model.createProject(); - Application application = model.createApplication(); - application.setId("api"); - application.setMigration(model.createManagedMigration()); - var process = model.createProcess(); - process.setImage("api"); - Sidecar sidecar = model.createSidecar(); - sidecar.setImage("exporter"); - process.getSidecars().add(sidecar); - application.getProcesses().add(process); - project.getApplications().add(application); - - assertThat(Pipeline.rootAliases(Map.of("api", 0, "api-migration", 0, "exporter", 0), List.of(project))) - .containsExactly("api", "api-migration"); - assertThat(Pipeline.rootAliases(Map.of("api", 1000, "api-migration", 0, "exporter", 0), List.of(project))) - .containsExactly("api-migration"); - // An alias the lock does not hold, the sidecar's too, is the share's own refusal. - assertThat(Pipeline.rootAliases(Map.of("api", 0, "api-migration", 0), List.of(project))) - .isEmpty(); - assertThat(Pipeline.rootAliases(Map.of("api", 0, "exporter", 0), List.of(project))) - .isEmpty(); - // An image that moves its own schema, or moves none, runs no migration image. - application.setMigration(model.createSelfMigration()); - assertThat(Pipeline.rootAliases(Map.of("api", 0, "exporter", 0), List.of(project))) - .containsExactly("api"); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineTest.java deleted file mode 100644 index 10edcf88e..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineTest.java +++ /dev/null @@ -1,270 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import dev.jorisjonkers.deploykit.emf.metamodel.json.CanonicalJson; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import org.eclipse.emf.common.util.URI; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** The pipeline entry: an authored file in, its intent or the diagnostics that refused it out. */ -class PipelineTest { - - private static final String MINIMAL = """ - apiVersion: intent.jorisjonkers.dev/v1 - kind: Project - schemaVersion: 1.0.0 - project: notes - owner: joris - applications: - - id: notes - processes: - - name: notes-api - lifecycle: application - image: notes-api - runtime: node - placement: - memory: 256Mi - cpu: 50m - cutover: continuous - """; - - private static Path file(Path directory, String text) throws IOException { - Path file = directory.resolve("notes.project.yml"); - Files.writeString(file, text); - return file; - } - - @Test - void aModelIsWrittenAsXmiWithItsForeignNamesRelativeToTheFileBesideIt() throws IOException { - // The Platform document alone: its tiers' proxies name Applications no file read with it - // declares, so they stay proxies, and a proxy is written against the authored file, never as - // a path on the machine that ran the pipeline. - String platform = Pipeline.xmi(Examples.of("platform/platform.intent.yml")); - - assertThat(platform).contains("projectintent:Platform").contains("href=\"platform.intent.yml#"); - assertThat(platform).doesNotContain("file:"); - } - - @Test - void aSetIsWrittenAsXmiWhoseDocumentsLinkToEachOther() throws IOException { - // The tier's proxy names an Application the project file beside it declares, so read together - // the Platform document's XMI refers to the project file's XMI, not to either authored file, - // and each XMI is named after its authored file. - Path platform = Examples.of("refusals/no-tier-for-audience/platform.intent.yml"); - Path project = Examples.of("refusals/no-tier-for-audience/refusals.project.yml"); - - Map xmi = Pipeline.xmi(List.of(platform, project)); - - assertThat(xmi).containsOnlyKeys(platform, project); - assertThat(xmi.get(platform)) - .contains("href=\"refusals.project.xmi#//@applications.1\"") - .doesNotContain(".yml#") - .doesNotContain("file:"); - // The Application `api` and its Process `api` share a name, so a link is written as a path, - // which names one object when the file is read back, rather than as the ambiguous ID. - assertThat(xmi.get(project)) - .contains("projectintent:Project") - .contains("process=\"//@applications.0/@processes.0\"") - .doesNotContain("process=\"api\""); - assertThat(Pipeline.xmiName(project)).isEqualTo("refusals.project.xmi"); - } - - @Test - void anObjectIsNamedByItsPathFromTheRootNeverByItsId() { - Project project = ProjectIntentFactory.eINSTANCE.createProject(); - Application application = ProjectIntentFactory.eINSTANCE.createApplication(); - application.setId("notes"); - project.getApplications().add(application); - Pipeline.ByPath names = new Pipeline.ByPath(URI.createURI("notes.project.xmi")); - - assertThat(names.getURIFragment(project)).isEqualTo("/"); - assertThat(names.getURIFragment(application)).isEqualTo("//@applications.0"); - } - - @Test - void anEmptyDocumentHasNoModelToWrite(@TempDir Path directory) throws IOException { - assertThat(Pipeline.xmi(List.of(file(directory, "")))).isEmpty(); - } - - @Test - void anAuthoredDocumentParsesToItsIntent(@TempDir Path directory) throws IOException { - Parsed parsed = Pipeline.intent(file(directory, MINIMAL)); - - assertThat(parsed.ok()).isTrue(); - assertThat(parsed.diagnostics()).isEmpty(); - assertThat(parsed.intent()).containsEntry("project", "notes").containsEntry("owner", "joris"); - } - - @Test - void yamlOutsideTheGrammarIsRefusedWithADiagnostic(@TempDir Path directory) throws IOException { - Parsed parsed = Pipeline.intent(file(directory, MINIMAL.replace("runtime: node", "runtime: rust"))); - - assertThat(parsed.ok()).isFalse(); - assertThat(parsed.intent()).isEmpty(); - assertThat(parsed.diagnostics()) - .allSatisfy(diagnostic -> { - assertThat(diagnostic.code()).isEqualTo(Diagnostic.SCHEMA); - assertThat(diagnostic.document()).isEqualTo("notes.project.yml"); - assertThat(diagnostic.path()).isEqualTo("/applications/0/processes/0/runtime"); - assertThat(diagnostic.message()).isEqualTo("does not match any shape the schema allows here"); - }) - .isNotEmpty(); - } - - @Test - void theRetiredCutoverValuesAreOutsideTheGrammar(@TempDir Path directory) throws IOException { - for (String retired : new String[] {"rolling", "recreate"}) { - Parsed parsed = - Pipeline.intent(file(directory, MINIMAL.replace("cutover: continuous", "cutover: " + retired))); - - assertThat(parsed.ok()).as(retired).isFalse(); - assertThat(parsed.diagnostics()).extracting(Diagnostic::code).containsOnly(Diagnostic.SCHEMA); - } - } - - @Test - void aNameThatLinksToNothingIsRefusedAtThePointerOfWhatWroteIt(@TempDir Path directory) throws IOException { - String routed = MINIMAL.replace("applications:\n - id: notes\n", """ - applications: - - id: notes - exposure: - - name: public - host: notes.jorisjonkers.dev - audience: lan - routes: - - { path: /, match: prefix, process: notes-api, surface: https } - """) - .replace(" runtime: node\n", " runtime: node\n provides: { http: 8080 }\n"); - - Parsed parsed = Pipeline.intent(file(directory, routed)); - - assertThat(parsed.diagnostics()) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path) - .containsExactly(org.assertj.core.groups.Tuple.tuple( - "E_UNKNOWN_SURFACE", "notes.project.yml", "/applications/0/exposure/0/routes/0")); - } - - @Test - void anEmptyDocumentIsRefused(@TempDir Path directory) throws IOException { - Parsed parsed = Pipeline.intent(file(directory, "")); - - assertThat(parsed.diagnostics()) - .extracting(Diagnostic::code, Diagnostic::path, Diagnostic::message) - .containsExactly(org.assertj.core.groups.Tuple.tuple( - Diagnostic.SCHEMA, "", "outside the YAML subset: no document")); - } - - @Test - void aFileThatCannotBeReadIsAnErrorRatherThanARefusal(@TempDir Path directory) { - assertThatThrownBy(() -> Pipeline.intent(directory.resolve("missing.project.yml"))) - .isInstanceOf(UncheckedIOException.class); - } - - /** {@code text} as an env file at {@code scope}, under the {@code env/} directory beside a project file. */ - private static void env(Path directory, String scope, String text) throws IOException { - Path file = directory.resolve("env").resolve(scope).resolve("base.env"); - Files.createDirectories(file.getParent()); - Files.writeString(file, text); - } - - @Test - void theMinimalCaseLowersToItsCommittedEffectiveOracle() throws IOException { - Parsed effective = Pipeline.effective(Examples.of("minimal/notes.project.yml")); - - assertThat(effective.ok()).isTrue(); - assertThat(CanonicalJson.write(effective.intent())).isEqualTo(Examples.read("minimal/expected/effective.json")); - } - - @Test - void aProjectFileWithNoEnvDirectoryLowersWithNoEnv(@TempDir Path directory) throws IOException { - Parsed effective = Pipeline.effective(file(directory, MINIMAL)); - - assertThat(effective.ok()).isTrue(); - assertThat(effective.intent().toString()).doesNotContain("env="); - } - - @Test - void anEnvFileReachesTheLevelItsScopeDirectoryNames(@TempDir Path directory) throws IOException { - Path project = file(directory, MINIMAL); - env(directory, "_project", "SHARED=1\n"); - env(directory, "_applications/notes", "OURS=1\n"); - Files.writeString(directory.resolve("env").resolve("README.md"), "not an env file\n"); - - Parsed effective = Pipeline.effective(project); - - assertThat(effective.ok()).isTrue(); - assertThat(effective.intent().toString()).contains("name=OURS").contains("name=SHARED"); - } - - @Test - void anEnvFileWhoseScopeNamesNothingDeclaredIsRefused(@TempDir Path directory) throws IOException { - Path project = file(directory, MINIMAL); - env(directory, "notes-worker", "A=1\n"); - env(directory, "_applications/elsewhere", "B=1\n"); - - Parsed effective = Pipeline.effective(project); - - assertThat(effective.diagnostics()) - .extracting(Diagnostic::code) - .containsExactly("E_UNKNOWN_ENV_SCOPE", "E_UNKNOWN_ENV_SCOPE"); - } - - @Test - void aRefusedDocumentOrEnvFileIsNotLowered(@TempDir Path directory) throws IOException { - Path project = file(directory, MINIMAL.replace("runtime: node", "runtime: cobol")); - env(directory, "notes-api", "not an assignment\n"); - - Parsed effective = Pipeline.effective(project); - - assertThat(effective.ok()).isFalse(); - assertThat(effective.diagnostics()).extracting(Diagnostic::code).contains("schema"); - assertThat(effective.intent()).isEmpty(); - } - - @Test - void aSetWhosePlanClaimsAPathTwiceWritesNothing(@TempDir Path out) throws IOException { - List refused = - Pipeline.renderTogether(List.of(ResolutionTest.minimal(), ResolutionTest.minimal()), out); - - assertThat(refused).isNotEmpty().extracting(Diagnostic::code).containsOnly("E_PATH_COLLISION"); - assertThat(out).isEmptyDirectory(); - } - - @Test - void aSetWhoseFilesHoldOneServiceAccountTwiceWritesNothing(@TempDir Path out) throws IOException { - ResolvedDeployment copy = ResolutionTest.minimal(); - copy.getDeliverables().removeIf(deliverable -> deliverable.getPath().contains("/policies/")); - copy.getDeliverables().forEach(deliverable -> deliverable.setPath("copy/" + deliverable.getPath())); - - List refused = Pipeline.renderTogether(List.of(ResolutionTest.minimal(), copy), out); - - assertThat(refused) - .isNotEmpty() - .allSatisfy(diagnostic -> assertThat(diagnostic.message()).startsWith("the ServiceAccount ")); - assertThat(out).isEmptyDirectory(); - } - - @Test - void yamlTheShapeCheckCannotReadLeavesTheVerdictToTheParser(@TempDir Path directory) throws IOException { - Parsed parsed = Pipeline.intent(file(directory, MINIMAL + "extra: {a: 1\n")); - - assertThat(parsed.ok()).isFalse(); - assertThat(parsed.diagnostics()).isNotEmpty().allSatisfy(diagnostic -> { - assertThat(diagnostic.code()).isEqualTo(Diagnostic.SCHEMA); - assertThat(diagnostic.path()).isEmpty(); - assertThat(diagnostic.message()).startsWith("line "); - }); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PlatformIntentTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PlatformIntentTest.java deleted file mode 100644 index 731f84a9d..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PlatformIntentTest.java +++ /dev/null @@ -1,63 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.groups.Tuple.tuple; - -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** - * REQ-030 (docs/requirements.md): the authored Platform document parses to its intent, and a tier that - * carries the authenticated audience without an endpoint to authenticate it is refused. - */ -class PlatformIntentTest { - - private static final String WORKED = Examples.read("platform/platform.intent.yml"); - - @Test - void aPlatformDocumentParsesAndATierWithoutItsEndpointIsRefused(@TempDir Path directory) { - Parsed parsed = Pipeline.intent(Examples.of("platform/platform.intent.yml")); - Parsed refused = Pipeline.intent( - Examples.write(directory, "platform.intent.yml", WORKED.replaceFirst("\n\\s+forwardAuth: [^\n]*", ""))); - - assertThat(parsed.diagnostics()).isEmpty(); - assertThat(refused.diagnostics()) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path) - .containsExactly(tuple("E_NO_FORWARD_AUTH_ENDPOINT", "platform.intent.yml", "/tiers/0")); - } - - @Test - void aTiersProxyReadAloneIsWrittenAsTheNameTheDocumentGaveIt(@TempDir Path directory) { - Parsed quoted = Pipeline.intent(Examples.write( - directory, - "platform.intent.yml", - WORKED.replace("traefik: edge/traefik-lan", "traefik: 'edge/traefik-lan'"))); - - assertThat(tiers(quoted)) - .extracting(tier -> tier.get("traefik")) - .containsExactly("edge/traefik-public", "edge/traefik-lan"); - } - - @Test - void aQuotedScalarHoldsTheColonsAPlainOneCannot() { - Parsed parsed = Pipeline.intent(Examples.of("platform/platform.intent.yml")); - - assertThat(parsed.intent().get("metadata")) - .asInstanceOf(org.assertj.core.api.InstanceOfAssertFactories.MAP) - .containsEntry("cluster", "production") - .extractingByKey("nodeContract") - .asString() - .startsWith("sha256:a989"); - assertThat(parsed.intent().get("signIn")) - .asInstanceOf(org.assertj.core.api.InstanceOfAssertFactories.MAP) - .containsEntry("issuer", "https://id.jorisjonkers.dev"); - } - - @SuppressWarnings("unchecked") - private static List> tiers(Parsed parsed) { - return (List>) parsed.intent().get("tiers"); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PointerTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PointerTest.java deleted file mode 100644 index d879361c2..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PointerTest.java +++ /dev/null @@ -1,61 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.LibraryDeclaration; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Observability; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Process; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import org.eclipse.emf.ecore.EObject; -import org.junit.jupiter.api.Test; - -/** Where an object sits in its document, as the pointer a diagnostic carries. */ -class PointerTest { - - private static final ProjectIntentFactory MODEL = ProjectIntentFactory.eINSTANCE; - - @Test - void theRootIsTheEmptyPointer() { - assertThat(Pointer.of(MODEL.createProject())).isEmpty(); - } - - @Test - void aFeatureHoldingManyValuesCarriesTheIndex() { - Project project = MODEL.createProject(); - Application first = MODEL.createApplication(); - Application second = MODEL.createApplication(); - project.getApplications().add(first); - project.getApplications().add(second); - Process process = MODEL.createProcess(); - second.getProcesses().add(process); - - assertThat(Pointer.of(first)).isEqualTo("/applications/0"); - assertThat(Pointer.of(second)).isEqualTo("/applications/1"); - assertThat(Pointer.of(process)).isEqualTo("/applications/1/processes/0"); - } - - @Test - void aFeatureHoldingOneValueCarriesItsNameAlone() { - Project project = MODEL.createProject(); - Application application = MODEL.createApplication(); - Observability observability = MODEL.createObservability(); - project.getApplications().add(application); - application.setObservability(observability); - - assertThat(Pointer.of(observability)).isEqualTo("/applications/0/observability"); - } - - @Test - void aMapEntryCarriesItsKeyAndItsValueSitsAtTheEntry() { - Platform platform = MODEL.createPlatform(); - LibraryDeclaration media = MODEL.createLibraryDeclaration(); - platform.getLibraries().put("a/b", MODEL.createLibraryDeclaration()); - platform.getLibraries().put("media", media); - - assertThat(Pointer.of(media)).isEqualTo("/libraries/media"); - assertThat(Pointer.of((EObject) platform.getLibraries().get(0))).isEqualTo("/libraries/a~1b"); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/QvtoLowering.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/QvtoLowering.java deleted file mode 100644 index 57951057e..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/QvtoLowering.java +++ /dev/null @@ -1,48 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EffectiveProject; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import dev.jorisjonkers.deploykit.emf.resolve.Lowering; -import java.util.Collections; -import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.emf.common.util.URI; -import org.eclipse.m2m.qvt.oml.BasicModelExtent; -import org.eclipse.m2m.qvt.oml.ExecutionContextImpl; -import org.eclipse.m2m.qvt.oml.TransformationExecutor; - -/** - * The shipped QVT-Operational lowering, {@code lower.qvto}, with its transformation loaded once and - * reused: the benchmark's match for {@link AtlLowering#prepared()} (docs/benchmarks.md). {@link - * Lowering#lower} loads it once per JVM too; this one can also be made afresh to time a load. - */ -final class QvtoLowering { - - private final TransformationExecutor executor; - - private QvtoLowering() { - ProjectIntentPackage.eINSTANCE.getName(); - executor = new TransformationExecutor( - URI.createURI(Lowering.class.getResource("/lower.qvto").toString())); - Diagnostic loaded = executor.loadTransformation(); - if (loaded.getSeverity() != Diagnostic.OK) { - throw new IllegalStateException("lower.qvto does not load: " + loaded); - } - } - - /** The lowering with its transformation parsed, compiled and loaded, ready to run. */ - static QvtoLowering prepared() { - return new QvtoLowering(); - } - - /** {@code project}, lowered; the source is left as it was. */ - EffectiveProject lower(Project project) { - BasicModelExtent target = new BasicModelExtent(); - Diagnostic run = executor.execute( - new ExecutionContextImpl(), new BasicModelExtent(Collections.singletonList(project)), target); - if (run.getSeverity() != Diagnostic.OK || target.getContents().size() != 1) { - throw new IllegalStateException(project.getProject() + " did not lower: " + run); - } - return (EffectiveProject) target.getContents().get(0); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/QvtoResolution.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/QvtoResolution.java deleted file mode 100644 index 796e2092a..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/QvtoResolution.java +++ /dev/null @@ -1,61 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.resolve.Resolution; -import java.util.ArrayList; -import java.util.List; -import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.m2m.qvt.oml.BasicModelExtent; -import org.eclipse.m2m.qvt.oml.ExecutionContextImpl; -import org.eclipse.m2m.qvt.oml.TransformationExecutor; - -/** - * The shipped resolution, {@code resolution.qvto}, with its transformation loaded once and reused, so - * the benchmark times its execution apart from its loading (docs/benchmarks.md#method), and can load - * it again on its own to time the load. - */ -final class QvtoResolution { - - private final TransformationExecutor executor; - - private QvtoResolution(List intent, List pinned, String project) { - // The shipped entry point registers the blackbox the transformation imports, which a load needs. - Resolution.resolve(intent, pinned, project, Outputs.INTEGRITY); - executor = load(); - } - - /** {@code resolution.qvto} parsed, compiled and loaded: what {@link Resolution#resolve} does on its first call. */ - static TransformationExecutor load() { - TransformationExecutor executor = new TransformationExecutor( - URI.createURI(Resolution.class.getResource("/resolution.qvto").toString())); - Diagnostic loaded = executor.loadTransformation(); - if (loaded.getSeverity() != Diagnostic.OK) { - throw new IllegalStateException("resolution.qvto does not load: " + loaded); - } - return executor; - } - - /** The resolution loaded once, after one shipped run over {@code intent} has registered its blackbox. */ - static QvtoResolution prepared(List intent, List pinned, String project) { - return new QvtoResolution(intent, pinned, project); - } - - /** {@code project} of {@code intent}, resolved against {@code pinned}, as {@link Resolution#resolve} resolves it. */ - ResolvedDeployment resolve(List intent, List pinned, String project) { - ExecutionContextImpl context = new ExecutionContextImpl(); - context.setConfigProperty("project", project); - context.setConfigProperty("integrity", Outputs.INTEGRITY); - BasicModelExtent target = new BasicModelExtent(); - Diagnostic run = executor.execute( - context, - new BasicModelExtent(new ArrayList<>(intent)), - new BasicModelExtent(new ArrayList<>(pinned)), - target); - if (run.getSeverity() != Diagnostic.OK || target.getContents().isEmpty()) { - throw new IllegalStateException(project + " did not resolve: " + run); - } - return (ResolvedDeployment) target.getContents().get(0); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/RenderedTreeTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/RenderedTreeTest.java deleted file mode 100644 index d3f5811a1..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/RenderedTreeTest.java +++ /dev/null @@ -1,194 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.descriptor.DependencyEdges; -import dev.jorisjonkers.deploykit.emf.metamodel.json.CanonicalJson; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -/** - * The pipeline's one entry, from the documents to the tree (issues #95 and #96): each case the - * production implementation renders equals its committed tree byte for byte, the estate-scoped share - * minimal and data hold between them equals the committed estate tree, a second run writes the same - * bytes as the first, and a set the checks refuse writes nothing. - */ -class RenderedTreeTest { - - private static List union() { - return Outputs.RENDERED_UNION.documents().stream().map(Examples::of).toList(); - } - - private static List filesUnder(Path root) throws IOException { - try (Stream walk = Files.walk(root)) { - return walk.filter(Files::isRegularFile) - .map(root::relativize) - .filter(file -> !file.toString().equals("README.md")) - .sorted() - .toList(); - } - } - - private static void assertSameTree(Path rendered, Path committed) throws IOException { - assertSameTree(rendered, List.of(committed)); - } - - /** {@code rendered} is every committed tree together, byte for byte. */ - private static void assertSameTree(Path rendered, List committed) throws IOException { - List expected = new ArrayList<>(); - for (Path tree : committed) { - expected.addAll(filesUnder(tree)); - } - assertThat(filesUnder(rendered)).isEqualTo(expected.stream().sorted().toList()); - for (Path tree : committed) { - for (Path file : filesUnder(tree)) { - assertThat(Files.readString(rendered.resolve(file))) - .as(file.toString()) - .isEqualTo(Files.readString(tree.resolve(file))); - } - } - } - - /** The platform's own estate-scoped share, which every render holds beside a Project's. */ - private static Path platformShare() { - return Examples.of("platform/rendered"); - } - - @ParameterizedTest(name = "{0}") - @CsvSource({"minimal, notes", "data, data", "delivery, delivery"}) - void aProjectsShareIsItsCommittedTreeByteForByte(String example, String project, @TempDir Path out) - throws IOException { - assertThat(Pipeline.render(union(), List.of(project), Outputs.INTEGRITY, out)) - .isEmpty(); - - Path share = Path.of("apps", project); - assertSameTree(out.resolve(share), Examples.of(example + "/rendered").resolve(share)); - } - - @Test - void authsShareAndTheEstateShareItDerivesAreItsCommittedTreeByteForByte(@TempDir Path out) throws IOException { - assertThat(Pipeline.render( - Outputs.AUTH_UNION.documents().stream() - .map(Examples::of) - .toList(), - Outputs.AUTH_UNION.projects(), - Outputs.INTEGRITY, - out)) - .isEmpty(); - - assertSameTree(out, List.of(Examples.of("auth/rendered"), platformShare())); - } - - @Test - void theKnowledgePlatformsShareAndTheEstateShareItDerivesAreItsCommittedTreeByteForByte(@TempDir Path out) - throws IOException { - assertThat(Pipeline.render( - Outputs.KNOWLEDGE_PLATFORM_UNION.documents().stream() - .map(Examples::of) - .toList(), - Outputs.KNOWLEDGE_PLATFORM_UNION.projects(), - Outputs.INTEGRITY, - out)) - .isEmpty(); - - assertSameTree(out, List.of(Examples.of("knowledge-platform/rendered"), platformShare())); - } - - /** - * Each real estate Project worked under {@code estate/}, read with the whole estate it was taken - * from, parses to its committed intent, resolves to its committed edges and renders, alone, to its - * committed share of the tree. - */ - @ParameterizedTest(name = "{0}") - @CsvSource({"hindsight", "immich", "observability"}) - void aRealEstateProjectIsItsCommittedOraclesByteForByte(String project, @TempDir Path out) throws IOException { - Outputs.Resolving resolving = Outputs.RESOLVED.get("estate/" + project); - List documents = resolving.documents().stream().map(Examples::of).toList(); - Path example = Examples.of("estate/" + project); - - assertThat(CanonicalJson.write(Pipeline.intent(example.resolve(project + ".project.yml")) - .intent())) - .isEqualTo(Files.readString(example.resolve("expected/intent.json"))); - assertThat(CanonicalJson.write(DependencyEdges.of( - Pipeline.resolve(documents, project, Outputs.INTEGRITY).deployment()))) - .isEqualTo(Files.readString(example.resolve("expected/" + DependencyEdges.NAME))); - assertThat(Pipeline.render(documents, List.of(project), Outputs.INTEGRITY, out)) - .isEmpty(); - assertSameTree(out.resolve("apps"), example.resolve("rendered/apps")); - } - - @Test - void minimalAndDataRenderedTogetherHoldNothingEstateScoped(@TempDir Path out) throws IOException { - assertThat(Pipeline.render(union(), Outputs.RENDERED_UNION.projects(), Outputs.INTEGRITY, out)) - .isEmpty(); - - // Every object each delivers is its own, its routes among them (issue #546): the - // estate-scoped share is the platform's alone. - assertThat(filesUnder(out).stream() - .filter(file -> file.startsWith("estate")) - .toList()) - .isEqualTo(filesUnder(platformShare())); - } - - /** - * The knowledge platform's set rendered with the datastore's own project: its catalog is applied - * from that project's unit, under the Job name the production implementation derives from the - * same catalog and method (issue #482), signing in with the derived login. - */ - @Test - void aDatastoreAppliesItsCatalogFromItsOwnProject(@TempDir Path out) throws IOException { - List files = Outputs.KNOWLEDGE_PLATFORM_UNION.documents().stream() - .map(Examples::of) - .toList(); - - assertThat(Pipeline.render(files, List.of("data", "knowledge-platform"), Outputs.INTEGRITY, out)) - .isEmpty(); - - Path owned = Path.of("apps/data/platform-postgres"); - assertThat(Files.readString(out.resolve(owned.resolve("postgres-catalog.yaml")))) - .contains(" name: postgres-catalog-565e7844099d\n") - .contains("{\"admin\":{\"password\":\"password\",\"path\":\"secret/data/data/postgres/catalog\"," - + "\"user\":\"user\"},\"connection\":\"postgres\",\"databases\":[{\"data\":\"knowledge-platform-data\"," - + "\"name\":\"knowledge-platform_db\",\"owner\":\"knowledge-platform-owner\"}]," - + "\"host\":\"postgres.data-system.svc.cluster.local\",\"port\":5432}"); - assertThat(out.resolve(owned.resolve("postgres-catalog-networkpolicy.yaml"))) - .isRegularFile(); - assertThat(Files.readString(out.resolve(owned.resolve("kustomization.yaml")))) - .contains(" - postgres-catalog.yaml\n"); - assertThat(out.resolve("apps/data/vault-policy/policies/data-system-postgres-catalog.policy.json")) - .isRegularFile(); - } - - @Test - void renderingTwiceFromTheSameInputsWritesTheSameBytes(@TempDir Path first, @TempDir Path second) - throws IOException { - Pipeline.render(union(), Outputs.RENDERED_UNION.projects(), Outputs.INTEGRITY, first); - Pipeline.render(union(), Outputs.RENDERED_UNION.projects(), Outputs.INTEGRITY, second); - - assertSameTree(second, first); - } - - @Test - void aSetTheChecksRefuseWritesNothingAndSaysWhy(@TempDir Path directory, @TempDir Path out) throws IOException { - Path broken = Examples.write( - directory, - "notes.project.yml", - Examples.read("minimal/notes.project.yml").replace("surface: http }", "surface: grpc }")); - List files = Outputs.RENDERED_UNION.documents().stream() - .map(file -> file.equals("minimal/notes.project.yml") ? broken : Examples.of(file)) - .toList(); - - assertThat(Pipeline.render(files, Outputs.RENDERED_UNION.projects(), Outputs.INTEGRITY, out)) - .extracting(Diagnostic::code) - .contains("E_UNKNOWN_SURFACE"); - assertThat(filesUnder(out)).isEmpty(); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ResolutionTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ResolutionTest.java deleted file mode 100644 index 9fa533a94..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ResolutionTest.java +++ /dev/null @@ -1,268 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.groups.Tuple.tuple; - -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentPackage; -import java.io.IOException; -import java.nio.file.Path; -import java.util.List; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** The resolution of minimal, through the QVT-Operational transformation (issue #90). */ -class ResolutionTest { - - /** minimal, the foundation it composes with, and the pinned inputs beside them. */ - static final List MINIMAL_SET = Outputs.RESOLVED.get("minimal").documents(); - - static ResolvedDeployment minimal() throws IOException { - Resolved resolved = - Pipeline.resolve(MINIMAL_SET.stream().map(Examples::of).toList(), "notes", Outputs.INTEGRITY); - assertThat(resolved.diagnostics()).isEmpty(); - return resolved.deployment(); - } - - /** The expected Resolved Deployment committed for {@code project} under {@code emf/models/}. */ - private static ResolvedDeployment expected(String project) { - ResolvedDeploymentPackage.eINSTANCE.getName(); - ResourceSetImpl resources = new ResourceSetImpl(); - resources.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new XMIResourceFactoryImpl()); - Path model = Examples.of("") - .getParent() - .getParent() - .getParent() - .resolve("emf/models/" + project + ".resolveddeployment"); - Resource resource = resources.getResource(URI.createFileURI(model.toString()), true); - return (ResolvedDeployment) resource.getContents().get(0); - } - - @Test - void aResolutionKeepsTheTwoExtentsItWasResolvedFrom() throws IOException { - Resolved resolved = - Pipeline.resolve(MINIMAL_SET.stream().map(Examples::of).toList(), "notes", Outputs.INTEGRITY); - - assertThat(resolved.ok()).isTrue(); - // Every authored project, its lowering, and the Platform document. - long projects = MINIMAL_SET.stream() - .filter(file -> file.endsWith(".project.yml")) - .count(); - assertThat(resolved.intent()).hasSize((int) (2 * projects + 1)); - // The node contract, the images lock and the cluster state, beside every Asset file read. - assertThat(resolved.pinned()) - .filteredOn(root -> !(root instanceof dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.AssetFile)) - .hasSize(3); - } - - @Test - void aSetTheChecksRefuseIsNeverResolved(@TempDir Path directory) throws IOException { - Path broken = Examples.write( - directory, - "notes.project.yml", - Examples.read("minimal/notes.project.yml").replace("surface: http }", "surface: grpc }")); - List files = MINIMAL_SET.stream() - .map(file -> file.equals("minimal/notes.project.yml") ? broken : Examples.of(file)) - .toList(); - - Resolved resolved = Pipeline.resolve(files, "notes", Outputs.INTEGRITY); - - assertThat(resolved.ok()).isFalse(); - assertThat(resolved.deployment()).isNull(); - assertThat(resolved.intent()).isEmpty(); - assertThat(resolved.diagnostics()).extracting(Diagnostic::code).contains("E_UNKNOWN_SURFACE"); - } - - @Test - void anEnvFileTheReaderRefusesRefusesTheSet(@TempDir Path directory) throws IOException { - Path project = Examples.write(directory, "notes.project.yml", Examples.read("minimal/notes.project.yml")); - java.nio.file.Files.createDirectories(directory.resolve("env/notes-api")); - Examples.write(directory.resolve("env/notes-api"), "base.env", "NODE_ENV=production\nNODE_ENV=test\n"); - List files = MINIMAL_SET.stream() - .map(file -> file.equals("minimal/notes.project.yml") ? project : Examples.of(file)) - .toList(); - - Resolved resolved = Pipeline.resolve(files, "notes", Outputs.INTEGRITY); - - assertThat(resolved.diagnostics()) - .extracting(Diagnostic::code) - .containsExactly("E_SHARED_DECLARATION_DUPLICATED"); - } - - @Test - void anAssetCarriesTheFileBesideItsProjectWordForWord() throws IOException { - Resolved data = Pipeline.resolve( - Outputs.RESOLVED.get("data").documents().stream() - .map(Examples::of) - .toList(), - "data", - Outputs.INTEGRITY); - - assertThat(data.deployment() - .getApplications() - .get(0) - .getProcesses() - .get(0) - .getAssets()) - .singleElement() - .satisfies(asset -> - assertThat(asset.getContent()).isEqualTo(Examples.read("data/config/postgresql.conf"))); - } - - @Test - void anAssetWhoseFileIsNotBesideItsProjectIsRefusedBeforeResolution(@TempDir Path directory) throws IOException { - Path data = Examples.write(directory, "data.project.yml", Examples.read("data/data.project.yml")); - List files = Outputs.RESOLVED.get("data").documents().stream() - .map(file -> file.equals("data/data.project.yml") ? data : Examples.of(file)) - .toList(); - - assertThat(Pipeline.resolve(files, "data", Outputs.INTEGRITY).diagnostics()) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path) - .containsExactly( - tuple("E_ASSET_NOT_FOUND", "data.project.yml", "/applications/0/processes/0/assets/0/from"), - tuple("E_ASSET_NOT_FOUND", "data.project.yml", "/applications/5/processes/0/assets/0/from"), - tuple("E_DASHBOARD_NOT_FOUND", "data.project.yml", "/applications/1/dashboards/0/from")); - } - - /** - * REQ-038: an Application's revision is the digest of its own element, as the production - * implementation writes it. Every committed projection records it, and the rendered tree carries - * it, so this implementation derives the same one: it does not move when only the provenance - * does, and it moves when a decision about the Application does. - */ - @Test - void theRevisionIsTheOneEveryCommittedProjectionRecordsAndMovesOnlyWithADecision(@TempDir Path directory) - throws IOException { - for (String example : List.of("minimal", "auth", "data", "delivery", "knowledge-platform")) { - Outputs.Resolving resolving = Outputs.RESOLVED.get(example); - ResolvedDeployment deployment = Pipeline.resolve( - resolving.documents().stream().map(Examples::of).toList(), - resolving.project(), - Outputs.INTEGRITY) - .deployment(); - try (var oracles = java.nio.file.Files.list(Examples.of(example + "/expected"))) { - for (Path oracle : oracles.filter( - file -> file.getFileName().toString().startsWith("resolved")) - .toList()) { - String text = java.nio.file.Files.readString(oracle); - String id = field(text, "id"); - assertThat(deployment.getApplications()) - .filteredOn(application -> application.getId().equals(id)) - .singleElement() - .satisfies(application -> assertThat(application.getRevision()) - .as(oracle.toString()) - .isEqualTo(field(text, "revision"))); - } - } - } - - String recorded = minimal().getApplications().get(0).getRevision(); - Path moved = Examples.write( - directory, - "notes.project.yml", - Examples.read("minimal/notes.project.yml").replace("memory: 256Mi", "memory: 512Mi")); - Path captured = Examples.write( - directory, - "cluster-state.yml", - Examples.read("platform/cluster-state.yml").replace("2026-09-30", "2026-10-01")); - assertThat(revisionWith("minimal/notes.project.yml", moved)).isNotEqualTo(recorded); - assertThat(revisionWith("platform/cluster-state.yml", captured)).isEqualTo(recorded); - } - - /** minimal's revision, resolved with {@code replaced} in place of the example file {@code name}. */ - private static String revisionWith(String name, Path replaced) throws IOException { - List files = MINIMAL_SET.stream() - .map(file -> file.equals(name) ? replaced : Examples.of(file)) - .toList(); - return Pipeline.resolve(files, "notes", Outputs.INTEGRITY) - .deployment() - .getApplications() - .get(0) - .getRevision(); - } - - /** The value of the top-level string field {@code key} in a canonical JSON text. */ - private static String field(String json, String key) { - java.util.regex.Matcher found = java.util.regex.Pattern.compile("\"" + key + "\":\"([^\"]*)\"") - .matcher(json.substring(json.lastIndexOf("\"" + key + "\":"))); - assertThat(found.find()).isTrue(); - return found.group(1); - } - - @Test - void minimalResolvesToTheHandWrittenTargetModel() throws IOException { - ResolvedDeployment resolved = minimal(); - - assertThat(ModelDiff.differences("minimal.resolveddeployment", List.of(expected("minimal")), List.of(resolved))) - .isEmpty(); - } - - @Test - void secretsResolvesToItsCompleteExpectedModel() throws IOException { - Resolved resolved = Pipeline.resolve( - Outputs.RESOLVED.get("secrets").documents().stream() - .map(Examples::of) - .toList(), - "secrets", - Outputs.INTEGRITY); - assertThat(resolved.diagnostics()).isEmpty(); - - assertThat(ModelDiff.differences( - "secrets.resolveddeployment", List.of(expected("secrets")), List.of(resolved.deployment()))) - .isEmpty(); - } - - /** - * The Secret Store's own Project follows nothing: every unit holding a grant follows it, so a - * store routed through another Project's proxy and reaching another Project would close a cycle - * (deploy-kit#780, spec/v1/20-resolved-deployment.md#the-reconcile-unit). - */ - @Test - void theSecretStoresOwnProjectFollowsNothingThoughItIsRoutedAndReachesAnotherProject(@TempDir Path directory) - throws IOException { - Path platform = Examples.write( - directory, - "platform.intent.yml", - Examples.read("platform/platform.intent.yml") - .replace("secretStore: secrets/vault", "secretStore: notes/notes")); - Path notes = Examples.write( - directory, - "notes.project.yml", - Examples.read("minimal/notes.project.yml").replace(REACHES, REACHED)); - List files = MINIMAL_SET.stream() - .map(file -> file.equals("platform/platform.intent.yml") - ? platform - : file.equals("minimal/notes.project.yml") ? notes : Examples.of(file)) - .toList(); - - Resolved resolved = Pipeline.resolve(files, "notes", Outputs.INTEGRITY); - - assertThat(resolved.diagnostics()).isEmpty(); - assertThat(resolved.deployment().getReconcileUnits()) - .extracting(unit -> unit.getName()) - .containsExactly("apps-notes"); - // The same edge, under the worked store, is a unit notes follows. - assertThat(Pipeline.resolve( - MINIMAL_SET.stream() - .map(file -> - file.equals("minimal/notes.project.yml") ? notes : Examples.of(file)) - .toList(), - "notes", - Outputs.INTEGRITY) - .deployment() - .getReconcileUnits()) - .extracting(unit -> unit.getName()) - .containsExactly("apps-notes", "apps-edge", "apps-observability"); - } - - /** notes-api's ports, after which a required edge into the metrics stack's collector is written. */ - static final String REACHES = - " provides:\n http: 8080 # the image's own port; any port binds (chapter 14)\n"; - - static final String REACHED = - REACHES + " dependsOn:\n - { application: otel-collector, surface: otlp }\n"; -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ShippedFilesTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ShippedFilesTest.java deleted file mode 100644 index 75e18cb46..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ShippedFilesTest.java +++ /dev/null @@ -1,215 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.tuple; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.AlertRules; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Dashboard; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - -/** The files an Application ships for the monitoring stack: there, keyed, and keyed once across the estate. */ -class ShippedFilesTest { - - private static final ProjectIntentFactory MODEL = ProjectIntentFactory.eINSTANCE; - - /** A project of one Application per entry, each shipping the dashboards and rule files named. */ - private static Project project(List dashboards, List rules) { - Project project = MODEL.createProject(); - project.setProject("refusals"); - Application application = MODEL.createApplication(); - application.setId("api"); - for (String from : dashboards) { - Dashboard dashboard = MODEL.createDashboard(); - dashboard.setFrom(from); - application.getDashboards().add(dashboard); - } - for (String from : rules) { - AlertRules file = MODEL.createAlertRules(); - file.setFrom(from); - application.getAlertRules().add(file); - } - project.getApplications().add(application); - return project; - } - - private static List check( - Project project, Map files, List placed) { - return ShippedFiles.check( - project, "refusals.project.yml", from -> Optional.ofNullable(files.get(from)), placed); - } - - @Test - void aDashboardThatIsNotThereOrNamesNoUidIsRefusedAndOneThatDoesIsPlaced() { - List placed = new ArrayList<>(); - Project project = project(List.of("absent.json", "keyless.json", "board.json"), List.of()); - - List refusals = check( - project, Map.of("keyless.json", "{\"title\": \"x\"}", "board.json", "{\"uid\": \"board\"}"), placed); - - assertThat(refusals) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path) - .containsExactly( - tuple( - ShippedFiles.DASHBOARD_NOT_FOUND, - "refusals.project.yml", - "/applications/0/dashboards/0/from"), - tuple( - ShippedFiles.DASHBOARD_WITHOUT_UID, - "refusals.project.yml", - "/applications/0/dashboards/1/from")); - assertThat(refusals.get(0).message()).isEqualTo("no file absent.json is read beside the project file"); - assertThat(refusals.get(1).message()) - .isEqualTo("keyless.json names no uid, so Grafana would key it by a value of its own"); - assertThat(placed) - .containsExactly( - new ShippedFiles.Placed("refusals.project.yml", "/applications/0/dashboards/2/from", "board")); - } - - @Test - void aRuleFileThatIsNotThereOrHoldsNoGroupsIsRefused() { - Project project = project(List.of(), List.of("absent.yaml", "rules.yaml", "groups.yaml")); - - List refusals = check( - project, - Map.of("rules.yaml", "rules:\n - alert: ApiDown\n", "groups.yaml", "groups:\n - name: api\n"), - new ArrayList<>()); - - assertThat(refusals) - .extracting(Diagnostic::code, Diagnostic::path, Diagnostic::message) - .containsExactly( - tuple( - ShippedFiles.ALERT_RULES_NOT_FOUND, - "/applications/0/alertRules/0/from", - "no file absent.yaml is read beside the project file"), - tuple( - ShippedFiles.ALERT_RULES_WITHOUT_GROUPS, - "/applications/0/alertRules/1/from", - "rules.yaml holds no list of rule groups under `groups`")); - } - - @ParameterizedTest - @ValueSource( - strings = { - "groups:\n - name: api\n", - "groups:\n- name: api\n", - "groups: # the rule groups\n\n # first\n - name: api\n", - "groups: [ {name: api} ]\n", - "# rules\ngroups:\n - name: api\n", - " groups:\n - name: api\n", - "{\n \"groups\": [\n {\"name\": \"api\"}\n ]\n}\n" - }) - void aListUnderATopLevelGroupsKeyHoldsGroups(String content) { - assertThat(check(project(List.of(), List.of("r.yaml")), Map.of("r.yaml", content), new ArrayList<>())) - .isEmpty(); - } - - @ParameterizedTest - @ValueSource( - strings = { - "", - "groups:\n", - "groups: []\n", - "groups: [ ]\n", - "groups: api\n", - "- groups: [a]\n", - "groups: [a\n" - }) - void anythingElseHoldsNone(String content) { - assertThat(check(project(List.of(), List.of("r.yaml")), Map.of("r.yaml", content), new ArrayList<>())) - .extracting(Diagnostic::code) - .containsExactly(ShippedFiles.ALERT_RULES_WITHOUT_GROUPS); - } - - @Test - void aUidTheEstateCarriesAlreadyIsRefusedAtEveryLaterDashboard() { - List placed = List.of( - new ShippedFiles.Placed("a.project.yml", "/applications/0/dashboards/0/from", "board"), - new ShippedFiles.Placed("b.project.yml", "/applications/1/dashboards/0/from", "other"), - new ShippedFiles.Placed("b.project.yml", "/applications/1/dashboards/1/from", "board")); - - assertThat(ShippedFiles.acrossTheEstate(placed, Optional.empty())) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path, Diagnostic::message) - .containsExactly(tuple( - ShippedFiles.DUPLICATE_DASHBOARD_UID, - "b.project.yml", - "/applications/1/dashboards/1/from", - "another dashboard of the estate already carries the uid board")); - } - - @Test - void aPlatformThatNamesNoGrafanaRefusesEveryDashboardAndOneThatDoesNone() { - List placed = - List.of(new ShippedFiles.Placed("a.project.yml", "/applications/0/dashboards/0/from", "board")); - Platform platform = MODEL.createPlatform(); - - assertThat(ShippedFiles.acrossTheEstate(placed, Optional.of(platform))) - .extracting(Diagnostic::code, Diagnostic::document, Diagnostic::path, Diagnostic::message) - .containsExactly(tuple( - ShippedFiles.NO_DASHBOARD_POLICY, - "a.project.yml", - "/applications/0/dashboards/0/from", - "the platform names no Grafana for a dashboard to ship to")); - platform.setTelemetry(MODEL.createTelemetryPolicy()); - assertThat(ShippedFiles.acrossTheEstate(placed, Optional.of(platform))) - .extracting(Diagnostic::code) - .containsExactly(ShippedFiles.NO_DASHBOARD_POLICY); - platform.getTelemetry().setDashboards(MODEL.createDashboardPolicy()); - assertThat(ShippedFiles.acrossTheEstate(placed, Optional.of(platform))).isEmpty(); - } - - @ParameterizedTest - @ValueSource( - strings = { - "{\"uid\":\"board\"}", - " { \"title\" : \"x\" , \"uid\" : \"board\" } \n", - "{\"panels\": [{\"uid\": \"nested\"}, 1, -2.5e3, true, false, null, [], {}], \"uid\": \"board\"}", - "{\"uid\": \"bo\\u0061rd\"}", - "{\"uid\": \"x\", \"uid\": \"board\"}", - "{\"a\": { }, \"b\": [ ], \"uid\": \"board\"}" - }) - void aDocumentsOwnUidIsReadAndNoNestedOne(String json) { - assertThat(ShippedFiles.TopLevel.uid(json)).contains("board"); - } - - @Test - void anEscapedStringReadsAsWhatItEscapes() { - assertThat(ShippedFiles.TopLevel.uid("{\"uid\": \"a\\nb\\tc\\rd\\be\\ff\\\"g\\\\h\\/i\"}")) - .contains("a\nb\tc\rd\be\ff\"g\\h/i"); - } - - @ParameterizedTest - @ValueSource( - strings = { - "", - "[]", - "{}", - "{\"uid\": \"\"}", - "{\"uid\": 7}", - "{\"panels\": [{\"uid\": \"nested\"}]}", - "{\"uid\": \"board\"} trailing", - "{\"uid\": \"board\" \"title\": \"x\"}", - "{\"uid\" \"board\"}", - "{\"a\": [1 2], \"uid\": \"board\"}", - "{\"a\": tru, \"uid\": \"board\"}", - "{\"uid\": \"\\u12G4\"}", - "{\"a\": truex, \"uid\": \"board\"}", - "{\"a\": , \"uid\": \"board\"}", - "{uid: \"board\"}", - "{\"uid\": \"board\"", - "{\"uid\": \"bo\\u00", - "{\"uid\": \"board\", \"a\": 1" - }) - void aDocumentThatIsNoObjectOrNamesNoUidOfItsOwnHasNone(String json) { - assertThat(ShippedFiles.TopLevel.uid(json)).isEmpty(); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/StageTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/StageTest.java deleted file mode 100644 index cef3d0e9f..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/StageTest.java +++ /dev/null @@ -1,125 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.stream.Stream; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.util.Diagnostician; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; - -/** - * Each stage of the pipeline on its own, in-process, file in and file out: what it writes for every - * case equals the case's {@code expected/} by content and then by bytes (Stages). A stage's case is - * read from the working copy, so an edited template, transformation or input is what the next run - * reads; {@code -Dgolden.update=true} rewrites the EMF-owned goldens instead of comparing. - */ -class StageTest { - - static Stream cases() { - return Stages.ORDER.stream() - .flatMap(stage -> Stages.produced(stage).stream().map(name -> Arguments.of(stage, name))); - } - - @ParameterizedTest(name = "{0} {1}") - @MethodSource("cases") - void aStageWritesWhatItsCaseExpects(String stage, String name) throws IOException { - Map written = Stages.run(stage, name); - - if (Stages.updating() && Stages.oracles(name).isEmpty()) { - Stages.update(Stages.expected(stage, name), written); - return; - } - List differences = Comparison.trees(Stages.expected(stage, name), written); - assertThat(differences) - .withFailMessage( - "%s %s: %d differences%n%s", stage, name, differences.size(), String.join("\n", differences)) - .isEmpty(); - } - - @Test - void everyCaseAfterTheFirstStageReadsACaseOfTheStageBefore() { - for (int i = 1; i < Stages.ORDER.size(); i++) { - assertThat(Stages.cases(Stages.ORDER.get(i - 1))) - .as("the cases of %s, which %s reads", Stages.ORDER.get(i - 1), Stages.ORDER.get(i)) - .containsAll(Stages.produced(Stages.ORDER.get(i))); - } - // A given case is written by hand only to drive the stage after it, and only render's - // given input, a Resolved Deployment, is one this harness reads by hand. - assertThat(Stages.ORDER.stream() - .flatMap(stage -> Stages.cases(stage).stream() - .filter(name -> Stages.given(stage, name)) - .map(name -> stage + " " + name)) - .toList()) - .allSatisfy(given -> assertThat(given).startsWith("resolve ")) - .allSatisfy(given -> assertThat(Stages.cases("render")).contains(given.substring(8))); - assertThat(Stages.cases("parse")) - .allSatisfy(name -> assertThat( - Stages.root().resolve("parse").resolve(name).resolve(Stages.INPUT)) - .isDirectory()); - } - - /** - * A given Resolved Deployment is written by hand, so the metamodel holds it to what the resolution - * would have to write: every feature's bounds, every type. - */ - @Test - void aGivenResolvedDeploymentIsAValidModel() throws IOException { - for (String name : Stages.cases("resolve")) { - if (!Stages.given("resolve", name)) { - continue; - } - for (String project : Stages.projects(name)) { - Path model = Stages.expected("resolve", name).resolve(project + Stages.RESOLVED_MODEL); - for (EObject root : Stages.load(Stages.resources(), model)) { - org.eclipse.emf.common.util.Diagnostic diagnostic = Diagnostician.INSTANCE.validate(root); - assertThat(diagnostic.getSeverity()) - .as("%s: %s", model, diagnostic.getChildren()) - .isLessThan(org.eclipse.emf.common.util.Diagnostic.ERROR); - } - } - } - } - - /** - * A render case of copied oracles names every file it expects, and each equals the production - * implementation's oracle byte for byte, so a copy cannot drift from what it was copied from. - */ - @Test - void aCopiedOracleIsTheProductionImplementationsOwnBytes() throws IOException { - for (String name : Stages.cases("render")) { - Map oracles = Stages.oracles(name); - if (oracles.isEmpty()) { - continue; - } - Path expected = Stages.expected("render", name); - assertThat(Comparison.read(expected).keySet()) - .as("the files render %s expects, each named in its %s", name, Stages.ORACLES) - .containsExactlyInAnyOrderElementsOf(oracles.keySet()); - for (Map.Entry copy : oracles.entrySet()) { - assertThat(expected.resolve(copy.getKey())) - .as("render %s: %s, a copy of %s", name, copy.getKey(), copy.getValue()) - .hasSameBinaryContentAs(Examples.of(copy.getValue())); - } - } - } - - @Test - void aGoldenUpdateNeverWritesTheProductionImplementationsOracles() { - assertThatThrownBy(() -> Stages.update(Examples.of("minimal/expected"), Map.of())) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("is not an EMF-owned golden"); - assertThat(Examples.of("minimal/expected/intent.json")).exists(); - assertThatThrownBy(() -> Stages.update(Stages.root().resolve("../../../../../../spec/v1/examples"), Map.of())) - .isInstanceOf(IllegalArgumentException.class); - assertThat(Files.isDirectory(Examples.of("minimal"))).isTrue(); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Stages.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Stages.java deleted file mode 100644 index 8fa3334c9..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/Stages.java +++ /dev/null @@ -1,380 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import dev.jorisjonkers.deploykit.emf.metamodel.descriptor.DependencyEdges; -import dev.jorisjonkers.deploykit.emf.metamodel.json.CanonicalJson; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.PinnedInputsPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EffectiveProject; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentPackage; -import dev.jorisjonkers.deploykit.emf.resolve.Lowering; -import dev.jorisjonkers.deploykit.emf.resolve.Resolution; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; - -/** - * The stage harness: each stage of the pipeline run in-process on its own, file in and file out - * (emf/docs/architecture.md#stage-tests). A case is a directory, {@code stages///}, - * whose {@code expected/} holds what the stage writes. Only {@code parse} holds an {@code input/}: - * every later stage reads the {@code expected/} of the stage before it, the same files, so one - * golden serves in two roles and two stages cannot drift apart. - * - *
    - *
  • {@code parse}: the authored documents under {@code input/}, read together, to {@link - * #INTENT_MODEL} (every authored Project with its env files, and the Platform document), {@link - * #PINNED_MODEL} (the pinned inputs with each Asset's file), and each intent document's parsed - * intent as {@code .json}. - *
  • {@code lower}: each Project of {@code parse}'s {@link #INTENT_MODEL}, lowered, to {@link - * #EFFECTIVE_MODEL} and {@code .effective.json}. - *
  • {@code resolve}: both extents, from {@code parse} and {@code lower}, resolved for each project - * {@link #PROJECTS} names, to {@code .resolveddeployment} and {@code - * .dependencies.json}. - *
  • {@code render}: every Resolved Deployment of {@code resolve}, rendered together, to the tree. - *
- * - *

A case of a later stage with no case of the stage before is given: its {@code - * expected/} is written by hand rather than by the stage, so the stage after it can be driven by a - * model no earlier stage produces yet. A given {@code resolve} case is how a {@code render} case - * reads a Resolved Deployment the resolution cannot write yet. A {@code render} case whose {@code - * expected/} files are copies of the production implementation's oracles names each in {@link - * #ORACLES}, one {@code } pair a line, the oracle path below {@code - * spec/v1/examples/}, and the copies must equal their oracles byte for byte. - * - *

With {@code -Dgolden.update=true} a run rewrites these {@code expected/} trees from what the - * stages wrote, for review in {@code git diff}, save a given case and a case of copied oracles. It - * never writes anywhere else: the oracles under {@code spec/v1/examples/} belong to the production - * implementation and are never regenerated here. - */ -final class Stages { - - /** The stages, in the order they run and the order a golden update must rewrite them in. */ - static final List ORDER = List.of("parse", "lower", "resolve", "render"); - - /** The property that turns a run into a golden update. */ - static final String UPDATE = "golden.update"; - - static final String INTENT_MODEL = "intent.xmi"; - static final String PINNED_MODEL = "pinned.xmi"; - static final String EFFECTIVE_MODEL = "effective.xmi"; - static final String RESOLVED_MODEL = ".resolveddeployment"; - - /** The file a resolve case names the projects it resolves in, one per line. */ - static final String PROJECTS = "projects"; - - /** The file a render case names the oracle each expected file is a copy of in. */ - static final String ORACLES = "oracles"; - - static final String INPUT = "input"; - static final String EXPECTED = "expected"; - - /** The pinned inputs, each by its own file name, beside the two intent documents' kinds. */ - private static final Set PINNED = - Set.of("node-contract.yml", "images.lock.yml", "cluster-state.yml", "migration-proof.yml"); - - private static final String PLATFORM = "platform.intent.yml"; - private static final String PROJECT = ".project.yml"; - - private Stages() {} - - /** {@code emf/bundles/cli/src/test/resources/stages}, in the working copy rather than on the class path. */ - static Path root() { - return Examples.repository().resolve("emf/bundles/cli/src/test/resources/stages"); - } - - /** The cases of {@code stage}, by name, sorted. */ - static List cases(String stage) { - Path directory = root().resolve(stage); - if (!Files.isDirectory(directory)) { - return List.of(); - } - try (Stream entries = Files.list(directory)) { - return entries.filter(Files::isDirectory) - .map(path -> path.getFileName().toString()) - .sorted() - .toList(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** Whether case {@code name} of {@code stage} is given: a later stage's case with no case of the stage before. */ - static boolean given(String stage, String name) { - int at = ORDER.indexOf(stage); - return at > 0 && !cases(ORDER.get(at - 1)).contains(name); - } - - /** The cases of {@code stage} the stage itself writes, every case but a given one. */ - static List produced(String stage) { - return cases(stage).stream().filter(name -> !given(stage, name)).toList(); - } - - /** - * The oracle each expected file of render case {@code name} is a copy of, by its path below - * {@code expected/}, the oracle's below {@code spec/v1/examples/}; nothing for a case of this - * implementation's own goldens. - */ - static Map oracles(String name) throws IOException { - Path file = root().resolve("render").resolve(name).resolve(ORACLES); - Map oracles = new TreeMap<>(); - if (!Files.isRegularFile(file)) { - return oracles; - } - for (String line : Files.readAllLines(file)) { - String[] pair = line.strip().split("\\s+"); - if (pair.length == 2) { - oracles.put(pair[0], pair[1]); - } else if (!line.isBlank()) { - throw new IllegalArgumentException(file + ": not an pair: " + line); - } - } - return oracles; - } - - static Path expected(String stage, String name) { - return root().resolve(stage).resolve(name).resolve(EXPECTED); - } - - static boolean updating() { - return Boolean.getBoolean(UPDATE); - } - - /** What {@code stage} writes for case {@code name}, by path below its {@code expected/}. */ - static Map run(String stage, String name) throws IOException { - return switch (stage) { - case "parse" -> parse(name); - case "lower" -> lower(name); - case "resolve" -> resolve(name); - case "render" -> render(name); - default -> throw new IllegalArgumentException("no stage " + stage); - }; - } - - /** - * Rewrites {@code expected} as {@code written}: what is no longer written is removed. Only a tree - * under {@link #root()} is ever rewritten. - */ - static void update(Path expected, Map written) throws IOException { - Path target = expected.toAbsolutePath().normalize(); - if (!target.startsWith(root().toAbsolutePath().normalize()) - || target.toString().replace('\\', '/').contains("spec/v1/examples")) { - throw new IllegalArgumentException( - target + " is not an EMF-owned golden, and a golden update never" + " writes it"); - } - if (Files.isDirectory(target)) { - try (Stream tree = Files.walk(target)) { - for (Path path : tree.sorted(Comparator.reverseOrder()).toList()) { - Files.delete(path); - } - } - } - for (Map.Entry file : written.entrySet()) { - Path path = target.resolve(file.getKey()); - Files.createDirectories(path.getParent()); - Files.write(path, file.getValue()); - } - } - - // ------------------------------------------------------------------------------------- stages - - private static Map parse(String name) throws IOException { - Path input = root().resolve("parse").resolve(name).resolve(INPUT); - List documents = documents(input); - Map written = new TreeMap<>(); - Authored authored = Pipeline.authored(documents); - if (!authored.ok()) { - written.put("diagnostics.json", json(diagnostics(authored.diagnostics()))); - return written; - } - Path expected = expected("parse", name); - EcoreUtil.Copier copier = new EcoreUtil.Copier(); - Resource intent = model(expected.resolve(INTENT_MODEL)); - Resource pinned = model(expected.resolve(PINNED_MODEL)); - intent.getContents().addAll(copier.copyAll(authored.intent())); - pinned.getContents().addAll(copier.copyAll(authored.pinned())); - copier.copyReferences(); - written.put(INTENT_MODEL, bytes(intent)); - written.put(PINNED_MODEL, bytes(pinned)); - for (Path document : documents) { - if (!PINNED.contains(document.getFileName().toString())) { - Parsed parsed = Pipeline.intent(document); - String json = - input.relativize(document).toString().replace('\\', '/').replaceFirst("\\.yml$", ".json"); - written.put(json, json(parsed.ok() ? parsed.intent() : diagnostics(parsed.diagnostics()))); - } - } - return written; - } - - private static Map lower(String name) throws IOException { - Map written = new TreeMap<>(); - Resource effective = model(expected("lower", name).resolve(EFFECTIVE_MODEL)); - for (EObject root : load(resources(), expected("parse", name).resolve(INTENT_MODEL))) { - if (root instanceof Project project) { - EffectiveProject lowered = Lowering.lower(project); - written.put(lowered.getProject() + ".effective.json", json(IntentJson.of(lowered))); - effective.getContents().add(lowered); - } - } - written.put(EFFECTIVE_MODEL, bytes(effective)); - return written; - } - - private static Map resolve(String name) throws IOException { - Map written = new TreeMap<>(); - for (String project : projects(name)) { - ResourceSet resources = resources(); - List authored = load(resources, expected("parse", name).resolve(INTENT_MODEL)); - List lowered = load(resources, expected("lower", name).resolve(EFFECTIVE_MODEL)); - List pinned = load(resources, expected("parse", name).resolve(PINNED_MODEL)); - List intent = new ArrayList<>(); - int next = 0; - for (EObject root : authored) { - intent.add(root); - // Each authored Project sits beside its lowering, as the pipeline reads them. - if (root instanceof Project) { - intent.add(lowered.get(next++)); - } - } - ResolvedDeployment deployment = Resolution.resolve(intent, pinned, project, Outputs.INTEGRITY); - Resource model = model(expected("resolve", name).resolve(project + RESOLVED_MODEL)); - model.getContents().add(deployment); - written.put(project + RESOLVED_MODEL, bytes(model)); - written.put(project + "." + DependencyEdges.NAME, json(DependencyEdges.of(deployment))); - } - return written; - } - - /** - * What a case of copied oracles compares: main commits a Project's own artifact, the - * estate-scoped artifact and the pinned sources each only in the trees holding its top-level - * directory, so the rendering is compared on the directories the case's copies hold. - */ - private static Map copiedShare(String name, Map written) { - if (!Files.exists(root().resolve("render").resolve(name).resolve(ORACLES))) { - return written; - } - Set held = Comparison.read(expected("render", name)).keySet().stream() - .map(path -> path.substring(0, path.indexOf('/') + 1)) - .collect(Collectors.toSet()); - written.keySet().removeIf(path -> !held.contains(path.substring(0, path.indexOf('/') + 1))); - return written; - } - - private static Map render(String name) throws IOException { - List deployments = new ArrayList<>(); - for (String project : projects(name)) { - Path model = expected("resolve", name).resolve(project + RESOLVED_MODEL); - deployments.add((ResolvedDeployment) load(resources(), model).get(0)); - } - Path out = Files.createTempDirectory("stage-render"); - try { - List refused = Pipeline.renderTogether(deployments, out); - if (!refused.isEmpty()) { - throw new AssertionError("the render case " + name + " was refused: " + refused); - } - return copiedShare(name, Comparison.read(out)); - } finally { - try (Stream tree = Files.walk(out)) { - for (Path path : tree.sorted(Comparator.reverseOrder()).toList()) { - Files.delete(path); - } - } - } - } - - // ------------------------------------------------------------------------------------ helpers - - /** The projects a case resolves, from the resolve case's {@link #PROJECTS}. */ - static List projects(String name) throws IOException { - return Files.readAllLines(root().resolve("resolve").resolve(name).resolve(PROJECTS)).stream() - .map(String::strip) - .filter(line -> !line.isEmpty()) - .toList(); - } - - /** The authored documents under {@code input}, by path: a project file, the Platform document, or a pinned input. */ - static List documents(Path input) throws IOException { - try (Stream tree = Files.walk(input)) { - return tree.filter(Files::isRegularFile) - .filter(path -> { - String file = path.getFileName().toString(); - return file.endsWith(PROJECT) || file.equals(PLATFORM) || PINNED.contains(file); - }) - .sorted() - .toList(); - } - } - - /** A resource set reading XMI under any name, with every metamodel registered. */ - static ResourceSet resources() { - ProjectIntentPackage.eINSTANCE.getName(); - PinnedInputsPackage.eINSTANCE.getName(); - ResolvedDeploymentPackage.eINSTANCE.getName(); - ResourceSet resources = new ResourceSetImpl(); - resources - .getResourceFactoryRegistry() - .getExtensionToFactoryMap() - .put(Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl()); - return resources; - } - - /** The roots of the XMI file at {@code path}, read into {@code resources}, so links between files resolve. */ - static List load(ResourceSet resources, Path path) { - Resource resource = resources.getResource( - URI.createFileURI(path.toAbsolutePath().normalize().toString()), true); - return new ArrayList<>(resource.getContents()); - } - - private static Resource model(Path path) { - return new Outputs.ByIndex( - URI.createFileURI(path.toAbsolutePath().normalize().toString())); - } - - /** {@code root} saved as the XMI file at {@code path} would hold it, without writing it. */ - static byte[] xmi(Path path, EObject root) throws IOException { - Resource model = model(path); - model.getContents().add(root); - return bytes(model); - } - - private static byte[] bytes(Resource resource) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - resource.save(out, null); - return out.toByteArray(); - } - - private static byte[] json(Object value) { - return CanonicalJson.write(value).getBytes(StandardCharsets.UTF_8); - } - - /** The {@code (code, document, path)} triples the parity contract fixes, sorted. */ - static List diagnostics(List diagnostics) { - return diagnostics.stream() - .map(diagnostic -> (Object) new TreeMap<>(Map.of( - "code", diagnostic.code(), - "document", diagnostic.document(), - "path", diagnostic.path()))) - .sorted(Comparator.comparing(Object::toString)) - .toList(); - } -} diff --git a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/WorkedExamplesTest.java b/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/WorkedExamplesTest.java deleted file mode 100644 index e7be9dce5..000000000 --- a/emf/bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/WorkedExamplesTest.java +++ /dev/null @@ -1,85 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import java.util.stream.Stream; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.MethodSource; - -/** - * Every worked example parses, and so does every refusal fixture the refusals README marks - * `accepted`: the counterpart that makes a refusal a refusal rather than the only thing the rules - * can see. - */ -class WorkedExamplesTest { - - private static List projectFiles() { - Path examples = repository().resolve("spec/v1/examples"); - try (Stream tree = Files.walk(examples)) { - return tree.filter(path -> path.getFileName().toString().endsWith(".project.yml")) - .filter(path -> !path.toString().contains("refusals")) - .sorted() - .toList(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** The `accepted` rows of `spec/v1/examples/refusals/README.md`, as the files they name. */ - private static List acceptedCounterparts() { - Path refusals = repository().resolve("spec/v1/examples/refusals"); - Pattern row = Pattern.compile("^\\| \\[`([^`]+\\.project\\.yml)`\\]\\([^)]+\\) \\| accepted \\|"); - try (Stream lines = Files.lines(refusals.resolve("README.md"))) { - return lines.map(row::matcher) - .filter(Matcher::find) - .map(match -> refusals.resolve(match.group(1))) - .sorted() - .toList(); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - /** - * The accepted counterparts main's own validate refuses all the same, each with the codes it - * refuses them with: the README's row predates the rule. shared-intent-merged's worker holds a - * grant delivered self and wires no Vault client, which main refuses with - * E_SELF_WITHOUT_VAULT_CLIENT since that rule landed. - */ - private static final java.util.Map> REFUSED_BY_MAIN_TOO = - java.util.Map.of("shared-intent-merged.project.yml", List.of("E_SELF_WITHOUT_VAULT_CLIENT")); - - @ParameterizedTest(name = "{0}") - @MethodSource("acceptedCounterparts") - void everyAcceptedCounterpartParses(Path file) { - Parsed parsed = Pipeline.intent(file); - - assertThat(parsed.diagnostics()) - .extracting(Diagnostic::code) - .containsExactlyElementsOf( - REFUSED_BY_MAIN_TOO.getOrDefault(file.getFileName().toString(), List.of())); - } - - @ParameterizedTest(name = "{0}") - @MethodSource("projectFiles") - void everyWorkedExampleParses(Path file) { - Parsed parsed = Pipeline.intent(file); - - assertThat(parsed.diagnostics()).isEmpty(); - } - - private static Path repository() { - Path dir = Path.of("").toAbsolutePath(); - while (!Files.isRegularFile(dir.resolve("emf/pom.xml"))) { - dir = dir.getParent(); - } - return dir; - } -} diff --git a/emf/bundles/cli/src/test/resources/benchmark/lower.atl b/emf/bundles/cli/src/test/resources/benchmark/lower.atl deleted file mode 100644 index 082a25c64..000000000 --- a/emf/bundles/cli/src/test/resources/benchmark/lower.atl +++ /dev/null @@ -1,625 +0,0 @@ --- @atlcompiler emftvm --- @nsURI PI=https://jorisjonkers.dev/deploy-kit/project-intent/1 --- --- The lowering, ported from bundles/resolve/model/lower.qvto to ATL (EMFTVM) for --- the benchmark only (docs/benchmarks.md): it ships in no bundle, and the --- pipeline runs the QVT-Operational lowering. A rule is named for the class --- whose QVTo mapping it ports; the semantics are the same, and --- LoweringEquivalenceTest holds the two outputs equal under EMF Compare on --- every example. --- --- Two shapes of rule, because ATL ties a target to how its source is matched: --- * a matched rule where the source has exactly one image: the Project, its --- Applications and Processes, and everything they own outright. References --- to a lowered Process or Surface then resolve through the default trace, --- with no ordering to get right (QVTo's `resolveone`); --- * a lazy rule where a shared declaration is copied once per Process that --- inherits it (QVTo's `copyFor(owner)`): a matched rule gives one target per --- source, and a Grant on the Project has one image per Process below it. --- --- An unsettable feature is written only where the source states it. A binding --- is unconditional, and EMFTVM writes a null it is given, which marks such a --- feature set; so every conditional write sits in the rule's imperative `do` --- block instead. -module lower; -create OUT : PI from IN : PI; - --- ------------------------------------------------------------------- helpers - --- Whether the source states `feature`: QVTo's `states`, through EMFTVM's call --- of the Java method. -helper context OclAny def: states(feature : String) : Boolean = - self.eIsSet(self.eClass().getEStructuralFeature(feature)); - -helper context OclAny def: present : Boolean = not self.oclIsUndefined(); - --- EMFTVM reads an enumerator by its literal, not its name, and every `absent` --- literal is the empty string: the value reads as `#` followed by nothing, and --- `#absent` equals no value EMFTVM reads. So the comparison is with the text. -helper context OclAny def: absent : Boolean = self.toString() = '#'; - -helper context PI!Process def: app : PI!Application = self.refImmediateComposite(); - -helper context PI!Process def: prj : PI!Project = self.app.refImmediateComposite(); - --- Lowest level first, which is what decides every merge below. -helper context PI!Process def: levels : Sequence(PI!Placement) = - Sequence{self.placement, self.app.placement, self.prj.placement}->select(p | p.present); - -helper context PI!Process def: withArch : Sequence(PI!Placement) = self.levels->select(p | p.arch->notEmpty()); -helper context PI!Process def: withSite : Sequence(PI!Placement) = self.levels->select(p | p.site.present); -helper context PI!Process def: withDisk : Sequence(PI!Placement) = self.levels->select(p | p.disk.present); -helper context PI!Process def: withGpu : Sequence(PI!Placement) = self.levels->select(p | p.gpu.present); -helper context PI!Process def: withCapabilities : Sequence(PI!Placement) = - self.levels->select(p | p.capabilities->notEmpty()); - -helper context PI!Process def: budgets : Sequence(String) = - Sequence{self.startupBudget, self.app.startupBudget, self.prj.startupBudget}->select(b | b.present); - -helper context PI!Process def: cutovers : Sequence(PI!Cutover) = - Sequence{self.cutover, self.app.cutover, self.prj.cutover}->select(c | not c.absent); - --- The entries of every file of one scope; no file varies by cluster. -helper def: entriesIn(files : Sequence(PI!EnvFile)) : Sequence(PI!EnvVariable) = - files->collect(f | f.entries)->flatten(); - -helper def: mergeEntries(own : Sequence(PI!EnvVariable), shared : Sequence(PI!EnvVariable)) : Sequence(PI!EnvVariable) = - own->union(shared->select(e | own->forAll(m | m.name <> e.name))); - --- The derived read path is the identity, so a `kv` grant and a `database` grant --- never collide. -helper def: sameGrant(one : PI!Grant, other : PI!Grant) : Boolean = - (one.oclIsKindOf(PI!KvGrant) and other.oclIsKindOf(PI!KvGrant) and one.path = other.path) - or (one.oclIsKindOf(PI!DatabaseGrant) and other.oclIsKindOf(PI!DatabaseGrant) and one.role = other.role) - or (one.oclIsKindOf(PI!TransitGrant) and other.oclIsKindOf(PI!TransitGrant) and one.key = other.key); - -helper def: mergeGrants(own : Sequence(PI!Grant), shared : Sequence(PI!Grant)) : Sequence(PI!Grant) = - own->union(shared->select(g | own->forAll(m | not thisModule.sameGrant(m, g)))); - --- `required` is excluded: the same edge declared twice is the same declaration. -helper def: mergeEdges(own : Sequence(PI!DependencyEdge), shared : Sequence(PI!DependencyEdge)) : Sequence(PI!DependencyEdge) = - own->union(shared->select(e | own->forAll(m | m.application <> e.application or m.surface <> e.surface))); - --- Two files cannot arrive at one path, so where an Asset lands is its identity. -helper context PI!Asset def: landsAt : String = self.mountAt; -helper context PI!SeededAsset def: landsAt : String = self.seedAt; - -helper def: mergeAssets(own : Sequence(PI!AssetDeclaration), shared : Sequence(PI!AssetDeclaration)) : Sequence(PI!AssetDeclaration) = - own->union(shared->select(a | own->forAll(m | m.landsAt <> a.landsAt))); - --- A path is its own identity, so the union is the merge. -helper def: mergePaths(own : Sequence(PI!WritablePathDeclaration), shared : Sequence(PI!WritablePathDeclaration)) : Sequence(PI!WritablePathDeclaration) = - own->union(shared->select(w | own->forAll(m | m.path <> w.path))); - --- QVTo's `disjuncts`: a helper on each concrete type, which ATL dispatches on --- the runtime type, calls the lazy rule for it. -helper context PI!KvGrant def: copied() : PI!Grant = thisModule.KvGrantCopy(self); -helper context PI!DatabaseGrant def: copied() : PI!Grant = thisModule.DatabaseGrantCopy(self); -helper context PI!TransitGrant def: copied() : PI!Grant = thisModule.TransitGrantCopy(self); -helper context PI!PlainKey def: copied() : PI!KvKey = thisModule.PlainKeyCopy(self); -helper context PI!GeneratedKey def: copied() : PI!KvKey = thisModule.GeneratedKeyCopy(self); -helper context PI!OptionalKey def: copied() : PI!KvKey = thisModule.OptionalKeyCopy(self); -helper context PI!Asset def: copied() : PI!AssetDeclaration = thisModule.AssetCopy(self); -helper context PI!SeededAsset def: copied() : PI!AssetDeclaration = thisModule.SeededAssetCopy(self); -helper context PI!PlainPath def: copied() : PI!WritablePathDeclaration = thisModule.PlainPathCopy(self); -helper context PI!MemoryPath def: copied() : PI!WritablePathDeclaration = thisModule.MemoryPathCopy(self); -helper context PI!EnvLiteral def: copied() : PI!EnvValue = thisModule.EnvLiteralCopy(self); -helper context PI!Placeholder def: copied() : PI!EnvValue = thisModule.PlaceholderCopy(self); -helper context PI!DependencyEdge def: copied() : PI!DependencyEdge = thisModule.DependencyEdgeCopy(self); - --- ------------------------------------------------- matched rules: one image - --- Project::lower. Nobody authors the Effective Intent, so the header stays behind. -rule Project { - from s : PI!Project - to t : PI!EffectiveProject ( - project <- s.project, - owner <- s.owner, - applications <- s.applications - ) -} - --- Application::lower. -rule Application { - from s : PI!Application - to t : PI!EffectiveApplication ( - id <- s.id, - processes <- s.processes, - client <- s.client, - l4Exposure <- s.l4Exposure, - dashboards <- s.dashboards, - alertRules <- s.alertRules, - observability <- s.observability, - exposure <- s.exposure, - migration <- s.migration - ) - do { - if (s.description.present) { t.description <- s.description; } - } -} - -rule ManagedMigration { - from s : PI!ManagedMigration - to t : PI!ManagedMigration (changelog <- s.changelog) -} - -rule SelfMigration { - from s : PI!SelfMigration - to t : PI!SelfMigration -} - -rule NoMigration { - from s : PI!NoMigration - to t : PI!NoMigration -} - --- Process::lower. -rule Process { - from s : PI!Process - to t : PI!Process ( - name <- s.name, - lifecycle <- s.lifecycle, - image <- s.image, - runtime <- s.runtime, - provides <- s.provides, - sidecars <- s.sidecars, - probes <- s.probes, - volumes <- s.volumes, - replicas <- s.replicas, - api <- s.api, - egress <- s.egress, - vpn <- s.vpn, - libraries <- s.libraries, - parked <- s.parked, - command <- s.command, - args <- s.args, - spawns <- s.spawns, - secrets <- thisModule.mergeGrants(thisModule.mergeGrants(s.secrets, s.app.secrets), s.prj.secrets) - ->collect(g | g.copied()), - dependsOn <- thisModule.mergeEdges(thisModule.mergeEdges(s.dependsOn, s.app.dependsOn), s.prj.dependsOn) - ->collect(e | e.copied()), - assets <- thisModule.mergeAssets(thisModule.mergeAssets(s.assets, s.app.assets), s.prj.assets) - ->collect(a | a.copied()), - writablePaths <- thisModule.mergePaths(thisModule.mergePaths(s.writablePaths, s.app.writablePaths), s.prj.writablePaths) - ->collect(w | w.copied()), - -- The Process's one file, its entries extended by every scope above, or none. - env <- if s.env->union(s.app.env)->union(s.prj.env)->isEmpty() then Sequence{} - else Sequence{thisModule.EnvFileFor(s)} endif, - -- Key by key: each dimension from the lowest level that set it. - placement <- if s.levels->isEmpty() then OclUndefined else thisModule.PlacementFor(s) endif - ) - do { - if (s.states('engine')) { t.engine <- s.engine; } - if (s.description.present) { t.description <- s.description; } - if (s.schedule.present) { t.schedule <- s.schedule; } - -- The single values, from the lowest level that declared one. - if (s.budgets->notEmpty()) { t.startupBudget <- s.budgets->first(); } - -- A prepare Process cuts over nothing, so a shared answer does not reach it. - if (s.lifecycle <> #prepare and s.lifecycle <> #scheduled and s.cutovers->notEmpty()) { - t.cutover <- s.cutovers->first(); - } - } -} - -rule Parked { - from s : PI!Parked - to t : PI!Parked (reason <- s.reason) -} - -rule Observability { - from s : PI!Observability - to t : PI!Observability (scrape <- s.scrape) -} - -rule Scrape { - from s : PI!Scrape - to t : PI!Scrape ( - path <- s.path, - process <- s.process, - surface <- s.surface - ) - do { - if (s.honorLabels.present) { t.honorLabels <- s.honorLabels; } - } -} - -rule Exposure { - from s : PI!Exposure - to t : PI!Exposure ( - name <- s.name, - host <- s.host, - audience <- s.audience, - routes <- s.routes - ) - do { - if (s.states('contentPolicy')) { t.contentPolicy <- s.contentPolicy; } - if (s.proxied.present) { t.proxied <- s.proxied; } - } -} - -rule Route { - from s : PI!Route - to t : PI!Route ( - path <- s.path, - match <- s.match, - process <- s.process, - surface <- s.surface, - rateLimit <- s.rateLimit - ) - do { - if (s.states('audience')) { t.audience <- s.audience; } - if (s.redirectTo.present) { t.redirectTo <- s.redirectTo; } - } -} - -rule RateLimit { - from s : PI!RateLimit - to t : PI!RateLimit (requests <- s.requests, per <- s.per) -} - -rule Surface { - from s : PI!Surface - to t : PI!Surface (key <- s.key, value <- s.value) -} - -rule Sidecar { - from s : PI!Sidecar - to t : PI!Sidecar ( - name <- s.name, - image <- s.image, - command <- s.command, - args <- s.args, - memory <- s.memory, - cpu <- s.cpu, - volumes <- s.volumes, - assets <- s.assets - ) - do { - if (s."init".present) { t."init" <- s."init"; } - } -} - -rule SidecarMount { - from s : PI!SidecarMount - to t : PI!SidecarMount (claim <- s.claim, mountAt <- s.mountAt) -} - -rule SidecarAsset { - from s : PI!SidecarAsset - to t : PI!SidecarAsset ("from" <- s."from", mountAt <- s.mountAt) -} - --- A spawn template is the Process's own, so it is copied whole. -rule SpawnTemplate { - from s : PI!SpawnTemplate - to t : PI!SpawnTemplate ( - name <- s.name, - image <- s.image, - placement <- s.placement, - provides <- s.provides, - dependsOn <- s.dependsOn->collect(e | e.copied()), - egress <- s.egress - ) -} - -rule SpawnPlacement { - from s : PI!SpawnPlacement - to t : PI!SpawnPlacement (memory <- s.memory, cpu <- s.cpu) -} - -rule Client { - from s : PI!Client - to t : PI!Client ( - signIn <- s.signIn, - redirectPaths <- s.redirectPaths, - roles <- s.roles - ) - do { - if (s.exposure.present) { t.exposure <- s.exposure; } - if (s.label.present) { t.label <- s.label; } - if (s.description.present) { t.description <- s.description; } - if (s.iconPath.present) { t.iconPath <- s.iconPath; } - if (s.launchPath.present) { t.launchPath <- s.launchPath; } - if (s.protectedPath.present) { t.protectedPath <- s.protectedPath; } - if (s.backChannelLogoutPath.present) { t.backChannelLogoutPath <- s.backChannelLogoutPath; } - if (s.states('credential')) { t.credential <- s.credential; } - } -} - --- The port's Process and surface are the lowered Process's, as a route's are. -rule L4Exposure { - from s : PI!L4Exposure - to t : PI!L4Exposure ( - address <- s.address, - port <- s.port, - protocol <- s.protocol, - process <- s.process, - surface <- s.surface - ) -} - -rule Dashboard { - from s : PI!Dashboard - to t : PI!Dashboard ("from" <- s."from") -} - -rule AlertRules { - from s : PI!AlertRules - to t : PI!AlertRules ("from" <- s."from") -} - -rule Volume { - from s : PI!Volume - to t : PI!Volume (claim <- s.claim, mountAt <- s.mountAt, durability <- s.durability) - do { - if (s.size.present) { t.size <- s.size; } - } -} - -rule LibraryMount { - from s : PI!LibraryMount - to t : PI!LibraryMount ("library" <- s."library", mountAt <- s.mountAt, access <- s.access) - do { - if (s.subPath.present) { t.subPath <- s.subPath; } - } -} - -rule Egress { - from s : PI!Egress - to t : PI!Egress ("to" <- s."to", reason <- s.reason) -} - -rule VpnAttachment { - from s : PI!VpnAttachment - to t : PI!VpnAttachment (forwardedPort <- s.forwardedPort) -} - -rule ApiAccess { - from s : PI!ApiAccess - to t : PI!ApiAccess (reason <- s.reason, rules <- s.rules) -} - -rule ApiRule { - from s : PI!ApiRule - to t : PI!ApiRule (group <- s.group, objects <- s.objects, verbs <- s.verbs) - do { - if (s.states('scope')) { t.scope <- s.scope; } - } -} - -rule Capacity { - from s : PI!Capacity - to t : PI!Capacity (count <- s.count, reason <- s.reason) - do { - if (s.states('across')) { t.across <- s.across; } - } -} - -rule Probes { - from s : PI!Probes - to t : PI!Probes (readiness <- s.readiness, liveness <- s.liveness) -} - -rule NoProbes { - from s : PI!NoProbes - to t : PI!NoProbes -} - -rule HttpProbe { - from s : PI!HttpProbe - to t : PI!HttpProbe (path <- s.path, port <- s.port) -} - -rule TcpProbe { - from s : PI!TcpProbe - to t : PI!TcpProbe (tcp <- s.tcp) -} - --- ------------------------------------------- lazy rules: one image per Process - --- Process::lower's placement: each dimension from the lowest level that set --- it, the quantities from the Process and nowhere else. -lazy rule PlacementFor { - from s : PI!Process - to t : PI!Placement ( - arch <- if s.withArch->isEmpty() then Sequence{} else s.withArch->first().arch endif, - disk <- if s.withDisk->isEmpty() then OclUndefined - else thisModule.DiskRequestCopy(s.withDisk->first().disk) endif, - gpu <- if s.withGpu->isEmpty() then OclUndefined - else thisModule.GpuRequestCopy(s.withGpu->first().gpu) endif, - capabilities <- if s.withCapabilities->isEmpty() then Sequence{} - else s.withCapabilities->first().capabilities endif - ) - do { - if (s.placement.present) { - if (s.placement.memory.present) { t.memory <- s.placement.memory; } - if (s.placement.cpu.present) { t.cpu <- s.placement.cpu; } - } - if (s.withSite->notEmpty()) { t.site <- s.withSite->first().site; } - -- A lazy rule with a `do` block answers its last statement, not its target. - t; - } -} - -lazy rule DiskRequestCopy { - from s : PI!DiskRequest - to t : PI!DiskRequest (media <- s.media) -} - -lazy rule GpuRequestCopy { - from s : PI!GpuRequest - to t : PI!GpuRequest ("class" <- s."class", memory <- s.memory, vendor <- s.vendor, model <- s.model) -} - --- Process::envFor. -lazy rule EnvFileFor { - from s : PI!Process - to t : PI!EnvFile ( - entries <- thisModule.mergeEntries( - thisModule.mergeEntries(thisModule.entriesIn(s.env), thisModule.entriesIn(s.app.env)), - thisModule.entriesIn(s.prj.env)) - ->collect(e | thisModule.EnvVariableCopy(e)) - ) -} - -lazy rule EnvVariableCopy { - from s : PI!EnvVariable - to t : PI!EnvVariable ( - name <- s.name, - value <- if s.value.present then s.value.copied() else OclUndefined endif - ) -} - -lazy rule EnvLiteralCopy { - from s : PI!EnvLiteral - to t : PI!EnvLiteral (text <- s.text) -} - -lazy rule PlaceholderCopy { - from s : PI!Placeholder - to t : PI!Placeholder (kind <- s.kind, source <- s.source) - do { - if (s.states('suffix')) { t.suffix <- s.suffix; } - -- A lazy rule with a `do` block answers its last statement, not its target. - t; - } -} - -lazy rule DependencyEdgeCopy { - from s : PI!DependencyEdge - to t : PI!DependencyEdge ( - application <- s.application, - surface <- s.surface, - buckets <- s.buckets, - credentials <- if s.credentials.present then thisModule.CredentialsCopy(s.credentials) else OclUndefined endif - ) - do { - if (s.required.present) { t.required <- s.required; } - -- A lazy rule with a `do` block answers its last statement, not its target. - t; - } -} - -lazy rule CredentialsCopy { - from s : PI!Credentials - to t : PI!Credentials ( - rotation <- if s.rotation.present then thisModule.RotationCopy(s.rotation) else OclUndefined endif - ) - do { - if (s.states('delivery')) { t.delivery <- s.delivery; } - if (s.mountAt.present) { t.mountAt <- s.mountAt; } - if (s.fileMode.present) { t.fileMode <- s.fileMode; } - -- A lazy rule with a `do` block answers its last statement, not its target. - t; - } -} - -lazy rule AssetCopy { - from s : PI!Asset - to t : PI!Asset ("from" <- s."from", mountAt <- s.mountAt) -} - -lazy rule SeededAssetCopy { - from s : PI!SeededAsset - to t : PI!SeededAsset ("from" <- s."from", seedAt <- s.seedAt) -} - -lazy rule PlainPathCopy { - from s : PI!PlainPath - to t : PI!PlainPath (path <- s.path) -} - -lazy rule MemoryPathCopy { - from s : PI!MemoryPath - to t : PI!MemoryPath (path <- s.path, memory <- s.memory) -} - -lazy rule KvGrantCopy { - from s : PI!KvGrant - to t : PI!KvGrant ( - path <- s.path, - keys <- s.keys->collect(k | k.copied()), - access <- s.access, - delivery <- s.delivery, - rotation <- if s.rotation.present then thisModule.RotationCopy(s.rotation) else OclUndefined endif - ) - do { - if (s.mountAt.present) { t.mountAt <- s.mountAt; } - if (s.fileMode.present) { t.fileMode <- s.fileMode; } - -- A lazy rule with a `do` block answers its last statement, not its target. - t; - } -} - -lazy rule OptionalKeyCopy { - from s : PI!OptionalKey - to t : PI!OptionalKey (name <- s.name, optional <- s.optional) -} - -lazy rule PlainKeyCopy { - from s : PI!PlainKey - to t : PI!PlainKey (name <- s.name) -} - -lazy rule GeneratedKeyCopy { - from s : PI!GeneratedKey - to t : PI!GeneratedKey ( - name <- s.name, - generate <- if s.generate.present then thisModule.GenerateCopy(s.generate) else OclUndefined endif - ) -} - -lazy rule GenerateCopy { - from s : PI!Generate - to t : PI!Generate - do { - if (s.bytes.present) { t.bytes <- s.bytes; } - if (s.adopt.present) { t.adopt <- s.adopt; } - if (not s.encoding.absent) { t.encoding <- s.encoding; } - -- A lazy rule with a `do` block answers its last statement, not its target. - t; - } -} - -lazy rule DatabaseGrantCopy { - from s : PI!DatabaseGrant - to t : PI!DatabaseGrant ( - engine <- s.engine, - role <- s.role, - delivery <- s.delivery, - rotation <- if s.rotation.present then thisModule.RotationCopy(s.rotation) else OclUndefined endif - ) - do { - if (s.mountAt.present) { t.mountAt <- s.mountAt; } - if (s.fileMode.present) { t.fileMode <- s.fileMode; } - -- A lazy rule with a `do` block answers its last statement, not its target. - t; - } -} - -lazy rule TransitGrantCopy { - from s : PI!TransitGrant - to t : PI!TransitGrant ( - engine <- s.engine, - key <- s.key, - operations <- s.operations, - delivery <- s.delivery, - rotation <- if s.rotation.present then thisModule.RotationCopy(s.rotation) else OclUndefined endif - ) - do { - if (s.mountAt.present) { t.mountAt <- s.mountAt; } - if (s.fileMode.present) { t.fileMode <- s.fileMode; } - -- A lazy rule with a `do` block answers its last statement, not its target. - t; - } -} - -lazy rule RotationCopy { - from s : PI!Rotation - to t : PI!Rotation (tolerates <- s.tolerates) - do { - if (s.maxAge.present) { t.maxAge <- s.maxAge; } - -- A lazy rule with a `do` block answers its last statement, not its target. - t; - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/agents.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/agents.effective.json deleted file mode 100644 index 0bb7efbb5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/agents.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"client":{"credential":"pkce","description":"The agent gateway","exposure":"public","label":"Hermes","protectedPath":"/api/status","redirectPaths":["/auth/callback"],"signIn":"native"},"exposure":[{"audience":"authenticated","host":"hermes.jorisjonkers.dev","name":"public","proxied":false,"routes":[{"match":"prefix","path":"/","process":"hermes","surface":"dashboard"}]},{"audience":"lan","host":"hermes.jorisjonkers.dev","name":"lan","routes":[{"match":"prefix","path":"/","process":"hermes","surface":"dashboard"}]}],"id":"hermes","processes":[{"args":["gateway","run"],"assets":[{"from":"config/hermes/config.yaml","seedAt":"/opt/data/config.yaml"}],"cutover":"interrupted","dependsOn":[{"application":"kubernetes-mcp-server","surface":"mcp"}],"egress":{"reason":"Hermes calls its model providers and remote MCP servers, and installs the skills it is given.","to":"internet"},"engine":"files","env":[{"entries":[{"name":"HERMES_DASHBOARD","value":{"text":"1"}},{"name":"HERMES_DASHBOARD_HOST","value":{"text":"0.0.0.0"}},{"name":"HERMES_DASHBOARD_PORT","value":{"text":"9119"}},{"name":"HERMES_DASHBOARD_PUBLIC_URL","value":{"kind":"exposure","source":"hermes.public#url"}},{"name":"HERMES_DASHBOARD_OIDC_ISSUER","value":{"kind":"client","source":"issuer"}},{"name":"HERMES_DASHBOARD_OIDC_CLIENT_ID","value":{"kind":"client","source":"id"}},{"name":"HERMES_DASHBOARD_OIDC_SCOPES","value":{"text":"openid profile email"}},{"name":"API_SERVER_ENABLED","value":{"text":"false"}},{"name":"HERMES_SKIP_CONFIG_MIGRATION","value":{"text":"false"}},{"name":"S6_YES_I_WANT_A_WORLD_WRITABLE_RUN_BECAUSE_KUBERNETES","value":{"text":"1"}},{"name":"ANTHROPIC_API_KEY","value":{"kind":"secret","source":"secret/data/agents/hermes#anthropic-api-key"}},{"name":"OPENAI_API_KEY","value":{"kind":"secret","source":"secret/data/agents/hermes#openai-api-key"}},{"name":"OPENROUTER_API_KEY","value":{"kind":"secret","source":"secret/data/agents/hermes#openrouter-api-key"}},{"name":"GITHUB_PAT","value":{"kind":"secret","source":"secret/data/agents/hermes#github-pat"}},{"name":"HINDSIGHT_API_TOKEN","value":{"kind":"secret","source":"secret/data/agents/hermes#hindsight-api-token"}},{"name":"MEMORY_API_KEY","value":{"kind":"secret","source":"secret/data/agents/hermes#memory-api-key"}},{"name":"OVERLEAF_SESSION","value":{"kind":"secret","source":"secret/data/agents/hermes#overleaf-session"}}]}],"image":"hermes","lifecycle":"application","name":"hermes","placement":{"cpu":"250m","memory":"2Gi","site":"enschede"},"probes":{"liveness":{"path":"/api/status","port":9119},"readiness":{"path":"/api/status","port":9119}},"provides":{"dashboard":9119},"runtime":"none","secrets":[{"access":"read","delivery":"env","keys":[{"name":"memory-api-key","optional":true},{"name":"overleaf-session","optional":true},{"name":"github-pat","optional":true},{"name":"hindsight-api-token","optional":true},{"name":"openrouter-api-key","optional":true},{"name":"anthropic-api-key","optional":true},{"name":"openai-api-key","optional":true}],"path":"secret/data/agents/hermes","rotation":{"tolerates":"restart"}}],"startupBudget":"120s","volumes":[{"claim":"hermes-data","durability":"recoverable","mountAt":"/opt/data","size":"10Gi"}],"writablePaths":["/run","/tmp",{"memory":"1Gi","path":"/dev/shm"}]}]},{"id":"kubernetes-mcp-server","processes":[{"api":{"reason":"the MCP server answers an agent's questions about workloads, logs, routes and Flux, cluster-wide, and changes nothing","rules":[{"group":"core","objects":["pods","pods/log","events","services","endpoints","nodes","namespaces"],"verbs":["get","list","watch"]},{"group":"apps","objects":["deployments","statefulsets","daemonsets","replicasets"],"verbs":["get","list","watch"]},{"group":"batch","objects":["jobs","cronjobs"],"verbs":["get","list","watch"]},{"group":"networking.k8s.io","objects":["ingresses","networkpolicies"],"verbs":["get","list","watch"]},{"group":"traefik.io","objects":["ingressroutes","middlewares"],"verbs":["get","list","watch"]},{"group":"kustomize.toolkit.fluxcd.io","objects":["kustomizations"],"verbs":["get","list","watch"]},{"group":"helm.toolkit.fluxcd.io","objects":["helmreleases"],"verbs":["get","list","watch"]},{"group":"source.toolkit.fluxcd.io","objects":["gitrepositories","helmrepositories","ocirepositories"],"verbs":["get","list","watch"]}]},"args":["--port=8080","--read-only"],"cutover":"continuous","image":"kubernetes-mcp-server","lifecycle":"application","name":"kubernetes-mcp-server","placement":{"cpu":"50m","memory":"256Mi"},"probes":{"liveness":{"path":"/healthz","port":8080},"readiness":{"path":"/healthz","port":8080}},"provides":{"mcp":8080},"runtime":"none","startupBudget":"20s"}]},{"id":"agents-api","processes":[{"api":{"reason":"it reads the session settings it keeps beside itself","rules":[{"group":"core","objects":["configmaps"],"scope":"namespace","verbs":["get","list","watch"]}]},"cutover":"continuous","image":"agents-api","lifecycle":"application","name":"agents-api","parked":{"reason":"Agent sessions run through hermes since 2026-09-01."},"placement":{"cpu":"100m","memory":"512Mi"},"probes":{"liveness":{"path":"/actuator/health/liveness","port":8082},"readiness":{"path":"/actuator/health/readiness","port":8082}},"provides":{"http":8082},"runtime":"jvm","spawns":[{"dependsOn":[{"application":"agents-api","surface":"http"}],"egress":{"reason":"an agent clones and pushes the repositories it works on","to":"internet"},"image":"agent-runner","name":"runner","placement":{"cpu":"500m","memory":"1Gi"},"provides":{"http":8090}}],"startupBudget":"60s"}]},{"exposure":[{"audience":"anonymous","host":"agents.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"agents-ui","surface":"http"}]}],"id":"agents-ui","processes":[{"cutover":"continuous","image":"agents-ui","lifecycle":"application","name":"agents-ui","parked":{"reason":"Agent sessions run through hermes since 2026-09-01."},"placement":{"cpu":"100m","memory":"96Mi"},"probes":{"liveness":{"path":"/","port":80},"readiness":{"path":"/","port":80}},"provides":{"http":80},"runtime":"static","writablePaths":["/var/cache/nginx","/var/run"]}]}],"owner":"joris","project":"agents"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/auth.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/auth.effective.json deleted file mode 100644 index 7638746ba..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/auth.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"exposure":[{"audience":"anonymous","contentPolicy":"strict","host":"auth.jorisjonkers.dev","name":"public","routes":[{"match":"exact","path":"/api/v1/users/register","process":"auth-api","rateLimit":{"per":"1h","requests":10},"surface":"http"},{"match":"prefix","path":"/api","process":"auth-api","surface":"http"},{"match":"prefix","path":"/","process":"auth-ui","surface":"http"}]}],"id":"auth","migration":{"changelog":"auth-api/src/main/resources/db/changelog/db.changelog-master.yaml"},"observability":{"scrape":{"path":"/api/actuator/prometheus","process":"auth-api","surface":"http"}},"processes":[{"cutover":"continuous","dependsOn":[{"application":"platform-postgres","surface":"postgres"},{"application":"platform-valkey","surface":"redis"},{"application":"platform-rabbitmq","surface":"amqp"},{"application":"stalwart","surface":"smtp"}],"env":[{"entries":[{"name":"SPRING_PROFILES_ACTIVE","value":{"text":"prod"}},{"name":"SESSION_COOKIE_SECURE","value":{"text":"true"}},{"name":"DB_HOST","value":{"kind":"dependency","source":"platform-postgres.host"}},{"name":"DB_PORT","value":{"kind":"dependency","source":"platform-postgres.port"}},{"name":"VALKEY_HOST","value":{"kind":"dependency","source":"platform-valkey.host"}},{"name":"VALKEY_PORT","value":{"kind":"dependency","source":"platform-valkey.port"}},{"name":"SPRING_RABBITMQ_HOST","value":{"kind":"dependency","source":"platform-rabbitmq.host"}},{"name":"SPRING_RABBITMQ_PORT","value":{"kind":"dependency","source":"platform-rabbitmq.port"}},{"name":"MAIL_HOST","value":{"kind":"dependency","source":"stalwart.host"}},{"name":"MAIL_PORT","value":{"kind":"dependency","source":"stalwart.port"}},{"name":"AUTH_ISSUER","value":{"kind":"exposure","source":"auth.public#url"}},{"name":"AUTH_LOGIN_URL","value":{"kind":"exposure","source":"auth.public#url","suffix":"/login"}},{"name":"CONFIRMATION_URL","value":{"kind":"exposure","source":"auth.public#url","suffix":"/confirm"}},{"name":"SPRING_CONFIG_IMPORT","value":{"text":"vault://"}},{"name":"VAULT_ENABLED","value":{"text":"true"}},{"name":"VAULT_AUTHENTICATION","value":{"text":"KUBERNETES"}},{"name":"VAULT_KUBERNETES_ROLE","value":{"kind":"identity","source":"vaultRole"}}]}],"image":"auth-api","lifecycle":"application","name":"auth-api","placement":{"arch":["amd64"],"capabilities":["public-ingress"],"cpu":"250m","memory":"768Mi"},"probes":{"liveness":{"path":"/api/actuator/health/liveness","port":8081},"readiness":{"path":"/api/actuator/health/readiness","port":8081}},"provides":{"http":8080},"replicas":{"count":2,"reason":"Capacity, not availability: the pair was provisioned on freed Frankfurt budget and both pods land on the one public-ingress node. Retires when that budget is reclaimed or the capability spreads to a second node."},"runtime":"jvm","secrets":[{"access":"read","delivery":"self","keys":["user","password"],"path":"secret/data/platform/postgres/auth","rotation":{"maxAge":"168h","tolerates":"reload"}},{"access":"read","delivery":"self","keys":["mail.password","valkey.password","rabbitmq.user","rabbitmq.password"],"path":"secret/data/auth-api","rotation":{"tolerates":"reload"}},{"delivery":"self","engine":"transit","key":"auth-api-jwt","operations":["sign","rotate","read"],"rotation":{"tolerates":"reload"}}],"startupBudget":"600s","writablePaths":["/tmp"]},{"cutover":"continuous","image":"auth-ui","lifecycle":"application","name":"auth-ui","placement":{"cpu":"10m","memory":"64Mi"},"probes":{"liveness":{"path":"/","port":80},"readiness":{"path":"/","port":80}},"provides":{"http":80},"runtime":"static","startupBudget":"30s","writablePaths":["/var/cache/nginx","/var/run"]}]}],"owner":"joris","project":"auth"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/coverage.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/coverage.effective.json deleted file mode 100644 index 3a49f8ecc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/coverage.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"client":{"backChannelLogoutPath":"/logout","credential":"pkce","label":"Coverage","protectedPath":"/api","redirectPaths":["/callback"],"roles":["reader"],"signIn":"native"},"description":"Reads every key the other projects leave out","id":"coverage-api","processes":[{"api":{"reason":"it reads the nodes it places work on","rules":[{"group":"core","objects":["nodes"],"scope":"cluster","verbs":["get"]}]},"args":["serve","--verbose"],"assets":[{"from":"config/seed.conf","seedAt":"/var/cache/coverage/seed.conf"},{"from":"config/coverage.conf","mountAt":"/etc/coverage/project.conf"}],"command":["/bin/coverage"],"cutover":"interrupted","dependsOn":[{"application":"platform-valkey","required":false,"surface":"redis"},{"application":"platform-rabbitmq","required":true,"surface":"amqp"}],"env":[{"entries":[{"name":"VAULT_ROLE","value":{"kind":"identity","source":"vaultRole"}},{"name":"LEVEL","value":{"text":"info"}},{"name":"MODE","value":{"text":"full"}}]}],"image":"coverage-api","lifecycle":"application","name":"coverage-api","placement":{"arch":["arm64"],"cpu":"10m","disk":{"media":["hdd"]},"gpu":{"memory":"8Gi","vendor":["nvidia"]},"memory":"64Mi","site":"enschede"},"provides":{"http":8080},"runtime":"none","secrets":[{"access":"self-roll","delivery":"file","fileMode":"0400","keys":["password"],"mountAt":"/run/secrets/rolled","path":"secret/data/coverage/rolled","rotation":{"tolerates":"restart"}},{"access":"self-renew","delivery":"file","fileMode":"0400","keys":["lease"],"mountAt":"/run/secrets/renewed","path":"secret/data/coverage/renewed","rotation":{"tolerates":"restart"}},{"access":"custody","delivery":"self","keys":["root"],"path":"secret/data/coverage/custody","rotation":{"tolerates":"reload"}},{"delivery":"self","engine":"transit","fileMode":"0400","key":"coverage","mountAt":"/run/secrets/transit","operations":["encrypt","decrypt","verify"],"rotation":{"tolerates":"restart"}},{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"bytes":32,"encoding":"base64"},"name":"session"}],"mountAt":"/run/secrets/session","path":"secret/data/coverage-system/session","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"bytes":16,"encoding":"base64url"},"name":"cookie"}],"mountAt":"/run/secrets/cookie","path":"secret/data/coverage-system/cookie","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"encoding":"hex"},"name":"salt"}],"mountAt":"/run/secrets/salt","path":"secret/data/coverage-system/salt","rotation":{"tolerates":"restart"}}],"sidecars":[{"args":["run"],"command":["/bin/helper"],"cpu":"5m","image":"coverage-helper","memory":"16Mi","name":"helper"}],"startupBudget":"60s","writablePaths":[{"memory":"64Mi","path":"/var/cache/coverage"},"/tmp"]},{"assets":[{"from":"config/seed.conf","seedAt":"/var/cache/coverage/seed.conf"},{"from":"config/coverage.conf","mountAt":"/etc/coverage/project.conf"}],"dependsOn":[{"application":"platform-valkey","required":false,"surface":"redis"},{"application":"platform-rabbitmq","required":true,"surface":"amqp"}],"env":[{"entries":[{"name":"LEVEL","value":{"text":"info"}},{"name":"MODE","value":{"text":"full"}}]}],"image":"coverage-seed","lifecycle":"prepare","name":"coverage-seed","placement":{"cpu":"5m","memory":"32Mi","site":"enschede"},"runtime":"none","secrets":[{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"bytes":32,"encoding":"base64"},"name":"session"}],"mountAt":"/run/secrets/session","path":"secret/data/coverage-system/session","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"bytes":16,"encoding":"base64url"},"name":"cookie"}],"mountAt":"/run/secrets/cookie","path":"secret/data/coverage-system/cookie","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"encoding":"hex"},"name":"salt"}],"mountAt":"/run/secrets/salt","path":"secret/data/coverage-system/salt","rotation":{"tolerates":"restart"}}],"startupBudget":"60s","writablePaths":[{"memory":"64Mi","path":"/var/cache/coverage"},"/tmp"]},{"assets":[{"from":"config/seed.conf","seedAt":"/var/cache/coverage/seed.conf"},{"from":"config/coverage.conf","mountAt":"/etc/coverage/project.conf"}],"cutover":"interrupted","dependsOn":[{"application":"platform-valkey","required":false,"surface":"redis"},{"application":"platform-rabbitmq","required":true,"surface":"amqp"}],"env":[{"entries":[{"name":"LEVEL","value":{"text":"info"}},{"name":"MODE","value":{"text":"full"}}]}],"image":"coverage-job","lifecycle":"job","name":"coverage-job","placement":{"cpu":"5m","memory":"32Mi","site":"enschede"},"runtime":"none","secrets":[{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"bytes":32,"encoding":"base64"},"name":"session"}],"mountAt":"/run/secrets/session","path":"secret/data/coverage-system/session","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"bytes":16,"encoding":"base64url"},"name":"cookie"}],"mountAt":"/run/secrets/cookie","path":"secret/data/coverage-system/cookie","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"encoding":"hex"},"name":"salt"}],"mountAt":"/run/secrets/salt","path":"secret/data/coverage-system/salt","rotation":{"tolerates":"restart"}}],"startupBudget":"60s","writablePaths":[{"memory":"64Mi","path":"/var/cache/coverage"},"/tmp"]}]}],"owner":"joris","project":"coverage"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/data.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/data.effective.json deleted file mode 100644 index 01540445b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/data.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"id":"platform-postgres","observability":{"scrape":{"path":"/metrics","process":"postgres","surface":"metrics"}},"processes":[{"assets":[{"from":"config/postgresql.conf","mountAt":"/etc/postgresql/postgresql.conf"}],"cutover":"interrupted","engine":"postgres","env":[{"entries":[{"name":"POSTGRES_DB","value":{"text":"postgres"}},{"name":"POSTGRES_USER","value":{"text":"postgres"}},{"name":"DATA_SOURCE_NAME","value":{"kind":"secret","source":"secret/data/platform/postgres/exporter#datasource"}}]}],"image":"postgres","lifecycle":"application","name":"postgres","placement":{"arch":["amd64"],"cpu":"500m","disk":{"media":["nvme","ssd"]},"memory":"2Gi"},"probes":{"liveness":{"tcp":5432},"readiness":{"tcp":5432}},"provides":{"metrics":9187,"postgres":5432},"runtime":"none","secrets":[{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"adopt":"secret/data/platform/postgres/exporter#datasource"},"name":"datasource"}],"mountAt":"/run/secrets/exporter","path":"secret/data/data-system/exporter","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"env","keys":["datasource"],"path":"secret/data/platform/postgres/exporter","rotation":{"tolerates":"restart"}}],"sidecars":[{"cpu":"10m","image":"postgres-exporter","memory":"64Mi","name":"postgres-exporter"}],"startupBudget":"60s","volumes":[{"claim":"postgres-data","durability":"irreplaceable","mountAt":"/var/lib/postgresql/data","size":"20Gi"}],"writablePaths":["/var/run/postgresql","/tmp"]}]},{"dashboards":[{"from":"dashboards/rabbitmq.json"}],"exposure":[{"audience":"authenticated","host":"rabbitmq.jorisjonkers.dev","name":"management","routes":[{"match":"prefix","path":"/","process":"rabbitmq","surface":"management"}]},{"audience":"lan","host":"rabbitmq.jorisjonkers.dev","name":"lan","routes":[{"match":"prefix","path":"/","process":"rabbitmq","surface":"management"}]}],"id":"platform-rabbitmq","l4Exposure":[{"address":"lan-mqtt","port":1883,"process":"rabbitmq","protocol":"tcp","surface":"mqtt"}],"observability":{"scrape":{"honorLabels":true,"path":"/metrics","process":"rabbitmq","surface":"metrics"}},"processes":[{"cutover":"interrupted","engine":"rabbitmq","image":"rabbitmq","lifecycle":"application","name":"rabbitmq","placement":{"cpu":"500m","memory":"2Gi"},"probes":{"liveness":{"tcp":5672},"readiness":{"tcp":5672}},"provides":{"amqp":5672,"management":15672,"metrics":15692,"mqtt":1883},"runtime":"none","startupBudget":"120s","volumes":[{"claim":"rabbitmq-data","durability":"recoverable","mountAt":"/var/lib/rabbitmq","size":"20Gi"}]}]},{"id":"platform-valkey","processes":[{"cutover":"interrupted","image":"valkey","lifecycle":"application","name":"valkey","placement":{"cpu":"50m","memory":"256Mi"},"probes":{"liveness":{"tcp":6379},"readiness":{"tcp":6379}},"provides":{"redis":6379},"runtime":"none","startupBudget":"30s","volumes":[{"claim":"valkey-data","durability":"reconstructible","mountAt":"/data","size":"2Gi"}]}]},{"id":"platform-mongo","processes":[{"cutover":"interrupted","engine":"mongo","image":"mongo","lifecycle":"application","name":"mongo","placement":{"cpu":"200m","memory":"2Gi"},"probes":{"liveness":{"tcp":27017},"readiness":{"tcp":27017}},"provides":{"mongo":27017},"runtime":"none","startupBudget":"60s","volumes":[{"claim":"mongo-data","durability":"irreplaceable","mountAt":"/data/db","size":"20Gi"}],"writablePaths":["/tmp","/data/configdb"]}]},{"id":"asset-sync","processes":[{"egress":{"reason":"reads the latest release from GitHub and uploads it to the public assets bucket","to":"internet"},"image":"asset-sync","lifecycle":"scheduled","name":"asset-sync","placement":{"cpu":"25m","memory":"64Mi","site":"frankfurt"},"runtime":"none","schedule":"*/15 * * * *","secrets":[{"access":"read","delivery":"file","fileMode":"0400","keys":["credentials"],"mountAt":"/run/secrets/garage/credentials","path":"secret/data/platform/garage/web-key","rotation":{"tolerates":"restart"}}]}]},{"id":"platform-garage","processes":[{"assets":[{"from":"config/garage.toml","mountAt":"/etc/garage.toml"}],"cutover":"interrupted","engine":"s3","env":[{"entries":[{"name":"GARAGE_RPC_SECRET","value":{"kind":"secret","source":"secret/data/platform/garage#rpc-secret"}},{"name":"GARAGE_ADMIN_TOKEN","value":{"kind":"secret","source":"secret/data/platform/garage#admin-token"}}]}],"image":"garage","lifecycle":"application","name":"garage","placement":{"cpu":"200m","memory":"1Gi","site":"frankfurt"},"probes":{"liveness":{"tcp":3900},"readiness":{"path":"/health","port":3903}},"provides":{"admin":3903,"s3":3900},"runtime":"none","secrets":[{"access":"read","delivery":"env","keys":["rpc-secret","admin-token"],"path":"secret/data/platform/garage","rotation":{"tolerates":"restart"}}],"startupBudget":"60s","volumes":[{"claim":"garage-meta","durability":"reconstructible","mountAt":"/var/lib/garage/meta","size":"2Gi"},{"claim":"garage-snapshots","durability":"recoverable","mountAt":"/var/lib/garage/snapshots","size":"4Gi"},{"claim":"garage-data","durability":"recoverable","mountAt":"/var/lib/garage/data","size":"20Gi"}]}]}],"owner":"joris","project":"data"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/delivery.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/delivery.effective.json deleted file mode 100644 index 904692c92..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/delivery.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"id":"flagger","processes":[{"api":{"reason":"Flagger switches every blue-green Process, so it scales its Deployment, generates its Services and copies, and records the Canary","rules":[{"group":"flagger.app","objects":["canaries","canaries/status"],"verbs":["get","list","watch","update","patch"]},{"group":"apps","objects":["deployments"],"verbs":["get","list","watch","create","update","patch","delete"]},{"group":"autoscaling","objects":["horizontalpodautoscalers"],"verbs":["get","list","watch","create","update","patch","delete"]},{"group":"core","objects":["services","configmaps"],"verbs":["get","list","watch","create","update","patch","delete"]},{"group":"core","objects":["secrets"],"verbs":["get"]},{"group":"core","objects":["events"],"verbs":["create","update","patch"]}]},"cutover":"continuous","dependsOn":[{"application":"release-gate","surface":"http"}],"image":"flagger","lifecycle":"application","name":"flagger","placement":{"cpu":"10m","memory":"64Mi"},"probes":{"liveness":{"path":"/healthz","port":8080},"readiness":{"path":"/healthz","port":8080}},"provides":{"http":8080},"runtime":"none","startupBudget":"30s","writablePaths":["/tmp"]}]},{"id":"release-gate","observability":{"scrape":{"path":"/metrics","process":"release-gate","surface":"http"}},"processes":[{"api":{"reason":"the Release Gate answers Flagger from what the cluster holds, so it reads each gated Application's inputs, Canaries, Deployments, Jobs and pods; it finds the gated Applications by listing ConfigMaps, keeps each one's release record in a ConfigMap of its own, unsuspends the migration Jobs it starts, and deletes a gated Application's Vault sync objects of an older revision once it serves the new one","rules":[{"group":"core","objects":["configmaps"],"verbs":["get","list"]},{"group":"core","objects":["configmaps"],"scope":"namespace","verbs":["create","update"]},{"group":"core","objects":["pods"],"verbs":["list"]},{"group":"apps","objects":["deployments"],"verbs":["get"]},{"group":"batch","objects":["jobs"],"verbs":["list","patch"]},{"group":"flagger.app","objects":["canaries"],"verbs":["get"]},{"group":"secrets.hashicorp.com","objects":["vaultauths","vaultstaticsecrets","vaultdynamicsecrets"],"verbs":["list","delete"]}]},"cutover":"continuous","image":"release-gate","lifecycle":"application","name":"release-gate","placement":{"cpu":"25m","memory":"64Mi"},"probes":{"liveness":{"path":"/healthz","port":8080},"readiness":{"path":"/readyz","port":8080}},"provides":{"http":8080},"runtime":"none","startupBudget":"10s"}]},{"id":"collector","processes":[{"api":{"reason":"the Collector captures where each bound claim and each rendered pod is, so it lists the three kinds that say so, cluster-wide, and writes nothing","rules":[{"group":"core","objects":["persistentvolumes","persistentvolumeclaims","pods"],"verbs":["get","list"]}]},"cutover":"interrupted","image":"collector","lifecycle":"application","name":"collector","placement":{"cpu":"10m","memory":"64Mi"},"probes":{"liveness":{"path":"/fresh","port":8080},"readiness":{"path":"/readyz","port":8080}},"provides":{"http":8080},"runtime":"none","startupBudget":"10s"}]},{"id":"reporter","processes":[{"api":{"reason":"the Reporter reads every Project's unit and every Canary again on start and on an interval, to correct a status an event it missed left behind, and writes nothing","rules":[{"group":"kustomize.toolkit.fluxcd.io","objects":["kustomizations"],"verbs":["get","list","watch"]},{"group":"flagger.app","objects":["canaries"],"verbs":["get","list","watch"]}]},"cutover":"interrupted","image":"reporter","lifecycle":"application","name":"reporter","placement":{"cpu":"10m","memory":"64Mi"},"probes":{"liveness":{"path":"/healthz","port":8080},"readiness":{"path":"/readyz","port":8080}},"provides":{"http":8080},"runtime":"none","startupBudget":"10s"}]}],"owner":"joris","project":"delivery"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/edge.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/edge.effective.json deleted file mode 100644 index 3b019f0ba..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/edge.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"id":"traefik-public","processes":[{"cutover":"continuous","image":"traefik","lifecycle":"application","name":"traefik-public","placement":{"capabilities":["public-ingress"],"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/ping","port":8080},"readiness":{"path":"/ping","port":8080}},"provides":{"admin":8080,"web":8000,"websecure":8443},"runtime":"none","startupBudget":"20s","writablePaths":["/tmp"]}]},{"id":"traefik-lan","processes":[{"cutover":"continuous","image":"traefik","lifecycle":"application","name":"traefik-lan","placement":{"capabilities":["lan-ingress"],"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/ping","port":8080},"readiness":{"path":"/ping","port":8080}},"provides":{"admin":8080,"web":8000,"websecure":8443},"runtime":"none","startupBudget":"20s","writablePaths":["/tmp"]}]},{"id":"external-dns","processes":[{"api":{"reason":"external-dns reads every route and the Services behind it, cluster-wide, to publish their hosts","rules":[{"group":"core","objects":["services","endpoints","pods","nodes"],"verbs":["get","list","watch"]},{"group":"traefik.io","objects":["ingressroutes"],"verbs":["get","list","watch"]}]},"cutover":"interrupted","egress":{"reason":"the DNS provider's API","to":"internet"},"image":"external-dns","lifecycle":"application","name":"external-dns","placement":{"cpu":"10m","memory":"64Mi"},"probes":{"liveness":{"path":"/healthz","port":7979},"readiness":{"path":"/healthz","port":7979}},"provides":{"metrics":7979},"runtime":"none","startupBudget":"30s"}]}],"owner":"joris","project":"edge"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/effective.xmi b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/effective.xmi deleted file mode 100644 index 715db11a7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/effective.xmi +++ /dev/null @@ -1,1840 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gateway - run - - - /auth/callback - - - - - - - - - - - - - pods - pods/log - events - services - endpoints - nodes - namespaces - get - list - watch - - - deployments - statefulsets - daemonsets - replicasets - get - list - watch - - - jobs - cronjobs - get - list - watch - - - ingresses - networkpolicies - get - list - watch - - - ingressroutes - middlewares - get - list - watch - - - kustomizations - get - list - watch - - - helmreleases - get - list - watch - - - gitrepositories - helmrepositories - ocirepositories - get - list - watch - - - --port=8080 - --read-only - - - - - - - - - - - - - configmaps - get - list - watch - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sign - rotate - read - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - amd64 - public-ingress - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - encrypt - decrypt - verify - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - arm64 - - hdd - - - nvidia - - - - - /bin/helper - run - - - - nodes - get - - - /bin/coverage - serve - --verbose - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /callback - reader - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - amd64 - - nvme - ssd - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - canaries - canaries/status - get - list - watch - update - patch - - - deployments - get - list - watch - create - update - patch - delete - - - horizontalpodautoscalers - get - list - watch - create - update - patch - delete - - - services - configmaps - get - list - watch - create - update - patch - delete - - - secrets - get - - - events - create - update - patch - - - - - - - - - - - - - - - - - - configmaps - get - list - - - configmaps - create - update - - - pods - list - - - deployments - get - - - jobs - list - patch - - - canaries - get - - - vaultauths - vaultstaticsecrets - vaultdynamicsecrets - list - delete - - - - - - - - - - - - - - - persistentvolumes - persistentvolumeclaims - pods - get - list - - - - - - - - - - - - - - - kustomizations - get - list - watch - - - canaries - get - list - watch - - - - - - - - - - - public-ingress - - - - - - - - - - - - - - - lan-ingress - - - - - - - - - - - - - - - - - - - - - services - endpoints - pods - nodes - get - list - watch - - - ingressroutes - get - list - watch - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /callback - /silent-renew - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - assets - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public-ingress - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - t1000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - services - endpoints - pods - get - list - watch - - - endpointslices - get - list - watch - - - --storage.tsdb.retention.time=15d - --storage.tsdb.retention.size=10GB - --enable-feature=exemplar-storage - --enable-feature=native-histograms - --web.enable-remote-write-receiver - --log.level=info - --query.max-concurrency - - - - - - - - - - - - - - prometheuses - prometheuses/status - alertmanagers - alertmanagers/status - servicemonitors - podmonitors - prometheusrules - alertmanagerconfigs - get - list - watch - create - update - patch - delete - - - services - endpoints - pods - nodes - namespaces - configmaps - secrets - get - list - watch - create - update - delete - - - statefulsets - get - list - watch - create - update - delete - - - - - - - - - - - - - - - - pods - nodes - namespaces - services - persistentvolumeclaims - persistentvolumes - list - watch - - - deployments - statefulsets - daemonsets - replicasets - list - watch - - - jobs - cronjobs - list - watch - - - - - - - - - - - - - - - - grafanas - grafanas/status - grafanadashboards - grafanadashboards/status - get - list - watch - update - patch - - - configmaps - secrets - get - list - watch - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /login/generic_oauth - viewer - editor - admin - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmaps - get - list - watch - - - - - - - - - - - - - - - pods - pods/log - namespaces - get - list - watch - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - vaultstaticsecrets - vaultstaticsecrets/status - vaultdynamicsecrets - vaultdynamicsecrets/status - vaultauths - vaultauths/status - vaultconnections - vaultconnections/status - get - list - watch - create - update - patch - delete - deletecollection - - - secrets - get - list - watch - create - update - patch - delete - - - serviceaccounts/token - create - - - deployments - statefulsets - daemonsets - get - list - watch - patch - - - events - create - patch - - - - - - - - - - - - - adguard - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/identity.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/identity.effective.json deleted file mode 100644 index 9efe34b4b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/identity.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"exposure":[{"audience":"anonymous","contentPolicy":"strict","host":"id.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"identity","surface":"http"}]}],"id":"identity","processes":[{"cutover":"continuous","image":"identity","lifecycle":"application","name":"identity","placement":{"cpu":"50m","memory":"256Mi"},"probes":{"liveness":{"path":"/health/live","port":8080},"readiness":{"path":"/health/ready","port":8080}},"provides":{"http":8080},"runtime":"none","startupBudget":"30s"}]},{"client":{"credential":"pkce","description":"Every application you can open","label":"Home","launchPath":"/apps","protectedPath":"/api/me","redirectPaths":["/callback","/silent-renew"],"signIn":"native"},"exposure":[{"audience":"authenticated","host":"home.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"portal","surface":"http"}]}],"id":"portal","processes":[{"cutover":"continuous","image":"portal","lifecycle":"application","name":"portal","placement":{"cpu":"10m","memory":"64Mi"},"probes":{"readiness":{"path":"/","port":8080}},"provides":{"http":8080},"runtime":"none"}]},{"client":{"iconPath":"/favicon.ico","label":"Who am I","signIn":"gated"},"exposure":[{"audience":"authenticated","host":"whoami.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"whoami","surface":"http"},{"audience":"anonymous","match":"exact","path":"/health","process":"whoami","surface":"http"}]}],"id":"whoami","processes":[{"cutover":"continuous","image":"whoami","lifecycle":"application","name":"whoami","placement":{"cpu":"10m","memory":"32Mi"},"probes":{"readiness":{"path":"/health","port":8080}},"provides":{"http":8080},"replicas":{"across":"node","count":2,"reason":"Availability of the sign-in probe across a node loss."},"runtime":"none"}]}],"owner":"joris","project":"identity"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/knowledge-platform.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/knowledge-platform.effective.json deleted file mode 100644 index eef55c0bf..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/knowledge-platform.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"id":"docling-serve","processes":[{"cutover":"interrupted","engine":"files","env":[{"entries":[{"name":"UVICORN_HOST","value":{"text":"0.0.0.0"}},{"name":"UVICORN_PORT","value":{"text":"8000"}}]}],"image":"docling-serve","lifecycle":"application","name":"docling-serve","placement":{"cpu":"500m","memory":"1Gi","site":"frankfurt"},"probes":{"liveness":{"path":"/health","port":8000},"readiness":{"path":"/health","port":8000}},"provides":{"http":8000},"runtime":"python","startupBudget":"120s","volumes":[{"claim":"docling-serve-archive","durability":"irreplaceable","mountAt":"/archive","size":"50Gi"}]}]},{"exposure":[{"audience":"authenticated","contentPolicy":"strict","host":"memory.jorisjonkers.dev","name":"console","routes":[{"match":"prefix","path":"/","process":"hindsight-control-plane","surface":"console"}]},{"audience":"authenticated","contentPolicy":"strict","host":"memory-api.jorisjonkers.dev","name":"api","routes":[{"match":"prefix","path":"/","process":"hindsight-api","surface":"api"}]}],"id":"hindsight","migration":"self","processes":[{"cutover":"continuous","dependsOn":[{"application":"platform-postgres","credentials":{"delivery":"env","rotation":{"tolerates":"restart"}},"surface":"postgres"},{"application":"hindsight-embedding","surface":"embeddings"}],"env":[{"entries":[{"name":"HINDSIGHT_API_LLM_PROVIDER","value":{"text":"openai"}},{"name":"HINDSIGHT_API_LLM_BASE_URL","value":{"text":"https://eu.openrouter.ai/api/v1"}},{"name":"HINDSIGHT_API_LLM_MODEL","value":{"text":"mistralai/mistral-small-2603"}},{"name":"HINDSIGHT_API_LLM_API_KEY","value":{"kind":"secret","source":"secret/data/platform/hindsight#llm-api-key"}},{"name":"HINDSIGHT_API_EMBEDDINGS_PROVIDER","value":{"text":"tei"}},{"name":"PGUSER","value":{"kind":"dependency","source":"platform-postgres.username"}},{"name":"PGPASSWORD","value":{"kind":"dependency","source":"platform-postgres.password"}},{"name":"HINDSIGHT_API_WORKER_ENABLED","value":{"text":"false"}},{"name":"HINDSIGHT_API_PORT","value":{"text":"8888"}}]}],"image":"hindsight-api","lifecycle":"application","name":"hindsight-api","placement":{"cpu":"500m","memory":"1Gi","site":"enschede"},"probes":{"liveness":{"path":"/health/live","port":8888},"readiness":{"path":"/health","port":8888}},"provides":{"api":8888},"runtime":"python","secrets":[{"access":"read","delivery":"env","keys":["llm-api-key"],"path":"secret/data/platform/hindsight","rotation":{"tolerates":"restart"}}],"startupBudget":"120s"},{"cutover":"continuous","dependsOn":[{"application":"platform-postgres","credentials":{"delivery":"file","fileMode":"0400","mountAt":"/run/secrets/database","rotation":{"tolerates":"restart"}},"surface":"postgres"},{"application":"hindsight-embedding","surface":"embeddings"}],"env":[{"entries":[{"name":"HINDSIGHT_API_LLM_PROVIDER","value":{"text":"openai"}},{"name":"HINDSIGHT_API_LLM_BASE_URL","value":{"text":"https://eu.openrouter.ai/api/v1"}},{"name":"HINDSIGHT_API_LLM_MODEL","value":{"text":"mistralai/mistral-small-2603"}},{"name":"HINDSIGHT_API_LLM_API_KEY","value":{"kind":"secret","source":"secret/data/platform/hindsight#llm-api-key"}},{"name":"HINDSIGHT_API_EMBEDDINGS_PROVIDER","value":{"text":"tei"}},{"name":"HINDSIGHT_API_PORT","value":{"text":"8889"}},{"name":"HINDSIGHT_API_WORKER_HTTP_PORT","value":{"text":"8889"}},{"name":"HINDSIGHT_API_WORKER_POLL_INTERVAL_MS","value":{"text":"500"}},{"name":"HINDSIGHT_API_WORKER_BATCH_SIZE","value":{"text":"10"}},{"name":"HINDSIGHT_API_WORKER_MAX_RETRIES","value":{"text":"3"}}]}],"image":"hindsight-api","lifecycle":"application","name":"hindsight-worker","parked":{"reason":"Ingestion paused while the job store is migrated."},"placement":{"cpu":"500m","memory":"1Gi","site":"enschede"},"probes":{"liveness":{"path":"/health/live","port":8889},"readiness":{"path":"/health","port":8889}},"provides":{"worker":8889},"runtime":"python","secrets":[{"access":"read","delivery":"env","keys":["llm-api-key"],"path":"secret/data/platform/hindsight","rotation":{"tolerates":"restart"}}],"startupBudget":"120s"},{"cutover":"continuous","dependsOn":[{"application":"hindsight","surface":"api"}],"env":[{"entries":[{"name":"HINDSIGHT_CP_HOSTNAME","value":{"text":"0.0.0.0"}},{"name":"HINDSIGHT_CP_PORT","value":{"text":"3000"}},{"name":"NODE_ENV","value":{"text":"production"}}]}],"image":"hindsight-control-plane","lifecycle":"application","name":"hindsight-control-plane","placement":{"cpu":"250m","memory":"512Mi","site":"enschede"},"probes":{"liveness":{"tcp":3000},"readiness":{"tcp":3000}},"provides":{"console":3000},"runtime":"node","startupBudget":"60s"}]},{"exposure":[{"audience":"authenticated","contentPolicy":"strict","host":"memory-mcp.jorisjonkers.dev","name":"mcp","routes":[{"match":"prefix","path":"/","process":"basic-memory","surface":"mcp"}]}],"id":"basic-memory","processes":[{"cutover":"interrupted","env":[{"entries":[{"name":"BASIC_MEMORY_PROJECT_ROOT","value":{"text":"/vault"}},{"name":"BASIC_MEMORY_HOME","value":{"text":"/vault"}},{"name":"BASIC_MEMORY_DEFAULT_PROJECT","value":{"text":"main"}},{"name":"BASIC_MEMORY_DISABLE_PERMALINKS","value":{"text":"true"}},{"name":"BASIC_MEMORY_ENSURE_FRONTMATTER_ON_SYNC","value":{"text":"false"}},{"name":"BASIC_MEMORY_SEMANTIC_EMBEDDING_CACHE_DIR","value":{"text":"/app/.basic-memory/fastembed"}},{"name":"BASIC_MEMORY_CONFIG_DIR","value":{"text":"/app/.basic-memory"}},{"name":"BASIC_MEMORY_SYNC_CHANGES","value":{"text":"true"}},{"name":"BASIC_MEMORY_SYNC_DELAY","value":{"text":"1000"}},{"name":"BASIC_MEMORY_LOG_LEVEL","value":{"text":"INFO"}},{"name":"VAULT_CLONE_URL","value":{"text":"git@github.com:JorisJonkers-dev/knowledge-vault.git"}},{"name":"VAULT_DIR","value":{"text":"/vault"}},{"name":"VAULT_BRANCH","value":{"text":"main"}},{"name":"VAULT_SSH_KEY_PATH","value":{"text":"/run/secrets/knowledge-vault/id_ed25519"}},{"name":"VAULT_AUTHOR_NAME","value":{"text":"basic-memory-vault"}},{"name":"VAULT_AUTHOR_EMAIL","value":{"text":"basicmemory@knowledge.local"}},{"name":"GIT_CONFIG_COUNT","value":{"text":"1"}},{"name":"GIT_CONFIG_KEY_0","value":{"text":"safe.directory"}},{"name":"GIT_CONFIG_VALUE_0","value":{"text":"/vault"}},{"name":"POLL_SECONDS","value":{"text":"10"}},{"name":"PUSH","value":{"text":"true"}},{"name":"LOG_LEVEL","value":{"text":"INFO"}}]}],"image":"basic-memory","lifecycle":"application","name":"basic-memory","placement":{"cpu":"500m","memory":"1Gi","site":"frankfurt"},"probes":{"liveness":{"tcp":8000},"readiness":{"tcp":8000}},"provides":{"mcp":8000},"runtime":"python","secrets":[{"access":"read","delivery":"file","fileMode":"0400","keys":["private_key"],"mountAt":"/run/secrets/knowledge-vault/id_ed25519","path":"secret/data/knowledge-system/vault-deploy-key","rotation":{"tolerates":"reload"}}],"sidecars":[{"cpu":"50m","image":"basic-memory-git-sync","init":true,"memory":"64Mi","name":"git-clone","volumes":[{"claim":"basic-memory-vault","mountAt":"/vault"}]},{"cpu":"50m","image":"basic-memory-git-sync","memory":"64Mi","name":"git-sync","volumes":[{"claim":"basic-memory-vault","mountAt":"/vault"}]}],"startupBudget":"120s","volumes":[{"claim":"basic-memory-vault","durability":"reconstructible","mountAt":"/vault","size":"5Gi"},{"claim":"basic-memory-config","durability":"reconstructible","mountAt":"/app/.basic-memory","size":"2Gi"}]}]},{"exposure":[{"audience":"authenticated","contentPolicy":"strict","host":"karakeep.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"karakeep","surface":"http"}]}],"id":"karakeep","processes":[{"cutover":"interrupted","dependsOn":[{"application":"platform-garage","buckets":["assets"],"surface":"s3"}],"egress":{"reason":"The browser fetches the pages it bookmarks.","to":"internet"},"engine":"files","env":[{"entries":[{"name":"NEXTAUTH_SECRET","value":{"kind":"secret","source":"secret/data/platform/karakeep#nextauth-secret"}},{"name":"NEXTAUTH_URL","value":{"kind":"exposure","source":"karakeep.public#url"}},{"name":"DATA_DIR","value":{"text":"/data"}},{"name":"MEILI_ADDR","value":{"text":"http://localhost:7700"}},{"name":"MEILI_MASTER_KEY","value":{"kind":"secret","source":"secret/data/platform/karakeep#meili-master-key"}},{"name":"MEILI_NO_ANALYTICS","value":{"text":"true"}},{"name":"BROWSER_WEB_URL","value":{"text":"http://localhost:9222"}},{"name":"OPENAI_API_KEY","value":{"kind":"secret","source":"secret/data/platform/karakeep#openrouter-api-key"}},{"name":"OPENAI_API_BASE","value":{"text":"https://eu.openrouter.ai/api/v1"}},{"name":"INFERENCE_TEXT_MODEL","value":{"text":"mistralai/mistral-small-2603"}},{"name":"INFERENCE_CONTEXT_LENGTH","value":{"text":"2048"}},{"name":"INFERENCE_ENABLE_AUTO_TAGGING","value":{"text":"true"}},{"name":"INFERENCE_ENABLE_AUTO_SUMMARIZATION","value":{"text":"true"}},{"name":"ASSET_STORE_S3_ENDPOINT","value":{"kind":"dependency","source":"platform-garage.endpoint"}},{"name":"ASSET_STORE_S3_REGION","value":{"text":"garage"}},{"name":"ASSET_STORE_S3_BUCKET","value":{"text":"knowledge-platform-assets"}},{"name":"ASSET_STORE_S3_FORCE_PATH_STYLE","value":{"text":"true"}},{"name":"ASSET_STORE_S3_ACCESS_KEY_ID","value":{"kind":"dependency","source":"platform-garage.accessKeyId"}},{"name":"ASSET_STORE_S3_SECRET_ACCESS_KEY","value":{"kind":"dependency","source":"platform-garage.secretAccessKey"}}]}],"image":"karakeep","lifecycle":"application","name":"karakeep","placement":{"cpu":"200m","memory":"512Mi","site":"frankfurt"},"probes":{"liveness":{"path":"/api/health","port":3000},"readiness":{"path":"/api/health","port":3000}},"provides":{"http":3000},"runtime":"node","secrets":[{"access":"read","delivery":"env","keys":["nextauth-secret","meili-master-key","openrouter-api-key"],"path":"secret/data/platform/karakeep","rotation":{"tolerates":"restart"}}],"sidecars":[{"cpu":"100m","image":"meilisearch","memory":"256Mi","name":"meilisearch","volumes":[{"claim":"karakeep-meili","mountAt":"/meili_data"}]},{"cpu":"500m","image":"karakeep-chrome","memory":"512Mi","name":"chrome"}],"startupBudget":"200s","volumes":[{"claim":"karakeep-data","durability":"recoverable","mountAt":"/data","size":"50Gi"},{"claim":"karakeep-meili","durability":"reconstructible","mountAt":"/meili_data","size":"5Gi"},{"claim":"meilisearch-data","durability":"reconstructible","mountAt":"/meili_data","size":"20Gi"}],"vpn":{"forwardedPort":false}}]},{"id":"hindsight-embedding","processes":[{"cutover":"interrupted","env":[{"entries":[{"name":"PORT","value":{"text":"8091"}},{"name":"PAYLOAD_LIMIT","value":{"text":"10000000"}},{"name":"MAX_CLIENT_BATCH_SIZE","value":{"text":"256"}}]}],"image":"text-embeddings-inference","lifecycle":"application","name":"hindsight-tei-embedding","placement":{"cpu":"500m","memory":"6Gi","site":"enschede"},"probes":{"liveness":{"path":"/health","port":8091},"readiness":{"path":"/health","port":8091}},"provides":{"embeddings":8091},"runtime":"none","startupBudget":"300s","volumes":[{"claim":"hindsight-tei-model-cache","durability":"reconstructible","mountAt":"/data","size":"8Gi"}]}]}],"owner":"joris","project":"knowledge-platform"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/knowledge.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/knowledge.effective.json deleted file mode 100644 index 2a158548d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/knowledge.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"exposure":[{"audience":"authenticated","host":"knowledge.jorisjonkers.dev","name":"public","routes":[{"audience":"anonymous","match":"exact","path":"/mcp","process":"knowledge-api","surface":"http"},{"audience":"anonymous","match":"prefix","path":"/mcp/","process":"knowledge-api","surface":"http"},{"audience":"anonymous","match":"exact","path":"/install.sh","process":"knowledge-api","surface":"http"},{"audience":"anonymous","match":"exact","path":"/install-agents.sh","process":"knowledge-api","surface":"http"},{"match":"prefix","path":"/","process":"knowledge-api","surface":"http"}]}],"id":"knowledge","migration":{"changelog":"knowledge-api/src/main/resources/db/changelog.yml"},"observability":{"scrape":{"path":"/api/actuator/prometheus","process":"knowledge-api","surface":"http"}},"processes":[{"cutover":"continuous","dependsOn":[{"application":"platform-postgres","surface":"postgres"},{"application":"platform-rabbitmq","surface":"amqp"}],"env":[{"entries":[{"name":"SPRING_PROFILES_ACTIVE","value":{"text":"prod"}},{"name":"KB_RECALL_DEFAULT_MODE","value":{"text":"hybrid"}},{"name":"KNOWLEDGE_MODE","value":{"text":"lite"}},{"name":"KNOWLEDGE_MCP_TOKENS_WORKSTATION","value":{"kind":"secret","source":"secret/data/knowledge-system/mcp-bearer#workstation"}},{"name":"DB_HOST","value":{"kind":"dependency","source":"platform-postgres.host"}},{"name":"DB_PORT","value":{"kind":"dependency","source":"platform-postgres.port"}},{"name":"RABBITMQ_HOST","value":{"kind":"dependency","source":"platform-rabbitmq.host"}},{"name":"RABBITMQ_PORT","value":{"kind":"dependency","source":"platform-rabbitmq.port"}},{"name":"DB_USER","value":{"kind":"secret","source":"secret/data/platform/postgres/kb#user"}},{"name":"DB_PASSWORD","value":{"kind":"secret","source":"secret/data/platform/postgres/kb#password"}},{"name":"RABBITMQ_USER","value":{"kind":"secret","source":"secret/data/platform/rabbitmq#rabbitmq.user"}},{"name":"RABBITMQ_PASSWORD","value":{"kind":"secret","source":"secret/data/platform/rabbitmq#rabbitmq.password"}}]}],"image":"knowledge-api","lifecycle":"application","name":"knowledge-api","placement":{"capabilities":["public-ingress"],"cpu":"250m","memory":"768Mi"},"probes":{"liveness":{"path":"/api/actuator/health/liveness","port":8080},"readiness":{"path":"/api/actuator/health/readiness","port":8080}},"provides":{"http":8080},"runtime":"jvm","secrets":[{"access":"read","delivery":"env","keys":["workstation"],"path":"secret/data/knowledge-system/mcp-bearer","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"env","keys":["user","password"],"path":"secret/data/platform/postgres/kb","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"env","keys":["rabbitmq.user","rabbitmq.password"],"path":"secret/data/platform/rabbitmq","rotation":{"tolerates":"restart"}}],"startupBudget":"600s","writablePaths":["/tmp"]}]},{"description":"Turns the notes dropped into the vault into searchable knowledge.","id":"knowledge-ingest","migration":"none","processes":[{"cutover":"interrupted","dependsOn":[{"application":"platform-rabbitmq","surface":"amqp"},{"application":"platform-postgres","surface":"postgres"}],"description":"Takes one note at a time off the queue and indexes it.","engine":"files","env":[{"entries":[{"name":"INGEST_QUEUE","value":{"text":"knowledge.ingest"}},{"name":"INGEST_PREFETCH","value":{"text":"4"}},{"name":"LOG_LEVEL","value":{"text":"INFO"}},{"name":"DB_HOST","value":{"kind":"dependency","source":"platform-postgres.host"}},{"name":"DB_PORT","value":{"kind":"dependency","source":"platform-postgres.port"}},{"name":"RABBITMQ_HOST","value":{"kind":"dependency","source":"platform-rabbitmq.host"}},{"name":"RABBITMQ_PORT","value":{"kind":"dependency","source":"platform-rabbitmq.port"}},{"name":"DB_USER","value":{"kind":"secret","source":"secret/data/platform/postgres/kb#user"}},{"name":"DB_PASSWORD","value":{"kind":"secret","source":"secret/data/platform/postgres/kb#password"}},{"name":"RABBITMQ_USER","value":{"kind":"secret","source":"secret/data/platform/rabbitmq#rabbitmq.user"}},{"name":"RABBITMQ_PASSWORD","value":{"kind":"secret","source":"secret/data/platform/rabbitmq#rabbitmq.password"}}]}],"image":"knowledge-ingest-worker","lifecycle":"application","name":"knowledge-ingest-worker","placement":{"cpu":"50m","memory":"256Mi"},"probes":"none","runtime":"python","secrets":[{"access":"read","delivery":"file","fileMode":"0400","keys":["key"],"mountAt":"/home/worker/.ssh/id_ed25519","path":"secret/data/knowledge-system/vault-deploy-key","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"env","keys":["user","password"],"path":"secret/data/platform/postgres/kb","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"env","keys":["rabbitmq.user","rabbitmq.password"],"path":"secret/data/platform/rabbitmq","rotation":{"tolerates":"restart"}}],"startupBudget":"120s","volumes":[{"claim":"knowledge-vault-clone","durability":"irreplaceable","mountAt":"/var/lib/knowledge-vault","size":"20Gi"}]}]}],"owner":"joris","project":"knowledge"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/mail.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/mail.effective.json deleted file mode 100644 index f8588975d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/mail.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"exposure":[{"audience":"authenticated","host":"mail.jorisjonkers.dev","name":"admin","routes":[{"match":"exact","path":"/","process":"stalwart","redirectTo":"/admin/","surface":"http"},{"match":"prefix","path":"/","process":"stalwart","surface":"http"}]}],"id":"stalwart","l4Exposure":[{"address":"mail-node","port":25,"process":"stalwart","protocol":"tcp","surface":"smtp"},{"address":"mail-node","port":993,"process":"stalwart","protocol":"tcp","surface":"imaps"},{"address":"mail-node","port":2525,"process":"stalwart","protocol":"tcp","surface":"smtp"}],"processes":[{"assets":[{"from":"config/manifest.json","mountAt":"/etc/stalwart-provisioner/manifest.json"}],"cutover":"interrupted","image":"stalwart","lifecycle":"application","name":"stalwart","placement":{"cpu":"100m","memory":"512Mi"},"probes":{"liveness":{"path":"/healthz/live","port":8080},"readiness":{"path":"/healthz/ready","port":8080}},"provides":{"http":8080,"imaps":993,"smtp":25},"runtime":"none","sidecars":[{"assets":[{"from":"config/manifest.json","mountAt":"/etc/stalwart-provisioner/manifest.json"}],"cpu":"10m","image":"stalwart-provisioner","memory":"64Mi","name":"stalwart-apply"}],"startupBudget":"60s","writablePaths":["/tmp"]}]}],"owner":"joris","project":"mail"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/notes.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/notes.effective.json deleted file mode 100644 index 56c4d3377..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/notes.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"exposure":[{"audience":"anonymous","contentPolicy":"strict","host":"notes.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"notes-api","surface":"http"}]}],"id":"notes","observability":{"scrape":{"path":"/metrics","process":"notes-api","surface":"http"}},"processes":[{"cutover":"continuous","env":[{"entries":[{"name":"NODE_ENV","value":{"text":"production"}},{"name":"NOTES_PAGE_SIZE","value":{"text":"50"}}]}],"image":"notes-api","libraries":[{"access":"write","library":"media","mountAt":"/attachments","subPath":"Notes"}],"lifecycle":"application","name":"notes-api","placement":{"cpu":"50m","gpu":{"class":"transcode","model":["t1000"]},"memory":"256Mi"},"probes":{"liveness":{"path":"/healthz/live","port":8080},"readiness":{"path":"/healthz/ready","port":8080}},"provides":{"http":8080},"runtime":"node","startupBudget":"20s"}]}],"owner":"joris","project":"notes"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/observability.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/observability.effective.json deleted file mode 100644 index 054baec3c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/observability.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"id":"otel-collector","processes":[{"cutover":"continuous","image":"otel-collector","lifecycle":"application","name":"otel-collector","placement":{"cpu":"50m","memory":"256Mi"},"probes":{"liveness":{"path":"/","port":13133},"readiness":{"path":"/","port":13133}},"provides":{"health":13133,"otlp":4317},"runtime":"none","startupBudget":"20s"}]},{"alertRules":[{"from":"rules/platform.yaml"}],"id":"prometheus","processes":[{"api":{"reason":"Prometheus discovers every monitor's targets through the API, cluster-wide","rules":[{"group":"core","objects":["services","endpoints","pods"],"verbs":["get","list","watch"]},{"group":"discovery.k8s.io","objects":["endpointslices"],"verbs":["get","list","watch"]}]},"args":["--storage.tsdb.retention.time=15d","--storage.tsdb.retention.size=10GB","--enable-feature=exemplar-storage","--enable-feature=native-histograms","--web.enable-remote-write-receiver","--log.level=info","--query.max-concurrency"],"cutover":"interrupted","image":"prometheus","lifecycle":"application","name":"prometheus","placement":{"cpu":"100m","memory":"512Mi"},"probes":{"liveness":{"path":"/-/healthy","port":9090},"readiness":{"path":"/-/ready","port":9090}},"provides":{"http":9090},"runtime":"none","startupBudget":"60s","writablePaths":["/prometheus"]}]},{"id":"prometheus-operator","processes":[{"api":{"reason":"the operator reconciles every monitor, rule and Alertmanager routing object into the Prometheus and Alertmanager configuration, cluster-wide","rules":[{"group":"monitoring.coreos.com","objects":["prometheuses","prometheuses/status","alertmanagers","alertmanagers/status","servicemonitors","podmonitors","prometheusrules","alertmanagerconfigs"],"verbs":["get","list","watch","create","update","patch","delete"]},{"group":"core","objects":["services","endpoints","pods","nodes","namespaces","configmaps","secrets"],"verbs":["get","list","watch","create","update","delete"]},{"group":"apps","objects":["statefulsets"],"verbs":["get","list","watch","create","update","delete"]}]},"cutover":"interrupted","image":"prometheus-operator","lifecycle":"application","name":"prometheus-operator","placement":{"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/healthz","port":8080},"readiness":{"path":"/healthz","port":8080}},"provides":{"http":8080},"runtime":"none","startupBudget":"30s"}]},{"id":"kube-state-metrics","processes":[{"api":{"reason":"kube-state-metrics reports the state of every object it lists, cluster-wide","rules":[{"group":"core","objects":["pods","nodes","namespaces","services","persistentvolumeclaims","persistentvolumes"],"verbs":["list","watch"]},{"group":"apps","objects":["deployments","statefulsets","daemonsets","replicasets"],"verbs":["list","watch"]},{"group":"batch","objects":["jobs","cronjobs"],"verbs":["list","watch"]}]},"cutover":"continuous","image":"kube-state-metrics","lifecycle":"application","name":"kube-state-metrics","placement":{"cpu":"20m","memory":"128Mi"},"probes":{"liveness":{"path":"/livez","port":8080},"readiness":{"path":"/livez","port":8080}},"provides":{"http":8080,"telemetry":8081},"runtime":"none","startupBudget":"30s"}]},{"id":"grafana-operator","processes":[{"api":{"reason":"the operator imports every Application's dashboards into the Grafana it selects, cluster-wide","rules":[{"group":"grafana.integreatly.org","objects":["grafanas","grafanas/status","grafanadashboards","grafanadashboards/status"],"verbs":["get","list","watch","update","patch"]},{"group":"core","objects":["configmaps","secrets"],"verbs":["get","list","watch"]}]},"cutover":"interrupted","image":"grafana-operator","lifecycle":"application","name":"grafana-operator","placement":{"cpu":"20m","memory":"64Mi"},"probes":{"liveness":{"path":"/healthz","port":8081},"readiness":{"path":"/healthz","port":8081}},"provides":{"health":8081,"metrics":8080},"runtime":"none","startupBudget":"30s"}]},{"client":{"credential":"secret","description":"Metrics and dashboards","iconPath":"/public/img/grafana_icon.svg","label":"Grafana","protectedPath":"/api/user","redirectPaths":["/login/generic_oauth"],"roles":["viewer","editor","admin"],"signIn":"native"},"exposure":[{"audience":"authenticated","host":"grafana.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"grafana","surface":"http"}]}],"id":"grafana","processes":[{"cutover":"continuous","env":[{"entries":[{"name":"GF_SERVER_ROOT_URL","value":{"kind":"exposure","source":"grafana.public#url"}},{"name":"GF_AUTH_GENERIC_OAUTH_ENABLED","value":{"text":"true"}},{"name":"GF_AUTH_GENERIC_OAUTH_NAME","value":{"text":"jorisjonkers.dev"}},{"name":"GF_AUTH_GENERIC_OAUTH_CLIENT_ID","value":{"kind":"client","source":"id"}},{"name":"GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET","value":{"kind":"client","source":"secret"}},{"name":"GF_AUTH_GENERIC_OAUTH_AUTH_URL","value":{"kind":"client","source":"issuer","suffix":"/oauth2/authorize"}},{"name":"GF_AUTH_GENERIC_OAUTH_TOKEN_URL","value":{"kind":"client","source":"issuer","suffix":"/oauth2/token"}},{"name":"GF_AUTH_GENERIC_OAUTH_API_URL","value":{"kind":"client","source":"issuer","suffix":"/userinfo"}},{"name":"GF_AUTH_GENERIC_OAUTH_SCOPES","value":{"text":"openid,profile,email"}},{"name":"GF_AUTH_DISABLE_LOGIN_FORM","value":{"text":"true"}}]}],"image":"grafana","lifecycle":"application","name":"grafana","placement":{"cpu":"50m","memory":"256Mi"},"probes":{"readiness":{"path":"/api/health","port":3000}},"provides":{"http":3000},"runtime":"none","startupBudget":"30s","writablePaths":["/var/lib/grafana"]}]},{"id":"loki","processes":[{"cutover":"interrupted","image":"loki","lifecycle":"application","name":"loki","placement":{"cpu":"100m","memory":"512Mi"},"probes":{"liveness":{"path":"/ready","port":3100},"readiness":{"path":"/ready","port":3100}},"provides":{"http":3100},"runtime":"none","startupBudget":"30s","volumes":[{"claim":"loki","durability":"reconstructible","mountAt":"/loki","size":"10Gi"}]}]},{"id":"tempo","processes":[{"cutover":"interrupted","image":"tempo","lifecycle":"application","name":"tempo","placement":{"cpu":"100m","memory":"512Mi"},"probes":{"liveness":{"path":"/ready","port":3200},"readiness":{"path":"/ready","port":3200}},"provides":{"http":3200},"runtime":"none","startupBudget":"30s","volumes":[{"claim":"tempo","durability":"reconstructible","mountAt":"/var/tempo","size":"10Gi"}]}]},{"id":"pyroscope","processes":[{"cutover":"interrupted","image":"pyroscope","lifecycle":"application","name":"pyroscope","placement":{"cpu":"100m","memory":"512Mi"},"probes":{"liveness":{"path":"/ready","port":4040},"readiness":{"path":"/ready","port":4040}},"provides":{"http":4040},"runtime":"none","startupBudget":"30s","volumes":[{"claim":"pyroscope","durability":"reconstructible","mountAt":"/data","size":"10Gi"}]}]},{"id":"gatus","processes":[{"api":{"reason":"the checks sidecar watches every Project's external-checks ConfigMap, cluster-wide","rules":[{"group":"core","objects":["configmaps"],"verbs":["get","list","watch"]}]},"cutover":"interrupted","image":"gatus","lifecycle":"application","name":"gatus","placement":{"cpu":"20m","memory":"64Mi"},"probes":{"liveness":{"path":"/health","port":8080},"readiness":{"path":"/health","port":8080}},"provides":{"http":8080},"runtime":"none","sidecars":[{"cpu":"10m","image":"gatus-checks","memory":"32Mi","name":"checks"}],"startupBudget":"30s"}]},{"id":"alloy","processes":[{"api":{"reason":"Alloy tails every pod's log through the API, cluster-wide","rules":[{"group":"core","objects":["pods","pods/log","namespaces"],"verbs":["get","list","watch"]}]},"cutover":"continuous","image":"alloy","lifecycle":"application","name":"alloy","placement":{"cpu":"50m","memory":"256Mi"},"probes":{"liveness":{"path":"/-/ready","port":12345},"readiness":{"path":"/-/ready","port":12345}},"provides":{"http":12345},"runtime":"none","startupBudget":"30s"}]},{"id":"alertmanager","processes":[{"cutover":"interrupted","image":"alertmanager","lifecycle":"application","name":"alertmanager","placement":{"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/-/healthy","port":9093},"readiness":{"path":"/-/ready","port":9093}},"provides":{"http":9093},"runtime":"none","startupBudget":"30s","writablePaths":["/alertmanager"]}]}],"owner":"joris","project":"observability"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/secrets.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/secrets.effective.json deleted file mode 100644 index 29f345c58..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/secrets.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"id":"vault","processes":[{"cutover":"interrupted","image":"vault","lifecycle":"application","name":"vault","placement":{"cpu":"100m","memory":"256Mi"},"probes":{"liveness":{"path":"/v1/sys/health","port":8200},"readiness":{"path":"/v1/sys/health","port":8200}},"provides":{"http":8200},"runtime":"none","startupBudget":"30s"}]},{"id":"vault-secrets-operator","processes":[{"api":{"reason":"the operator syncs every grant's sync object into its Secret, cluster-wide, and restarts the Processes a rotation names","rules":[{"group":"secrets.hashicorp.com","objects":["vaultstaticsecrets","vaultstaticsecrets/status","vaultdynamicsecrets","vaultdynamicsecrets/status","vaultauths","vaultauths/status","vaultconnections","vaultconnections/status"],"verbs":["get","list","watch","create","update","patch","delete","deletecollection"]},{"group":"core","objects":["secrets"],"verbs":["get","list","watch","create","update","patch","delete"]},{"group":"core","objects":["serviceaccounts/token"],"verbs":["create"]},{"group":"apps","objects":["deployments","statefulsets","daemonsets"],"verbs":["get","list","watch","patch"]},{"group":"core","objects":["events"],"verbs":["create","patch"]}]},"cutover":"interrupted","image":"vault-secrets-operator","lifecycle":"application","name":"vault-secrets-operator","placement":{"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/healthz","port":8081},"readiness":{"path":"/healthz","port":8081}},"provides":{"health":8081,"metrics":8080},"runtime":"none","startupBudget":"30s"}]}],"owner":"joris","project":"secrets"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/utility.effective.json b/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/utility.effective.json deleted file mode 100644 index 6e5fd991b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/estate/expected/utility.effective.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"id":"adguard","l4Exposure":[{"address":"lan-dns","port":53,"process":"adguard","protocol":"udp","surface":"dns"},{"address":"lan-dns","port":53,"process":"adguard","protocol":"tcp","surface":"dns"}],"processes":[{"assets":[{"from":"config/adguard/AdGuardHome.yaml","seedAt":"/opt/adguardhome/conf/AdGuardHome.yaml"}],"cutover":"continuous","egress":{"reason":"answers the LAN from a DNS-over-HTTPS upstream","to":"internet"},"image":"adguard","lifecycle":"application","name":"adguard","placement":{"capabilities":["adguard"],"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/login.html","port":3000},"readiness":{"path":"/login.html","port":3000}},"provides":{"dns":5353,"http":3000},"replicas":{"across":"node","count":2,"reason":"the LAN keeps its resolver while one node is down"},"runtime":"none","startupBudget":"30s","writablePaths":[{"memory":"128Mi","path":"/opt/adguardhome/work"},"/opt/adguardhome/conf"]}]},{"exposure":[{"audience":"lan","host":"dashboard.lan.jorisjonkers.dev","name":"lan","routes":[{"match":"prefix","path":"/","process":"headlamp","surface":"http"}]}],"id":"headlamp","processes":[{"api":{"reason":"it acts on the API with each signed-in user's own token, and holds nothing of its own"},"cutover":"continuous","image":"headlamp","lifecycle":"application","name":"headlamp","placement":{"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/","port":4466},"readiness":{"path":"/","port":4466}},"provides":{"http":4466},"runtime":"none","startupBudget":"30s"}]}],"owner":"joris","project":"utility"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/lower/gaps.txt b/emf/bundles/cli/src/test/resources/stages/lower/gaps.txt deleted file mode 100644 index 3b8f9438b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/lower/gaps.txt +++ /dev/null @@ -1,26 +0,0 @@ -Audience.internal is never used by a lower case -ContentPolicy.admin is never used by a lower case -ContentPolicy.admin is never used in a lower case's input -ContentPolicy.workflow is never used by a lower case -ContentPolicy.workflow is never used in a lower case's input -DatabaseEngine.database is never used by a lower case -DatabaseEngine.database is never used in a lower case's input -DatabaseGrant is never instantiated by a lower case -DatabaseGrant is never instantiated in a lower case's input -DatabaseGrant.delivery is never set by a lower case -DatabaseGrant.delivery is never set in a lower case's input -DatabaseGrant.engine is never set by a lower case -DatabaseGrant.engine is never set in a lower case's input -DatabaseGrant.fileMode is never set by a lower case -DatabaseGrant.fileMode is never set in a lower case's input -DatabaseGrant.mountAt is never set by a lower case -DatabaseGrant.mountAt is never set in a lower case's input -DatabaseGrant.role is never set by a lower case -DatabaseGrant.role is never set in a lower case's input -DatabaseGrant.rotation is never set by a lower case -DatabaseGrant.rotation is never set in a lower case's input -Engine.valkey is never used by a lower case -Engine.valkey is never used in a lower case's input -LibraryAccess.read is never used by a lower case -SignInMode.token is never used by a lower case -SignInMode.token is never used in a lower case's input diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/agents/agents.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/agents/agents.project.json deleted file mode 100644 index 106ba573e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/agents/agents.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"client":{"credential":"pkce","description":"The agent gateway","exposure":"public","label":"Hermes","protectedPath":"/api/status","redirectPaths":["/auth/callback"],"signIn":"native"},"exposure":[{"audience":"authenticated","host":"hermes.jorisjonkers.dev","name":"public","proxied":false,"routes":[{"match":"prefix","path":"/","process":"hermes","surface":"dashboard"}]},{"audience":"lan","host":"hermes.jorisjonkers.dev","name":"lan","routes":[{"match":"prefix","path":"/","process":"hermes","surface":"dashboard"}]}],"id":"hermes","processes":[{"args":["gateway","run"],"assets":[{"from":"config/hermes/config.yaml","seedAt":"/opt/data/config.yaml"}],"cutover":"interrupted","dependsOn":[{"application":"kubernetes-mcp-server","surface":"mcp"}],"egress":{"reason":"Hermes calls its model providers and remote MCP servers, and installs the skills it is given.","to":"internet"},"engine":"files","image":"hermes","lifecycle":"application","name":"hermes","placement":{"cpu":"250m","memory":"2Gi","site":"enschede"},"probes":{"liveness":{"path":"/api/status","port":9119},"readiness":{"path":"/api/status","port":9119}},"provides":{"dashboard":9119},"runtime":"none","secrets":[{"access":"read","delivery":"env","keys":[{"name":"memory-api-key","optional":true},{"name":"overleaf-session","optional":true},{"name":"github-pat","optional":true},{"name":"hindsight-api-token","optional":true},{"name":"openrouter-api-key","optional":true},{"name":"anthropic-api-key","optional":true},{"name":"openai-api-key","optional":true}],"path":"secret/data/agents/hermes","rotation":{"tolerates":"restart"}}],"startupBudget":"120s","volumes":[{"claim":"hermes-data","durability":"recoverable","mountAt":"/opt/data","size":"10Gi"}],"writablePaths":["/run","/tmp",{"memory":"1Gi","path":"/dev/shm"}]}]},{"id":"kubernetes-mcp-server","processes":[{"api":{"reason":"the MCP server answers an agent's questions about workloads, logs, routes and Flux, cluster-wide, and changes nothing","rules":[{"group":"core","objects":["pods","pods/log","events","services","endpoints","nodes","namespaces"],"verbs":["get","list","watch"]},{"group":"apps","objects":["deployments","statefulsets","daemonsets","replicasets"],"verbs":["get","list","watch"]},{"group":"batch","objects":["jobs","cronjobs"],"verbs":["get","list","watch"]},{"group":"networking.k8s.io","objects":["ingresses","networkpolicies"],"verbs":["get","list","watch"]},{"group":"traefik.io","objects":["ingressroutes","middlewares"],"verbs":["get","list","watch"]},{"group":"kustomize.toolkit.fluxcd.io","objects":["kustomizations"],"verbs":["get","list","watch"]},{"group":"helm.toolkit.fluxcd.io","objects":["helmreleases"],"verbs":["get","list","watch"]},{"group":"source.toolkit.fluxcd.io","objects":["gitrepositories","helmrepositories","ocirepositories"],"verbs":["get","list","watch"]}]},"args":["--port=8080","--read-only"],"cutover":"continuous","image":"kubernetes-mcp-server","lifecycle":"application","name":"kubernetes-mcp-server","placement":{"cpu":"50m","memory":"256Mi"},"probes":{"liveness":{"path":"/healthz","port":8080},"readiness":{"path":"/healthz","port":8080}},"provides":{"mcp":8080},"runtime":"none","startupBudget":"20s"}]},{"id":"agents-api","processes":[{"api":{"reason":"it reads the session settings it keeps beside itself","rules":[{"group":"core","objects":["configmaps"],"scope":"namespace","verbs":["get","list","watch"]}]},"cutover":"continuous","image":"agents-api","lifecycle":"application","name":"agents-api","parked":{"reason":"Agent sessions run through hermes since 2026-09-01."},"placement":{"cpu":"100m","memory":"512Mi"},"probes":{"liveness":{"path":"/actuator/health/liveness","port":8082},"readiness":{"path":"/actuator/health/readiness","port":8082}},"provides":{"http":8082},"runtime":"jvm","spawns":[{"dependsOn":[{"application":"agents-api","surface":"http"}],"egress":{"reason":"an agent clones and pushes the repositories it works on","to":"internet"},"image":"agent-runner","name":"runner","placement":{"cpu":"500m","memory":"1Gi"},"provides":{"http":8090}}],"startupBudget":"60s"}]},{"exposure":[{"audience":"anonymous","host":"agents.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"agents-ui","surface":"http"}]}],"id":"agents-ui","processes":[{"cutover":"continuous","image":"agents-ui","lifecycle":"application","name":"agents-ui","parked":{"reason":"Agent sessions run through hermes since 2026-09-01."},"placement":{"cpu":"100m","memory":"96Mi"},"probes":{"liveness":{"path":"/","port":80},"readiness":{"path":"/","port":80}},"provides":{"http":80},"runtime":"static","writablePaths":["/var/cache/nginx","/var/run"]}]}],"kind":"Project","owner":"joris","project":"agents","schemaVersion":"1.0.0"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/auth/auth.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/auth/auth.project.json deleted file mode 100644 index 054de2a85..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/auth/auth.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"exposure":[{"audience":"anonymous","contentPolicy":"strict","host":"auth.jorisjonkers.dev","name":"public","routes":[{"match":"exact","path":"/api/v1/users/register","process":"auth-api","rateLimit":{"per":"1h","requests":10},"surface":"http"},{"match":"prefix","path":"/api","process":"auth-api","surface":"http"},{"match":"prefix","path":"/","process":"auth-ui","surface":"http"}]}],"id":"auth","migration":{"changelog":"auth-api/src/main/resources/db/changelog/db.changelog-master.yaml"},"observability":{"scrape":{"path":"/api/actuator/prometheus","process":"auth-api","surface":"http"}},"processes":[{"cutover":"continuous","dependsOn":[{"application":"platform-postgres","surface":"postgres"},{"application":"platform-valkey","surface":"redis"},{"application":"platform-rabbitmq","surface":"amqp"},{"application":"stalwart","surface":"smtp"}],"image":"auth-api","lifecycle":"application","name":"auth-api","placement":{"arch":["amd64"],"capabilities":["public-ingress"],"cpu":"250m","memory":"768Mi"},"probes":{"liveness":{"path":"/api/actuator/health/liveness","port":8081},"readiness":{"path":"/api/actuator/health/readiness","port":8081}},"provides":{"http":8080},"replicas":{"count":2,"reason":"Capacity, not availability: the pair was provisioned on freed Frankfurt budget and both pods land on the one public-ingress node. Retires when that budget is reclaimed or the capability spreads to a second node."},"runtime":"jvm","secrets":[{"access":"read","delivery":"self","keys":["user","password"],"path":"secret/data/platform/postgres/auth","rotation":{"maxAge":"168h","tolerates":"reload"}},{"access":"read","delivery":"self","keys":["mail.password","valkey.password","rabbitmq.user","rabbitmq.password"],"path":"secret/data/auth-api","rotation":{"tolerates":"reload"}},{"delivery":"self","engine":"transit","key":"auth-api-jwt","operations":["sign","rotate","read"],"rotation":{"tolerates":"reload"}}],"startupBudget":"600s","writablePaths":["/tmp"]},{"cutover":"continuous","image":"auth-ui","lifecycle":"application","name":"auth-ui","placement":{"cpu":"10m","memory":"64Mi"},"probes":{"liveness":{"path":"/","port":80},"readiness":{"path":"/","port":80}},"provides":{"http":80},"runtime":"static","startupBudget":"30s","writablePaths":["/var/cache/nginx","/var/run"]}]}],"kind":"Project","owner":"joris","project":"auth","schemaVersion":"1.0.0"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/breadth/coverage.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/breadth/coverage.project.json deleted file mode 100644 index c51ece1eb..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/breadth/coverage.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"assets":[{"from":"config/seed.conf","seedAt":"/var/cache/coverage/seed.conf"}],"client":{"backChannelLogoutPath":"/logout","credential":"pkce","label":"Coverage","protectedPath":"/api","redirectPaths":["/callback"],"roles":["reader"],"signIn":"native"},"dependsOn":[{"application":"platform-valkey","required":false,"surface":"redis"}],"description":"Reads every key the other projects leave out","id":"coverage-api","processes":[{"api":{"reason":"it reads the nodes it places work on","rules":[{"group":"core","objects":["nodes"],"scope":"cluster","verbs":["get"]}]},"args":["serve","--verbose"],"command":["/bin/coverage"],"cutover":"interrupted","image":"coverage-api","lifecycle":"application","name":"coverage-api","placement":{"arch":["arm64"],"cpu":"10m","disk":{"media":["hdd"]},"gpu":{"memory":"8Gi","vendor":["nvidia"]},"memory":"64Mi"},"provides":{"http":8080},"runtime":"none","secrets":[{"access":"self-roll","delivery":"file","fileMode":"0400","keys":["password"],"mountAt":"/run/secrets/rolled","path":"secret/data/coverage/rolled","rotation":{"tolerates":"restart"}},{"access":"self-renew","delivery":"file","fileMode":"0400","keys":["lease"],"mountAt":"/run/secrets/renewed","path":"secret/data/coverage/renewed","rotation":{"tolerates":"restart"}},{"access":"custody","delivery":"self","keys":["root"],"path":"secret/data/coverage/custody","rotation":{"tolerates":"reload"}},{"delivery":"self","engine":"transit","fileMode":"0400","key":"coverage","mountAt":"/run/secrets/transit","operations":["encrypt","decrypt","verify"],"rotation":{"tolerates":"restart"}}],"sidecars":[{"args":["run"],"command":["/bin/helper"],"cpu":"5m","image":"coverage-helper","memory":"16Mi","name":"helper"}]},{"image":"coverage-seed","lifecycle":"prepare","name":"coverage-seed","placement":{"cpu":"5m","memory":"32Mi"},"runtime":"none"},{"cutover":"interrupted","image":"coverage-job","lifecycle":"job","name":"coverage-job","placement":{"cpu":"5m","memory":"32Mi"},"runtime":"none"}],"secrets":[{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"bytes":32,"encoding":"base64"},"name":"session"}],"mountAt":"/run/secrets/session","path":"secret/data/coverage-system/session","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"bytes":16,"encoding":"base64url"},"name":"cookie"}],"mountAt":"/run/secrets/cookie","path":"secret/data/coverage-system/cookie","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"encoding":"hex"},"name":"salt"}],"mountAt":"/run/secrets/salt","path":"secret/data/coverage-system/salt","rotation":{"tolerates":"restart"}}],"startupBudget":"60s","writablePaths":[{"memory":"64Mi","path":"/var/cache/coverage"}]}],"assets":[{"from":"config/coverage.conf","mountAt":"/etc/coverage/project.conf"}],"dependsOn":[{"application":"platform-rabbitmq","required":true,"surface":"amqp"}],"kind":"Project","owner":"joris","placement":{"site":"enschede"},"project":"coverage","schemaVersion":"1.0.0","startupBudget":"90s","writablePaths":["/tmp"]} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/data/data.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/data/data.project.json deleted file mode 100644 index c9e2c5826..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/data/data.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"id":"platform-postgres","observability":{"scrape":{"path":"/metrics","process":"postgres","surface":"metrics"}},"processes":[{"assets":[{"from":"config/postgresql.conf","mountAt":"/etc/postgresql/postgresql.conf"}],"cutover":"interrupted","engine":"postgres","image":"postgres","lifecycle":"application","name":"postgres","placement":{"arch":["amd64"],"cpu":"500m","disk":{"media":["nvme","ssd"]},"memory":"2Gi"},"probes":{"liveness":{"tcp":5432},"readiness":{"tcp":5432}},"provides":{"metrics":9187,"postgres":5432},"runtime":"none","secrets":[{"access":"read","delivery":"file","fileMode":"0400","keys":[{"generate":{"adopt":"secret/data/platform/postgres/exporter#datasource"},"name":"datasource"}],"mountAt":"/run/secrets/exporter","path":"secret/data/data-system/exporter","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"env","keys":["datasource"],"path":"secret/data/platform/postgres/exporter","rotation":{"tolerates":"restart"}}],"sidecars":[{"cpu":"10m","image":"postgres-exporter","memory":"64Mi","name":"postgres-exporter"}],"startupBudget":"60s","volumes":[{"claim":"postgres-data","durability":"irreplaceable","mountAt":"/var/lib/postgresql/data","size":"20Gi"}],"writablePaths":["/var/run/postgresql","/tmp"]}]},{"dashboards":[{"from":"dashboards/rabbitmq.json"}],"exposure":[{"audience":"authenticated","host":"rabbitmq.jorisjonkers.dev","name":"management","routes":[{"match":"prefix","path":"/","process":"rabbitmq","surface":"management"}]},{"audience":"lan","host":"rabbitmq.jorisjonkers.dev","name":"lan","routes":[{"match":"prefix","path":"/","process":"rabbitmq","surface":"management"}]}],"id":"platform-rabbitmq","l4Exposure":[{"address":"lan-mqtt","port":1883,"process":"rabbitmq","protocol":"tcp","surface":"mqtt"}],"observability":{"scrape":{"honorLabels":true,"path":"/metrics","process":"rabbitmq","surface":"metrics"}},"processes":[{"cutover":"interrupted","engine":"rabbitmq","image":"rabbitmq","lifecycle":"application","name":"rabbitmq","placement":{"cpu":"500m","memory":"2Gi"},"probes":{"liveness":{"tcp":5672},"readiness":{"tcp":5672}},"provides":{"amqp":5672,"management":15672,"metrics":15692,"mqtt":1883},"runtime":"none","startupBudget":"120s","volumes":[{"claim":"rabbitmq-data","durability":"recoverable","mountAt":"/var/lib/rabbitmq","size":"20Gi"}]}]},{"id":"platform-valkey","processes":[{"cutover":"interrupted","image":"valkey","lifecycle":"application","name":"valkey","placement":{"cpu":"50m","memory":"256Mi"},"probes":{"liveness":{"tcp":6379},"readiness":{"tcp":6379}},"provides":{"redis":6379},"runtime":"none","startupBudget":"30s","volumes":[{"claim":"valkey-data","durability":"reconstructible","mountAt":"/data","size":"2Gi"}]}]},{"id":"platform-mongo","processes":[{"cutover":"interrupted","engine":"mongo","image":"mongo","lifecycle":"application","name":"mongo","placement":{"cpu":"200m","memory":"2Gi"},"probes":{"liveness":{"tcp":27017},"readiness":{"tcp":27017}},"provides":{"mongo":27017},"runtime":"none","startupBudget":"60s","volumes":[{"claim":"mongo-data","durability":"irreplaceable","mountAt":"/data/db","size":"20Gi"}],"writablePaths":["/tmp","/data/configdb"]}]},{"id":"asset-sync","processes":[{"egress":{"reason":"reads the latest release from GitHub and uploads it to the public assets bucket","to":"internet"},"image":"asset-sync","lifecycle":"scheduled","name":"asset-sync","placement":{"cpu":"25m","memory":"64Mi","site":"frankfurt"},"runtime":"none","schedule":"*/15 * * * *","secrets":[{"access":"read","delivery":"file","fileMode":"0400","keys":["credentials"],"mountAt":"/run/secrets/garage/credentials","path":"secret/data/platform/garage/web-key","rotation":{"tolerates":"restart"}}]}]},{"id":"platform-garage","processes":[{"assets":[{"from":"config/garage.toml","mountAt":"/etc/garage.toml"}],"cutover":"interrupted","engine":"s3","image":"garage","lifecycle":"application","name":"garage","placement":{"cpu":"200m","memory":"1Gi","site":"frankfurt"},"probes":{"liveness":{"tcp":3900},"readiness":{"path":"/health","port":3903}},"provides":{"admin":3903,"s3":3900},"runtime":"none","secrets":[{"access":"read","delivery":"env","keys":["rpc-secret","admin-token"],"path":"secret/data/platform/garage","rotation":{"tolerates":"restart"}}],"startupBudget":"60s","volumes":[{"claim":"garage-meta","durability":"reconstructible","mountAt":"/var/lib/garage/meta","size":"2Gi"},{"claim":"garage-snapshots","durability":"recoverable","mountAt":"/var/lib/garage/snapshots","size":"4Gi"},{"claim":"garage-data","durability":"recoverable","mountAt":"/var/lib/garage/data","size":"20Gi"}]}]}],"kind":"Project","owner":"joris","project":"data","schemaVersion":"1.0.0"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/delivery/delivery.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/delivery/delivery.project.json deleted file mode 100644 index 7253e9357..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/delivery/delivery.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"id":"flagger","processes":[{"api":{"reason":"Flagger switches every blue-green Process, so it scales its Deployment, generates its Services and copies, and records the Canary","rules":[{"group":"flagger.app","objects":["canaries","canaries/status"],"verbs":["get","list","watch","update","patch"]},{"group":"apps","objects":["deployments"],"verbs":["get","list","watch","create","update","patch","delete"]},{"group":"autoscaling","objects":["horizontalpodautoscalers"],"verbs":["get","list","watch","create","update","patch","delete"]},{"group":"core","objects":["services","configmaps"],"verbs":["get","list","watch","create","update","patch","delete"]},{"group":"core","objects":["secrets"],"verbs":["get"]},{"group":"core","objects":["events"],"verbs":["create","update","patch"]}]},"cutover":"continuous","dependsOn":[{"application":"release-gate","surface":"http"}],"image":"flagger","lifecycle":"application","name":"flagger","placement":{"cpu":"10m","memory":"64Mi"},"probes":{"liveness":{"path":"/healthz","port":8080},"readiness":{"path":"/healthz","port":8080}},"provides":{"http":8080},"runtime":"none","startupBudget":"30s","writablePaths":["/tmp"]}]},{"id":"release-gate","observability":{"scrape":{"path":"/metrics","process":"release-gate","surface":"http"}},"processes":[{"api":{"reason":"the Release Gate answers Flagger from what the cluster holds, so it reads each gated Application's inputs, Canaries, Deployments, Jobs and pods; it finds the gated Applications by listing ConfigMaps, keeps each one's release record in a ConfigMap of its own, unsuspends the migration Jobs it starts, and deletes a gated Application's Vault sync objects of an older revision once it serves the new one","rules":[{"group":"core","objects":["configmaps"],"verbs":["get","list"]},{"group":"core","objects":["configmaps"],"scope":"namespace","verbs":["create","update"]},{"group":"core","objects":["pods"],"verbs":["list"]},{"group":"apps","objects":["deployments"],"verbs":["get"]},{"group":"batch","objects":["jobs"],"verbs":["list","patch"]},{"group":"flagger.app","objects":["canaries"],"verbs":["get"]},{"group":"secrets.hashicorp.com","objects":["vaultauths","vaultstaticsecrets","vaultdynamicsecrets"],"verbs":["list","delete"]}]},"cutover":"continuous","image":"release-gate","lifecycle":"application","name":"release-gate","placement":{"cpu":"25m","memory":"64Mi"},"probes":{"liveness":{"path":"/healthz","port":8080},"readiness":{"path":"/readyz","port":8080}},"provides":{"http":8080},"runtime":"none","startupBudget":"10s"}]},{"id":"collector","processes":[{"api":{"reason":"the Collector captures where each bound claim and each rendered pod is, so it lists the three kinds that say so, cluster-wide, and writes nothing","rules":[{"group":"core","objects":["persistentvolumes","persistentvolumeclaims","pods"],"verbs":["get","list"]}]},"cutover":"interrupted","image":"collector","lifecycle":"application","name":"collector","placement":{"cpu":"10m","memory":"64Mi"},"probes":{"liveness":{"path":"/fresh","port":8080},"readiness":{"path":"/readyz","port":8080}},"provides":{"http":8080},"runtime":"none","startupBudget":"10s"}]},{"id":"reporter","processes":[{"api":{"reason":"the Reporter reads every Project's unit and every Canary again on start and on an interval, to correct a status an event it missed left behind, and writes nothing","rules":[{"group":"kustomize.toolkit.fluxcd.io","objects":["kustomizations"],"verbs":["get","list","watch"]},{"group":"flagger.app","objects":["canaries"],"verbs":["get","list","watch"]}]},"cutover":"interrupted","image":"reporter","lifecycle":"application","name":"reporter","placement":{"cpu":"10m","memory":"64Mi"},"probes":{"liveness":{"path":"/healthz","port":8080},"readiness":{"path":"/readyz","port":8080}},"provides":{"http":8080},"runtime":"none","startupBudget":"10s"}]}],"kind":"Project","owner":"joris","project":"delivery","schemaVersion":"1.0.0"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/edge/edge.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/edge/edge.project.json deleted file mode 100644 index aaabf5291..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/edge/edge.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"id":"traefik-public","processes":[{"cutover":"continuous","image":"traefik","lifecycle":"application","name":"traefik-public","placement":{"capabilities":["public-ingress"],"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/ping","port":8080},"readiness":{"path":"/ping","port":8080}},"provides":{"admin":8080,"web":8000,"websecure":8443},"runtime":"none","startupBudget":"20s","writablePaths":["/tmp"]}]},{"id":"traefik-lan","processes":[{"cutover":"continuous","image":"traefik","lifecycle":"application","name":"traefik-lan","placement":{"capabilities":["lan-ingress"],"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/ping","port":8080},"readiness":{"path":"/ping","port":8080}},"provides":{"admin":8080,"web":8000,"websecure":8443},"runtime":"none","startupBudget":"20s","writablePaths":["/tmp"]}]},{"id":"external-dns","processes":[{"api":{"reason":"external-dns reads every route and the Services behind it, cluster-wide, to publish their hosts","rules":[{"group":"core","objects":["services","endpoints","pods","nodes"],"verbs":["get","list","watch"]},{"group":"traefik.io","objects":["ingressroutes"],"verbs":["get","list","watch"]}]},"cutover":"interrupted","egress":{"reason":"the DNS provider's API","to":"internet"},"image":"external-dns","lifecycle":"application","name":"external-dns","placement":{"cpu":"10m","memory":"64Mi"},"probes":{"liveness":{"path":"/healthz","port":7979},"readiness":{"path":"/healthz","port":7979}},"provides":{"metrics":7979},"runtime":"none","startupBudget":"30s"}]}],"kind":"Project","owner":"joris","project":"edge","schemaVersion":"1.0.0"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/identity/identity.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/identity/identity.project.json deleted file mode 100644 index 50ed84bc9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/identity/identity.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"exposure":[{"audience":"anonymous","contentPolicy":"strict","host":"id.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"identity","surface":"http"}]}],"id":"identity","processes":[{"cutover":"continuous","image":"identity","lifecycle":"application","name":"identity","placement":{"cpu":"50m","memory":"256Mi"},"probes":{"liveness":{"path":"/health/live","port":8080},"readiness":{"path":"/health/ready","port":8080}},"provides":{"http":8080},"runtime":"none","startupBudget":"30s"}]},{"client":{"credential":"pkce","description":"Every application you can open","label":"Home","launchPath":"/apps","protectedPath":"/api/me","redirectPaths":["/callback","/silent-renew"],"signIn":"native"},"exposure":[{"audience":"authenticated","host":"home.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"portal","surface":"http"}]}],"id":"portal","processes":[{"cutover":"continuous","image":"portal","lifecycle":"application","name":"portal","placement":{"cpu":"10m","memory":"64Mi"},"probes":{"readiness":{"path":"/","port":8080}},"provides":{"http":8080},"runtime":"none"}]},{"client":{"iconPath":"/favicon.ico","label":"Who am I","signIn":"gated"},"exposure":[{"audience":"authenticated","host":"whoami.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"whoami","surface":"http"},{"audience":"anonymous","match":"exact","path":"/health","process":"whoami","surface":"http"}]}],"id":"whoami","processes":[{"cutover":"continuous","image":"whoami","lifecycle":"application","name":"whoami","placement":{"cpu":"10m","memory":"32Mi"},"probes":{"readiness":{"path":"/health","port":8080}},"provides":{"http":8080},"replicas":{"across":"node","count":2,"reason":"Availability of the sign-in probe across a node loss."},"runtime":"none"}]}],"kind":"Project","owner":"joris","project":"identity","schemaVersion":"1.0.0"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/intent.xmi b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/intent.xmi deleted file mode 100644 index 8ef1ed2ca..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/intent.xmi +++ /dev/null @@ -1,1898 +0,0 @@ - - - - - - /auth/callback - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gateway - run - - - - - - - - - - - - - pods - pods/log - events - services - endpoints - nodes - namespaces - get - list - watch - - - deployments - statefulsets - daemonsets - replicasets - get - list - watch - - - jobs - cronjobs - get - list - watch - - - ingresses - networkpolicies - get - list - watch - - - ingressroutes - middlewares - get - list - watch - - - kustomizations - get - list - watch - - - helmreleases - get - list - watch - - - gitrepositories - helmrepositories - ocirepositories - get - list - watch - - - --port=8080 - --read-only - - - - - - - - - - - - - configmaps - get - list - watch - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - sign - rotate - read - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - amd64 - public-ingress - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /callback - reader - - - - - - - - - - - - - - - - - encrypt - decrypt - verify - - - - - - - - arm64 - - hdd - - - nvidia - - - - - /bin/helper - run - - - - nodes - get - - - /bin/coverage - serve - --verbose - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - amd64 - - nvme - ssd - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - canaries - canaries/status - get - list - watch - update - patch - - - deployments - get - list - watch - create - update - patch - delete - - - horizontalpodautoscalers - get - list - watch - create - update - patch - delete - - - services - configmaps - get - list - watch - create - update - patch - delete - - - secrets - get - - - events - create - update - patch - - - - - - - - - - - - - - - - - - configmaps - get - list - - - configmaps - create - update - - - pods - list - - - deployments - get - - - jobs - list - patch - - - canaries - get - - - vaultauths - vaultstaticsecrets - vaultdynamicsecrets - list - delete - - - - - - - - - - - - - - - persistentvolumes - persistentvolumeclaims - pods - get - list - - - - - - - - - - - - - - - kustomizations - get - list - watch - - - canaries - get - list - watch - - - - - - - - - - - public-ingress - - - - - - - - - - - - - - - lan-ingress - - - - - - - - - - - - - - - - - - - - - services - endpoints - pods - nodes - get - list - watch - - - ingressroutes - get - list - watch - - - - - - - - - - - - - - - - - - - - - - - /callback - /silent-renew - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - assets - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - public-ingress - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - t1000 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - services - endpoints - pods - get - list - watch - - - endpointslices - get - list - watch - - - --storage.tsdb.retention.time=15d - --storage.tsdb.retention.size=10GB - --enable-feature=exemplar-storage - --enable-feature=native-histograms - --web.enable-remote-write-receiver - --log.level=info - --query.max-concurrency - - - - - - - - - - - - - prometheuses - prometheuses/status - alertmanagers - alertmanagers/status - servicemonitors - podmonitors - prometheusrules - alertmanagerconfigs - get - list - watch - create - update - patch - delete - - - services - endpoints - pods - nodes - namespaces - configmaps - secrets - get - list - watch - create - update - delete - - - statefulsets - get - list - watch - create - update - delete - - - - - - - - - - - - - - - - pods - nodes - namespaces - services - persistentvolumeclaims - persistentvolumes - list - watch - - - deployments - statefulsets - daemonsets - replicasets - list - watch - - - jobs - cronjobs - list - watch - - - - - - - - - - - - - - - - grafanas - grafanas/status - grafanadashboards - grafanadashboards/status - get - list - watch - update - patch - - - configmaps - secrets - get - list - watch - - - - - - - /login/generic_oauth - viewer - editor - admin - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmaps - get - list - watch - - - - - - - - - - - - - - - pods - pods/log - namespaces - get - list - watch - - - - - - - - - - - - - - - - - - - - 9.9.9.10 - 149.112.112.10 - - - - - - - - - - - - - - - - - traefik.io/v1alpha1 - secrets.hashicorp.com/v1beta1 - monitoring.coreos.com/v1 - flagger.app/v1beta1 - identity.jorisjonkers.dev/v1 - metallb.io/v1beta1 - - - anonymous - authenticated - - X-Forwarded-User - - - - - lan - - - internal - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - coverage - identity - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - vaultstaticsecrets - vaultstaticsecrets/status - vaultdynamicsecrets - vaultdynamicsecrets/status - vaultauths - vaultauths/status - vaultconnections - vaultconnections/status - get - list - watch - create - update - patch - delete - deletecollection - - - secrets - get - list - watch - create - update - patch - delete - - - serviceaccounts/token - create - - - deployments - statefulsets - daemonsets - get - list - watch - patch - - - events - create - patch - - - - - - - - - - - - - - - adguard - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/knowledge-platform/knowledge-platform.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/knowledge-platform/knowledge-platform.project.json deleted file mode 100644 index 975e7d486..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/knowledge-platform/knowledge-platform.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"id":"docling-serve","processes":[{"engine":"files","image":"docling-serve","lifecycle":"application","name":"docling-serve","placement":{"cpu":"500m","memory":"1Gi","site":"frankfurt"},"probes":{"liveness":{"path":"/health","port":8000},"readiness":{"path":"/health","port":8000}},"provides":{"http":8000},"runtime":"python","startupBudget":"120s","volumes":[{"claim":"docling-serve-archive","durability":"irreplaceable","mountAt":"/archive","size":"50Gi"}]}]},{"cutover":"continuous","exposure":[{"audience":"authenticated","contentPolicy":"strict","host":"memory.jorisjonkers.dev","name":"console","routes":[{"match":"prefix","path":"/","process":"hindsight-control-plane","surface":"console"}]},{"audience":"authenticated","contentPolicy":"strict","host":"memory-api.jorisjonkers.dev","name":"api","routes":[{"match":"prefix","path":"/","process":"hindsight-api","surface":"api"}]}],"id":"hindsight","migration":"self","placement":{"site":"enschede"},"processes":[{"dependsOn":[{"application":"platform-postgres","credentials":{"delivery":"env","rotation":{"tolerates":"restart"}},"surface":"postgres"},{"application":"hindsight-embedding","surface":"embeddings"}],"image":"hindsight-api","lifecycle":"application","name":"hindsight-api","placement":{"cpu":"500m","memory":"1Gi"},"probes":{"liveness":{"path":"/health/live","port":8888},"readiness":{"path":"/health","port":8888}},"provides":{"api":8888},"runtime":"python","secrets":[{"access":"read","delivery":"env","keys":["llm-api-key"],"path":"secret/data/platform/hindsight","rotation":{"tolerates":"restart"}}],"startupBudget":"120s"},{"dependsOn":[{"application":"platform-postgres","credentials":{"delivery":"file","fileMode":"0400","mountAt":"/run/secrets/database","rotation":{"tolerates":"restart"}},"surface":"postgres"},{"application":"hindsight-embedding","surface":"embeddings"}],"image":"hindsight-api","lifecycle":"application","name":"hindsight-worker","parked":{"reason":"Ingestion paused while the job store is migrated."},"placement":{"cpu":"500m","memory":"1Gi"},"probes":{"liveness":{"path":"/health/live","port":8889},"readiness":{"path":"/health","port":8889}},"provides":{"worker":8889},"runtime":"python","secrets":[{"access":"read","delivery":"env","keys":["llm-api-key"],"path":"secret/data/platform/hindsight","rotation":{"tolerates":"restart"}}],"startupBudget":"120s"},{"dependsOn":[{"application":"hindsight","surface":"api"}],"image":"hindsight-control-plane","lifecycle":"application","name":"hindsight-control-plane","placement":{"cpu":"250m","memory":"512Mi"},"probes":{"liveness":{"tcp":3000},"readiness":{"tcp":3000}},"provides":{"console":3000},"runtime":"node","startupBudget":"60s"}]},{"exposure":[{"audience":"authenticated","contentPolicy":"strict","host":"memory-mcp.jorisjonkers.dev","name":"mcp","routes":[{"match":"prefix","path":"/","process":"basic-memory","surface":"mcp"}]}],"id":"basic-memory","processes":[{"image":"basic-memory","lifecycle":"application","name":"basic-memory","placement":{"cpu":"500m","memory":"1Gi","site":"frankfurt"},"probes":{"liveness":{"tcp":8000},"readiness":{"tcp":8000}},"provides":{"mcp":8000},"runtime":"python","secrets":[{"access":"read","delivery":"file","fileMode":"0400","keys":["private_key"],"mountAt":"/run/secrets/knowledge-vault/id_ed25519","path":"secret/data/knowledge-system/vault-deploy-key","rotation":{"tolerates":"reload"}}],"sidecars":[{"cpu":"50m","image":"basic-memory-git-sync","init":true,"memory":"64Mi","name":"git-clone","volumes":[{"claim":"basic-memory-vault","mountAt":"/vault"}]},{"cpu":"50m","image":"basic-memory-git-sync","memory":"64Mi","name":"git-sync","volumes":[{"claim":"basic-memory-vault","mountAt":"/vault"}]}],"startupBudget":"120s","volumes":[{"claim":"basic-memory-vault","durability":"reconstructible","mountAt":"/vault","size":"5Gi"},{"claim":"basic-memory-config","durability":"reconstructible","mountAt":"/app/.basic-memory","size":"2Gi"}]}]},{"exposure":[{"audience":"authenticated","contentPolicy":"strict","host":"karakeep.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"karakeep","surface":"http"}]}],"id":"karakeep","processes":[{"dependsOn":[{"application":"platform-garage","buckets":["assets"],"surface":"s3"}],"egress":{"reason":"The browser fetches the pages it bookmarks.","to":"internet"},"engine":"files","image":"karakeep","lifecycle":"application","name":"karakeep","placement":{"cpu":"200m","memory":"512Mi","site":"frankfurt"},"probes":{"liveness":{"path":"/api/health","port":3000},"readiness":{"path":"/api/health","port":3000}},"provides":{"http":3000},"runtime":"node","secrets":[{"access":"read","delivery":"env","keys":["nextauth-secret","meili-master-key","openrouter-api-key"],"path":"secret/data/platform/karakeep","rotation":{"tolerates":"restart"}}],"sidecars":[{"cpu":"100m","image":"meilisearch","memory":"256Mi","name":"meilisearch","volumes":[{"claim":"karakeep-meili","mountAt":"/meili_data"}]},{"cpu":"500m","image":"karakeep-chrome","memory":"512Mi","name":"chrome"}],"startupBudget":"200s","volumes":[{"claim":"karakeep-data","durability":"recoverable","mountAt":"/data","size":"50Gi"},{"claim":"karakeep-meili","durability":"reconstructible","mountAt":"/meili_data","size":"5Gi"},{"claim":"meilisearch-data","durability":"reconstructible","mountAt":"/meili_data","size":"20Gi"}],"vpn":{"forwardedPort":false}}]},{"id":"hindsight-embedding","placement":{"site":"enschede"},"processes":[{"image":"text-embeddings-inference","lifecycle":"application","name":"hindsight-tei-embedding","placement":{"cpu":"500m","memory":"6Gi"},"probes":{"liveness":{"path":"/health","port":8091},"readiness":{"path":"/health","port":8091}},"provides":{"embeddings":8091},"runtime":"none","startupBudget":"300s","volumes":[{"claim":"hindsight-tei-model-cache","durability":"reconstructible","mountAt":"/data","size":"8Gi"}]}]}],"cutover":"interrupted","kind":"Project","owner":"joris","project":"knowledge-platform","schemaVersion":"1.0.0"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/knowledge/knowledge.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/knowledge/knowledge.project.json deleted file mode 100644 index 8ab537a94..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/knowledge/knowledge.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"exposure":[{"audience":"authenticated","host":"knowledge.jorisjonkers.dev","name":"public","routes":[{"audience":"anonymous","match":"exact","path":"/mcp","process":"knowledge-api","surface":"http"},{"audience":"anonymous","match":"prefix","path":"/mcp/","process":"knowledge-api","surface":"http"},{"audience":"anonymous","match":"exact","path":"/install.sh","process":"knowledge-api","surface":"http"},{"audience":"anonymous","match":"exact","path":"/install-agents.sh","process":"knowledge-api","surface":"http"},{"match":"prefix","path":"/","process":"knowledge-api","surface":"http"}]}],"id":"knowledge","migration":{"changelog":"knowledge-api/src/main/resources/db/changelog.yml"},"observability":{"scrape":{"path":"/api/actuator/prometheus","process":"knowledge-api","surface":"http"}},"processes":[{"cutover":"continuous","dependsOn":[{"application":"platform-postgres","surface":"postgres"},{"application":"platform-rabbitmq","surface":"amqp"}],"image":"knowledge-api","lifecycle":"application","name":"knowledge-api","placement":{"capabilities":["public-ingress"],"cpu":"250m","memory":"768Mi"},"probes":{"liveness":{"path":"/api/actuator/health/liveness","port":8080},"readiness":{"path":"/api/actuator/health/readiness","port":8080}},"provides":{"http":8080},"runtime":"jvm","secrets":[{"access":"read","delivery":"env","keys":["workstation"],"path":"secret/data/knowledge-system/mcp-bearer","rotation":{"tolerates":"restart"}}],"startupBudget":"600s","writablePaths":["/tmp"]}]},{"description":"Turns the notes dropped into the vault into searchable knowledge.","id":"knowledge-ingest","migration":"none","processes":[{"cutover":"interrupted","dependsOn":[{"application":"platform-rabbitmq","surface":"amqp"},{"application":"platform-postgres","surface":"postgres"}],"description":"Takes one note at a time off the queue and indexes it.","engine":"files","image":"knowledge-ingest-worker","lifecycle":"application","name":"knowledge-ingest-worker","placement":{"cpu":"50m","memory":"256Mi"},"probes":"none","runtime":"python","secrets":[{"access":"read","delivery":"file","fileMode":"0400","keys":["key"],"mountAt":"/home/worker/.ssh/id_ed25519","path":"secret/data/knowledge-system/vault-deploy-key","rotation":{"tolerates":"restart"}}],"startupBudget":"120s","volumes":[{"claim":"knowledge-vault-clone","durability":"irreplaceable","mountAt":"/var/lib/knowledge-vault","size":"20Gi"}]}]}],"kind":"Project","owner":"joris","project":"knowledge","schemaVersion":"1.0.0","secrets":[{"access":"read","delivery":"env","keys":["user","password"],"path":"secret/data/platform/postgres/kb","rotation":{"tolerates":"restart"}},{"access":"read","delivery":"env","keys":["rabbitmq.user","rabbitmq.password"],"path":"secret/data/platform/rabbitmq","rotation":{"tolerates":"restart"}}]} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/mail/mail.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/mail/mail.project.json deleted file mode 100644 index 8e96fa35a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/mail/mail.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"exposure":[{"audience":"authenticated","host":"mail.jorisjonkers.dev","name":"admin","routes":[{"match":"exact","path":"/","process":"stalwart","redirectTo":"/admin/","surface":"http"},{"match":"prefix","path":"/","process":"stalwart","surface":"http"}]}],"id":"stalwart","l4Exposure":[{"address":"mail-node","port":25,"process":"stalwart","protocol":"tcp","surface":"smtp"},{"address":"mail-node","port":993,"process":"stalwart","protocol":"tcp","surface":"imaps"},{"address":"mail-node","port":2525,"process":"stalwart","protocol":"tcp","surface":"smtp"}],"processes":[{"assets":[{"from":"config/manifest.json","mountAt":"/etc/stalwart-provisioner/manifest.json"}],"cutover":"interrupted","image":"stalwart","lifecycle":"application","name":"stalwart","placement":{"cpu":"100m","memory":"512Mi"},"probes":{"liveness":{"path":"/healthz/live","port":8080},"readiness":{"path":"/healthz/ready","port":8080}},"provides":{"http":8080,"imaps":993,"smtp":25},"runtime":"none","sidecars":[{"assets":[{"from":"config/manifest.json","mountAt":"/etc/stalwart-provisioner/manifest.json"}],"cpu":"10m","image":"stalwart-provisioner","memory":"64Mi","name":"stalwart-apply"}],"startupBudget":"60s","writablePaths":["/tmp"]}]}],"kind":"Project","owner":"joris","project":"mail","schemaVersion":"1.0.0"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/minimal/notes.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/minimal/notes.project.json deleted file mode 100644 index ae74b9e3f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/minimal/notes.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"exposure":[{"audience":"anonymous","contentPolicy":"strict","host":"notes.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"notes-api","surface":"http"}]}],"id":"notes","observability":{"scrape":{"path":"/metrics","process":"notes-api","surface":"http"}},"processes":[{"cutover":"continuous","image":"notes-api","libraries":[{"access":"write","library":"media","mountAt":"/attachments","subPath":"Notes"}],"lifecycle":"application","name":"notes-api","placement":{"cpu":"50m","gpu":{"class":"transcode","model":["t1000"]},"memory":"256Mi"},"probes":{"liveness":{"path":"/healthz/live","port":8080},"readiness":{"path":"/healthz/ready","port":8080}},"provides":{"http":8080},"runtime":"node","startupBudget":"20s"}]}],"kind":"Project","owner":"joris","project":"notes","schemaVersion":"1.0.0"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/observability/observability.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/observability/observability.project.json deleted file mode 100644 index 3833762b7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/observability/observability.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"id":"otel-collector","processes":[{"cutover":"continuous","image":"otel-collector","lifecycle":"application","name":"otel-collector","placement":{"cpu":"50m","memory":"256Mi"},"probes":{"liveness":{"path":"/","port":13133},"readiness":{"path":"/","port":13133}},"provides":{"health":13133,"otlp":4317},"runtime":"none","startupBudget":"20s"}]},{"alertRules":[{"from":"rules/platform.yaml"}],"id":"prometheus","processes":[{"api":{"reason":"Prometheus discovers every monitor's targets through the API, cluster-wide","rules":[{"group":"core","objects":["services","endpoints","pods"],"verbs":["get","list","watch"]},{"group":"discovery.k8s.io","objects":["endpointslices"],"verbs":["get","list","watch"]}]},"args":["--storage.tsdb.retention.time=15d","--storage.tsdb.retention.size=10GB","--enable-feature=exemplar-storage","--enable-feature=native-histograms","--web.enable-remote-write-receiver","--log.level=info","--query.max-concurrency"],"cutover":"interrupted","image":"prometheus","lifecycle":"application","name":"prometheus","placement":{"cpu":"100m","memory":"512Mi"},"probes":{"liveness":{"path":"/-/healthy","port":9090},"readiness":{"path":"/-/ready","port":9090}},"provides":{"http":9090},"runtime":"none","startupBudget":"60s","writablePaths":["/prometheus"]}]},{"id":"prometheus-operator","processes":[{"api":{"reason":"the operator reconciles every monitor, rule and Alertmanager routing object into the Prometheus and Alertmanager configuration, cluster-wide","rules":[{"group":"monitoring.coreos.com","objects":["prometheuses","prometheuses/status","alertmanagers","alertmanagers/status","servicemonitors","podmonitors","prometheusrules","alertmanagerconfigs"],"verbs":["get","list","watch","create","update","patch","delete"]},{"group":"core","objects":["services","endpoints","pods","nodes","namespaces","configmaps","secrets"],"verbs":["get","list","watch","create","update","delete"]},{"group":"apps","objects":["statefulsets"],"verbs":["get","list","watch","create","update","delete"]}]},"cutover":"interrupted","image":"prometheus-operator","lifecycle":"application","name":"prometheus-operator","placement":{"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/healthz","port":8080},"readiness":{"path":"/healthz","port":8080}},"provides":{"http":8080},"runtime":"none","startupBudget":"30s"}]},{"id":"kube-state-metrics","processes":[{"api":{"reason":"kube-state-metrics reports the state of every object it lists, cluster-wide","rules":[{"group":"core","objects":["pods","nodes","namespaces","services","persistentvolumeclaims","persistentvolumes"],"verbs":["list","watch"]},{"group":"apps","objects":["deployments","statefulsets","daemonsets","replicasets"],"verbs":["list","watch"]},{"group":"batch","objects":["jobs","cronjobs"],"verbs":["list","watch"]}]},"cutover":"continuous","image":"kube-state-metrics","lifecycle":"application","name":"kube-state-metrics","placement":{"cpu":"20m","memory":"128Mi"},"probes":{"liveness":{"path":"/livez","port":8080},"readiness":{"path":"/livez","port":8080}},"provides":{"http":8080,"telemetry":8081},"runtime":"none","startupBudget":"30s"}]},{"id":"grafana-operator","processes":[{"api":{"reason":"the operator imports every Application's dashboards into the Grafana it selects, cluster-wide","rules":[{"group":"grafana.integreatly.org","objects":["grafanas","grafanas/status","grafanadashboards","grafanadashboards/status"],"verbs":["get","list","watch","update","patch"]},{"group":"core","objects":["configmaps","secrets"],"verbs":["get","list","watch"]}]},"cutover":"interrupted","image":"grafana-operator","lifecycle":"application","name":"grafana-operator","placement":{"cpu":"20m","memory":"64Mi"},"probes":{"liveness":{"path":"/healthz","port":8081},"readiness":{"path":"/healthz","port":8081}},"provides":{"health":8081,"metrics":8080},"runtime":"none","startupBudget":"30s"}]},{"client":{"credential":"secret","description":"Metrics and dashboards","iconPath":"/public/img/grafana_icon.svg","label":"Grafana","protectedPath":"/api/user","redirectPaths":["/login/generic_oauth"],"roles":["viewer","editor","admin"],"signIn":"native"},"exposure":[{"audience":"authenticated","host":"grafana.jorisjonkers.dev","name":"public","routes":[{"match":"prefix","path":"/","process":"grafana","surface":"http"}]}],"id":"grafana","processes":[{"cutover":"continuous","image":"grafana","lifecycle":"application","name":"grafana","placement":{"cpu":"50m","memory":"256Mi"},"probes":{"readiness":{"path":"/api/health","port":3000}},"provides":{"http":3000},"runtime":"none","startupBudget":"30s","writablePaths":["/var/lib/grafana"]}]},{"id":"loki","processes":[{"cutover":"interrupted","image":"loki","lifecycle":"application","name":"loki","placement":{"cpu":"100m","memory":"512Mi"},"probes":{"liveness":{"path":"/ready","port":3100},"readiness":{"path":"/ready","port":3100}},"provides":{"http":3100},"runtime":"none","startupBudget":"30s","volumes":[{"claim":"loki","durability":"reconstructible","mountAt":"/loki","size":"10Gi"}]}]},{"id":"tempo","processes":[{"cutover":"interrupted","image":"tempo","lifecycle":"application","name":"tempo","placement":{"cpu":"100m","memory":"512Mi"},"probes":{"liveness":{"path":"/ready","port":3200},"readiness":{"path":"/ready","port":3200}},"provides":{"http":3200},"runtime":"none","startupBudget":"30s","volumes":[{"claim":"tempo","durability":"reconstructible","mountAt":"/var/tempo","size":"10Gi"}]}]},{"id":"pyroscope","processes":[{"cutover":"interrupted","image":"pyroscope","lifecycle":"application","name":"pyroscope","placement":{"cpu":"100m","memory":"512Mi"},"probes":{"liveness":{"path":"/ready","port":4040},"readiness":{"path":"/ready","port":4040}},"provides":{"http":4040},"runtime":"none","startupBudget":"30s","volumes":[{"claim":"pyroscope","durability":"reconstructible","mountAt":"/data","size":"10Gi"}]}]},{"id":"gatus","processes":[{"api":{"reason":"the checks sidecar watches every Project's external-checks ConfigMap, cluster-wide","rules":[{"group":"core","objects":["configmaps"],"verbs":["get","list","watch"]}]},"cutover":"interrupted","image":"gatus","lifecycle":"application","name":"gatus","placement":{"cpu":"20m","memory":"64Mi"},"probes":{"liveness":{"path":"/health","port":8080},"readiness":{"path":"/health","port":8080}},"provides":{"http":8080},"runtime":"none","sidecars":[{"cpu":"10m","image":"gatus-checks","memory":"32Mi","name":"checks"}],"startupBudget":"30s"}]},{"id":"alloy","processes":[{"api":{"reason":"Alloy tails every pod's log through the API, cluster-wide","rules":[{"group":"core","objects":["pods","pods/log","namespaces"],"verbs":["get","list","watch"]}]},"cutover":"continuous","image":"alloy","lifecycle":"application","name":"alloy","placement":{"cpu":"50m","memory":"256Mi"},"probes":{"liveness":{"path":"/-/ready","port":12345},"readiness":{"path":"/-/ready","port":12345}},"provides":{"http":12345},"runtime":"none","startupBudget":"30s"}]},{"id":"alertmanager","processes":[{"cutover":"interrupted","image":"alertmanager","lifecycle":"application","name":"alertmanager","placement":{"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/-/healthy","port":9093},"readiness":{"path":"/-/ready","port":9093}},"provides":{"http":9093},"runtime":"none","startupBudget":"30s","writablePaths":["/alertmanager"]}]}],"kind":"Project","owner":"joris","project":"observability","schemaVersion":"1.0.0"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/pinned.xmi b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/pinned.xmi deleted file mode 100644 index 874833777..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/pinned.xmi +++ /dev/null @@ -1,248 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - nvidia - samba - lan-ingress - adguard - - - - - - - - amd-gpu - llm-host - backup-store - lan-ingress - adguard - - - - - - - - nvidia - lan-ingress - - - - - - - - adguard - - - - - adguard - - - - - adguard - - - - - public-ingress - - - - - - diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/platform/platform.intent.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/platform/platform.intent.json deleted file mode 100644 index c6cd267ea..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/platform/platform.intent.json +++ /dev/null @@ -1 +0,0 @@ -{"acme":{"dnsProvider":"cloudflare","email":"hostmaster@jorisjonkers.dev","token":"secret/data/platform/cloudflare"},"apiAccess":{"holders":["delivery/flagger","delivery/release-gate","delivery/collector","delivery/reporter","edge/external-dns","secrets/vault-secrets-operator","observability/prometheus","observability/prometheus-operator","observability/kube-state-metrics","observability/grafana-operator","observability/gatus","observability/alloy","agents/kubernetes-mcp-server","coverage/coverage-api"],"namespaceHolders":["agents/agents-api","utility/headlamp"],"server":[{"cidr":"10.43.0.1/32","port":443}]},"apiVersion":"intent.jorisjonkers.dev/v1","bootstrap":{"crds":["traefik.io/v1alpha1","secrets.hashicorp.com/v1beta1","monitoring.coreos.com/v1","flagger.app/v1beta1","identity.jorisjonkers.dev/v1","metallb.io/v1beta1"],"flux":{"artifacts":{"pullSecret":"flux-system/render-pull","repository":"ghcr.io/jorisjonkers-dev/render","signer":{"issuer":"https://token.actions.githubusercontent.com","subject":"https://github.com/JorisJonkers-dev/estate/.github/workflows/compose.yml@refs/heads/main"}},"metrics":{"path":"/metrics","port":8080},"sourceRef":"flux-system/platform"},"k3s":{"metrics":{"apiServer":{"port":"https","service":"default/kube-apiserver"},"coreDns":{"port":9153},"kubelet":{"port":10250}}},"vault":{"unsealed":true}},"delivery":{"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"gate":"delivery/release-gate","machinery":["edge/traefik-public","edge/traefik-lan","delivery/flagger","delivery/release-gate"],"reporter":"delivery/reporter"},"durability":{"irreplaceable":{"offCluster":{"credential":"secret/data/platform/backup/off-cluster","destination":"s3://backup-storage/jorisjonkers-dev","egress":[{"cidr":"203.0.113.0/24","port":443}],"recipient":"age1s6v5qrx3mgcgk37gscv8y6z43rssksdct5lx3xk5xrtptjndqvhsnhj7h8"},"retain":90,"schedule":"45 2 * * *"},"reconstructible":{},"recoverable":{"retain":14,"schedule":"15 3 * * *"}},"engines":{"files":{"backup":"file-backup"},"mongo":{"backup":"mongo-backup","surface":"mongo"},"postgres":{"backup":"postgres-backup","catalog":"postgres-catalog","surface":"postgres"},"rabbitmq":{"backup":"rabbitmq-backup","surface":"management"},"s3":{"backup":"file-backup","catalog":"garage-catalog","catalogSurface":"admin"},"valkey":{"backup":"valkey-backup","surface":"redis"}},"ephemeral":{"size":"64Mi"},"gpus":{"nvidia":{"resource":"nvidia.com/gpu","runtimeClass":"nvidia-cdi"}},"hardening":"restricted","humanGrants":[{"clusterRole":"admin","group":"oidc:k8s-operators","reason":"the operators administer the namespaces they run"},{"clusterRole":"edit","group":"oidc:k8s-developers","reason":"the developers change what they deploy"},{"clusterRole":"view","group":"oidc:k8s-readers","reason":"anyone signed in reads the cluster's state"},{"clusterRole":"cluster-admin","group":"oidc:k8s-admin","reason":"the platform owner administers the cluster with kubectl and headlamp over OIDC"}],"kind":"Platform","l4Addresses":{"edge-frankfurt":{"kind":"node","node":"frankfurt-contabo-1"},"lan-dns":{"kind":"pool","range":"192.168.0.98/32","site":"enschede"},"lan-edge":{"kind":"pool","range":"192.168.0.99/32","site":"enschede"},"lan-mqtt":{"kind":"pool","range":"192.168.0.97/32","site":"enschede"},"mail-node":{"kind":"node","node":"frankfurt-contabo-1"}},"libraries":{"media":{"gid":3001,"grants":{"jellyfin":"read","notes":"write"},"node":"enschede-t1000-1","path":"/srv/media"}},"mesh":{"enrolled":["coverage","identity"]},"metadata":{"cluster":"production","nodeContract":"sha256:a989e80337efb294fa1a7175b3ad3eea8bed9bf13fbd503a26691c9265575fc2","project":"jorisjonkers.dev"},"migration":{"cpu":"100m","deadline":"10m","memory":"256Mi","runner":"liquibase-runner"},"monitoring":{"alertmanager":"observability/alertmanager","grafana":"observability/grafana","prometheus":"observability/prometheus","receivers":[{"discord":{"webhook":{"key":"webhook-url","path":"secret/data/platform/alertmanager-discord"}},"name":"discord"}],"routes":[{"receiver":"discord","repeat":"4h","severity":"critical"},{"receiver":"discord","repeat":"12h","severity":"warning"}],"stores":{"loki":"observability/loki","pyroscope":"observability/pyroscope","tempo":"observability/tempo"}},"monitors":{"interval":"30s","labels":{"release":"metrics-stack"},"timeout":"10s"},"nodeAgents":{"gpu-device":{"cpu":"10m","image":"nvidia-device-plugin","memory":"64Mi"},"gpu-metrics":{"cpu":"50m","image":"dcgm-exporter","memory":"256Mi"},"l4-speaker":{"controller":{"cpu":"10m","image":"metallb-controller","memory":"64Mi"},"cpu":"20m","image":"metallb-speaker","memory":"64Mi"},"node-metrics":{"cpu":"20m","image":"node-exporter","memory":"64Mi"}},"owner":"joris","policyJob":{"cpu":"10m","deadline":"120s","image":"vault-policy","memory":"64Mi","role":"policy-admin"},"priority":{"critical":{"name":"platform-critical-app","value":100000},"criticalApplications":["auth/auth"],"data":{"name":"platform-data","value":1000000}},"probes":{"failures":3,"period":"10s","timeout":"5s"},"providers":[{"address":"10.0.0.12","name":"stalwart","surfaces":{"http":8080,"smtp":25}}],"schemaVersion":"1.0.0","secretStore":"secrets/vault","seeder":{"cpu":"10m","image":"busybox","memory":"16Mi"},"signIn":{"contract":"1.2","issuer":"https://id.jorisjonkers.dev","provider":"identity/identity"},"substrate":{"clusterDns":"kube-system","cni":"flannel","datastore":"sqlite","imagePull":"2m","kubernetesVersion":"v1.31.4+k3s1","networkPolicyController":"embedded","secretsEncryption":true,"serverCount":1,"upstreamNameservers":["9.9.9.10","149.112.112.10"]},"telemetry":{"collector":"observability/otel-collector","dashboards":{"datasource":"prometheus","instance":{"dashboards":"grafana"}},"metrics":"observability/prometheus"},"tiers":[{"address":"edge-frankfurt","audiences":["anonymous","authenticated"],"certificates":"acme","dns":{"direct":"167.86.79.203","proxied":true,"target":"ingress.jorisjonkers.dev"},"forwardAuth":{"path":"/gate/forward","provider":"identity/identity","responseHeaders":["X-Forwarded-User"],"surface":"http"},"ingressClass":"traefik-public","listener":"tls","name":"public-frankfurt","proxiedBy":"cloudflare","traefik":"edge/traefik-public"},{"address":"lan-edge","audiences":["lan"],"certificateFrom":"secret/data/platform/tls/wildcard","certificates":"none","ingressClass":"traefik-lan","listener":"tls","name":"lan","traefik":"edge/traefik-lan"},{"audiences":["internal"],"certificates":"none","ingressClass":"traefik-lan","listener":"plain","name":"internal","traefik":"edge/traefik-lan"}],"vpn":{"cpu":"50m","credential":"secret/data/platform/vpn","image":"gluetun","memory":"128Mi","settings":{"DNS_KEEP_NAMESERVER":"on","DOT":"off","PORT_FORWARD_ONLY":"on","SERVER_COUNTRIES":"Netherlands","VPN_SERVICE_PROVIDER":"protonvpn","VPN_TYPE":"wireguard"}}} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/secrets/secrets.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/secrets/secrets.project.json deleted file mode 100644 index 8a7fa8b2c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/secrets/secrets.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"id":"vault","processes":[{"cutover":"interrupted","image":"vault","lifecycle":"application","name":"vault","placement":{"cpu":"100m","memory":"256Mi"},"probes":{"liveness":{"path":"/v1/sys/health","port":8200},"readiness":{"path":"/v1/sys/health","port":8200}},"provides":{"http":8200},"runtime":"none","startupBudget":"30s"}]},{"id":"vault-secrets-operator","processes":[{"api":{"reason":"the operator syncs every grant's sync object into its Secret, cluster-wide, and restarts the Processes a rotation names","rules":[{"group":"secrets.hashicorp.com","objects":["vaultstaticsecrets","vaultstaticsecrets/status","vaultdynamicsecrets","vaultdynamicsecrets/status","vaultauths","vaultauths/status","vaultconnections","vaultconnections/status"],"verbs":["get","list","watch","create","update","patch","delete","deletecollection"]},{"group":"core","objects":["secrets"],"verbs":["get","list","watch","create","update","patch","delete"]},{"group":"core","objects":["serviceaccounts/token"],"verbs":["create"]},{"group":"apps","objects":["deployments","statefulsets","daemonsets"],"verbs":["get","list","watch","patch"]},{"group":"core","objects":["events"],"verbs":["create","patch"]}]},"cutover":"interrupted","image":"vault-secrets-operator","lifecycle":"application","name":"vault-secrets-operator","placement":{"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/healthz","port":8081},"readiness":{"path":"/healthz","port":8081}},"provides":{"health":8081,"metrics":8080},"runtime":"none","startupBudget":"30s"}]}],"kind":"Project","owner":"joris","project":"secrets","schemaVersion":"1.0.0"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/utility/utility.project.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/utility/utility.project.json deleted file mode 100644 index a3f675a70..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/expected/utility/utility.project.json +++ /dev/null @@ -1 +0,0 @@ -{"apiVersion":"intent.jorisjonkers.dev/v1","applications":[{"id":"adguard","l4Exposure":[{"address":"lan-dns","port":53,"process":"adguard","protocol":"udp","surface":"dns"},{"address":"lan-dns","port":53,"process":"adguard","protocol":"tcp","surface":"dns"}],"processes":[{"assets":[{"from":"config/adguard/AdGuardHome.yaml","seedAt":"/opt/adguardhome/conf/AdGuardHome.yaml"}],"cutover":"continuous","egress":{"reason":"answers the LAN from a DNS-over-HTTPS upstream","to":"internet"},"image":"adguard","lifecycle":"application","name":"adguard","placement":{"capabilities":["adguard"],"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/login.html","port":3000},"readiness":{"path":"/login.html","port":3000}},"provides":{"dns":5353,"http":3000},"replicas":{"across":"node","count":2,"reason":"the LAN keeps its resolver while one node is down"},"runtime":"none","startupBudget":"30s","writablePaths":[{"memory":"128Mi","path":"/opt/adguardhome/work"},"/opt/adguardhome/conf"]}]},{"exposure":[{"audience":"lan","host":"dashboard.lan.jorisjonkers.dev","name":"lan","routes":[{"match":"prefix","path":"/","process":"headlamp","surface":"http"}]}],"id":"headlamp","processes":[{"api":{"reason":"it acts on the API with each signed-in user's own token, and holds nothing of its own"},"cutover":"continuous","image":"headlamp","lifecycle":"application","name":"headlamp","placement":{"cpu":"50m","memory":"128Mi"},"probes":{"liveness":{"path":"/","port":4466},"readiness":{"path":"/","port":4466}},"provides":{"http":4466},"runtime":"none","startupBudget":"30s"}]}],"kind":"Project","owner":"joris","project":"utility","schemaVersion":"1.0.0"} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/agents/agents.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/agents/agents.project.yml deleted file mode 100644 index d1d815482..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/agents/agents.project.yml +++ /dev/null @@ -1,230 +0,0 @@ -# Worked example: agents, as it runs live (JorisJonkers-dev/fleet-infra -# cluster/flux/apps/agents/ and apps/stateless/agents-*, at 64f25b0e). -# -# hermes the agent gateway and its dashboard, which signs -# people in itself as a public Client of the provider -# kubernetes-mcp-server read-only cluster diagnostics hermes calls, through -# a cluster-wide read of what it reports on -# agents-api, agents-ui parked since 2026-09-01: no pod runs, and their -# grants, Services and policies stay, so unparking is -# deleting a line (spec/v1/10-project-intent.md#parked-processes) -# -# What the live manifests do that this file cannot say yet is a row of -# RENDER-GAPS.md's agents section, each with its own issue. None of it is -# guessed at here. -# -# Exercises: a spawn template, on a parked Process. agents-api starts one runner -# pod per agent session. It declares what those pods are, and the render derives -# the rest: the namespaced rules that let agents-api create and remove them, the -# label each carries, their policy, and the variables that hand agents-api the -# pinned image and those labels (spec/v1/10-project-intent.md#spawn-templates). -# -# Also exercises: an api rule scoped to its Process's namespace (agents-api -# reads its own ConfigMaps, and nothing in another namespace), and a -# cluster-wide read held by a running Process (kubernetes-mcp-server), and a -# grant of optional keys (hermes, spec/v1/10-project-intent.md#optional-keys). - -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -project: agents # the namespace derives: agents-system -owner: joris - -applications: - # The agent gateway. Its dashboard is a public PKCE Client: there is no - # secret to hold, and the route takes no forward-auth, which would intercept - # the dashboard's own callback. The host is on both edges, so the LAN reaches - # it without leaving the house. - - id: hermes - exposure: - - name: public - host: hermes.jorisjonkers.dev - audience: authenticated - # Not proxied: Cloudflare closes an idle WebSocket after about 100 - # seconds, and the dashboard's chat tab runs over one, so the host - # resolves straight to the edge, grey-cloud, as it does live. - proxied: false - routes: - - { path: /, match: prefix, process: hermes, surface: dashboard } - - name: lan - host: hermes.jorisjonkers.dev - audience: lan - routes: - - { path: /, match: prefix, process: hermes, surface: dashboard } - client: - signIn: native - exposure: public - label: Hermes - description: The agent gateway - redirectPaths: [/auth/callback] - protectedPath: /api/status - credential: pkce - processes: - - name: hermes - lifecycle: application - image: hermes - args: [gateway, run] # the gateway its dashboard belongs to - runtime: none # no telemetry to wire: hermes exports none - engine: files # its data is plain files, backed up as files - provides: - dashboard: 9119 - # Its claim is bound to the node the agents share live, so the - # ClusterState snapshot holds it there; no node is named here. Live it - # works at about 1.1Gi and peaked at 1.4Gi over two weeks (2026-10-29). - placement: - memory: 2Gi - cpu: 250m - site: enschede - # The memory, sessions and installed skills: hermes writes them and - # nothing rebuilds them. - volumes: - - { claim: hermes-data, mountAt: /opt/data, size: 10Gi, durability: recoverable } - # Its config, copied onto the volume before every start, because hermes - # migrates it and edits it from its dashboard; the copy it replaces is - # kept beside it. The file holds no secret: hermes expands its - # `${GITHUB_PAT}` from the env file (spec/v1/10-project-intent.md#seeded-assets). - assets: - - { from: config/hermes/config.yaml, seedAt: /opt/data/config.yaml } - # Model providers, the GitHub MCP server, context7, and the skills it - # installs: every call leaves the cluster on 443. - egress: - to: internet - reason: >- - Hermes calls its model providers and remote MCP servers, and installs the skills it is given. - dependsOn: - - { application: kubernetes-mcp-server, surface: mcp } - # Every key is optional, as live: a missing one disables only the tool - # it feeds, and the Process starts without it. - secrets: - - path: secret/data/agents/hermes - keys: - - { name: memory-api-key, optional: true } - - { name: overleaf-session, optional: true } - - { name: github-pat, optional: true } - - { name: hindsight-api-token, optional: true } - - { name: openrouter-api-key, optional: true } - - { name: anthropic-api-key, optional: true } - - { name: openai-api-key, optional: true } - access: read - delivery: env - rotation: { tolerates: restart } - # Its supervisor keeps its state under /run and hermes its own under - # /tmp; the browser its tools drive needs shared memory far beyond the - # runtime's 64MB, held in memory and counted toward the Process. - # Started as its own uid with every capability dropped, which hermes - # was shown to run as (JorisJonkers-dev/deploy-kit#692). - writablePaths: [/run, /tmp, { path: /dev/shm, memory: 1Gi }] - probes: - readiness: { path: /api/status, port: 9119 } - liveness: { path: /api/status, port: 9119 } - startupBudget: 120s - cutover: interrupted - - # Read-only cluster diagnostics for hermes. It reads what it reports on - # across the cluster and writes nothing. - - id: kubernetes-mcp-server - processes: - - name: kubernetes-mcp-server - lifecycle: application - image: kubernetes-mcp-server - # HTTP on its surface rather than stdio, and its write tools withheld. - args: [--port=8080, --read-only] - runtime: none - provides: - mcp: 8080 - placement: - memory: 256Mi # it peaked at 216Mi over two weeks (2026-10-29) - cpu: 50m - probes: - readiness: { path: /healthz, port: 8080 } - liveness: { path: /healthz, port: 8080 } - startupBudget: 20s - cutover: continuous - api: - reason: >- - the MCP server answers an agent's questions about workloads, logs, routes and Flux, cluster-wide, and changes nothing - rules: - - group: core - objects: [pods, pods/log, events, services, endpoints, nodes, namespaces] - verbs: [get, list, watch] - - group: apps - objects: [deployments, statefulsets, daemonsets, replicasets] - verbs: [get, list, watch] - - group: batch - objects: [jobs, cronjobs] - verbs: [get, list, watch] - - group: networking.k8s.io - objects: [ingresses, networkpolicies] - verbs: [get, list, watch] - - group: traefik.io - objects: [ingressroutes, middlewares] - verbs: [get, list, watch] - - group: kustomize.toolkit.fluxcd.io - objects: [kustomizations] - verbs: [get, list, watch] - - group: helm.toolkit.fluxcd.io - objects: [helmreleases] - verbs: [get, list, watch] - - group: source.toolkit.fluxcd.io - objects: [gitrepositories, helmrepositories, ocirepositories] - verbs: [get, list, watch] - - # The agent sessions' API, parked with the UI. Its routes are left out: live - # it shares the UI's host by path, and a host is one Application's. - - id: agents-api - processes: - - name: agents-api - lifecycle: application - parked: { reason: Agent sessions run through hermes since 2026-09-01. } - image: agents-api - runtime: jvm - provides: - http: 8082 - placement: - memory: 512Mi - cpu: 100m - api: - reason: it reads the session settings it keeps beside itself - rules: - - { group: core, objects: [configmaps], verbs: [get, list, watch], scope: namespace } - spawns: - - name: runner - image: agent-runner - placement: { memory: 1Gi, cpu: 500m } - provides: - http: 8090 # agents-api drives the session over it - dependsOn: - - { application: agents-api, surface: http } # the runner reports back - egress: { to: internet, reason: an agent clones and pushes the repositories it works on } - probes: - readiness: { path: /actuator/health/readiness, port: 8082 } - liveness: { path: /actuator/health/liveness, port: 8082 } - startupBudget: 60s - cutover: continuous - - # The sessions' UI, parked with its API: nginx serving a built bundle. Live, - # the edge asks nothing of its route. - - id: agents-ui - exposure: - - name: public - host: agents.jorisjonkers.dev - audience: anonymous - routes: - - { path: /, match: prefix, process: agents-ui, surface: http } - processes: - - name: agents-ui - lifecycle: application - parked: { reason: Agent sessions run through hermes since 2026-09-01. } - image: agents-ui - runtime: static - provides: - http: 80 - placement: - memory: 96Mi - cpu: 100m - writablePaths: [/var/cache/nginx, /var/run] - probes: - readiness: { path: /, port: 80 } - liveness: { path: /, port: 80 } - cutover: continuous diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/agents/config/hermes/config.yaml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/agents/config/hermes/config.yaml deleted file mode 100644 index 4ad2dd058..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/agents/config/hermes/config.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# A stand-in for hermes's configuration, written for this example: the live -# file is fleet-infra's, and this repository does not copy it. hermes expands -# each ${VAR} below from its own environment as it reads the file, so the file -# holds no secret: the values reach hermes through its env file -# (spec/v1/10-project-intent.md#seeded-assets). -model: - provider: openrouter - default: anthropic/claude-sonnet-4.5 -mcp_servers: - github: - url: https://api.githubcopilot.com/mcp/ - headers: - Authorization: Bearer ${GITHUB_PAT} - context7: - url: https://mcp.context7.com/mcp diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/agents/env/hermes/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/agents/env/hermes/base.env deleted file mode 100644 index 6fef7a065..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/agents/env/hermes/base.env +++ /dev/null @@ -1,27 +0,0 @@ -# hermes runs its gateway, and serves its dashboard on the dashboard surface. The -# dashboard signs people in itself, as a public Client of the Identity Provider: -# the Issuer is the Platform document's and the Client id the Application Id -# (spec/v1/17-sign-in.md#credentials-and-placeholders). -HERMES_DASHBOARD=1 -HERMES_DASHBOARD_HOST=0.0.0.0 -HERMES_DASHBOARD_PORT=9119 -HERMES_DASHBOARD_PUBLIC_URL=${exposure:hermes.public#url} -HERMES_DASHBOARD_OIDC_ISSUER=${client:issuer} -HERMES_DASHBOARD_OIDC_CLIENT_ID=${client:id} -HERMES_DASHBOARD_OIDC_SCOPES=openid profile email -API_SERVER_ENABLED=false -HERMES_SKIP_CONFIG_MIGRATION=false -# An emptyDir at /run is root-owned and world-writable, which s6-overlay, its -# supervisor, refuses from a non-root start unless told to accept it. -S6_YES_I_WANT_A_WORLD_WRITABLE_RUN_BECAUSE_KUBERNETES=1 - -# The model providers it calls, and the tokens of the MCP servers it reaches, -# which hermes expands into its seeded config itself -# (spec/v1/10-project-intent.md#seeded-assets). -ANTHROPIC_API_KEY=${secret:secret/data/agents/hermes#anthropic-api-key} -OPENAI_API_KEY=${secret:secret/data/agents/hermes#openai-api-key} -OPENROUTER_API_KEY=${secret:secret/data/agents/hermes#openrouter-api-key} -GITHUB_PAT=${secret:secret/data/agents/hermes#github-pat} -HINDSIGHT_API_TOKEN=${secret:secret/data/agents/hermes#hindsight-api-token} -MEMORY_API_KEY=${secret:secret/data/agents/hermes#memory-api-key} -OVERLEAF_SESSION=${secret:secret/data/agents/hermes#overleaf-session} diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/auth/auth.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/auth/auth.project.yml deleted file mode 100644 index 801295809..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/auth/auth.project.yml +++ /dev/null @@ -1,439 +0,0 @@ -# Worked example: the auth project's Intent Fragment -# -# applications/auth/platform/auth.project.yml -# -# Intent is authored ONE FILE PER PROJECT, holding every Application that project -# owns, and one file is one Intent Fragment -# (docs/adr/model/0009-intent-is-authored-one-file-per-project.md). The namespace derives from the -# header -- auth-system -- and no field exists that could divert it. -# -# Exercises: two Processes that switch together because they are one Application, -# ONE authored hostname fronting both of them through two routes -- the case -# that forced `exposure` from the Process to the Application -- placement as hard -# dimensions carrying an arch set and a capability, three `delivery: self` -# grants including a Transit key that takes no placeholder, four dependencies, -# writable paths that retired a hardening exception, and config that is almost entirely -# derived. -# -# Companion env files, one per PROCESS -# (docs/adr/model/0013-configuration-is-dotenv-at-three-scopes.md): -# platform/env/auth-api/base.env -- reproduced as env/auth-api/base.env -# platform/env/auth-ui/base.env - -# The DATA MODEL's own semver, not the toolkit package's version -# (docs/adr/model/0032-the-resolved-deployment-is-a-versioned-artifact.md). It starts at 1.0.0 and is -# bumped only when the model changes, so a literal here is legitimate and does -# not go stale on a toolkit release. Composition admits same-major, minor <= -# toolkit; the composition lock records the exact versions that ran. -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -# The header is three fields, and `owner` is the ONLY one raised to the project. -# `observability` stays per Application -- raising it makes a project page as loudly as -# its loudest member -- and so does `secrets`, because a project-level grant -# hands every Application in the file a reader slot on the whole path -# (docs/adr/model/0008-vault-read-is-per-path.md, -# docs/adr/model/0009-intent-is-authored-one-file-per-project.md). -project: auth -owner: joris - -applications: - # ==================================================================== auth - # This Application was two Applications -- `auth-api` and `auth-ui` -- coupled by a - # `releaseUnit: auth` name that each declared in its own repository. That - # field is deleted. An Application is itself the unit of atomic release - # (docs/adr/model/0052-an-application-is-the-release-unit.md): its Processes switch - # together or none switches. No Process's new version receives traffic until - # every Process's new version is healthy by its own declared readiness, and - # if any misses its `startupBudget`, none of them switch and the old versions - # keep serving. Going back is Application-scoped for the same reason. - # - # The requirement is unchanged; only the mechanism is. A new UI against an old - # API is a broken product even though both pods report healthy, and that is - # now carried by the boundary drawn here rather than by a name two files had - # to agree on. The two Processes below are adjacent, so a reader sees the - # coupling without searching the composed union. - # - # The merge costs no reference: auth's estate-wide role is the forward-auth - # middleware derived from every route's exposure audience - # (docs/adr/model/0023-exposure-is-declared-by-audience.md), never a `dependsOn` edge, and - # nothing in the estate names `auth-ui` at all. - # - # Still not a Reconcile Unit. That one is DERIVED from the dependency graph - # and answers ordering (postgres before auth); this one is DECLARED, by - # drawing a boundary, and answers atomicity - # (docs/adr/model/0033-reconcile-unit-derived.md). - - id: auth - - # REQUIRED, because auth-api's edge to platform-postgres derives a database - # (spec/v1/10-project-intent.md#migration). One estate-wide system moves - # every managed schema: a Liquibase YAML changelog, applied by the - # platform's runner before the new version starts, while the old one still - # serves. The path is the repository's own layout, from its root; the - # runner image, its identity, the owner role and the deadline are derived. - migration: - changelog: auth-api/src/main/resources/db/changelog/db.changelog-master.yaml - - # Whole or absent. The class states urgency and the scrape names the surface - # that carries the signal, both on the Application, because both are facts about - # the Application rather than about one of its two containers. auth-api - # publishes for the pair; auth-ui exports nothing and needs to say nothing - # (docs/adr/model/0025-observability-is-one-optional-block.md). - observability: - scrape: - process: auth-api - surface: http # the name declared in auth-api's `provides` - path: /api/actuator/prometheus - - # No Application-level `secrets`. The three grants below are auth-api's alone, - # so they sit on that Process: an Application-level grant is held by EVERY - # Process, including ones added later - # (docs/adr/model/0012-shared-intent-descends-and-is-lowered.md), and leaving them here would - # hand the nginx container a Vault identity holding `read` on the database - # credentials. Folding the pair into one Application is what moved them down a - # level, and the level is an access boundary only because identity is per - # Process (docs/adr/model/0031-identity-per-process.md). - - # ONE HOSTNAME, TWO PROCESSES -- the case that forced `exposure` up from the - # Process to the Application. `auth.jorisjonkers.dev/api` is auth-api and `/` - # is auth-ui, and at the Process level that is unsayable: two Processes - # each declaring a port and an audience produce two routes claiming the - # whole host, which is exactly what this example's rendered tree used to - # show. `provides` stays on the Process, because the two are different - # facts: `provides` is *this process listens on this port*, `exposure` is - # *this hostname routes here* (review/EXPOSURE-MANIFEST.md, - # docs/adr/model/0023-exposure-is-declared-by-audience.md). - # - # `host` is the full FQDN, AUTHORED. No zone mapping, no `.` - # rule, no apex flag -- an apex host is written `host: jorisjonkers.dev`. - # That it matches the Application id here is a coincidence and does not - # generalise: `platform-rabbitmq` serves rabbitmq, `headlamp` serves - # dashboard, and `status` belongs to no Application at all. The host is unique - # across the estate -- E_DUPLICATE_HOST at composition, evaluated over the - # composed union. - exposure: - - name: public # required, unique within the Application: what - # ${exposure:auth.public#url} addresses and - # what E_DUPLICATE_EXPOSURE_NAME checks - host: auth.jorisjonkers.dev - audience: anonymous # both surfaces. This Application is what performs - # authentication, so it cannot sit behind it; - # the applications enforce their own - # authorization and this describes the edge - contentPolicy: strict # one of the THREE authored proxy fields, the - # others being `redirectTo` and `rateLimit` on - # a route. It picks the CSP profile only: the - # security-headers baseline, forward-auth, - # the listener, certificates and the chain derive - # from audience and tier, and no middleware - # name, header block or timeout is authorable - # anywhere in layer 1 - routes: - # A route names {path, match, process, surface}, `match` being - # `prefix` or `exact`. The surface must be one the named Process - # declares in `provides` (E_UNKNOWN_SURFACE otherwise), and two routes - # on one exposure may not share a path + match pair - # (E_DUPLICATE_ROUTE_MATCH). - # - # Registering takes a request from anyone and stores a user for each, - # so one client may register ten times an hour. The burst and who - # counts as one client derive: the tier is proxied by Cloudflare, so a - # client is the address Cloudflare forwards. - - {path: /api/v1/users/register, match: exact, process: auth-api, surface: http, rateLimit: {requests: 10, per: 1h}} - - {path: /api, match: prefix, process: auth-api, surface: http} - - {path: /, match: prefix, process: auth-ui, surface: http} - - processes: - # ------------------------------------------------------------ auth-api - - name: auth-api - # The ServiceAccount and the Vault role are the PROCESS NAME, unique - # within the project: `auth-system.auth-api`, never - # `auth-system.auth-auth-api` (docs/adr/model/0031-identity-per-process.md). - lifecycle: application - - # An ALIAS resolved to a digest through the images lock -- never a tag - # and never a digest here. That is what keeps every rendered Deliverable - # E_FLOATING_IMAGE clean without layer 1 carrying a hash. - image: auth-api - runtime: jvm - - # A port is a property of a process, so `provides` sits on the Process - # (chapter 10). `dependsOn` still targets `{application, surface}`: surface - # names are unique within an Application, and a consumer names the Application, - # never a Process. - provides: - http: 8080 # the port the JVM listens on. A route names a - # surface, not a number, so the edge never - # sees it - - # Placement is a set of HARD dimensions, every one of which must match - # (docs/adr/model/0017-placement-is-hard-dimensions.md). A list is a SET of - # equally acceptable values -- no ordering, no weight. There is no - # `requires`/`prefers` split: the estate paid for the soft half once, - # when a preference naming a capability no node advertised was discarded - # by the scheduler without an event, a warning or a condition, and read - # as GPU-aware placement while doing nothing. A dimension set no node - # satisfies is E_PLACEMENT_UNSATISFIABLE, a build error, raised before - # any manifest exists. - placement: - # `memory` and `cpu` are required on every Process, as raw - # quantities, and are matched against node ALLOCATABLE from the pinned - # node contract -- total minus the reserve declared in the node file, - # never a live read (docs/adr/model/0048-node-facts-are-authored-once.md, - # docs/adr/model/0006-pinned-inputs.md). This is ELIGIBILITY, not - # bin-packing: three Processes asking 2Gi each all pass against a - # 4096Mi node, and the scheduler refuses the third at apply. - # - # Contention has not moved. Memory and cpu are contended values, and - # contention decides who ARBITRATES, not who AUTHORS - # (docs/adr/model/0004-contention-decides-authority.md): this Application states - # its requirement, and the platform decides whether it fits and where. - memory: 768Mi # request == limit, derived: memory is - # incompressible, and a pod that cannot exceed - # its own request is not the one that puts a - # node under eviction pressure - cpu: 250m # request only, no limit, derived: a cpu limit - # throttles exactly the class-loading burst - # `startupBudget` exists to bound, and shows up - # as slow application code - arch: [amd64] # a set of one: this image is built amd64-only. - # Stated even though the only node carrying - # public-ingress today is amd64 -- the two are - # independent facts, and a second public-ingress - # node on arm64 must not silently become - # eligible for an image that cannot run there. - capabilities: [public-ingress] - # frankfurt-contabo-1 is the only node advertising public-ingress, so - # this replaces `nodeSelector: {site: frankfurt}` without naming a - # site or a label. Labels are not the Application's to name: the node - # contract emits 110 of them for 7 nodes, 55 under a prefix named - # after an archived repository that rejects pushes, and retiring that - # prefix must not be an edit in every project repository - # (docs/adr/model/0048-node-facts-are-authored-once.md). - # - # `tailscale` is not written here and is no longer vocabulary: 7 of 7 - # nodes advertise it, so it excludes nothing, and a filter that never - # excludes teaches authors that filters do nothing. - - # No `hardening` block. The class defaults to `restricted` -- - # runAsNonRoot, readOnlyRootFilesystem, all capabilities dropped, - # seccomp RuntimeDefault -- and this image meets it. The JVM writes to - # /tmp, which is declared below rather than assumed: a writable path is - # mounted as an emptyDir and the read-only root control stays intact, so - # it is not an exception and takes no inventory entry - # (docs/adr/model/0020-hardening-is-one-platform-posture.md). - - # The paths this process must write. Nothing is implicit: a mount nobody - # declared would appear in every image, including those that never - # write. The ephemeral size is platform-assigned from one Platform document default. - writablePaths: [/tmp] - - dependsOn: - - {application: platform-postgres, surface: postgres} - - {application: platform-valkey, surface: redis} - - {application: platform-rabbitmq, surface: amqp} - - {application: stalwart, surface: smtp} - - # No `exposure` here, and none is missing: it sits on the Application - # above, where one hostname can front both Processes. What stays is - # `provides` (http: 8081) -- the port this process listens on, and - # `http` is the surface the `/api` route names. - - # Siblings, each carrying its own endpoint, neither falling back to the - # other (docs/adr/model/0016-probes-are-siblings-and-startup-targets-liveness.md). Deliberately identical - # endpoints would still be written twice. - probes: - readiness: - path: /api/actuator/health/readiness - port: 8081 - liveness: - path: /api/actuator/health/liveness - port: 8081 - - startupBudget: 600s - - # REQUIRED, and there is no default. `continuous` asks the platform to - # keep serving throughout the cutover, so the new version starts beside - # the old one and takes traffic only once every member of the - # Application has passed analysis (blue/green); `interrupted` accepts a - # stop-then-start. This Process holds no volume, so a continuous cutover - # is honourable and is what its owner asks for. The Kubernetes and - # Flagger spellings -- RollingUpdate, maxSurge, a Canary -- are derived - # by the adapters and appear nowhere here. - cutover: continuous - - # No `minAvailable`: the field is deleted - # (docs/adr/model/0022-a-derived-value-has-one-declaring-site.md). Availability - # by replica count does not exist on this substrate -- local-path, RWO, - # one node per stateful volume -- so `replicas` derives as 1. - # - # `replicas` is the ONLY local exception to a derived value in layer 1, - # and it is narrow: `count` must be above one, and `reason` is required - # whenever the block is present. auth-api's live pair was a capacity - # decision on freed Frankfurt budget, not an availability requirement. - replicas: - count: 2 - reason: >- - Capacity, not availability: the pair was provisioned on freed - Frankfurt budget and both pods land on the one public-ingress - node. Retires when that budget is reclaimed or the capability - spreads to a second node. - - # All three grants use `delivery: self` -- the application fetches them - # through spring-cloud-vault at runtime, which is what it already does - # in production via SPRING_CONFIG_IMPORT: vault:// and VAULT_DB_ENABLED: - # true. Consequently this Process's env file contains no ${secret:...} - # placeholder at all, and the dead-grant check correctly does not fire. - # - # The grant unit is the PATH, never the key - # (docs/adr/model/0028-grant-unit-is-the-path.md): a KV-v2 read returns the - # whole document, so `keys:` documents the expected keys, feeds - # validation, and confers nothing. No wildcard is expressible. - secrets: - # Dynamic database credentials, minted per lease by the database - # engine and re-read at runtime. The only combination achieving - # zero-downtime rotation: a pod's environment is fixed for its - # lifetime, so `tolerates: reload` with `delivery: env` would be a - # build error. - # - # SPLIT PATH. `secret/data/platform/postgres` used to be one document - # holding every consumer's credentials, which made this Process's - # password readable by knowledge's pods. One path per reader set is - # the layout rule; this path's reader set is auth-api alone, and - # knowledge reads .../postgres/kb. - - path: secret/data/platform/postgres/auth - keys: [user, password] - access: read - delivery: self - rotation: - tolerates: reload - maxAge: 168h - - # auth-api's own document: the static credentials for the three - # dependencies whose credentials are not minted by an engine. They sit - # here rather than under the platform Subtrees because the reader set - # is this Process alone -- 0028 asks for one path per reader set, not - # one path per consumer. Only the Postgres pair above is dynamic, - # which is why it must live under the data project's mount. - # - # Every key is enumerated. A wildcard key list -- `keys` naming a - # single star, which this grant used to carry -- left the vocabulary: - # it appears in no field table and no invariant, and it made the - # reader set undecidable without reading live Vault contents, which - # the pinned-input rule forbids (docs/adr/model/0006-pinned-inputs.md). - # Adding a key is now an edit to this file. - - path: secret/data/auth-api - keys: - - mail.password - - valkey.password - - rabbitmq.user - - rabbitmq.password - access: read - delivery: self - rotation: {tolerates: reload} - - # JWT signing through Vault Transit. This Process rotates the key - # itself, so `self-roll` rather than `read` -- which derives the - # `patch` capability on the named key rather than `update`, granting - # no read access to anything else in the mount. No rollAffectsReaders - # acknowledgement is needed: composition shows no other Application reads - # it, and verifiers follow JWKS rather than caching the key. - # - # A non-KV mount takes NO placeholder and `delivery: self` is its only - # legal delivery (docs/adr/model/0030-secret-delivery-is-env-file-or-self.md): a - # transit key is never materialised into an env var or a file, so - # there is nothing for a ${secret:...} reference to carry. `keys:` - # names the mount object. - - engine: transit - key: auth-api-jwt - operations: [sign, rotate, read] - delivery: self - rotation: {tolerates: reload} - - # ------------------------------------------------------------- auth-ui - # The second half of the product. It is here, in this Application, because it - # must cut over with auth-api and for no other reason - # (docs/adr/model/0052-an-application-is-the-release-unit.md). Its identity is its own: - # `auth-system.auth-ui`, holding none of the grants above. - - name: auth-ui - lifecycle: application - image: auth-ui # an alias, resolved through the images lock - runtime: static # nginx serving a built bundle: no OTEL_* or - # PYROSCOPE_* wiring to inject, and saying - # `static` is a decision rather than an omission - provides: - http: 80 # nginx's own port. A pod off the host network - # binds any port without a capability (chapter 14, - # substrate facts), so a non-root nginx with every - # capability dropped listens on 80 as built - - placement: - # The two required dimensions, and nothing else. Every further - # dimension would exclude nodes for nothing: the image is multi-arch, - # it needs no node capability and it holds no volume, so all 7 nodes - # are eligible. auth-api's public-ingress filter is deliberately NOT - # repeated -- the two Processes may land on different nodes and still - # switch together, because atomic release is not co-location. - memory: 64Mi # the estate measures its nginx pods at - # "~10-20Mi RAM each"; this is the headroom - # above that, and request == limit - cpu: 10m - - # No `hardening` block, because there is no hardening to author. nginx - # writes its temporary bodies and cache under /var/cache/nginx and its - # pid file under /var/run; both are declared writable paths, mounted as - # emptyDirs, and readOnlyRootFilesystem stays true - # (docs/adr/model/0020-hardening-is-one-platform-posture.md). The exception - # this Process used to carry retired with that decision, without the - # rebuilt image its own reason was waiting for. - writablePaths: [/var/cache/nginx, /var/run] - - # No `dependsOn`. The bundle is static and the API call is made by the - # browser, not by this container, so there is no egress edge to declare - # and the derived default-deny policy gives it none - # (docs/adr/model/0035-network-policy-is-default-deny-and-render-only.md). A dependency edge - # would claim a connection this pod never opens. - - # No `exposure` here either. The Application's `public` exposure routes - # `/` to this Process's `http` surface -- the login page is what - # unauthenticated users are sent to, so it cannot sit behind the - # authentication it starts. - - # Siblings, written twice on purpose. For a static server the two - # questions genuinely have the same answer -- there is no dependency to - # be unready for -- and 0016 still refuses to infer one from the other - # (docs/adr/model/0016-probes-are-siblings-and-startup-targets-liveness.md). - probes: - readiness: - path: / - port: 80 - liveness: - path: / - port: 80 - - startupBudget: 30s # nginx serves within a second of starting; the - # budget is the gate auth-api's 600s dominates - - # REQUIRED on every Process. Same value as auth-api, and stated again: - # this Process holds no volume either, so a continuous cutover is - # honourable here too. The two Processes switch together because they - # are one Application, and one Application answers the question alike - # (E_RELEASE_UNIT_MIXED_CUTOVER otherwise). - cutover: continuous - - # No `replicas` block: one is the derived count, and one is what this - # Process wants. The block exists for a count above one with a reason, - # not to restate the default. - - # Nothing observability-shaped here, and nothing to omit either: the - # whole block sits on the Application above and names auth-api's surface. - # This image exports no metrics, and a scrape path the platform guessed - # would collect nothing and report success - # (docs/adr/model/0025-observability-is-one-optional-block.md). - - # No `secrets`. Everything this Process needs is baked into the bundle - # at build time or reached through the browser, so no Vault role is - # derived for it: `auth-system.auth-ui` is a ServiceAccount with no - # policy bound to it, which is exactly what moving the three grants down - # a level bought. diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/auth/env/auth-api/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/auth/env/auth-api/base.env deleted file mode 100644 index 582ff5693..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/auth/env/auth-api/base.env +++ /dev/null @@ -1,83 +0,0 @@ -# applications/auth/platform/env/auth-api/base.env -# -# Env files are per PROCESS, never per Application -# (docs/adr/model/0013-configuration-is-dotenv-at-three-scopes.md). Application `auth` holds -# two Processes and therefore two files: this one, and auth-ui's beside it at -# platform/env/auth-ui/base.env. The grants they may reference differ, because -# the identity reading them differs. -# -# The Application is declared in the auth project's Intent Fragment, -# platform/auth.project.yml -- one file per project -# (docs/adr/model/0009-intent-is-authored-one-file-per-project.md), reproduced as -# examples/auth/auth.project.yml. -# -# Note what is NOT here. auth-api holds three grants and none of them appear in -# this file, because all three are delivery: self -- the application fetches -# them through spring-cloud-vault at runtime. Only a delivery: env grant -# requires a matching ${secret:...} placeholder, so the dead-grant check does -# not fire on any of the three. - -SPRING_PROFILES_ACTIVE=prod -SESSION_COOKIE_SECURE=true - -DB_HOST=${dependency:platform-postgres.host} -DB_PORT=${dependency:platform-postgres.port} -VALKEY_HOST=${dependency:platform-valkey.host} -VALKEY_PORT=${dependency:platform-valkey.port} -SPRING_RABBITMQ_HOST=${dependency:platform-rabbitmq.host} -SPRING_RABBITMQ_PORT=${dependency:platform-rabbitmq.port} -MAIL_HOST=${dependency:stalwart.host} -MAIL_PORT=${dependency:stalwart.port} - -# --- the Application's own hostname, addressed by exposure NAME -# ${exposure:.#} is the third placeholder source, -# beside ${dependency:...} and ${secret:...}, and `field` is one of `url`, -# `host`, `scheme`. `auth.public` is the exposure declared on Application auth -# in the project file; a name no exposure carries is a build error, and so is -# writing https://auth.jorisjonkers.dev here as a literal. -# -# The PATH IS WRITTEN OUTSIDE the placeholder. That keeps substitution a -# named source resolving to exactly one value rather than a template taking -# arguments, so the composer's check stays a string comparison -- the same -# property that makes ${secret:...} byte-matchable against a granted path. -# -# Three hand-written URLs collapse to one declaration: the host moves once, -# in the project file, and these three follow it. -AUTH_ISSUER=${exposure:auth.public#url} -AUTH_LOGIN_URL=${exposure:auth.public#url}/login -CONFIRMATION_URL=${exposure:auth.public#url}/confirm - -# Hand-written today, derived under this model, and a build error to author: -# -# AUTH_CORS_ALLOWED_ORIGINS -# -> from INBOUND edges. Nine hostnames are maintained by hand today: -# jorisjonkers.dev, auth, agents, vault, n8n, grafana, dashboard, -# rabbitmq, status. See chapter 16 -- the exact predicate is open. -# -# MAIL_USERNAME (auth@jorisjonkers.dev) -# -> from the cluster public domain plus this Application's id, which is now -# `auth` (docs/adr/model/0052-an-application-is-the-release-unit.md) -# -# VAULT_ADDR, DEPLOYMENT_ENVIRONMENT -> pinned Platform document facts. -# -# Authored here, and NOT derived: spring-cloud-vault's own wiring. The model -# does not know what a framework is, so SPRING_CONFIG_IMPORT, -# VAULT_AUTHENTICATION and VAULT_ENABLED are written below like any other -# literal (docs/adr/model/0013-configuration-is-dotenv-at-three-scopes.md). -# The one value that must not drift is a placeholder: VAULT_KUBERNETES_ROLE is -# the PROCESS's derived Vault role -- `auth-system-auth-api`, the namespace -# and the Process (docs/adr/model/0031-identity-per-process.md) -- so it is written as -# ${identity:vaultRole} and cannot disagree with the role the platform derived. -# -# AUTH_TRANSIT_ENABLED, AUTH_TRANSIT_KEY_NAME -# -> from the transit grant in auth.yml -# -# OTEL_* (10), PYROSCOPE_* (6) -> from runtime: jvm -# SERVER_PORT, DEPLOYMENT_ENVIRONMENT -> from `provides`, the render's cluster - -# spring-cloud-vault, authored because the framework owns its own configuration -# surface. Only the role name is a placeholder. -SPRING_CONFIG_IMPORT=vault:// -VAULT_ENABLED=true -VAULT_AUTHENTICATION=KUBERNETES -VAULT_KUBERNETES_ROLE=${identity:vaultRole} diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/auth/migration-proof.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/auth/migration-proof.yml deleted file mode 100644 index 508fe4b19..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/auth/migration-proof.yml +++ /dev/null @@ -1,18 +0,0 @@ -# The migration proof for the auth project, written beside its project file by -# auth-api's own CI (spec/v1/55-delivery.md#migration-safety) and read with it: -# the fragment's digest covers it, so a new proof is a new fragment. -# -# One entry per Application that moves its schema with a changelog. `auth` -# serves today, so its suite ran against the serving revision, which is what -# `testedAgainst` names: the Application revision the projection published back. -# No changeset in this release runs outside a transaction, so the release may -# be undone automatically (spec/v1/55-delivery.md#failure-and-undo). - -apiVersion: proof.jorisjonkers.dev/v1 -kind: MigrationProof -schemaVersion: 1.0.0 - -applications: - - id: auth - testedAgainst: "sha256:2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a" - nonTransactional: false diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/config/coverage.conf b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/config/coverage.conf deleted file mode 100644 index f647c252a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/config/coverage.conf +++ /dev/null @@ -1 +0,0 @@ -threads = 4 diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/config/seed.conf b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/config/seed.conf deleted file mode 100644 index 166202f20..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/config/seed.conf +++ /dev/null @@ -1 +0,0 @@ -seed = true diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/coverage.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/coverage.project.yml deleted file mode 100644 index 07e5b7c93..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/coverage.project.yml +++ /dev/null @@ -1,123 +0,0 @@ -# A project that writes, between them, every key the estate's own projects leave -# out, so each stage of the harness reads all of the source model. -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 -project: coverage -owner: joris -placement: { site: enschede } -startupBudget: 90s -writablePaths: [/tmp] -dependsOn: - - { application: platform-rabbitmq, surface: amqp, required: true } -assets: - - { from: config/coverage.conf, mountAt: /etc/coverage/project.conf } -applications: - - id: coverage-api - description: Reads every key the other projects leave out - startupBudget: 60s - writablePaths: [{ path: /var/cache/coverage, memory: 64Mi }] - assets: - - { from: config/seed.conf, seedAt: /var/cache/coverage/seed.conf } - dependsOn: - - { application: platform-valkey, surface: redis, required: false } - secrets: - - path: secret/data/coverage-system/session - keys: - - name: session - generate: { bytes: 32, encoding: base64 } - access: read - delivery: file - mountAt: /run/secrets/session - fileMode: "0400" - rotation: { tolerates: restart } - - path: secret/data/coverage-system/cookie - keys: - - name: cookie - generate: { bytes: 16, encoding: base64url } - access: read - delivery: file - mountAt: /run/secrets/cookie - fileMode: "0400" - rotation: { tolerates: restart } - - path: secret/data/coverage-system/salt - keys: - - name: salt - generate: { encoding: hex } - access: read - delivery: file - mountAt: /run/secrets/salt - fileMode: "0400" - rotation: { tolerates: restart } - client: - signIn: native - label: Coverage - redirectPaths: [/callback] - protectedPath: /api - backChannelLogoutPath: /logout - credential: pkce - roles: [reader] - processes: - - name: coverage-api - lifecycle: application - image: coverage-api - runtime: none - command: [/bin/coverage] - args: [serve, --verbose] - cutover: interrupted - provides: { http: 8080 } - placement: - memory: 64Mi - cpu: 10m - arch: [arm64] - disk: { media: [hdd] } - gpu: { memory: 8Gi, vendor: [nvidia] } - api: - reason: it reads the nodes it places work on - rules: - - { group: core, objects: [nodes], verbs: [get], scope: cluster } - sidecars: - - name: helper - image: coverage-helper - command: [/bin/helper] - args: [run] - memory: 16Mi - cpu: 5m - secrets: - - path: secret/data/coverage/rolled - keys: [password] - access: self-roll - delivery: file - mountAt: /run/secrets/rolled - fileMode: "0400" - rotation: { tolerates: restart } - - path: secret/data/coverage/renewed - keys: [lease] - access: self-renew - delivery: file - mountAt: /run/secrets/renewed - fileMode: "0400" - rotation: { tolerates: restart } - - path: secret/data/coverage/custody - keys: [root] - access: custody - delivery: self - rotation: { tolerates: reload } - - engine: transit - key: coverage - operations: [encrypt, decrypt, verify] - delivery: self - mountAt: /run/secrets/transit - fileMode: "0400" - rotation: { tolerates: restart } - - name: coverage-seed - lifecycle: prepare - image: coverage-seed - runtime: none - placement: { memory: 32Mi, cpu: 5m } - - name: coverage-job - lifecycle: job - image: coverage-job - runtime: none - placement: { memory: 32Mi, cpu: 5m } - cutover: interrupted diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/env/_applications/coverage-api/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/env/_applications/coverage-api/base.env deleted file mode 100644 index e0ef8410e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/env/_applications/coverage-api/base.env +++ /dev/null @@ -1 +0,0 @@ -LEVEL=info diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/env/_project/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/env/_project/base.env deleted file mode 100644 index 5c5af0246..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/env/_project/base.env +++ /dev/null @@ -1 +0,0 @@ -MODE=full diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/env/coverage-api/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/env/coverage-api/base.env deleted file mode 100644 index 0feb66be1..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/breadth/env/coverage-api/base.env +++ /dev/null @@ -1 +0,0 @@ -VAULT_ROLE=${identity:vaultRole} diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/config/garage.toml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/config/garage.toml deleted file mode 100644 index 9b8f54088..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/config/garage.toml +++ /dev/null @@ -1,20 +0,0 @@ -# Garage's own configuration, an Asset: nothing in it is derived. The RPC -# secret and the admin token come from the environment. -metadata_dir = "/var/lib/garage/meta" -data_dir = "/var/lib/garage/data" -db_engine = "lmdb" - -# A consistent copy of the metadata database, which the backup archives in -# place of the live one. -metadata_snapshots_dir = "/var/lib/garage/snapshots" -metadata_auto_snapshot_interval = "6h" - -replication_factor = 1 -rpc_bind_addr = "[::]:3901" - -[s3_api] -s3_region = "garage" -api_bind_addr = "[::]:3900" - -[admin] -api_bind_addr = "[::]:3903" diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/config/postgresql.conf b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/config/postgresql.conf deleted file mode 100644 index 656f5b626..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/config/postgresql.conf +++ /dev/null @@ -1,39 +0,0 @@ -# collections/data/platform/config/postgresql.conf -# -# The Asset platform-postgres mounts at /etc/postgresql/postgresql.conf -# (docs/adr/model/0014-file-shaped-configuration-is-an-asset.md). Fully -# static: no placeholder and no derived value, so the file is carried into -# the projection as written, under a name its content digest decides. - -# ------------------------------------------------------------ connections -listen_addresses = '*' -port = 5432 -max_connections = 100 -unix_socket_directories = '/var/run/postgresql' - -# ----------------------------------------------------------------- memory -shared_buffers = 512MB -effective_cache_size = 1536MB -work_mem = 8MB -maintenance_work_mem = 128MB - -# -------------------------------------------------------------------- WAL -wal_level = replica -max_wal_size = 2GB -min_wal_size = 256MB -checkpoint_completion_target = 0.9 - -# -------------------------------------------------------------- extensions -shared_preload_libraries = 'vector' - -# ---------------------------------------------------------------- logging -log_destination = 'stderr' -logging_collector = off -log_min_duration_statement = 1000 -log_line_prefix = '%m [%p] %q%u@%d ' - -# ---------------------------------------------------------------- locale -datestyle = 'iso, mdy' -timezone = 'UTC' -lc_messages = 'en_US.utf8' -default_text_search_config = 'pg_catalog.english' diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/dashboards/rabbitmq.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/dashboards/rabbitmq.json deleted file mode 100644 index 36fe1b390..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/dashboards/rabbitmq.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "Prometheus", - "type": "datasource", - "pluginId": "prometheus" - } - ], - "uid": "rabbitmq", - "title": "RabbitMQ", - "tags": ["rabbitmq", "messaging"], - "editable": false, - "refresh": "30s", - "time": { "from": "now-1h", "to": "now" }, - "panels": [ - { - "id": 1, - "title": "Queue Messages (Ready)", - "type": "timeseries", - "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 }, - "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "targets": [ - { "expr": "rabbitmq_queue_messages_ready", "legendFormat": "{{queue}} ready" } - ] - } - ], - "schemaVersion": 39 -} diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/data.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/data.project.yml deleted file mode 100644 index a8e931ce5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/data.project.yml +++ /dev/null @@ -1,590 +0,0 @@ -# Worked example: the data project's Intent Fragment -# -# collections/data/platform/data.project.yml -# -# FOUR Applications in one file. They are neighbours, not a unit: co-location in a -# project file couples nothing, and each of the four releases on its own -# (docs/adr/model/0052-an-application-is-the-release-unit.md, -# docs/adr/model/0009-intent-is-authored-one-file-per-project.md). "Every Application in a project file -# releases as one" was considered and rejected exactly because it would let -# someone couple nine rollouts by editing an unrelated line. Atomicity stops at -# the Application boundary; the file is an authoring and publication unit. -# -# None of the four has a repository of its own. The data project ships from -# homelab-collections, and publication is repository-scoped, so the project may -# stay there or split out later -- composition behaves identically -# (docs/adr/model/0042-declarations-compose-from-intent-fragments.md). What may not happen is a project -# spanning two repositories: this file is the whole project. -# -# Exercises: four independently released Applications, a scheduled Process, a third-party image behind -# an alias with `runtime: none`, declared writable paths, structured -# `disk` placement, TCP probes, a static Asset, a sidecar, all three -# Durability Classes, `provides` consumed by eight Applications, one authored -# hostname that does not follow its Application id, and a document store -# whose engine owns no databases. -# -# Companion env file (per Process, like every env file): -# platform/env/postgres/base.env -- reproduced as env/postgres/base.env - -# The data model's own semver, not the toolkit's -# (docs/adr/model/0032-the-resolved-deployment-is-a-versioned-artifact.md). -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -project: data # namespace derives: data-system -owner: joris # one owner for every Application in the file; an Application - # needing a different owner needs its own project - -applications: - # ======================================================= platform-postgres - - id: platform-postgres - - # The scrape surface belongs to the exporter sidecar inside the `postgres` - # Process, and the block names it the same way a route does: by Process - # and surface, never by port. `metrics` is declared once, in `provides`. - observability: - scrape: - process: postgres - surface: metrics - path: /metrics - - processes: - - name: postgres - # `platform-postgres` is the repository/product name; `postgres` is what - # the process is actually called. That is not a divergence needing a - # field to record it -- it is the name - # (docs/adr/model/0009-intent-is-authored-one-file-per-project.md). The identity derived - # from it is `data-system.postgres`. - lifecycle: application - - # An ALIAS, resolved to a digest through the images lock -- exactly like - # a first-party image. Third-party is not a reason to exempt the most - # stateful process in the estate: `pgvector/pgvector:pg17` is a mutable - # tag that moves on every upstream build, and this Process is Recreate - # on a local-path RWO volume, so any reschedule is a fresh pull. - # Renovate raises the digest bump behind the ordering gate - # (docs/adr/model/0047-one-publication-path.md), and every rendered - # Deliverable stays E_FLOATING_IMAGE clean. - image: postgres - - # No Runtime Profile. A third-party image cannot consume OTEL_* or - # PYROSCOPE_* wiring, and injecting it would be noise. 'none' says so - # deliberately rather than leaving `runtime` unset. - runtime: none - - # What this process IS, which the platform keys its backup method off. - # Not `runtime`, which is instrumentation and is correctly `none` here - # (docs/adr/model/0019-engine-is-process-vocabulary.md). Required - # because this Process holds a volume whose class derives a backup. - engine: postgres - - # Declared on the Process that opens the sockets. Every consumer names - # the Application and the surface, never the port -- `dependsOn` targets - # `{application, surface}`, and surface names are unique within an Application. - # The eight consumers today: auth (its api Process), agents-api, - # knowledge (api and ingest worker), lightrag, n8n, outline, and the - # observability backup jobs. - # - # NOTE: the live cluster names this port 'db', not 'postgres'. Naming - # the surface for what it serves is the right call, so this is a - # deliberate rename recorded as a parity entry rather than a divergence. - provides: - postgres: 5432 - metrics: 9187 - - placement: - # The datastore eight Applications queue behind. Raw quantities, matched - # against node allocatable from the pinned node contract - # (docs/adr/model/0017-placement-is-hard-dimensions.md, - # docs/adr/model/0048-node-facts-are-authored-once.md). - memory: 2Gi # request == limit - cpu: 500m # request only, no limit - arch: [amd64] # pgvector publishes no arm64 build of pg17 - - # Structured, and a SET where a set makes sense: nvme or ssd, either - # is acceptable, with no ordering between them. The three Pis carry a - # 64G sdcard and nothing else, so `media` alone excludes them and the - # 100Gi ask excludes them twice over -- which is the point. Under the - # deleted class model this Process could sit beside a placement - # admitting only the Pis, pass the build, and go Pending at apply. - # - # `disk` filters FIRST placement only. Once a PV is bound, the binding - # wins, and a `disk` value that contradicts an existing binding in the - # pinned ClusterState is E_DISK_BINDING_CONFLICT - # (docs/adr/model/0034-cluster-state-is-a-pinned-input.md). - # - # This is the NODE's disk, not the claim's. The PVC's storage class - # and size are still assigned (chapter 20); this dimension only - # decides which nodes are eligible to hold it. - disk: - media: [nvme, ssd] - # No `size`: it is derived as the sum of this Process's volume - # sizes, so the quantity has one declaring site - # (docs/adr/model/0017-placement-is-hard-dimensions.md) - - # The `restricted` class applies whole: the pod runs as uid 999, drops - # all capabilities, takes seccomp RuntimeDefault and keeps - # readOnlyRootFilesystem true. There is no hardening block to author - # and no control to relax -- an image that cannot meet the class is - # E_HARDENING_UNMET, not an entry in an exception list - # (docs/adr/model/0020-hardening-is-one-platform-posture.md). - # The upstream entrypoint writes its unix socket to - # /var/run/postgresql and lock files under /tmp before the server - # starts; both are declared writable paths and readOnlyRootFilesystem - # stays true (docs/adr/model/0020-hardening-is-one-platform-posture.md). - # runAsNonRoot needs no exception either: the images lock resolves this - # image's uid and gid, and fsGroup derives from the gid so a freshly - # provisioned local-path volume is writable without an init chown - # (docs/adr/model/0020-hardening-is-one-platform-posture.md). - writablePaths: [/var/run/postgresql, /tmp] - - # postgres-exporter runs in the same pod and serves the metrics port - # this Process declares in `provides`. stalwart (stalwart-apply) and - # agent-runner (the agent-gateway jar) have the same shape - # (docs/adr/model/0015-sidecars-are-process-vocabulary.md). - # - # A sidecar carries what a container carries: its own memory, cpu and - # hardening. The node dimensions stay on the Process above, because - # nodeSelector is pod-level and the pod is one. Eligibility SUMS: this - # Process needs a node with 2112Mi free, not 2Gi. - sidecars: - - name: postgres-exporter - image: postgres-exporter - memory: 64Mi - cpu: 10m - # No exception: the exporter is a static Go binary that meets the - # restricted class, even though postgres beside it does not. - - # TCP, not HTTP. postgres has no HTTP surface, and this is what the live - # probes do -- tcpSocket on port db for both. An HTTP-only probe - # vocabulary could not express the estate's data tier at all - # (docs/adr/model/0016-probes-are-siblings-and-startup-targets-liveness.md). - probes: - readiness: {tcp: 5432} - liveness: {tcp: 5432} - - startupBudget: 60s - - # REQUIRED, no default, and `interrupted` is the only honourable answer: - # this Process holds a ReadWriteOnce local-path volume, which cannot - # attach to two pods at once. Declaring `continuous` here is - # E_CUTOVER_UNHONOURABLE rather than a silent downgrade to stop-start -- - # the owner states the stop-then-start they already have. - cutover: interrupted - - volumes: - - claim: postgres-data - mountAt: /var/lib/postgresql/data - size: 20Gi - durability: irreplaceable - # The one fact only the owning Application knows - # (docs/adr/model/0018-durability-class-derives-a-backup.md); schedule, sweep - # and destination are derived. This is the database eight Applications - # queue behind, on a `local-path` volume in a cluster with no - # VolumeSnapshot CRDs and no CSI snapshot support, so losing the - # node loses every consumer's data at once. `irreplaceable` renders - # a backup job keeping 90 copies plus an off-cluster copy, and - # its restore must be rehearsed before the first production apply - # (docs/adr/model/0049-datastore-and-restore.md) -- which is the gap the - # workspace backup-coverage decision recorded, where each job writes - # a fixed filename so the PVC holds only the newest copy: - # https://github.com/JorisJonkers-dev/workspace/blob/main/docs/decisions/ADR-0011-backup-coverage-gaps.md - # - # `size` is how much data the volume holds, a requirement the platform - # matches against node disk (spec/v1/10-project-intent.md#storage-and-durability); - # the storage class is assigned. - - assets: - # Fully static: zero derived values in 54 lines. Baking it into the - # image was rejected because that means a derived image, a build - # pipeline, a registry entry and a Renovate rule, plus a rebuild on - # every upstream pg17 bump -- to change one settings file - # (docs/adr/model/0014-file-shaped-configuration-is-an-asset.md). - - from: config/postgresql.conf - mountAt: /etc/postgresql/postgresql.conf - # No `onChange`. A change to an Asset is content-hashed and restarts - # the Process unconditionally; the field does not exist - # (docs/adr/model/0014-file-shaped-configuration-is-an-asset.md). - - # NOT declared: init-databases.sh. - # - # Its 98 lines create one database and one owning user per consuming - # Application -- auth_db, agents_db, knowledge_db, n8n_db -- which the - # dependency graph already knows from inbound edges and grants. It - # becomes a derived Deliverable (chapter 16). An executable is code, - # and code is not configuration. - # - # It also reads /run/secrets/, a Docker Compose convention that - # does not exist in Kubernetes, then falls back to env vars. That dead - # path is how long the file has gone unexamined. - - # SPLIT PATH, one path per reader set - # (docs/adr/model/0028-grant-unit-is-the-path.md). The exporter's datasource - # used to sit in the same document as every consumer's credentials, so - # holding `read` for the exporter meant holding `read` on auth's and - # knowledge's database passwords too -- a KV-v2 read returns the whole - # document. The subtree is now: - # - # .../platform/postgres/auth -> auth's api Process - # .../platform/postgres/kb -> knowledge (both Processes) - # .../platform/postgres/exporter -> this Process - # - # The data project owns that Subtree and lists the readers of each path, - # which is what makes "who breaks if I rotate this" answerable without - # reading live Vault contents. postgres itself does not read its - # consumers' credentials; each consumer declares its own grant. - # - # `delivery: env`, so this Application is refused until the pinned Cluster - # Context advertises `secretsEncryption: true` -- - # E_SECRETS_AT_REST_REQUIRED (docs/adr/model/0030-secret-delivery-is-env-file-or-self.md). - secrets: - # A generated key that adopts the exporter's existing value, so the - # lower, resolve and render stage cases carry an adopted location. - - path: secret/data/data-system/exporter - keys: [{ name: datasource, generate: { adopt: "secret/data/platform/postgres/exporter#datasource" } }] - access: read - delivery: file - mountAt: /run/secrets/exporter - fileMode: "0400" - rotation: {tolerates: restart} - - path: secret/data/platform/postgres/exporter - keys: [datasource] - access: read - delivery: env - rotation: {tolerates: restart} - - # ======================================================= platform-rabbitmq - # - # A second Application in the same file and the same namespace. It shares nothing - # with postgres: not a release, not an identity, not a grant. `data-system` - # holds four Applications by construction, so it is NOT a trust boundary -- no - # isolation claim may rest on the namespace wall. Isolation here is the - # derived default-deny edge set, evaluated per pod - # (docs/adr/model/0035-network-policy-is-default-deny-and-render-only.md), plus per-Process identity - # (docs/adr/model/0031-identity-per-process.md). - - id: platform-rabbitmq - # The broker's dashboard, vendored from the live one as JSON beside this - # file and shipped with the Application into the data folder of the - # Grafana the Platform document names - # (spec/v1/10-project-intent.md#dashboards). Its DS_PROMETHEUS input is - # mapped to that Grafana's data source; nothing is fetched at run time. - dashboards: - - {from: dashboards/rabbitmq.json} - # Its own urgency, not the project's: raising the class to the header would - # make this file page as loudly as postgres does. rabbitmq exports metrics - # itself, so no sidecar is involved and the surface is the Process's own. - observability: - scrape: - process: rabbitmq - surface: metrics # the prometheus plugin's own listener - path: /metrics - # Its series describe queues and connections, labelled as the plugin publishes them. - honorLabels: true - - # THE HOST DOES NOT FOLLOW THE APPLICATION ID, and this Application is the estate's - # evidence for authoring hostnames rather than deriving them: the Application is - # `platform-rabbitmq` and the live host is `rabbitmq.jorisjonkers.dev`. Any - # `.` rule produces `platform-rabbitmq.jorisjonkers.dev`, - # which resolves to nothing -- and it would be right for auth, so the - # derivation would look correct until someone read this line. `host` is - # therefore the full FQDN, authored, unique on a tier - # (E_DUPLICATE_HOST at composition) (review/EXPOSURE-MANIFEST.md). - exposure: - - name: management # unique within the Application; names what this - # host is, which `public` would not - host: rabbitmq.jorisjonkers.dev - audience: authenticated # the management UI behind forward-auth. One - # word: the chain, the tier and the middleware - # name are all derived and none is authorable - # (docs/adr/model/0023-exposure-is-declared-by-audience.md) - routes: - - {path: /, match: prefix, process: rabbitmq, surface: management} - # No `contentPolicy` and no `redirectTo`: this route takes the derived - # header baseline and redirects nowhere. Those two fields are the whole - # authored proxy vocabulary, and neither is needed here. - # - # This is also the inbound edge that puts `rabbitmq` among the nine - # hostnames auth's CORS list maintains by hand today -- under this model - # that list derives from edges like this one rather than being retyped - # (chapter 16). The predicate is still open. - - name: lan # the same host on the LAN tier: split horizon. - host: rabbitmq.jorisjonkers.dev - audience: lan # a second tier is a second proxy, so one host - # on two tiers has a winner in each; on one - # tier it would be E_DUPLICATE_HOST - # (spec/v1/10-project-intent.md#what-is-checked) - routes: - - {path: /, match: prefix, process: rabbitmq, surface: management} - - # The sensors on the LAN publish over MQTT from off the cluster, so the - # broker's `mqtt` surface is a raw TCP surface on an L4 Address the - # Platform document declares (spec/v1/10-project-intent.md#l4-exposure). - # The entry names the address, never an IP or a node; `port` is the one a - # sensor dials, and the port the broker listens on stays the surface's. - # The address is a pool on the Enschede LAN, so the broker is held to that - # site, and a sensor's own address reaches it unchanged. - l4Exposure: - - {address: lan-mqtt, port: 1883, protocol: tcp, process: rabbitmq, surface: mqtt} - - processes: - - name: rabbitmq - lifecycle: application - image: rabbitmq # an alias, resolved through the images lock - runtime: none # third-party image; no profile values to inject - engine: rabbitmq # keys the backup method: a definitions export - # (docs/adr/model/0019-engine-is-process-vocabulary.md) - - provides: - amqp: 5672 # named by auth and knowledge in `dependsOn` - management: 15672 - metrics: 15692 # the prometheus plugin's own listener - mqtt: 1883 # the MQTT plugin's listener, reached off the cluster - - placement: - memory: 2Gi # the broker the estate's async work queues behind - cpu: 500m - - # No `hardening` exceptions: the upstream image runs non-root with a - # read-only root filesystem once its mnesia directory is a volume. - - # No `exposure` here: it sits on the Application above, and its one route - # names the `management` surface declared in `provides`. `amqp` and - # `metrics` are provided and not routed -- providing a port is not - # exposing it, and only the route decides which of the four the edge - # can reach. `mqtt` is reached through no edge at all, but on the L4 - # Address the Application's `l4Exposure` names. - - probes: - readiness: {tcp: 5672} - liveness: {tcp: 5672} - - startupBudget: 120s - - # `interrupted`: this Process holds an RWO local-path volume. - # `continuous` would be E_CUTOVER_UNHONOURABLE, not a silent stop-start. - cutover: interrupted - - volumes: - - claim: rabbitmq-data - mountAt: /var/lib/rabbitmq - size: 20Gi - durability: recoverable - # One step below `irreplaceable` - # (docs/adr/model/0018-durability-class-derives-a-backup.md): a nightly - # application-level backup keeping 14 copies suffices, and no - # off-cluster copy is required. Losing the mnesia directory costs - # undelivered messages and the definitions, not a consumer's data. - - # No `secrets`, and therefore no env file placeholder to bind. This - # Process reads no Secret Store path: its clients hold the grants -- - # knowledge reads `secret/data/platform/rabbitmq`, and auth's api - # Process keeps its broker credentials in its own document. - - # ========================================================= platform-valkey - - id: platform-valkey - - # No `observability` block, and that is the whole statement. valkey speaks - # RESP and exports no Prometheus surface, no exporter runs beside it, and a - # datastore is correctly not exposed, so there is no signal to name. An - # omission says it: there is no `none` value to write, because a value - # meaning "I wrote the field to say I did not want the field" is ceremony - # (docs/adr/model/0025-observability-is-one-optional-block.md). Observing - # it takes an exporter sidecar plus a scrape surface, as postgres has above. - - processes: - - name: valkey - lifecycle: application - image: valkey # an alias, resolved through the images lock - runtime: none - - provides: - redis: 6379 # the surface auth's api Process names; the wire - # protocol is the surface's name, not the product's - - placement: - memory: 256Mi - cpu: 50m - # No further dimensions. The image is multi-arch and this Process - # needs no node capability, so every node is eligible -- which is what - # a cache should be, and what a `tailscale` filter would have - # pretended to narrow while excluding none of the 7. - - probes: - readiness: {tcp: 6379} - liveness: {tcp: 6379} - - startupBudget: 30s - - # `interrupted`: RWO volume again. The cache is reconstructible, so the - # stop-then-start costs a cold cache and nothing else. - cutover: interrupted - - volumes: - - claim: valkey-data - mountAt: /data - size: 2Gi - # No `engine`. `reconstructible` derives no backup, and an engine on - # a Process that derives none is refused -- - # E_ENGINE_WITHOUT_DURABILITY - # (docs/adr/model/0018-durability-class-derives-a-backup.md) - durability: reconstructible - # The estate's own words for this volume: "deliberately unbacked as - # reconstructible cache". Losing it costs a rebuild, not data, so no - # backup job is rendered at all - # (docs/adr/model/0018-durability-class-derives-a-backup.md). Stating the class - # is what makes that a decision rather than an omission. The class - # is also the model's gate on destruction -- a claim backing - # non-`reconstructible` data may not be removed as a side effect of - # a render -- and this is the one class that gate does not cover, - # which is a further reason to write it down rather than infer it. - - # ========================================================== platform-mongo - # - # The document store. Overleaf is its one consumer today, which is not this - # file's to state: a consumer names `platform-mongo.mongo` in its own - # `dependsOn`, and the edge lives in that consumer's project file. - - id: platform-mongo - processes: - - name: mongo - lifecycle: application - image: mongo # an alias, resolved through the images lock - runtime: none - - # Keys the backup method: a dump over the wire protocol, on the surface - # the platform's `mongo` entry names - # (spec/v1/14-platform-intent.md#engines). A `mongo` owns no - # databases, so no edge into it derives a catalog: its one consumer - # needs none (spec/v1/16-dependencies.md#the-database-catalog). - engine: mongo - - provides: - mongo: 27017 - - placement: - memory: 2Gi - cpu: 200m - - # mongod writes its socket under /tmp and its config database under - # /data/configdb before it serves; /data/db is the volume. - writablePaths: [/tmp, /data/configdb] - - probes: - readiness: {tcp: 27017} - liveness: {tcp: 27017} - - startupBudget: 60s - - # `interrupted`: an RWO volume, as every datastore here. - cutover: interrupted - - volumes: - - claim: mongo-data - mountAt: /data/db - size: 20Gi - # Every document and every account its consumer holds, so the - # same class as postgres: a backup job keeping 90 copies and an - # off-cluster copy. - durability: irreplaceable - - # ============================================================== asset-sync - # Publishes the latest release assets of the agent toolkit to the public - # assets bucket, as fleet-infra's `garage-asset-sync` CronJob does today. It - # runs to completion at each slot and serves nothing, so it is a scheduled - # Process (spec/v1/10-project-intent.md#scheduled-processes): it authors its - # own `schedule`, and never a cutover, probes, a port or a copy count. Never - # two runs at once, and a run more than 300 seconds late is skipped; neither - # is written here. Everything else it declares as any Process does. - - id: asset-sync - processes: - - name: asset-sync - lifecycle: scheduled - schedule: "*/15 * * * *" # every run is idempotent, so a tight slot costs nothing - image: asset-sync - runtime: none - placement: - memory: 64Mi - cpu: 25m - # Beside the bucket's store, which runs only in Frankfurt, so the - # uploads never cross the overlay network between sites. - site: frankfurt - # The bucket key, as one file: a scheduled Process holds a grant like - # any other, and its identity is its own. - secrets: - - path: secret/data/platform/garage/web-key - keys: [credentials] - access: read - delivery: file - mountAt: /run/secrets/garage/credentials - fileMode: "0400" - rotation: { tolerates: restart } - # It reads the release from GitHub and writes the bucket at its public - # address: no edge names either. - egress: - to: internet - reason: reads the latest release from GitHub and uploads it to the public assets bucket - - # ========================================================= platform-garage - # The estate's object store. Its engine is `s3`, so every edge naming - # buckets in it derives a bucket catalog: one bucket per name, as - # `-`, and one key per consuming project, which the catalog - # method mints (spec/v1/16-dependencies.md#the-bucket-catalog). Nothing here - # names a bucket or a key. - - id: platform-garage - processes: - - name: garage - lifecycle: application - image: garage - runtime: none - engine: s3 - - # `s3` is what consumers' edges name; `admin` is the admin API the - # catalog method applies the catalog over, as the platform's `s3` - # entry names it (spec/v1/14-platform-intent.md#catalog-methods). - provides: - s3: 3900 - admin: 3903 - - placement: - memory: 1Gi - cpu: 200m - site: frankfurt - - probes: - readiness: {path: /health, port: 3903} - liveness: {tcp: 3900} - - startupBudget: 60s - cutover: interrupted - - assets: - - from: config/garage.toml - mountAt: /etc/garage.toml - - # The cluster secret and the admin token Garage reads from its - # environment. The token is also the catalog method's login while data - # is legacy, which the platform's serving location names. - secrets: - - path: secret/data/platform/garage - keys: [rpc-secret, admin-token] - access: read - delivery: env - rotation: {tolerates: restart} - - # Three volumes, so the backup never reads the live metadata database: - # Garage writes a consistent snapshot of it on its own schedule, and the - # files method archives the snapshots and the data blocks, which are - # never changed in place. - volumes: - - claim: garage-meta - mountAt: /var/lib/garage/meta - size: 2Gi - durability: reconstructible # restored from the newest snapshot - - claim: garage-snapshots - mountAt: /var/lib/garage/snapshots - size: 4Gi - durability: recoverable - - claim: garage-data - mountAt: /var/lib/garage/data - size: 20Gi - durability: recoverable diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/env/garage/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/env/garage/base.env deleted file mode 100644 index c3cf98330..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/env/garage/base.env +++ /dev/null @@ -1,7 +0,0 @@ -# collections/data/platform/env/garage/base.env -# -# Garage reads its cluster secret and admin token from these two variables in -# place of its configuration file, so the file stays an Asset with nothing -# secret in it. -GARAGE_RPC_SECRET=${secret:secret/data/platform/garage#rpc-secret} -GARAGE_ADMIN_TOKEN=${secret:secret/data/platform/garage#admin-token} diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/env/postgres/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/env/postgres/base.env deleted file mode 100644 index 58946ba47..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/data/env/postgres/base.env +++ /dev/null @@ -1,24 +0,0 @@ -# collections/data/platform/env/postgres/base.env -# -# Per Process, like every env file -# (docs/adr/model/0013-configuration-is-dotenv-at-three-scopes.md). A third-party image -# with runtime: none receives no profile values at all, so this file is short. -# The single secret placeholder is consumed by the postgres-exporter sidecar. -# -# The Application this Process belongs to is declared in the data project's Intent -# Fragment, platform/data.project.yml, alongside platform-rabbitmq and platform-valkey -# (docs/adr/model/0009-intent-is-authored-one-file-per-project.md) -- reproduced as -# examples/data/data.project.yml. Sharing that file couples nothing: the three -# Applications release independently -# (docs/adr/model/0052-an-application-is-the-release-unit.md). - -POSTGRES_DB=postgres -POSTGRES_USER=postgres - -# The exporter's connection string. The string between ${secret: and # BYTE- -# MATCHES the `path:` of the Process-level grant in data.yml -# (docs/adr/model/0030-secret-delivery-is-env-file-or-self.md) -- mount and KV `data/` segment -# included, and pointing at the exporter's own split path rather than the old -# shared document. Without that grant this line is an unauthorised reference; -# without this line the grant is a dead grant. -DATA_SOURCE_NAME=${secret:secret/data/platform/postgres/exporter#datasource} diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/delivery/delivery.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/delivery/delivery.project.yml deleted file mode 100644 index eff6e5332..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/delivery/delivery.project.yml +++ /dev/null @@ -1,195 +0,0 @@ -# The delivery machinery as Project Intent: the Applications that perform a -# switch and are never switched by one (spec/v1/14-platform-intent.md#delivery-policy), -# and the ClusterState Collector beside them. -# -# The Platform document names Flagger and the Release Gate in -# `delivery.machinery`, so this file is the one project the platform owns -# outright. Both answer `continuous`: they must keep serving while they cut -# over. On any other Application that derives a blue/green switch the Release -# Gate decides; here it derives a rolling one, because a gate cannot gate its -# own release, and nothing gates Flagger's -# (spec/v1/55-delivery.md#the-release-gate). The Release Gate's projection, -# `expected/resolved.json`, records exactly that: a `rolling` switchover and no -# release-gate inputs. -# -# All three call the Kubernetes API, which no other Process of the estate does. -# Each declares what it asks and why, and the Platform document admits the -# three by name in `apiAccess.holders` -# (spec/v1/16-dependencies.md#kubernetes-api-access-is-declared-and-admitted). - -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -project: delivery # the namespace derives: delivery-system -owner: joris - -applications: - - id: flagger - processes: - - name: flagger - lifecycle: application - image: flagger - runtime: none - provides: - http: 8080 - placement: - memory: 64Mi - cpu: 10m - writablePaths: [/tmp] - # Flagger asks the Release Gate its four questions. This is the one - # edge to the gate, so the gate's derived policy admits Flagger and - # nobody else. - dependsOn: - - { application: release-gate, surface: http } - api: - reason: >- - Flagger switches every blue-green Process, so it scales its - Deployment, generates its Services and copies, and records the - Canary - rules: - - group: flagger.app - objects: [canaries, canaries/status] - verbs: [get, list, watch, update, patch] - - group: apps - objects: [deployments] - verbs: [get, list, watch, create, update, patch, delete] - - group: autoscaling - objects: [horizontalpodautoscalers] - verbs: [get, list, watch, create, update, patch, delete] - - group: core - objects: [services, configmaps] - verbs: [get, list, watch, create, update, patch, delete] - # Reading a Secret a pod names is how Flagger learns it is excluded - # from configuration tracking; it copies none, so it writes none. - - group: core - objects: [secrets] - verbs: [get] - - group: core - objects: [events] - verbs: [create, update, patch] - probes: - readiness: { path: /healthz, port: 8080 } - liveness: { path: /healthz, port: 8080 } - startupBudget: 30s - cutover: continuous - - - id: release-gate - # The gate serves each round of tending at /metrics, to the metrics stack - # alone (JorisJonkers-dev/delivery#22): a rolling Process, scraped through - # a ServiceMonitor over its own Service. - observability: - scrape: { process: release-gate, surface: http, path: /metrics } - processes: - - name: release-gate - lifecycle: application - image: release-gate - runtime: none # a static binary needs no Runtime Profile - provides: - http: 8080 # Flagger's webhooks, answered from the projection - placement: - memory: 64Mi - cpu: 25m - api: - reason: >- - the Release Gate answers Flagger from what the cluster holds, so it - reads each gated Application's inputs, Canaries, Deployments, Jobs - and pods; it finds the gated Applications by listing ConfigMaps, - keeps each one's release record in a ConfigMap of its own, - unsuspends the migration Jobs it starts, and deletes a gated - Application's Vault sync objects of an older revision once it - serves the new one - rules: - - group: core - objects: [configmaps] - verbs: [get, list] - # Its own release records live in its own namespace, so writing - # them needs no reach beyond it: a Role, not a ClusterRole. - - group: core - objects: [configmaps] - verbs: [create, update] - scope: namespace - - group: core - objects: [pods] - verbs: [list] - - group: apps - objects: [deployments] - verbs: [get] - - group: batch - objects: [jobs] - verbs: [list, patch] - - group: flagger.app - objects: [canaries] - verbs: [get] - - group: secrets.hashicorp.com - objects: [vaultauths, vaultstaticsecrets, vaultdynamicsecrets] - verbs: [list, delete] - probes: - readiness: { path: /readyz, port: 8080 } - liveness: { path: /healthz, port: 8080 } - startupBudget: 10s - cutover: continuous - - # The ClusterState Collector (spec/v1/20-resolved-deployment.md#the-collector): - # not machinery, since it switches nothing, so it is not in - # `delivery.machinery`. It captures on its own interval and holds no state, so - # stopping it for a release costs one capture: `interrupted`. - - id: collector - processes: - - name: collector - lifecycle: application - image: collector - runtime: none - provides: - http: 8080 # its probes; nothing calls it - placement: - memory: 64Mi - cpu: 10m - api: - reason: >- - the Collector captures where each bound claim and each rendered pod - is, so it lists the three kinds that say so, cluster-wide, and - writes nothing - rules: - - group: core - objects: [persistentvolumes, persistentvolumeclaims, pods] - verbs: [get, list] - probes: - readiness: { path: /readyz, port: 8080 } - # Whether a capture succeeded within twice its interval: a Collector - # that stopped succeeding is restarted. - liveness: { path: /fresh, port: 8080 } - startupBudget: 10s - cutover: interrupted - - # The Reporter (spec/v1/55-delivery.md#rollouts): not machinery, since it - # switches nothing, so it is not in `delivery.machinery`. It writes each - # Rollout's statuses from the cluster's own events, and on start it reads - # every unit and Canary again and corrects a status that lags, so stopping it - # for a release costs nothing a status does not catch up on: `interrupted`. - - id: reporter - processes: - - name: reporter - lifecycle: application - image: reporter - runtime: none - provides: - http: 8080 # Flux's events, and its probes - placement: - memory: 64Mi - cpu: 10m - api: - reason: >- - the Reporter reads every Project's unit and every Canary again on start and on an interval, to correct a status an event it missed left behind, and writes nothing - rules: - - group: kustomize.toolkit.fluxcd.io - objects: [kustomizations] - verbs: [get, list, watch] - - group: flagger.app - objects: [canaries] - verbs: [get, list, watch] - probes: - readiness: { path: /readyz, port: 8080 } - liveness: { path: /healthz, port: 8080 } - startupBudget: 10s - cutover: interrupted diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/edge/edge.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/edge/edge.project.yml deleted file mode 100644 index d07e5283b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/edge/edge.project.yml +++ /dev/null @@ -1,91 +0,0 @@ -# The edge as Project Intent: the two Traefik instances the worked Platform -# document's tiers name (spec/v1/14-platform-intent.md#the-foundation-is-declared). -# -# Two instances are two Applications, placed by capability: one on the -# public-ingress node, one on a LAN node. Both are delivery machinery -# (`delivery.machinery`), so their `continuous` cutover derives a rolling -# switchover rather than a gated blue/green one: an edge proxy is what a -# blue/green switch is performed through. - -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -project: edge # the namespace derives: edge-system -owner: joris - -applications: - - id: traefik-public - processes: - - name: traefik-public - lifecycle: application - image: traefik - runtime: none - provides: - web: 8000 - websecure: 8443 - admin: 8080 - placement: - memory: 128Mi - cpu: 50m - capabilities: [public-ingress] - writablePaths: [/tmp] - probes: - readiness: { path: /ping, port: 8080 } - liveness: { path: /ping, port: 8080 } - startupBudget: 20s - cutover: continuous - - - id: traefik-lan - processes: - - name: traefik-lan - lifecycle: application - image: traefik - runtime: none - provides: - web: 8000 - websecure: 8443 - admin: 8080 - placement: - memory: 128Mi - cpu: 50m - capabilities: [lan-ingress] - writablePaths: [/tmp] - probes: - readiness: { path: /ping, port: 8080 } - liveness: { path: /ping, port: 8080 } - startupBudget: 20s - cutover: continuous - - # The DNS controller: it publishes each route's host under the tier its - # annotations name, so its records follow the routes and no one writes them - # by hand. Its flags are its environment, and the provider's token reaches it - # through the one secret delivery, as any Process's grant does; the estate's - # own file names both. - - id: external-dns - processes: - - name: external-dns - lifecycle: application - image: external-dns - runtime: none - provides: - metrics: 7979 - placement: - memory: 64Mi - cpu: 10m - probes: - readiness: { path: /healthz, port: 7979 } - liveness: { path: /healthz, port: 7979 } - startupBudget: 30s - cutover: interrupted - egress: { to: internet, reason: the DNS provider's API } - api: - reason: >- - external-dns reads every route and the Services behind it, cluster-wide, to publish their hosts - rules: - - group: core - objects: [services, endpoints, pods, nodes] - verbs: [get, list, watch] - - group: traefik.io - objects: [ingressroutes] - verbs: [get, list, watch] diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/identity/identity.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/identity/identity.project.yml deleted file mode 100644 index 1b394c10f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/identity/identity.project.yml +++ /dev/null @@ -1,120 +0,0 @@ -# Sign-in as Project Intent: the Identity Provider the worked Platform -# document's `signIn` names, and two Applications that sign people in through -# it, beside the third way chapter 17 works through (spec/v1/17-sign-in.md). -# -# portal a native Client signing in with PKCE: a public client, no secret -# whoami a gated Client: no OIDC in the image, so the Gate signs a person -# in at the edge and the route set gains the derived /.auth/ route -# -# The third, a native Client holding a secret, is grafana: its own OIDC, and a -# derived credential path the provider writes and grafana reads. It belongs to -# the observability project, beside the operator that ships its dashboards -# (observability/observability.project.yml). -# -# The Identity Provider is a platform Application, named by the Platform -# document as the secret store and the tier proxies are, so this project is -# part of the worked foundation every case composes with. Its process is -# granted write on every Client's credential path, in this project or another. - -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -project: identity # the namespace derives: identity-system -owner: joris - -applications: - # The sign-in provider. Its Process is granted write on every derived client - # credential path, derived and never authored, and the public tier's - # forward-auth endpoint is its Gate. - - id: identity - exposure: - - name: public - host: id.jorisjonkers.dev - audience: anonymous # the provider is what signs people in, so it cannot sit behind it - contentPolicy: strict - routes: - - { path: /, match: prefix, process: identity, surface: http } - processes: - - name: identity - lifecycle: application - image: identity - runtime: none - provides: - http: 8080 - placement: - memory: 256Mi - cpu: 50m - probes: - readiness: { path: /health/ready, port: 8080 } - liveness: { path: /health/live, port: 8080 } - startupBudget: 30s - cutover: continuous - - # Native, with PKCE: a single-page app is a public client and holds no - # secret, so ${client:secret} here would be E_CLIENT_PLACEHOLDER_WITHOUT_SECRET. - - id: portal - exposure: - - name: public - host: home.jorisjonkers.dev - audience: authenticated - routes: - - { path: /, match: prefix, process: portal, surface: http } - client: - signIn: native - label: Home - description: Every application you can open - launchPath: /apps - redirectPaths: [/callback, /silent-renew] - protectedPath: /api/me - credential: pkce - processes: - - name: portal - lifecycle: application - image: portal - runtime: none - provides: - http: 8080 - placement: - memory: 64Mi - cpu: 10m - probes: - readiness: { path: /, port: 8080 } - cutover: continuous - - # Gated: the image speaks no OIDC. Every route of the exposure takes the - # tier's forward-auth, but for the one route that takes itself out of the - # sign-in, and the Gate's /.auth/ route is derived, never authored. - - id: whoami - exposure: - - name: public - host: whoami.jorisjonkers.dev - audience: authenticated - routes: - - { path: /, match: prefix, process: whoami, surface: http } - - { path: /health, match: exact, process: whoami, surface: http, audience: anonymous } - client: - signIn: gated - label: Who am I - iconPath: /favicon.ico - processes: - - name: whoami - lifecycle: application - image: whoami - runtime: none - provides: - http: 8080 - placement: - memory: 32Mi - cpu: 10m - probes: - readiness: { path: /health, port: 8080 } - cutover: continuous - # Two replicas on different nodes: losing one node leaves the probe - # answering. Only pods of one revision repel each other, so a rollout - # completes even where the replicas fill every eligible node - # (spec/v1/10-project-intent.md#replicas). - replicas: - count: 2 - reason: Availability of the sign-in probe across a node loss. - across: node diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/basic-memory/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/basic-memory/base.env deleted file mode 100644 index 29cc54ec9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/basic-memory/base.env +++ /dev/null @@ -1,26 +0,0 @@ -# Basic Memory. The git-sync sidecar shares the pod's environment, so its -# variables are here too. -BASIC_MEMORY_PROJECT_ROOT=/vault -BASIC_MEMORY_HOME=/vault -BASIC_MEMORY_DEFAULT_PROJECT=main -BASIC_MEMORY_DISABLE_PERMALINKS=true -BASIC_MEMORY_ENSURE_FRONTMATTER_ON_SYNC=false -BASIC_MEMORY_SEMANTIC_EMBEDDING_CACHE_DIR=/app/.basic-memory/fastembed -BASIC_MEMORY_CONFIG_DIR=/app/.basic-memory -BASIC_MEMORY_SYNC_CHANGES=true -BASIC_MEMORY_SYNC_DELAY=1000 -BASIC_MEMORY_LOG_LEVEL=INFO - -# git-sync: the vault repository it keeps /vault in step with. -VAULT_CLONE_URL=git@github.com:JorisJonkers-dev/knowledge-vault.git -VAULT_DIR=/vault -VAULT_BRANCH=main -VAULT_SSH_KEY_PATH=/run/secrets/knowledge-vault/id_ed25519 -VAULT_AUTHOR_NAME=basic-memory-vault -VAULT_AUTHOR_EMAIL=basicmemory@knowledge.local -GIT_CONFIG_COUNT=1 -GIT_CONFIG_KEY_0=safe.directory -GIT_CONFIG_VALUE_0=/vault -POLL_SECONDS=10 -PUSH=true -LOG_LEVEL=INFO diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/docling-serve/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/docling-serve/base.env deleted file mode 100644 index 8144a2224..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/docling-serve/base.env +++ /dev/null @@ -1,3 +0,0 @@ -# docling-serve, as fleet-infra configures it. -UVICORN_HOST=0.0.0.0 -UVICORN_PORT=8000 diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-api/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-api/base.env deleted file mode 100644 index c22c80bdc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-api/base.env +++ /dev/null @@ -1,18 +0,0 @@ -# The language model hindsight reasons with, through OpenRouter. -HINDSIGHT_API_LLM_PROVIDER=openai -HINDSIGHT_API_LLM_BASE_URL=https://eu.openrouter.ai/api/v1 -HINDSIGHT_API_LLM_MODEL=mistralai/mistral-small-2603 -HINDSIGHT_API_LLM_API_KEY=${secret:secret/data/platform/hindsight#llm-api-key} - -# The embedding model, the Application's own tei-embedding Process. Its URL -# and the database URL are composed of two coordinates each, which no env value -# can say (RENDER-GAPS.md); the edges are the coordinates' only home here. -HINDSIGHT_API_EMBEDDINGS_PROVIDER=tei - -# The login the edge to platform-postgres derives, which the Secret Store issues. -PGUSER=${dependency:platform-postgres.username} -PGPASSWORD=${dependency:platform-postgres.password} - -# The API serves; the worker Process runs the queue. -HINDSIGHT_API_WORKER_ENABLED=false -HINDSIGHT_API_PORT=8888 diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-control-plane/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-control-plane/base.env deleted file mode 100644 index 1743e591d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-control-plane/base.env +++ /dev/null @@ -1,5 +0,0 @@ -# The API URL is composed of two coordinates, which no env value can say -# (RENDER-GAPS.md). -HINDSIGHT_CP_HOSTNAME=0.0.0.0 -HINDSIGHT_CP_PORT=3000 -NODE_ENV=production diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-tei-embedding/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-tei-embedding/base.env deleted file mode 100644 index f37926153..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-tei-embedding/base.env +++ /dev/null @@ -1,3 +0,0 @@ -PORT=8091 -PAYLOAD_LIMIT=10000000 -MAX_CLIENT_BATCH_SIZE=256 diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-worker/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-worker/base.env deleted file mode 100644 index 40a77f5c0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/hindsight-worker/base.env +++ /dev/null @@ -1,16 +0,0 @@ -# The language model hindsight reasons with, through OpenRouter. -HINDSIGHT_API_LLM_PROVIDER=openai -HINDSIGHT_API_LLM_BASE_URL=https://eu.openrouter.ai/api/v1 -HINDSIGHT_API_LLM_MODEL=mistralai/mistral-small-2603 -HINDSIGHT_API_LLM_API_KEY=${secret:secret/data/platform/hindsight#llm-api-key} - -# The embedding model, the Application's own tei-embedding Process. Its URL -# and the database URL are composed of two coordinates each, which no env value -# can say (RENDER-GAPS.md); the edges are the coordinates' only home here. -HINDSIGHT_API_EMBEDDINGS_PROVIDER=tei - -HINDSIGHT_API_PORT=8889 -HINDSIGHT_API_WORKER_HTTP_PORT=8889 -HINDSIGHT_API_WORKER_POLL_INTERVAL_MS=500 -HINDSIGHT_API_WORKER_BATCH_SIZE=10 -HINDSIGHT_API_WORKER_MAX_RETRIES=3 diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/karakeep/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/karakeep/base.env deleted file mode 100644 index dd60bc47e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/env/karakeep/base.env +++ /dev/null @@ -1,25 +0,0 @@ -# karakeep. meilisearch and chrome share the pod's environment and answer on -# localhost. -NEXTAUTH_SECRET=${secret:secret/data/platform/karakeep#nextauth-secret} -NEXTAUTH_URL=${exposure:karakeep.public#url} -DATA_DIR=/data -MEILI_ADDR=http://localhost:7700 -MEILI_MASTER_KEY=${secret:secret/data/platform/karakeep#meili-master-key} -MEILI_NO_ANALYTICS=true -BROWSER_WEB_URL=http://localhost:9222 - -# Tagging and summaries, through OpenRouter. -OPENAI_API_KEY=${secret:secret/data/platform/karakeep#openrouter-api-key} -OPENAI_API_BASE=https://eu.openrouter.ai/api/v1 -INFERENCE_TEXT_MODEL=mistralai/mistral-small-2603 -INFERENCE_CONTEXT_LENGTH=2048 -INFERENCE_ENABLE_AUTO_TAGGING=true -INFERENCE_ENABLE_AUTO_SUMMARIZATION=true - -# Assets in the object store's bucket, with the key the edge derives. -ASSET_STORE_S3_ENDPOINT=${dependency:platform-garage.endpoint} -ASSET_STORE_S3_REGION=garage -ASSET_STORE_S3_BUCKET=knowledge-platform-assets -ASSET_STORE_S3_FORCE_PATH_STYLE=true -ASSET_STORE_S3_ACCESS_KEY_ID=${dependency:platform-garage.accessKeyId} -ASSET_STORE_S3_SECRET_ACCESS_KEY=${dependency:platform-garage.secretAccessKey} diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/knowledge-platform.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/knowledge-platform.project.yml deleted file mode 100644 index 3aa128769..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge-platform/knowledge-platform.project.yml +++ /dev/null @@ -1,323 +0,0 @@ -# Worked example: the knowledge platform, as fleet-infra runs it -# -# cluster/flux/apps/knowledge-platform/ in JorisJonkers-dev/fleet-infra -# -# The platform that replaces knowledge-system (JorisJonkers-dev/fleet-infra#237): -# a document parser, a memory service with its embedding model and worker, a -# notes server whose vault is a git repository, and a bookmark archive. What the -# model cannot say about any of it is a row in RENDER-GAPS.md beside this file, -# never a guess here. -# -# Left out, deliberately: the ingest worker, parked at zero replicas, and its -# one-off copy Job (a Process has no zero, and a one-off migration is no -# Process); and LightRAG, which still runs in knowledge-system. - -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -project: knowledge-platform -owner: joris - -# Shared Intent at the header: every Process here holds a volume or serves one -# that does, so each runs one copy at a time and is replaced in place. -cutover: interrupted - -applications: - # ============================================================ docling-serve - # Parses PDFs and office documents into text. Its archive is the evidence - # layer: the original bytes, kept by content hash, which no rebuild recovers. - - id: docling-serve - processes: - - name: docling-serve - lifecycle: application - image: docling-serve - runtime: python - engine: files - provides: - http: 8000 - placement: - memory: 1Gi - cpu: 500m - site: frankfurt - probes: - readiness: { path: /health, port: 8000 } - liveness: { path: /health, port: 8000 } - startupBudget: 120s - volumes: - - claim: docling-serve-archive - mountAt: /archive - size: 50Gi - durability: irreplaceable - - # ================================================================= hindsight - # The memory service: an API, its control plane, and a worker that runs the - # jobs the API queues. One Application, because the three release together: a - # new API against an old worker is a broken queue. The embedding model they - # read is an Application of its own below, since it holds a volume and stops - # to start again, while these three switch with no gap. - - id: hindsight - migration: self # the API migrates its own schema at startup - # Overrides the header: none of the three holds a volume, so each new version - # starts beside the old one, and the Release Gate holds it until every - # stop-start Process it requires in this Project, the embedding model, has - # started its own (spec/v1/55-delivery.md#release-order). - cutover: continuous - # Shared Intent at the Application: the four run on one site, beside the - # model cache and the database they read. - placement: - site: enschede - exposure: - - name: console - host: memory.jorisjonkers.dev - audience: authenticated - contentPolicy: strict - routes: - - { path: /, match: prefix, process: hindsight-control-plane, surface: console } - - name: api - host: memory-api.jorisjonkers.dev - audience: authenticated - contentPolicy: strict - routes: - - { path: /, match: prefix, process: hindsight-api, surface: api } - processes: - - name: hindsight-api - lifecycle: application - image: hindsight-api - runtime: python - provides: - api: 8888 - placement: - memory: 1Gi - cpu: 500m - dependsOn: - # The edge delivers the database login it derives to the environment. - - application: platform-postgres - surface: postgres - credentials: { delivery: env, rotation: { tolerates: restart } } - - { application: hindsight-embedding, surface: embeddings } - secrets: - - path: secret/data/platform/hindsight - keys: [llm-api-key] - access: read - delivery: env - rotation: { tolerates: restart } - probes: - readiness: { path: /health, port: 8888 } - liveness: { path: /health/live, port: 8888 } - startupBudget: 120s - - - name: hindsight-worker - lifecycle: application - # Parked: it runs no pod while ingestion is paused, and keeps its - # grants, its edges, its Service and its network policy, so unparking - # is deleting these two lines (spec/v1/10-project-intent.md#parked-processes). - parked: {reason: Ingestion paused while the job store is migrated.} - image: hindsight-api # the same image, started as the worker - runtime: python - provides: - worker: 8889 - placement: - memory: 1Gi - cpu: 500m - dependsOn: - # The edge delivers the database login it derives as two files. - - application: platform-postgres - surface: postgres - credentials: - delivery: file - mountAt: /run/secrets/database - fileMode: "0400" - rotation: { tolerates: restart } - - { application: hindsight-embedding, surface: embeddings } - secrets: - - path: secret/data/platform/hindsight - keys: [llm-api-key] - access: read - delivery: env - rotation: { tolerates: restart } - probes: - readiness: { path: /health, port: 8889 } - liveness: { path: /health/live, port: 8889 } - startupBudget: 120s - - - name: hindsight-control-plane - lifecycle: application - image: hindsight-control-plane - runtime: node - provides: - console: 3000 - placement: - memory: 512Mi - cpu: 250m - dependsOn: - - { application: hindsight, surface: api } - probes: - readiness: { tcp: 3000 } - liveness: { tcp: 3000 } - startupBudget: 60s - - # ============================================================== basic-memory - # A notes server whose notes are a git clone of knowledge-vault, kept in sync - # by a sidecar that pulls and pushes with the repository's deploy key. - - id: basic-memory - exposure: - - name: mcp - host: memory-mcp.jorisjonkers.dev - audience: authenticated - contentPolicy: strict - routes: - - { path: /, match: prefix, process: basic-memory, surface: mcp } - processes: - - name: basic-memory - lifecycle: application - image: basic-memory - runtime: python - provides: - mcp: 8000 - placement: - memory: 1Gi - cpu: 500m - site: frankfurt - # git-sync clones the vault before the server starts, then pushes - # what the server writes; each mounts the vault it works in. - sidecars: - - name: git-clone - image: basic-memory-git-sync - memory: 64Mi - cpu: 50m - init: true - volumes: [{ claim: basic-memory-vault, mountAt: /vault }] - - name: git-sync - image: basic-memory-git-sync - memory: 64Mi - cpu: 50m - volumes: [{ claim: basic-memory-vault, mountAt: /vault }] - secrets: - # The deploy key git-sync pushes with, as a file SSH accepts. A file - # grant is mounted into every container of the pod. SSH reads the - # file on each push, so a reload would do; a static secret still - # restarts its consumer once the operator syncs a new value. - - path: secret/data/knowledge-system/vault-deploy-key - keys: [private_key] - access: read - delivery: file - mountAt: /run/secrets/knowledge-vault/id_ed25519 - fileMode: "0400" - rotation: { tolerates: reload } - probes: - readiness: { tcp: 8000 } - liveness: { tcp: 8000 } - startupBudget: 120s - volumes: - # A clone: the repository on GitHub is the copy that matters. - - claim: basic-memory-vault - mountAt: /vault - size: 5Gi - durability: reconstructible - - claim: basic-memory-config - mountAt: /app/.basic-memory - size: 2Gi - durability: reconstructible - - # ================================================================== karakeep - # A bookmark archive, with its search index and a headless browser that reads - # pages beside it in the same pod. - - id: karakeep - exposure: - - name: public - host: karakeep.jorisjonkers.dev - audience: authenticated - contentPolicy: strict - routes: - - { path: /, match: prefix, process: karakeep, surface: http } - processes: - - name: karakeep - lifecycle: application - image: karakeep - runtime: node - engine: files - provides: - http: 3000 - placement: - memory: 512Mi - cpu: 200m - site: frankfurt - sidecars: - # The search index, which meilisearch alone writes. - - name: meilisearch - image: meilisearch - memory: 256Mi - cpu: 100m - volumes: [{ claim: karakeep-meili, mountAt: /meili_data }] - - name: chrome - image: karakeep-chrome - memory: 512Mi - cpu: 500m - # The headless browser fetches every page bookmarked, from anywhere. - egress: - to: internet - reason: >- - The browser fetches the pages it bookmarks. - # Its assets in the object store: the edge names the bucket, which - # derives as `knowledge-platform-assets`, and the project's key to it, - # which the env file reads (spec/v1/16-dependencies.md#the-bucket-catalog). - dependsOn: - - { application: platform-garage, surface: s3, buckets: [assets] } - # And it fetches them through the platform's VPN, so the sites it - # archives see the tunnel's exit rather than the estate's address - # (docs/adr/model/0107-a-vpn-attachment-is-a-derived-sidecar.md). It - # serves no peer, so it takes no forwarded port. - vpn: { forwardedPort: false } - secrets: - - path: secret/data/platform/karakeep - keys: [nextauth-secret, meili-master-key, openrouter-api-key] - access: read - delivery: env - rotation: { tolerates: restart } - probes: - readiness: { path: /api/health, port: 3000 } - liveness: { path: /api/health, port: 3000 } - startupBudget: 200s - volumes: - - claim: karakeep-data - mountAt: /data - size: 50Gi - durability: recoverable - # The search index rebuilds from the bookmarks. - - claim: karakeep-meili - mountAt: /meili_data - size: 5Gi - durability: reconstructible - - claim: meilisearch-data - mountAt: /meili_data - size: 20Gi - durability: reconstructible # the index rebuilds from the archive - - # ======================================================= hindsight-embedding - # The embedding model the API and the worker read. It keeps its model cache on - # a volume, so it stops before it starts again, and a release of this Project - # recreates it; the gate keeps hindsight's new versions from starting until it - # serves again. - - id: hindsight-embedding - placement: - site: enschede - processes: - - name: hindsight-tei-embedding - lifecycle: application - image: text-embeddings-inference - runtime: none - provides: - embeddings: 8091 - placement: - memory: 6Gi - cpu: 500m - probes: - readiness: { path: /health, port: 8091 } - liveness: { path: /health, port: 8091 } - startupBudget: 300s # the first start downloads the model into the cache - volumes: - - claim: hindsight-tei-model-cache - mountAt: /data - size: 8Gi - durability: reconstructible # the model downloads again diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/env/_project/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/env/_project/base.env deleted file mode 100644 index 566b5ccbe..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/env/_project/base.env +++ /dev/null @@ -1,31 +0,0 @@ -# applications/knowledge/platform/env/_project/base.env -# -# The project scope: every Process of every Application in `knowledge` receives -# these (docs/adr/model/0012-shared-intent-descends-and-is-lowered.md). Nine of -# the twelve lines each Process file used to carry were byte-identical between -# them, which is the duplication a shared scope exists to end. Both Processes -# reach the same Postgres and the same RabbitMQ, so both read the same -# coordinates and the same credentials. They sat at the Application scope until -# the worker became an Application of its own (`knowledge-ingest`); the project -# scope is the one both still share. -# -# A Process that needed a different value for one of these would set it in its -# own file, where a reader sees it; setting it to the SAME value there is -# E_SHARED_DECLARATION_DUPLICATED, because the line would change nothing. - -# --- coordinates, from the dependsOn edges both Processes declare -DB_HOST=${dependency:platform-postgres.host} -DB_PORT=${dependency:platform-postgres.port} -# The database name is derived too, and an edge hands out only `host` and -# `port`: no placeholder names it yet (JorisJonkers-dev/deploy-kit#269). -RABBITMQ_HOST=${dependency:platform-rabbitmq.host} -RABBITMQ_PORT=${dependency:platform-rabbitmq.port} - -# --- secrets, each byte-matching a path the Application grants -# (docs/adr/model/0030-secret-delivery-is-env-file-or-self.md). The grants sit on the -# Application too, one level up from the Processes that hold them, so the -# grant and the reference that binds it are written at the same level. -DB_USER=${secret:secret/data/platform/postgres/kb#user} -DB_PASSWORD=${secret:secret/data/platform/postgres/kb#password} -RABBITMQ_USER=${secret:secret/data/platform/rabbitmq#rabbitmq.user} -RABBITMQ_PASSWORD=${secret:secret/data/platform/rabbitmq#rabbitmq.password} diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/env/knowledge-api/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/env/knowledge-api/base.env deleted file mode 100644 index 6654173fe..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/env/knowledge-api/base.env +++ /dev/null @@ -1,36 +0,0 @@ -# applications/knowledge/platform/env/knowledge-api/base.env -# -# The Process scope: what only this Process receives -# (docs/adr/model/0013-configuration-is-dotenv-at-three-scopes.md). What both -# Processes receive is one directory up, in env/_applications/knowledge/base.env. -# Literals are literal. Derived values are named placeholders. A literal for a -# derived key is a build error, and so is any OTEL_* or PYROSCOPE_* key -- -# those come from runtime: jvm. - -# --- app knobs -SPRING_PROFILES_ACTIVE=prod -KB_RECALL_DEFAULT_MODE=hybrid -KNOWLEDGE_MODE=lite - -# --- this Process's own secret: the API serves /mcp and the worker does not, so -# the grant is on the Process and so is the reference that binds it. -# The string between ${secret: and # is the same string the grant writes as -# `path:` -- mount and KV `data/` segment included -- so -# E_UNAUTHORISED_SECRET_REFERENCE and the dead-grant check are string -# comparisons over the composed union -# (docs/adr/model/0030-secret-delivery-is-env-file-or-self.md). The `#` half -# selects which value fills the variable and confers nothing: the grant -# unit is the path. -KNOWLEDGE_MCP_TOKENS_WORKSTATION=${secret:secret/data/knowledge-system/mcp-bearer#workstation} - -# The placeholder names the source; the key names the variable. That is what -# lets knowledge write DB_USER where another consumer of the same Postgres -# writes DB_POSTGRESDB_USER. Renaming a path edits the grant and every -# placeholder naming it in lockstep -- which is also what made the -# platform/postgres split a mechanical change: one grep finds every reader. - -# NOT here, and a build error if they were: -# SERVER_PORT -> from `provides` on this Process -# DEPLOYMENT_ENVIRONMENT -> from the cluster the render is for -# OTEL_* (10 keys) -> from runtime: jvm -# PYROSCOPE_* (6 keys) -> from runtime: jvm diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/env/knowledge-ingest-worker/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/env/knowledge-ingest-worker/base.env deleted file mode 100644 index 7f4c368cb..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/env/knowledge-ingest-worker/base.env +++ /dev/null @@ -1,16 +0,0 @@ -# applications/knowledge/platform/env/knowledge-ingest-worker/base.env -# -# The second Process of the same Application, and therefore the second file: -# Processes of one Application do not share every variable -# (docs/adr/model/0013-configuration-is-dotenv-at-three-scopes.md). What they do -# share is one directory up, in env/_applications/knowledge/base.env, which is -# where the Postgres and RabbitMQ coordinates and credentials now live: nine -# lines that used to sit in both Process files, identically. -# -# Note what is not here either. The deploy key is a Process-level grant with -# delivery: file, so it has no placeholder at all -- it lands on disk at 0400. - -# --- app knobs, none of them shared with the api -INGEST_QUEUE=knowledge.ingest -INGEST_PREFETCH=4 -LOG_LEVEL=INFO diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/knowledge.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/knowledge.project.yml deleted file mode 100644 index 659a23938..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/knowledge/knowledge.project.yml +++ /dev/null @@ -1,352 +0,0 @@ -# Worked example: the knowledge project's Intent Fragment -# -# applications/knowledge/platform/knowledge.project.yml -# -# One file per project, one file one Intent Fragment -# (docs/adr/model/0009-intent-is-authored-one-file-per-project.md). The knowledge project owns two -# Applications; the namespace derives from the header as knowledge-system, -# which is the namespace both already run in. -# -# Exercises: two Applications because their cutovers differ, two Processes on -# two runtimes and therefore two identities, one -# authored hostname whose five routes carry mixed audiences -- four anonymous -# overrides inside an authenticated host -- `probes: none` for a Process with -# no listener, grants at the project header and on a Process, a split Subtree -# path beside an unsplit one, and an irreplaceable volume. -# -# Companion env files, one per PROCESS, plus the variables both Processes share -# at the project scope (docs/adr/model/0013-configuration-is-dotenv-at-three-scopes.md): -# platform/env/_project/base.env -# -- reproduced as env/_project/base.env -# platform/env/knowledge-api/base.env -# -- reproduced as env/knowledge-api/base.env -# platform/env/knowledge-ingest-worker/base.env -# -- reproduced as env/knowledge-ingest-worker/base.env - -# The data model's own semver, not the toolkit's -# (docs/adr/model/0032-the-resolved-deployment-is-a-versioned-artifact.md). -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -project: knowledge -owner: joris # the project's own - -# Shared grants, one of the eight Shared Intent families -# (docs/adr/model/0012-shared-intent-descends-and-is-lowered.md). Both Processes read -# the same Postgres and RabbitMQ credentials, so declaring them once here is -# the difference between one edit and two when a key is added. A shared grant -# is held by every Process below it, including ones added later; a Process -# that needs different terms on one of these paths says so on the Process, -# and a Process that must not hold one at all is evidence it was never -# shared, so it moves down a level. There is no removal syntax. -# -# They sit at the project header because the two Processes are now two -# Applications. A project-level grant hands every Application in the file a -# reader slot on the whole path -# (docs/adr/model/0008-vault-read-is-per-path.md), and that is exactly this -# file's reader set: both of its Applications, and nothing else. -# -# `delivery: env` and `delivery: file` render a Kubernetes Secret, so both -# are refused unless the pinned Platform document advertises -# `secretsEncryption: true` -- E_SECRETS_AT_REST_REQUIRED -# (docs/adr/model/0030-secret-delivery-is-env-file-or-self.md). Until that flag lands on the -# pinned k3s version, knowledge cannot ship. -secrets: - # Hand-written for now. Once the resolver derives the data credential from - # the edge to platform-postgres (#92), this grant is what that derivation - # replaces, and it goes. - # - # SPLIT PATH, one path per reader set - # (docs/adr/model/0028-grant-unit-is-the-path.md). A KV-v2 read returns the - # whole document, so the only boundary the store can enforce is the path: - # while every consumer's credentials shared secret/data/platform/postgres, - # these pods could read auth-api's database password. The reader set here - # is knowledge's two Applications; auth-api reads .../postgres/auth. - - path: secret/data/platform/postgres/kb - keys: [user, password] - access: read - delivery: env - rotation: {tolerates: restart} - - # NOT split. Its reader set is already exactly this project's two - # Processes, and the rule is one path per reader SET, not one path per - # consumer. It splits on the day a third reader is granted it. - - path: secret/data/platform/rabbitmq - keys: [rabbitmq.user, rabbitmq.password] - access: read - delivery: env - rotation: {tolerates: restart} - -applications: - # =============================================================== knowledge - - id: knowledge - # REQUIRED: knowledge-api's edge to platform-postgres derives the project's - # database, knowledge_db. This Application moves its schema, with a - # Liquibase YAML changelog the platform's runner applies before the new - # version starts (spec/v1/10-project-intent.md#migration). - migration: - changelog: knowledge-api/src/main/resources/db/changelog.yml - - # Per Application; never raised to the project. The api Process publishes for - # the Application, and the ingest worker publishes nothing of its own. - observability: - scrape: - process: knowledge-api - surface: http - path: /api/actuator/prometheus - - # One Process, which releases blue/green: its new version starts beside the - # old one and takes traffic only once it has passed analysis. The ingest - # worker used to be a second Process here, and cannot be: its ReadWriteOnce - # volume forces a stop-start cutover, and one Application switches as one - # (docs/adr/model/0052-an-application-is-the-release-unit.md), so a continuous - # API and an interrupted worker in one Application is - # E_RELEASE_UNIT_MIXED_CUTOVER. The worker is `knowledge-ingest`, below. - # - # An Application is still not a Reconcile Unit: `platform-postgres` before - # `knowledge` is ordering, derived from the edge set - # (docs/adr/model/0033-reconcile-unit-derived.md), and the later unit waits rather - # than being held. - - # ONE hostname, ONE Process behind it -- and it still belongs to the - # Application, because `exposure` says *this hostname routes here* while - # `provides` says *this process listens on this port* - # (review/EXPOSURE-MANIFEST.md). - # - # `host` is the full FQDN, authored. Nothing derives it: the estate also - # answers on kb.jorisjonkers.dev, `platform-rabbitmq` serves rabbitmq, and - # `status` belongs to no Application -- a `.` rule would be right - # here and silently wrong there, and the wrong ones are the ones nobody - # checks. This block replaces the six places the hostname used to be - # declared independently: both catalogs, both IngressRoutes, the - # reachability channel and the Gatus endpoint. - exposure: - - name: public # unique within the Application, and what - # ${exposure:knowledge.public#url} addresses - host: knowledge.jorisjonkers.dev - audience: authenticated # the exposure's audience is the default for - # every route under it - routes: - # PER-ROUTE `audience` IS AN OVERRIDE, and this is the case it exists - # for: anonymous paths inside an authenticated host. /mcp answers a - # workstation holding only a bearer token, and the two install - # scripts are fetched by curl before any session exists. The `/` - # catch-all keeps the Application's audience, so everything else is - # behind forward-auth -- derived from the audience, never named here - # (docs/adr/model/0023-exposure-is-declared-by-audience.md). - # - # Written as block mappings rather than one-liners only because five - # fields do not fit a line; the shape is the same one auth's two - # routes use. - - path: /mcp - match: exact - process: knowledge-api - surface: http - audience: anonymous # override - - path: /mcp/ - match: prefix - process: knowledge-api - surface: http - audience: anonymous # override - - path: /install.sh - match: exact - process: knowledge-api - surface: http - audience: anonymous # override - - path: /install-agents.sh - match: exact - process: knowledge-api - surface: http - audience: anonymous # override - - path: / - match: prefix - process: knowledge-api - surface: http # no `audience`: the Application's stands - # No `contentPolicy`: this Application picks no CSP profile, so it takes the - # baseline the tier derives. The field is optional and the vocabulary - # stops there -- `contentPolicy` and `redirectTo` are the whole of what - # an author may say about the proxy. - - processes: - # ------------------------------------------------------ knowledge-api - - name: knowledge-api - # Identity is the Process name under the project namespace: - # `knowledge-system.knowledge-api` - # (docs/adr/model/0031-identity-per-process.md). - lifecycle: application - image: knowledge-api # alias -> digest through the images lock - runtime: jvm # -> otel-jvm profile: 10 OTEL, 6 PYROSCOPE - - # The JVM writes to /tmp. Declared, mounted as an emptyDir, and the - # read-only root control stays intact - # (docs/adr/model/0020-hardening-is-one-platform-posture.md). - writablePaths: [/tmp] - - # Surfaces are a property of the process, so they sit on the Process. - # The rendered Kubernetes port name is the surface name, which is how - # 'http' survives. A consumer names the Application and the surface, never - # a port integer: `dependsOn: {application: knowledge, surface: http}`. - provides: - http: 8080 - - # Hard dimensions, all of which must match - # (docs/adr/model/0017-placement-is-hard-dimensions.md). - placement: - memory: 768Mi # a JVM application at its default heap. Raw, not a - # class: a class name cannot be compared to a - # node's allocatable without carrying the table, - # and the comparison is now arithmetic - cpu: 250m # request only; no cpu limit is derived - capabilities: [public-ingress] - # frankfurt-contabo-1 is the only node advertising public-ingress, so - # this replaces `nodeSelector: {site: frankfurt}` without naming a - # site. It is a hard filter like every other dimension: if the - # capability leaves the fleet, the build fails with - # E_PLACEMENT_UNSATISFIABLE rather than the pod placing anywhere and - # the surface going dark. - - # No `hardening` block. The default `restricted` class applies - # unstated: runAsNonRoot, readOnlyRootFilesystem, drop ALL, seccomp - # RuntimeDefault. This image is built here and meets it - # (docs/adr/model/0020-hardening-is-one-platform-posture.md). - - dependsOn: - - {application: platform-postgres, surface: postgres} - - {application: platform-rabbitmq, surface: amqp} - - # No `exposure` here: the five routes and the hostname they hang off - # sit on the Application above, and each route names this Process and its - # `http` surface. `provides` is what stays. - - probes: - readiness: - path: /api/actuator/health/readiness - port: 8080 - liveness: - path: /api/actuator/health/liveness - port: 8080 - # Distinct paths, stated. A liveness probe on the readiness endpoint - # turns a Postgres outage into a crash-loop - # (docs/adr/model/0016-probes-are-siblings-and-startup-targets-liveness.md). - - startupBudget: 600s # JVM cold start measured at ~250-300s - - # REQUIRED, no default. This Process holds no volume, and its owner - # requires continuity: the MCP endpoint 503s if a roll opens a gap. - cutover: continuous - - # No `replicas` block: the derived count is one. Capacity is the only - # local exception to a derived value, and this Process needs none. - - # Process-level grant: the API serves /mcp, the worker does not. This - # is an access boundary only because identity is per Process -- this - # pod authenticates as `knowledge-api` and the worker as - # `knowledge-ingest-worker`, each bound to exactly its own effective - # grant set, which is every level's list merged with this one - # (docs/adr/model/0031-identity-per-process.md). - secrets: - - path: secret/data/knowledge-system/mcp-bearer - keys: [workstation] - access: read - delivery: env - rotation: {tolerates: restart} - - # ======================================================== knowledge-ingest - - id: knowledge-ingest - # An Application of its own because its cutover is not the API's: the - # ReadWriteOnce volume below cannot attach to a second copy, so this Process - # stops before it starts, and an Application switches as one. It has no - # `observability` block and no exposure: it publishes nothing and listens on - # nothing. - # - # It reads the project's database too, and one Application of a project - # moves that schema: `knowledge` does, so this one declares that it moves - # none. A second changelog here would be E_MIGRATION_OWNER_DUPLICATED. - migration: none - # One plain sentence each, for a reader who sees only the name. It derives - # nothing and renders nothing (spec/v1/10-project-intent.md#describing-an-application-and-a-process). - description: Turns the notes dropped into the vault into searchable knowledge. - processes: - - name: knowledge-ingest-worker - description: Takes one note at a time off the queue and indexes it. - lifecycle: application - image: knowledge-ingest-worker - runtime: python # a different profile: 5 OTEL keys plus - # OTEL_PYTHON_LOG_CORRELATION, no JVM batch - # tuning - - # No `provides`. A RabbitMQ consumer opens no listener, so it declares - # no surface, nothing can depend on it, and the derived default-deny - # policy gives it no ingress at all - # (docs/adr/model/0035-network-policy-is-default-deny-and-render-only.md). - - placement: - memory: 256Mi # a single-consumer queue worker, not a server - cpu: 50m - # Nothing else is declared, and the volume below is why nothing more - # is needed: a `local-path` PV pins this Process to the node holding - # it. That pinning is DERIVED -- read from the pinned ClusterState - # snapshot (docs/adr/model/0034-cluster-state-is-a-pinned-input.md) -- rather - # than restated here as a dimension that could disagree with the - # binding. - - # Default `restricted` again, and nothing here fights it: the deploy key - # arrives on a projected volume, not on the root filesystem, so - # readOnlyRootFilesystem costs this Process nothing. - - dependsOn: - - {application: platform-rabbitmq, surface: amqp} - - {application: platform-postgres, surface: postgres} - - # A RabbitMQ consumer with no listener. Declared, not omitted, so the - # absence is a decision rather than an oversight - # (docs/adr/model/0016-probes-are-siblings-and-startup-targets-liveness.md). - probes: none - - startupBudget: 120s - - # `interrupted`, and it is the only honourable answer: the ReadWriteOnce - # local-path volume below cannot attach to two pods at once, so - # `cutover: continuous` here is E_CUTOVER_UNHONOURABLE rather than a - # strategy silently derived to stop-start. The owner states the - # stop-then-start that the storage already forces. - cutover: interrupted - - # A file-level copy is the backup method for a directory of files, and - # `irreplaceable` derives one -- so the engine is required here - # (docs/adr/model/0018-durability-class-derives-a-backup.md, - # docs/adr/model/0019-engine-is-process-vocabulary.md). - engine: files - - volumes: - - claim: knowledge-vault-clone - mountAt: /var/lib/knowledge-vault - size: 20Gi - durability: irreplaceable - # The one fact only the owning Application knows - # (docs/adr/model/0018-durability-class-derives-a-backup.md); schedule, sweep - # and destination are derived. `irreplaceable` renders a backup job - # with retention plus an off-cluster copy, and its restore must be - # rehearsed before the first production apply - # (docs/adr/model/0049-datastore-and-restore.md). - # - # Not declared: storage class and volume size -- both draw on finite - # node disk and are assigned. A `placement.disk` dimension filters - # which nodes are ELIGIBLE to hold a claim; it does not decide how - # large the claim is. - - # Process-level, and `delivery: file` because an SSH private key cannot - # be an environment variable. This is the grant that makes per-Process - # identity load-bearing: under one identity per Application the - # internet-facing API Process would authenticate as a principal holding - # `read` on this key, and the store cannot narrow a read below the path - # (docs/adr/model/0008-vault-read-is-per-path.md). - secrets: - - path: secret/data/knowledge-system/vault-deploy-key - keys: [key] - access: read - delivery: file - mountAt: /home/worker/.ssh/id_ed25519 - fileMode: "0400" - rotation: {tolerates: restart} diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/mail/config/manifest.json b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/mail/config/manifest.json deleted file mode 100644 index 23bae5365..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/mail/config/manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "domains": [{ "name": "jorisjonkers.dev" }], - "accounts": [{ "name": "postmaster", "domain": "jorisjonkers.dev" }] -} diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/mail/mail.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/mail/mail.project.yml deleted file mode 100644 index dd0b502dc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/mail/mail.project.yml +++ /dev/null @@ -1,85 +0,0 @@ -# Worked example: mail's web admin, the live case of a route's redirect -# (spec/v1/10-project-intent.md#exposure). -# -# Exercises: a route that redirects. Stalwart serves its web admin under -# /admin/ and answers 404 at the bare root, so the root of the host redirects -# to /admin/. The redirect is the route's own: `match: exact` on `/`, so the -# path it lands on is served by the prefix route below and never redirected -# again (a redirect its own route matches is E_REDIRECT_LOOP). -# -# Also exercises: a raw surface on a node's own address -# (spec/v1/10-project-intent.md#l4-exposure). Mail's SMTP and IMAP listeners -# are reached on `mail-node`, the address of a node at a site with no pool, so -# each port renders a host port and the Process is held to that node. A host -# port holds one copy, so the cutover is `interrupted`: a `continuous` one is -# E_CUTOVER_UNHONOURABLE here. Mail's mailboxes are not this example's. -# -# Also exercises: a sidecar that mounts an Asset of its Process -# (spec/v1/10-project-intent.md#sidecars). The provisioner beside Stalwart -# applies the manifest of domains and accounts against the admin API on -# localhost. The manifest is the Process's Asset, rendered as its one -# content-hashed ConfigMap, and the sidecar names it by `from` to mount it; an -# Asset the Process does not hold is E_UNKNOWN_SIDECAR_ASSET. -# -# Also exercises: a container that listens below 1024 -# (spec/v1/10-project-intent.md#a-low-port-earns-net_bind_service). Stalwart -# binds 25 and 993, and its binary carries the file capability -# cap_net_bind_service+ep, which it cannot execute with every capability -# dropped, so its container adds NET_BIND_SERVICE back and nothing else. The -# sidecar listens on nothing and adds nothing. -# -# Also exercises: a home on the writable /tmp -# (spec/v1/10-project-intent.md#home-is-the-writable-tmp). The provisioner's CLI -# writes under $HOME, and its image names no user with one, so on a read-only -# root its home would be an unwritable /. The Process declares /tmp, which -# every container of its pod mounts, so each gets HOME=/tmp. - -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -project: mail # the namespace derives: mail-system -owner: joris - -applications: - - id: stalwart - exposure: - - name: admin - host: mail.jorisjonkers.dev - audience: authenticated # the web admin sits behind forward-auth - routes: - - { path: /, match: exact, process: stalwart, surface: http, redirectTo: /admin/ } - - { path: /, match: prefix, process: stalwart, surface: http } - l4Exposure: - - { address: mail-node, port: 25, protocol: tcp, process: stalwart, surface: smtp } - - { address: mail-node, port: 993, protocol: tcp, process: stalwart, surface: imaps } - # The breadth case's second port to one surface: the first is the surface's host port, this one a node port of its own. - - { address: mail-node, port: 2525, protocol: tcp, process: stalwart, surface: smtp } - processes: - - name: stalwart - lifecycle: application - image: stalwart - runtime: none - provides: - http: 8080 - smtp: 25 - imaps: 993 - placement: - memory: 512Mi - cpu: 100m - probes: - readiness: { path: /healthz/ready, port: 8080 } - liveness: { path: /healthz/live, port: 8080 } - startupBudget: 60s - cutover: interrupted - writablePaths: [/tmp] - assets: - - from: config/manifest.json - mountAt: /etc/stalwart-provisioner/manifest.json - sidecars: - - name: stalwart-apply - image: stalwart-provisioner - memory: 64Mi - cpu: 10m - assets: - - { from: config/manifest.json, mountAt: /etc/stalwart-provisioner/manifest.json } diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/minimal/env/notes-api/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/minimal/env/notes-api/base.env deleted file mode 100644 index 4d795bc46..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/minimal/env/notes-api/base.env +++ /dev/null @@ -1,14 +0,0 @@ -# One env file set per Process. Literals are written literally; a derived value -# is a named placeholder and writing one as a literal is a build error. -# -# This Process needs no placeholder at all: it has no dependency edge, no grant -# and no exposure reference of its own. That is what makes it the minimal case. - -NODE_ENV=production -NOTES_PAGE_SIZE=50 - -# Not written here, and a build error if they were: -# -# PORT -> from `provides` -# OTEL_*, PYROSCOPE_* -> from `runtime: node` -# DEPLOYMENT_ENVIRONMENT -> a pinned Platform Intent fact diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/minimal/notes.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/minimal/notes.project.yml deleted file mode 100644 index 7f7def148..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/minimal/notes.project.yml +++ /dev/null @@ -1,81 +0,0 @@ -# The smallest complete Project Intent in the model. -# -# One project, one Application, one Process, and nothing that is not required. -# Everything absent from this file is either derived (chapter 20) or refused -# (chapter 10). It is the file to read first, and the file to copy when -# onboarding an Application that has no storage and no secrets. -# -# The one field beyond those is `libraries`: the worked mount of a library the -# Platform document declares and grants this project. -# -# It is also the only worked example that renders on today's pinned inputs: -# it holds no grant, so the secrets-at-rest gate -# (docs/adr/model/0030-secret-delivery-is-env-file-or-self.md) has nothing to refuse. - -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -project: notes # the namespace derives: notes-system -owner: joris # the project's own; this project shares no intent below it - -applications: - - id: notes - # Whole or absent. The class states urgency; the scrape names the Process - # and the surface that carries the signal, so the port is declared once, in - # `provides`. Omitting the block entirely is how an Application says it wants no - # monitoring -- there is no `none` to write. - observability: - scrape: - process: notes-api - surface: http - path: /metrics - - exposure: - - name: public - host: notes.jorisjonkers.dev # the full FQDN, authored - audience: anonymous # selects the tier that carries it - contentPolicy: strict - routes: - - { path: /, match: prefix, process: notes-api, surface: http } - - processes: - - name: notes-api - lifecycle: application - image: notes-api # an alias; the lock resolves digest, uid and gid - runtime: node - - provides: - http: 8080 # the image's own port; any port binds (chapter 14) - - # Two dimensions are required. Both are matched against what the node - # contract publishes, never against free capacity - # (docs/adr/model/0017-placement-is-hard-dimensions.md). `gpu` locks - # the card, and the request and runtime class are derived from it - # (docs/adr/model/0106-a-gpu-request-is-derived-from-placement.md). - placement: - memory: 256Mi - cpu: 50m - gpu: { class: transcode, model: [t1000] } - - probes: - readiness: { path: /healthz/ready, port: 8080 } - liveness: { path: /healthz/live, port: 8080 } - - startupBudget: 20s - - # REQUIRED, no default. No volumes, so a continuous cutover is honourable. - cutover: continuous - - # A directory the Platform document declares and grants this project, - # mounted below one of its folders. It places the Process on the - # library's node and runs it with the library's group, and is not a - # volume of its own (spec/v1/10-project-intent.md#libraries). - libraries: - - library: media - mountAt: /attachments - subPath: Notes - access: write - - # No `replicas` block: the derived count is one, and one is what this - # Process runs. The block is for a count above one, with a reason. diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/observability/env/grafana/base.env b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/observability/env/grafana/base.env deleted file mode 100644 index a223ed7b4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/observability/env/grafana/base.env +++ /dev/null @@ -1,16 +0,0 @@ -# grafana signs people in itself, as a native Client of the Identity Provider. -# Everything it needs to know about that Client is a placeholder: the Issuer is -# the Platform document's, the Client id is the Application Id, and the secret -# is read from the credential path the Client derives, which the provider -# writes (spec/v1/17-sign-in.md#credentials-and-placeholders). - -GF_SERVER_ROOT_URL=${exposure:grafana.public#url} -GF_AUTH_GENERIC_OAUTH_ENABLED=true -GF_AUTH_GENERIC_OAUTH_NAME=jorisjonkers.dev -GF_AUTH_GENERIC_OAUTH_CLIENT_ID=${client:id} -GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET=${client:secret} -GF_AUTH_GENERIC_OAUTH_AUTH_URL=${client:issuer}/oauth2/authorize -GF_AUTH_GENERIC_OAUTH_TOKEN_URL=${client:issuer}/oauth2/token -GF_AUTH_GENERIC_OAUTH_API_URL=${client:issuer}/userinfo -GF_AUTH_GENERIC_OAUTH_SCOPES=openid,profile,email -GF_AUTH_DISABLE_LOGIN_FORM=true diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/observability/observability.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/observability/observability.project.yml deleted file mode 100644 index b78e5e56f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/observability/observability.project.yml +++ /dev/null @@ -1,351 +0,0 @@ -# The telemetry collector and the metrics stack as Project Intent: the -# Applications the worked Platform document's `telemetry` block names -# (spec/v1/14-platform-intent.md#telemetry). -# -# Every Process whose Runtime Profile exports telemetry is handed this -# collector's `otlp` surface as its endpoint -# (spec/v1/10-project-intent.md#runtime-profiles), so no project writes the -# address and none can write it wrong. - -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -project: observability # the namespace derives: observability-system -owner: joris - -applications: - - id: otel-collector - processes: - - name: otel-collector - lifecycle: application - image: otel-collector - runtime: none - provides: - otlp: 4317 - health: 13133 - placement: - memory: 256Mi - cpu: 50m - probes: - readiness: { path: /, port: 13133 } - liveness: { path: /, port: 13133 } - startupBudget: 20s - cutover: continuous - - # The metrics stack the Platform document's `telemetry.metrics` names: every - # declared scrape surface admits it, and nothing else scrapes - # (spec/v1/16-dependencies.md#the-derived-allow-set). - - id: prometheus - # The platform's alert rules: only the monitoring stack carries them - # (spec/v1/10-project-intent.md#alert-rules). - alertRules: - - {from: rules/platform.yaml} - processes: - - name: prometheus - lifecycle: application - image: prometheus - runtime: none - provides: - http: 9090 - placement: - memory: 512Mi - cpu: 100m - writablePaths: [/prometheus] - # The breadth case's flags: those the operator's object carries as fields - # of its own, and two it passes on as arguments. - args: - - --storage.tsdb.retention.time=15d - - --storage.tsdb.retention.size=10GB - - --enable-feature=exemplar-storage - - --enable-feature=native-histograms - - --web.enable-remote-write-receiver - - --log.level=info - - --query.max-concurrency - probes: - readiness: { path: /-/ready, port: 9090 } - liveness: { path: /-/healthy, port: 9090 } - startupBudget: 60s - # The operator replaces its one pod in place. - cutover: interrupted - api: - reason: >- - Prometheus discovers every monitor's targets through the API, cluster-wide - rules: - - group: core - objects: [services, endpoints, pods] - verbs: [get, list, watch] - - group: discovery.k8s.io - objects: [endpointslices] - verbs: [get, list, watch] - - # The Prometheus operator: Prometheus, Alertmanager and every monitor and - # rule are objects the render emits, and it reconciles them cluster-wide, - # running the monitoring stack's Prometheus and Alertmanager below. - - id: prometheus-operator - processes: - - name: prometheus-operator - lifecycle: application - image: prometheus-operator - runtime: none - provides: - http: 8080 - placement: - memory: 128Mi - cpu: 50m - probes: - readiness: { path: /healthz, port: 8080 } - liveness: { path: /healthz, port: 8080 } - startupBudget: 30s - cutover: interrupted - api: - reason: >- - the operator reconciles every monitor, rule and Alertmanager routing object into the Prometheus and Alertmanager configuration, cluster-wide - rules: - - group: monitoring.coreos.com - objects: [prometheuses, prometheuses/status, alertmanagers, alertmanagers/status, servicemonitors, podmonitors, prometheusrules, alertmanagerconfigs] - verbs: [get, list, watch, create, update, patch, delete] - - group: core - objects: [services, endpoints, pods, nodes, namespaces, configmaps, secrets] - verbs: [get, list, watch, create, update, delete] - - group: apps - objects: [statefulsets] - verbs: [get, list, watch, create, update, delete] - - # The cluster's object state as metrics. - - id: kube-state-metrics - processes: - - name: kube-state-metrics - lifecycle: application - image: kube-state-metrics - runtime: none - provides: - http: 8080 - telemetry: 8081 - placement: - memory: 128Mi - cpu: 20m - probes: - readiness: { path: /livez, port: 8080 } - liveness: { path: /livez, port: 8080 } - startupBudget: 30s - cutover: continuous - api: - reason: >- - kube-state-metrics reports the state of every object it lists, cluster-wide - rules: - - group: core - objects: [pods, nodes, namespaces, services, persistentvolumeclaims, persistentvolumes] - verbs: [list, watch] - - group: apps - objects: [deployments, statefulsets, daemonsets, replicasets] - verbs: [list, watch] - - group: batch - objects: [jobs, cronjobs] - verbs: [list, watch] - - # The operator that hands the Grafana below every Application's dashboards. - - id: grafana-operator - processes: - - name: grafana-operator - lifecycle: application - image: grafana-operator - runtime: none - provides: - metrics: 8080 - health: 8081 - placement: - memory: 64Mi - cpu: 20m - probes: - readiness: { path: /healthz, port: 8081 } - liveness: { path: /healthz, port: 8081 } - startupBudget: 30s - cutover: interrupted - api: - reason: >- - the operator imports every Application's dashboards into the Grafana it selects, cluster-wide - rules: - - group: grafana.integreatly.org - objects: [grafanas, grafanas/status, grafanadashboards, grafanadashboards/status] - verbs: [get, list, watch, update, patch] - - group: core - objects: [configmaps, secrets] - verbs: [get, list, watch] - - # Grafana signs people in itself, as a native Client of the identity - # project's provider, holding a secret (spec/v1/17-sign-in.md). Every path - # is on the exposure's host, which is authored once, there. The env file - # reads the credential through ${client:secret}, which derives the Process's - # read grant on the path the provider writes. - - id: grafana - exposure: - - name: public - host: grafana.jorisjonkers.dev - audience: authenticated - routes: - - { path: /, match: prefix, process: grafana, surface: http } - client: - signIn: native - label: Grafana - description: Metrics and dashboards - iconPath: /public/img/grafana_icon.svg - redirectPaths: [/login/generic_oauth] - protectedPath: /api/user - credential: secret - roles: [viewer, editor, admin] - processes: - - name: grafana - lifecycle: application - image: grafana - runtime: none - provides: - http: 3000 - placement: - memory: 256Mi - cpu: 50m - writablePaths: [/var/lib/grafana] - probes: - readiness: { path: /api/health, port: 3000 } - startupBudget: 30s - cutover: continuous - - # The loki store, which keeps what it is sent on a claim of its own. - - id: loki - processes: - - name: loki - lifecycle: application - image: loki - runtime: none - provides: - http: 3100 - placement: - memory: 512Mi - cpu: 100m - probes: - readiness: { path: /ready, port: 3100 } - liveness: { path: /ready, port: 3100 } - startupBudget: 30s - cutover: interrupted - volumes: - - { claim: loki, mountAt: /loki, size: 10Gi, durability: reconstructible } - - # The tempo store, which keeps what it is sent on a claim of its own. - - id: tempo - processes: - - name: tempo - lifecycle: application - image: tempo - runtime: none - provides: - http: 3200 - placement: - memory: 512Mi - cpu: 100m - probes: - readiness: { path: /ready, port: 3200 } - liveness: { path: /ready, port: 3200 } - startupBudget: 30s - cutover: interrupted - volumes: - - { claim: tempo, mountAt: /var/tempo, size: 10Gi, durability: reconstructible } - - # The pyroscope store, which keeps what it is sent on a claim of its own. - - id: pyroscope - processes: - - name: pyroscope - lifecycle: application - image: pyroscope - runtime: none - provides: - http: 4040 - placement: - memory: 512Mi - cpu: 100m - probes: - readiness: { path: /ready, port: 4040 } - liveness: { path: /ready, port: 4040 } - startupBudget: 30s - cutover: interrupted - volumes: - - { claim: pyroscope, mountAt: /data, size: 10Gi, durability: reconstructible } - - # Gatus, which gathers every Project's external checks through its sidecar - # (spec/v1/14-platform-intent.md#the-foundation-is-declared). - - id: gatus - processes: - - name: gatus - lifecycle: application - image: gatus - runtime: none - provides: - http: 8080 - placement: - memory: 64Mi - cpu: 20m - probes: - readiness: { path: /health, port: 8080 } - liveness: { path: /health, port: 8080 } - startupBudget: 30s - cutover: interrupted - sidecars: - - name: checks - image: gatus-checks - memory: 32Mi - cpu: 10m - api: - reason: >- - the checks sidecar watches every Project's external-checks ConfigMap, cluster-wide - rules: - - group: core - objects: [configmaps] - verbs: [get, list, watch] - - # The log collector: an ordinary Process that tails pod logs through the - # Kubernetes API, with no host privilege and one copy, not one per node. - - id: alloy - processes: - - name: alloy - lifecycle: application - image: alloy - runtime: none - provides: - http: 12345 - placement: - memory: 256Mi - cpu: 50m - probes: - readiness: { path: /-/ready, port: 12345 } - liveness: { path: /-/ready, port: 12345 } - startupBudget: 30s - cutover: continuous - api: - reason: >- - Alloy tails every pod's log through the API, cluster-wide - rules: - - group: core - objects: [pods, pods/log, namespaces] - verbs: [get, list, watch] - - # The monitoring stack's Alertmanager, which the Platform document names by - # role; the one routing of every alert renders into its namespace, and each - # receiver's webhook reaches it through the one secret delivery - # (spec/v1/14-platform-intent.md#monitoring). - - id: alertmanager - processes: - - name: alertmanager - lifecycle: application - image: alertmanager - runtime: none - provides: - http: 9093 - placement: - memory: 128Mi - cpu: 50m - writablePaths: [/alertmanager] - probes: - readiness: { path: /-/ready, port: 9093 } - liveness: { path: /-/healthy, port: 9093 } - startupBudget: 30s - # The operator replaces its one pod in place. - cutover: interrupted diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/observability/rules/platform.yaml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/observability/rules/platform.yaml deleted file mode 100644 index ababfb5b6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/observability/rules/platform.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# The platform's own alert rules, carried by the monitoring stack's Prometheus -# (spec/v1/10-project-intent.md#alert-rules). A rule's `severity` label picks -# the route the Platform document's monitoring block declares for it. -groups: - - name: platform - rules: - - alert: JobFailed - expr: kube_job_status_failed > 0 - for: 5m - labels: - severity: warning - annotations: - summary: "Job {{ $labels.namespace }}/{{ $labels.job_name }} failed" - - alert: TargetDown - expr: up == 0 - for: 10m - labels: - severity: critical - annotations: - summary: "{{ $labels.job }} on {{ $labels.instance }} is down" - # The breadth case's group: a file is read as the YAML it is, so a number, a - # boolean, a null and an empty mapping reach the PrometheusRule as written. - - name: breadth - interval: 1m - limit: 10 - rules: - - record: breadth:up:sum - expr: | - sum(up) - by (job) - labels: {} - annotations: {paged: false, runbook: null, note: 'say "up"'} diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/cluster-state.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/cluster-state.yml deleted file mode 100644 index f3d8d87b0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/cluster-state.yml +++ /dev/null @@ -1,18 +0,0 @@ -# The ClusterState snapshot: what the cluster alone can say, captured once by -# a read-only collector and pinned by digest -# (spec/v1/20-resolved-deployment.md#cluster-state). Nothing reads the live -# cluster; a changed fact is a new capture and a new digest. -# -# The worked estate has no bound PersistentVolume and records no placement yet, -# so the snapshot is the empty one: both lists present, both empty. - -apiVersion: state.jorisjonkers.dev/v1 -kind: ClusterState -schemaVersion: 1.0.0 -cluster: production -capturedAt: "2026-09-30T00:00:00Z" - -bindings: - - { claim: coverage-data, node: enschede-pi-1 } -placements: - - { process: coverage-api, node: enschede-pi-1 } diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/images.lock.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/images.lock.yml deleted file mode 100644 index 0364c3cad..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/images.lock.yml +++ /dev/null @@ -1,429 +0,0 @@ -# The images lock: every image alias the estate's documents name, resolved to -# one digest, the user the image runs as and the version of the software in it -# (spec/v1/20-resolved-deployment.md#the-images-lock). A pinned input like any -# other, carried by digest in every Resolved Deployment rendered from it. -# -# An alias is what a Process's `image` names; nothing authored names a tag or a -# digest. `uid` and `gid` are what the image's own user is, read once when the -# lock is written, and what the one hardening posture runs it as. - -apiVersion: lock.jorisjonkers.dev/v1 -kind: ImagesLock -schemaVersion: 1.0.0 -name: estate - -images: - asset-sync: - repository: ghcr.io/jorisjonkers-dev/platform/asset-sync - digest: "sha256:5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e" - uid: 65532 - gid: 65532 - version: "1.0.0" - collector: - repository: ghcr.io/jorisjonkers-dev/delivery/collector - digest: "sha256:7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e7b9d" - uid: 65532 - gid: 65532 - version: "1.0.0" - reporter: - repository: ghcr.io/jorisjonkers-dev/delivery/reporter - digest: "sha256:4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f" - uid: 65532 - gid: 65532 - version: "1.0.0" - file-backup: - repository: ghcr.io/jorisjonkers-dev/platform/file-backup - digest: "sha256:2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d" - uid: 1000 - gid: 1000 - version: "1.2.0" - agents-api: - repository: ghcr.io/jorisjonkers-dev/agents/agents-api - digest: "sha256:7a1c3e5b9d2f4a6c8e0b2d4f7e1f3c5a9b2d4f6e8a0c2e4b6d8f5a2c4e6b8d0f" - uid: 1000 - gid: 1000 - version: "2.3.0" - agent-runner: - repository: ghcr.io/jorisjonkers-dev/agents/agent-runner - digest: "sha256:8b2d4f6e8a0c2e4b6d8f5a2c4e6b8d0f7a1c3e5b9d2f4a6c8e0b2d4f7e1f3c5a" - uid: 1000 - gid: 1000 - version: "2.3.0" - # agents as it runs live: hermes starts as root and drops to 10000, which is - # the user its data is owned by; the posture runs it as 10000 from the start. - hermes: - repository: docker.io/nousresearch/hermes-agent - digest: "sha256:64923faeae267792bf9bf87fe3b4c4869e35004e360c7df01730ad801b74d524" - uid: 10000 - gid: 10000 - version: "2026.8.31" - kubernetes-mcp-server: - repository: quay.io/containers/kubernetes_mcp_server - digest: "sha256:6d650f4bd6ac303ad82713c997e73a2d001602f9bf17392c9b9a0e30e29c6423" - uid: 1000 - gid: 1000 - version: "0.0.66" - agents-ui: - repository: ghcr.io/jorisjonkers-dev/agents-ui - digest: "sha256:5b41e0ab23e60fbb3f14f42fe5138e6c266aa1bf1289967bfc8a7f9f820bcbc6" - uid: 101 - gid: 101 - version: "0.19.1" - headlamp: - repository: ghcr.io/headlamp-k8s/headlamp - digest: "sha256:9c3e5a7b1d4f6a8c0e2b4d6f8a1c3e5b7d9f2a4c6e8b0d2f4a6c8e1b3d5f7a9c" - uid: 100 - gid: 101 - version: "v0.35.0" - adguard: - repository: docker.io/adguard/adguardhome - digest: "sha256:6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f7e1f3c5a9b2d4f6e8a0c2e4b6d8f5a2c4e" - uid: 1000 - gid: 1000 - version: "v0.107.79" - stalwart: - repository: docker.io/stalwartlabs/stalwart - digest: "sha256:5a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f7e1f3c5a9b2d4f6e8a0c2e4b6d8f" - uid: 2000 - gid: 2000 - version: "v0.16.0" - stalwart-provisioner: - repository: ghcr.io/jorisjonkers-dev/stalwart-provisioner - digest: "sha256:7d1f3b5a9c2e4f6b8d0a2c4e6f8b1d3a5c7e9f2b4d6a8c0e2f4b6d8a1c3e5f7b" - uid: 65532 - gid: 65532 - version: "0.22.0" - alertmanager: - repository: quay.io/prometheus/alertmanager - digest: "sha256:4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f7e1f3c5a9b2d4f6e8a0c2e4b6d8f5a2c" - uid: 65534 - gid: 65534 - version: "v0.28.1" - gluetun: - repository: docker.io/qmcgaw/gluetun - digest: "sha256:7e1f3c5a9b2d4f6e8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f" - uid: 0 - gid: 0 - version: "v3.40.0" - # The seeder (spec/v1/14-platform-intent.md#the-seeder): Docker Hub's - # busybox 1.37.0, its multi-arch index, which runs as nobody. - busybox: - repository: docker.io/library/busybox - digest: "sha256:a7dbc319b1438115a207e11930dc4bb3e643dcb3ec0bdd694bb36cd8fad289ec" - uid: 65534 - gid: 65534 - version: "1.37.0" - flagger: - repository: ghcr.io/fluxcd/flagger - digest: "sha256:5d1b8f3e7a2c9d4b6e0f1a3c5e7b9d2f4a6c8e0b1d3f5a7c9e2b4d6f8a0c1e3b" - uid: 10001 - gid: 10001 - version: "1.41.0" - notes-api: - repository: ghcr.io/jorisjonkers-dev/notes/notes-api - digest: "sha256:9c1e5a4b7d2f8e3a6b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a" - uid: 1000 - gid: 1000 - version: "1.4.0" - otel-collector: - repository: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib - digest: "sha256:8e2c4a6f0b1d3e5a7c9f2b4d6e8a0c1f3b5d7e9a2c4f6b8d0e1a3c5f7b9d2e4a" - uid: 10001 - gid: 10001 - version: "0.120.0" - postgres-backup: - repository: ghcr.io/jorisjonkers-dev/platform/postgres-backup - digest: "sha256:6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f" - uid: 999 - gid: 999 - version: "1.2.0" - postgres-catalog: - repository: ghcr.io/jorisjonkers-dev/delivery/postgres-catalog - digest: "sha256:7e9a1c3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c" - uid: 65532 - gid: 65532 - version: "1.0.0" - garage-catalog: - repository: ghcr.io/jorisjonkers-dev/delivery/garage-catalog - digest: "sha256:3c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e" - uid: 65532 - gid: 65532 - version: "1.0.0" - prometheus: - repository: quay.io/prometheus/prometheus - digest: "sha256:4c6e8a0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c" - uid: 65534 - gid: 65534 - version: "v3.2.1" - mongo-backup: - repository: ghcr.io/jorisjonkers-dev/platform/mongo-backup - digest: "sha256:8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d" - uid: 999 - gid: 999 - version: "1.0.0" - rabbitmq-backup: - repository: ghcr.io/jorisjonkers-dev/platform/rabbitmq-backup - digest: "sha256:a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2" - uid: 999 - gid: 999 - version: "1.2.0" - release-gate: - repository: ghcr.io/jorisjonkers-dev/delivery/release-gate - digest: "sha256:3e7a9c1d5b2f8e4a6c0d9b7e5f3a1c8d6e4b2a0f9c7e5d3b1a8f6e4c2d0b9a7e" - uid: 1000 - gid: 1000 - version: "1.0.0" - traefik: - repository: docker.io/library/traefik - digest: "sha256:1f3d5b7a9c2e4f6a8b0d1c3e5f7a9b2d4c6e8f0a1b3d5c7e9f2a4b6d8c0e1f3a" - uid: 65532 - gid: 65532 - version: "v3.3.4" - vault: - repository: docker.io/hashicorp/vault - digest: "sha256:7e9a1c3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c" - uid: 100 - gid: 1000 - version: "1.18.5" - postgres-exporter: - repository: quay.io/prometheuscommunity/postgres-exporter - digest: "sha256:4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d" - uid: 65534 - gid: 65534 - version: "v0.17.1" - postgres: - repository: docker.io/pgvector/pgvector - digest: "sha256:9c1e3a5b7d9f1c3e5a7b9d1f3c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e" - uid: 999 - gid: 999 - version: "17.2.0" - rabbitmq: - repository: docker.io/library/rabbitmq - digest: "sha256:2d4f6b8a0c2e4d6f8b0a2c4e6d8f0b2a4c6e8d0f2b4a6c8e0d2f4b6a8c0e2d4f" - uid: 999 - gid: 999 - version: "4.0.7" - garage: - repository: docker.io/dxflrs/garage - digest: "sha256:8d0f2b4c6e8a0d2f4b6c8e0a2d4f6b8c0e2a4d6f8b0c2e4a6d8f0b2c4e6a8d0f" - uid: 1000 - gid: 1000 - version: "2.3.0" - mongo: - repository: docker.io/library/mongo - digest: "sha256:5f7b9d1a3c5e7f9b1d3a5c7e9f1b3d5a7c9e1f3b5d7a9c1e3f5b7d9a1c3e5f7b" - uid: 999 - gid: 999 - version: "8.0.15" - valkey: - repository: docker.io/valkey/valkey - digest: "sha256:6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c" - uid: 999 - gid: 1000 - version: "8.1.0" - auth-api: - repository: ghcr.io/jorisjonkers-dev/auth/auth-api - digest: "sha256:3e5a7c9b1d3f5e7a9c1b3d5f7e9a1c3b5d7f9e1a3c5b7d9f1e3a5c7b9d1f3e5a" - uid: 1000 - gid: 1000 - version: "2.3.0" - auth-ui: - repository: ghcr.io/jorisjonkers-dev/auth/auth-ui - digest: "sha256:8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d" - uid: 101 - gid: 101 - version: "2.3.0" - # Built FROM liquibase-runner with the Application's changelog in it, by the - # Application's own CI (spec/v1/14-platform-intent.md#migration-policy). - auth-migration: - repository: ghcr.io/jorisjonkers-dev/auth/auth-migration - digest: "sha256:5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7a9b1d3f5c7e" - uid: 1000 - gid: 1000 - version: "2.3.0" - vault-policy: - repository: ghcr.io/jorisjonkers-dev/delivery/vault-policy - digest: "sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7" - uid: 65532 - gid: 65532 - version: "1.0.0" - # The knowledge platform (spec/v1/examples/knowledge-platform): the digests fleet-infra pins. - # Where fleet-infra runs an image as its own user, that user is the lock's; karakeep's three - # run as their images' defaults there, which RENDER-GAPS.md beside the example records. - docling-serve: - repository: ghcr.io/docling-project/docling-serve - digest: "sha256:5d1a649d48b5715e23ec4906bb0624632b1971a1d975a4bc57d0f723114c7c6e" - uid: 1000 - gid: 1000 - version: "v1.5.0" - hindsight-api: - repository: ghcr.io/vectorize-io/hindsight-api - digest: "sha256:7b14a1f4062252992d0176758753615e0a2071d9a269995be007be223ab01812" - uid: 1000 - gid: 1000 - version: "0.4.0" - hindsight-control-plane: - repository: ghcr.io/vectorize-io/hindsight-control-plane - digest: "sha256:d9bf57083f7cb0a53ee5011bdfde6aae2490dbf5c360d2d1bff10473b45eb112" - uid: 1000 - gid: 1000 - version: "0.4.0" - text-embeddings-inference: - repository: ghcr.io/huggingface/text-embeddings-inference - digest: "sha256:8de25e75ce39617f17f2f6c77d60a4f75b65e779ed5005420eb1400072a15c1c" - uid: 1000 - gid: 1000 - version: "1.7.0" - basic-memory: - repository: ghcr.io/basicmachines-co/basic-memory - digest: "sha256:939f1173d96626c280763e14622f2381d49fbbb7db17cae2e832f4f639405643" - uid: 1000 - gid: 1000 - version: "v0.14.2" - basic-memory-git-sync: - repository: ghcr.io/jorisjonkers-dev/knowledge/basic-memory-git-sync - digest: "sha256:7507f69d7e903da30006f07d84091d892dfa42c359c125cccaec05506af36e50" - uid: 1000 - gid: 1000 - version: "1.0.0" - karakeep: - repository: ghcr.io/karakeep-app/karakeep - digest: "sha256:3d57623bf031f32a0597a3ebe0cd869bff6ba181c02ebc90fac492458bcfd4a4" - uid: 1000 - gid: 1000 - version: "0.33.2" - meilisearch: - repository: getmeili/meilisearch - digest: "sha256:860fa4baed04ae1c235de870edab0c8006227546dea1bbb6411fbfc5e27cf1db" - uid: 1000 - gid: 1000 - version: "v1.41.0" - karakeep-chrome: - repository: ghcr.io/karakeep-app/karakeep-chrome - digest: "sha256:5b19bbb160e9ff60681a3abd97e1c4ec9f64212301410de658c3900ab7ef31e7" - uid: 1000 - gid: 1000 - version: "124.0.6367.78" - # The worked sign-in (spec/v1/examples/identity): the Identity Provider and - # the Applications that sign people in through it, grafana among them, which - # the observability example declares. - identity: - repository: ghcr.io/jorisjonkers-dev/identity/identity - digest: "sha256:1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c" - uid: 65532 - gid: 65532 - version: "1.0.0" - grafana: - repository: docker.io/grafana/grafana - digest: "sha256:2c4e6a8b0d2f4c6e8a0b2d4f6c8e0a2b4d6f8c0e2a4b6d8f0c2e4a6b8d0f2c4e" - uid: 472 - gid: 472 - version: "12.2.0" - portal: - repository: ghcr.io/jorisjonkers-dev/identity/portal - digest: "sha256:3d5f7b9c1e3a5d7f9b1c3e5a7d9f1b3c5e7a9d1f3b5c7e9a1d3f5b7c9e1a3d5f" - uid: 101 - gid: 101 - version: "1.0.0" - whoami: - repository: docker.io/traefik/whoami - digest: "sha256:4e6a8c0d2f4b6e8a0c2d4f6b8e0a2c4d6f8b0e2a4c6d8f0b2e4a6c8d0f2b4e6a" - uid: 65532 - gid: 65532 - version: "v1.11.0" - dcgm-exporter: - repository: nvcr.io/nvidia/k8s/dcgm-exporter - digest: "sha256:6faf8666aeffe3aa674aa33eb59433addf6b8d5ec267ac1a096892d1ffab6a0b" - uid: 0 - gid: 0 - version: "4.1.1-4.0.4" - metallb-controller: - repository: quay.io/metallb/controller - digest: "sha256:8bd722cbf5d88cf8b9c82fed1ab069dc1a2f8e5ee383dcf57e49c359ee9d27a3" - uid: 65534 - gid: 65534 - version: "0.14.9" - metallb-speaker: - repository: quay.io/metallb/speaker - digest: "sha256:a2de24e2d206541cb9f101b66876944ecd5a2f19d1783d674e982bfb829defbe" - uid: 0 - gid: 0 - version: "0.14.9" - node-exporter: - repository: quay.io/prometheus/node-exporter - digest: "sha256:2303824a4e3dc61fe3195d1a6e978029d4774876cc9aba9d2c60ef85eb96a845" - uid: 65534 - gid: 65534 - version: "1.9.0" - nvidia-device-plugin: - repository: nvcr.io/nvidia/k8s-device-plugin - digest: "sha256:eeaf499dbb6f09bb79d95f788d3d87ca6ffa0ae36ed63210d5672e08ba266ff4" - uid: 0 - gid: 0 - version: "0.17.0" - external-dns: - repository: registry.k8s.io/external-dns/external-dns - digest: "sha256:32d7bec08ad97a73bf55e6bd4a434206f5eefb0b15adc05453203c72788fcd5d" - uid: 65532 - gid: 65532 - version: "0.15.1" - vault-secrets-operator: - repository: docker.io/hashicorp/vault-secrets-operator - digest: "sha256:286ccf0ef7da6fd261b12075a0e5c05f5df0a1676796614e5d8f53d9ddddfc7c" - uid: 65532 - gid: 65532 - version: "0.10.0" - prometheus-operator: - repository: quay.io/prometheus-operator/prometheus-operator - digest: "sha256:b32bec04dd57ec4c604c3f72b7103224b6006922536099eb5e92c017524819c6" - uid: 65534 - gid: 65534 - version: "0.81.0" - kube-state-metrics: - repository: registry.k8s.io/kube-state-metrics/kube-state-metrics - digest: "sha256:6e9bea4d3f394ba14fe405f6027d4d2187f751814702d595a0f68a9cc679171c" - uid: 65534 - gid: 65534 - version: "2.15.0" - grafana-operator: - repository: ghcr.io/grafana/grafana-operator - digest: "sha256:5689f1966f7e00acd0cdcff38ae0fc49d66469b384af9139412d645439937c2d" - uid: 65532 - gid: 65532 - version: "5.17.0" - loki: - repository: docker.io/grafana/loki - digest: "sha256:982945308d3682d16636fd628c314e293499e99c00120acd9b693f5ab16e1648" - uid: 10001 - gid: 10001 - version: "3.4.2" - tempo: - repository: docker.io/grafana/tempo - digest: "sha256:8d6546721a1d106cf8d27f7326ebae7e83c1592aeb7479b8f7ec9d8d700d464f" - uid: 10001 - gid: 10001 - version: "2.7.1" - pyroscope: - repository: docker.io/grafana/pyroscope - digest: "sha256:af2bcaf32f82481f3d0138ebd1f99ba2ca96ac6104acac0a10ee9b193e5df2af" - uid: 10001 - gid: 10001 - version: "1.12.0" - gatus: - repository: ghcr.io/twin/gatus - digest: "sha256:421c15f697f7992eb00e61643a4284e8d2f57bcc2eabea3639459fa1040add33" - uid: 65534 - gid: 65534 - version: "5.17.0" - gatus-checks: - repository: ghcr.io/jorisjonkers-dev/platform/gatus-checks - digest: "sha256:a542f60b6e21372a737b4f4dd62c5fd41d76939818b57b0ebb46b650f29dcd5a" - uid: 65532 - gid: 65532 - version: "1.0.0" - alloy: - repository: docker.io/grafana/alloy - digest: "sha256:65d9d6c5c7c2d5c29e38b777edf8da1dbd764f67deeeaa230724967cafe4e684" - uid: 473 - gid: 473 - version: "1.7.1" diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/node-contract.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/node-contract.yml deleted file mode 100644 index f2108b15a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/node-contract.yml +++ /dev/null @@ -1,135 +0,0 @@ -# The node contract: what each node can hold. -# -# GENERATED from one authored file per node, and pinned with the Platform -# Intent, which names this document by digest -# (spec/v1/60-setup.md#node-facts, docs/adr/model/0048-node-facts-are-authored-once.md). -# It is the other half of every placement comparison: a Process declares hard -# dimensions and layer 2 matches them against exactly these facts, never -# against a live cluster (docs/adr/model/0017-placement-is-hard-dimensions.md). -# -# `allocatable` is the node total minus the reserve the node's own file -# declares. It is an eligibility bound and NOT a budget: the contract records -# what a node has, never what already runs on it, so three Processes each -# declaring 2Gi all pass against a 4096Mi node and the scheduler refuses the -# third at apply. Nothing here, and nothing in layer 2, bin-packs. -# -# What this example takes from the specification, and what is its own: -# -# from chapter 60 the seven nodes, their sites, architectures, cpu and -# memory totals, their disks, which cards they hold, and -# every capability count -# its own the seven reserves, which chapter 60 records as authored -# guesses awaiting reconciliation against `kubectl describe -# node`; the two GPU memory figures the chapter does not -# state; and which node carries `adguard`, `lan-ingress`, -# `llm-host` and `backup-store`, where the chapter gives the -# count but not the node -# -# The capabilities the chapter does determine are placed where it puts them: -# `nvidia` on the two nvidia cards, `amd-gpu` on the Radeon, `public-ingress` -# on the one node that advertises it, and `samba` on the node that lets -# jellyfin and immich avoid the Maxwell card. `tailscale` is on all seven -# nodes, so it is not a capability: a filter that excludes nothing teaches -# authors that filters do nothing. No node carries a taint. - -apiVersion: contract.jorisjonkers.dev/v1 -kind: NodeContract -schemaVersion: 1.0.0 - -cluster: production - -# The selector key prefix. It comes from here rather than from the platform's -# name, so retiring a prefix changes rendered output for every Process carrying -# a selector, and retirement goes through this document rather than through a -# hand-applied label that drifts back on the next reconcile. -labelPrefix: platform.jorisjonkers.dev - -nodes: - # ---------------------------------------------------------------- enschede - - name: enschede-t1000-1 - site: enschede - arch: amd64 - allocatable: { cpu: 53500m, memory: 31488Mi } # 54000m / 32000Mi total - capabilities: [nvidia, samba, lan-ingress, adguard] - gpus: - - { vendor: nvidia, model: t1000, class: transcode, memory_mib: 4096 } - disks: - - { media: nvme, usable_gib: 120 } - - { media: nvme, usable_gib: 500 } - - { media: hdd, usable_gib: 4096 } - - - name: enschede-rx7900xtx-1 - site: enschede - arch: amd64 - allocatable: { cpu: 72300m, memory: 31488Mi } # 72800m / 32000Mi total - capabilities: [amd-gpu, llm-host, backup-store, lan-ingress, adguard] - gpus: - # The fastest card in the estate, and not an nvidia one, which is why a - # vendor string is not how a Process asks for a GPU. - - { - vendor: amd, - model: rx7900xtx, - class: render-compute, - memory_mib: 24576, - } - disks: - - { media: nvme, usable_gib: 160 } - - { media: nvme, usable_gib: 1000 } - - { media: hdd, usable_gib: 8192 } - - - name: enschede-gtx-960m-1 - site: enschede - arch: amd64 - allocatable: { cpu: 28300m, memory: 15872Mi } # 28800m / 16384Mi total - capabilities: [nvidia, lan-ingress] - gpus: - # Same `class` as the T1000 and a fifth of its memory. Only `memory_mib` - # separates the two, which is the case chapter 60 names for structure - # over strings. - - { vendor: nvidia, model: gtx960m, class: transcode, memory_mib: 2048 } - disks: - - { media: ssd, usable_gib: 100 } - - { media: ssd, usable_gib: 500 } - - { media: hdd, usable_gib: 2048 } - - - name: enschede-pi-1 - site: enschede - arch: arm64 - allocatable: { cpu: 5750m, memory: 7936Mi } # 6000m / 8192Mi total - capabilities: [adguard] - disks: - # `sdcard` is a medium no Process may ask for: the Medium vocabulary of - # chapter 10 is `nvme`, `ssd`, `hdd`. The fact is published anyway, - # because the contract says what a node has - # (docs/adr/model/0048-node-facts-are-authored-once.md). - - { media: sdcard, usable_gib: 64 } - - - name: enschede-pi-2 - site: enschede - arch: arm64 - # 4096Mi total, where a 512Mi error in the reserve is an eighth of the - # machine. This is the node a wrong reserve bites first. - allocatable: { cpu: 5750m, memory: 3840Mi } - capabilities: [adguard] - disks: - - { media: sdcard, usable_gib: 64 } - - - name: enschede-pi-3 - site: enschede - arch: arm64 - allocatable: { cpu: 5750m, memory: 3840Mi } # 6000m / 4096Mi total - capabilities: [adguard] - disks: - - { media: sdcard, usable_gib: 64 } - - # --------------------------------------------------------------- frankfurt - - name: frankfurt-contabo-1 - site: frankfurt - arch: amd64 - allocatable: { cpu: 15500m, memory: 32256Mi } # 16000m / 32768Mi total - # The one node advertising `public-ingress`, which is what makes - # knowledge-api's eligible set a single node. - capabilities: [public-ingress] - disks: - - { media: ssd, usable_gib: 80 } - - { media: ssd, usable_gib: 120 } diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/platform.intent.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/platform.intent.yml deleted file mode 100644 index 022495e4f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/platform/platform.intent.yml +++ /dev/null @@ -1,424 +0,0 @@ -# Platform Intent: the second authored document. What the estate offers, held to -# the same rule as a project file -- facts and policy, never mechanisms -- and -# published as an Intent Fragment by digest like any project -# (spec/v1/14-platform-intent.md, docs/adr/model/0045-platform-intent-is-the-second-authored-document.md). -# -# Every block is a value the contention test put on the platform's side -# (docs/adr/model/0004-contention-decides-authority.md). Nothing here names a -# Kubernetes field, a Traefik key, a k3s flag or a shell command -# (docs/adr/model/0011-authored-values-name-model-concepts.md). - -apiVersion: intent.jorisjonkers.dev/v1 -kind: Platform -schemaVersion: 1.0.0 -owner: joris - -metadata: - cluster: production - project: jorisjonkers.dev - nodeContract: "sha256:a989e80337efb294fa1a7175b3ad3eea8bed9bf13fbd503a26691c9265575fc2" - -# Facts about the cluster, named for what they are. How k3s is told is a -# derivation nobody authors (docs/adr/model/0049-datastore-and-restore.md). -substrate: - kubernetesVersion: v1.31.4+k3s1 - datastore: sqlite - serverCount: 1 - secretsEncryption: true # a delivery: env or file grant writes a secret into - # the cluster, which is readable on disk unless this is on; the refusal fixtures - # keep it off to prove the gate (docs/adr/model/0030-secret-delivery-is-env-file-or-self.md) - cni: flannel - networkPolicyController: embedded # no non-enforcing stage: default-deny stays - # render-only (docs/adr/model/0035-network-policy-is-default-deny-and-render-only.md) - clusterDns: kube-system # where the cluster's DNS runs: every egress policy admits it - upstreamNameservers: [9.9.9.10, 149.112.112.10] # what a Process that serves DNS - # resolves through, since it must not depend on the cluster's own DNS - imagePull: 2m # the slowest pull a pod may wait on: the Pis boot from SD cards, so - # every derived deadline allows for it (spec/v1/14-platform-intent.md#substrate-facts) - -# What must exist before the first rendered object can apply. Recorded and -# enumerated, never declared; growing this table is a decision -# (docs/adr/model/0046-the-foundation-is-declared.md). -bootstrap: - # Where k3s serves its own metrics: the metrics stack scrapes each from its - # own namespace (spec/v1/14-platform-intent.md#k3ss-metrics). - k3s: - metrics: - kubelet: {port: 10250} - # Not the worked example's `default/kubernetes`: written into the parsed - # model's XMI, that value reads to the secret scan as an API key. - apiServer: {service: default/kube-apiserver, port: https} - coreDns: {port: 9153} - flux: - sourceRef: flux-system/platform - # Where each Project's render is published, one artifact per Project at - # /, and the keyless identity Flux verifies it - # against: the estate repository's composition workflow on main - # (spec/v1/55-delivery.md#rendered-artifacts-and-pins). - artifacts: - repository: ghcr.io/jorisjonkers-dev/render - pullSecret: flux-system/render-pull - signer: - issuer: "https://token.actions.githubusercontent.com" - subject: "https://github.com/JorisJonkers-dev/estate/.github/workflows/compose.yml@refs/heads/main" - # Where Flux's controllers serve their metrics, as its install sets them: - # the metrics stack scrapes them there (spec/v1/14-platform-intent.md#fluxs-metrics). - metrics: {port: 8080, path: /metrics} - vault: - unsealed: true - crds: - - traefik.io/v1alpha1 - - secrets.hashicorp.com/v1beta1 - - monitoring.coreos.com/v1 - - flagger.app/v1beta1 # the Canary every blue-green Process renders - - identity.jorisjonkers.dev/v1 # the Client every client block renders - - metallb.io/v1beta1 # the address pools and advertisements l4-speaker renders - -# Where the edge terminates. Four facts per tier; the traefik adapter owns every -# Traefik spelling. A route's audience is the only way it reaches a tier, so a -# lan exposure -- jellyfin's high-volume traffic, which may not be proxied -# through Frankfurt -- can reach the LAN proxy and no other, by construction. -tiers: - - name: public-frankfurt - audiences: [anonymous, authenticated] - listener: tls - certificates: acme - forwardAuth: {provider: identity/identity, surface: http, path: /gate/forward, responseHeaders: [X-Forwarded-User]} # the - # sign-in provider's Gate, which every gated Client's routes ask - proxiedBy: cloudflare # on a host Cloudflare proxies, a client is the address it forwards - traefik: edge/traefik-public # the declared Application in the platform edge project, - # placed on the public-ingress node - ingressClass: traefik-public # the class this Traefik admits routes of - # Where every public name points, behind Cloudflare, and where a host - # Cloudflare does not proxy points instead: the Frankfurt node's own - # address, which `edge-frankfurt` names a node for and no document states. - dns: {target: ingress.jorisjonkers.dev, proxied: true, direct: 167.86.79.203} - address: edge-frankfurt # the node's own address: ports 80 and 443 derive from `tls` - - name: lan - audiences: [lan] - listener: tls - certificates: none - # The breadth case serves a certificate the Secret Store holds, so the - # default TLS store a tier's certificateFrom derives is resolved too. - certificateFrom: secret/data/platform/tls/wildcard - traefik: edge/traefik-lan # placed on a LAN node - ingressClass: traefik-lan - address: lan-edge # an address of the Enschede pool: ports 80 and 443 derive from `tls` - # A tier no route of the breadth case reaches, plain, on the LAN proxy beside - # the lan tier, under the same ingress class. - - name: internal - audiences: [internal] - listener: plain - certificates: none - traefik: edge/traefik-lan - ingressClass: traefik-lan - -# How an acme tier's proxy registers and proves its names -# (spec/v1/14-platform-intent.md#tiers): the account's email, the DNS provider -# that answers the DNS-01 challenge, and the Secret Store path holding its -# token, which only the proxy of an acme tier reads. -acme: - email: hostmaster@jorisjonkers.dev - dnsProvider: cloudflare - token: secret/data/platform/cloudflare - -# One policy per Durability Class (docs/adr/model/0018-durability-class-derives-a-backup.md). -durability: - reconstructible: {} - recoverable: - schedule: "15 3 * * *" - retain: 14 - irreplaceable: - schedule: "45 2 * * *" - retain: 90 - offCluster: - destination: "s3://backup-storage/jorisjonkers-dev" - credential: secret/data/platform/backup/off-cluster - # The age public key each copy is encrypted to on the pod; the private - # key is kept off the cluster, and only a restore holds it. - recipient: age1s6v5qrx3mgcgk37gscv8y6z43rssksdct5lx3xk5xrtptjndqvhsnhj7h8 - # Where that destination is, as a network policy can say it: a policy - # admits an address range and a port, never a hostname. It is what the - # backup identity's own policy lets its pods reach. - egress: - - { cidr: 203.0.113.0/24, port: 443 } - -# The method IS the image: one purpose-built image per engine, resolved through -# the images lock. Nothing executable is authored. -engines: - # `surface` is the surface of the Process the method connects to: postgres - # is dumped over its own protocol, rabbitmq through its management API, mongo - # over its wire protocol. A method that reads the volume alone names none. - # `catalog` applies the database catalog its consumers' edges derive - # (spec/v1/14-platform-intent.md#catalog-methods). - postgres: { backup: postgres-backup, surface: postgres, catalog: postgres-catalog } - rabbitmq: { backup: rabbitmq-backup, surface: management } - valkey: { backup: valkey-backup, surface: redis } - # No `catalog`: no mongo consumer needs a database of its own yet - # (spec/v1/16-dependencies.md#the-database-catalog). - mongo: { backup: mongo-backup, surface: mongo } - files: { backup: file-backup } - # An object store is backed up by the files method over its volumes, and its - # bucket catalog is applied over the admin API, not the S3 surface. - s3: { backup: file-backup, catalog: garage-catalog, catalogSurface: admin } - -# One cadence for every rendered monitor, for the same reason the probe cadence -# below is here: it is contended across the estate, and no Application knows better -# (docs/adr/model/0004-contention-decides-authority.md). -monitors: - interval: 30s - timeout: 10s - # The live Prometheus selects its ServiceMonitors and PodMonitors by this - # label, so every monitor the render writes carries it - # (spec/v1/14-platform-intent.md#monitor-cadence). - labels: - release: metrics-stack - -# Where every exporting Runtime Profile sends its telemetry, the collector's -# `otlp` surface, and the metrics stack every declared scrape surface admits, -# each named by the Application that is it, as a tier names its proxy -# (spec/v1/14-platform-intent.md#telemetry). -telemetry: - collector: observability/otel-collector - metrics: observability/prometheus - # The Grafana every Application's dashboards ship to: the labels its - # instance carries, and the data source a vendored dashboard's inputs map to. - dashboards: - instance: {dashboards: grafana} - datasource: prometheus - -# The monitoring stack by role, each a declared Application, and the one -# routing of every alert (spec/v1/14-platform-intent.md#monitoring). A -# receiver's webhook is read from Vault, never written here. -monitoring: - grafana: observability/grafana - prometheus: observability/prometheus - alertmanager: observability/alertmanager - # The stores Grafana reads beside them, each a data source its edges derive - # (spec/v1/14-platform-intent.md#grafanas-instance-and-data-sources). - stores: - loki: observability/loki - tempo: observability/tempo - pyroscope: observability/pyroscope - receivers: - - name: discord - discord: - webhook: {path: secret/data/platform/alertmanager-discord, key: webhook-url} - routes: - - {severity: critical, receiver: discord, repeat: 4h} - - {severity: warning, receiver: discord, repeat: 12h} - -# The Secret Store every grant is read from, on its `http` surface: the -# Application the worked `secrets` project declares -# (spec/v1/14-platform-intent.md#the-secret-store). -secretStore: secrets/vault - -# Who issues sign-ins (spec/v1/14-platform-intent.md#sign-in): the Issuer every -# Client trusts, and the Identity Provider the worked `identity` project -# declares, whose Process writes every derived client credential. -signIn: - issuer: "https://id.jorisjonkers.dev" - provider: identity/identity - # The Principal contract version identity serves, which every generated - # identity file states (spec/v1/17-sign-in.md#generated-app-roles). - contract: "1.2" - -# NO rule catalog, no receivers, no severity map. Those belong to the monitoring -# stack, which reads the published projection; this document decides how often -# to scrape and nothing else about alerting -# (spec/v1/10-project-intent.md#observability). - -# One posture for every container the estate renders. A Process authors no -# hardening at all: it declares the paths it writes, and an image that cannot -# meet this class is refused (docs/adr/model/0020-hardening-is-one-platform-posture.md). -hardening: restricted - -# One cadence for every rendered probe -# (docs/adr/model/0016-probes-are-siblings-and-startup-targets-liveness.md). -probes: - period: 10s - timeout: 5s - failures: 3 - -# The ephemeral default for a declared writable path -# (docs/adr/model/0020-hardening-is-one-platform-posture.md). -ephemeral: - size: 64Mi - -# The migration runner (spec/v1/14-platform-intent.md#migration-policy). Every -# Application that moves its schema through a changelog builds its migration -# image FROM this alias's digest, and its Job takes this deadline and these -# requests. One system for the estate: Liquibase, YAML changelogs. -migration: - runner: liquibase-runner - deadline: 10m - memory: 256Mi - cpu: 100m - -# How a release is switched (spec/v1/14-platform-intent.md#delivery-policy). -# The machinery performs the switch and is never switched by it: a gate cannot -# gate its own release, and an edge proxy on a host port cannot run two copies. -# The analysis cadence is the platform's, one for every blue/green member. -delivery: - machinery: [edge/traefik-public, edge/traefik-lan, delivery/flagger, delivery/release-gate] - gate: delivery/release-gate - reporter: delivery/reporter - analysis: - interval: 30s - iterations: 4 - threshold: 3 - errorRate: 1% - latency: 500ms - -# Who may hold Kubernetes API access, and where the API answers -# (spec/v1/14-platform-intent.md#kubernetes-api-access). A Process declares -# what it asks of the API; only a Process of an Application named here may, and -# anyone else's declaration is E_PROCESS_RBAC_GRANT. `server` is what such a -# Process's egress policy admits: the API server is no pod a selector reaches. -apiAccess: - holders: [delivery/flagger, delivery/release-gate, delivery/collector, delivery/reporter, edge/external-dns, secrets/vault-secrets-operator, observability/prometheus, observability/prometheus-operator, observability/kube-state-metrics, observability/grafana-operator, observability/gatus, observability/alloy, agents/kubernetes-mcp-server, coverage/coverage-api] - # Admitted to their own namespace alone: no privileged role, so no foundation. - namespaceHolders: [agents/agents-api, utility/headlamp] - server: - - { cidr: 10.43.0.1/32, port: 443 } - -# Who among people may use the cluster, and as what -# (spec/v1/14-platform-intent.md#human-grants): a group, written as the API -# server sees it, granted one of Kubernetes' built-in cluster roles, -# cluster-wide. Each grant renders one ClusterRoleBinding that no Application -# holds, so removing an Application removes no one's access. -# The priority classes the platform declares and renders: a datastore runs at -# the data class, and the foundation and the Applications named here at the -# critical one, so they keep scheduling when a node is short -# (spec/v1/14-platform-intent.md#priority). Nothing is authored on a Process. -priority: - data: {name: platform-data, value: 1000000} - critical: {name: platform-critical-app, value: 100000} - criticalApplications: [auth/auth] - -humanGrants: - - group: oidc:k8s-operators - clusterRole: admin - reason: the operators administer the namespaces they run - - group: oidc:k8s-developers - clusterRole: edit - reason: the developers change what they deploy - - group: oidc:k8s-readers - clusterRole: view - reason: anyone signed in reads the cluster's state - - group: oidc:k8s-admin - clusterRole: cluster-admin - reason: the platform owner administers the cluster with kubectl and headlamp over OIDC - -# The job that writes the rendered Vault policies and auth roles into the Secret -# Store (spec/v1/14-platform-intent.md#the-vault-policy-job). It is derived, in -# the Secret Store's namespace, from the documents each render holds; `role` is -# the Vault role it logs in as, a fixture created with the auth method. -policyJob: - image: vault-policy - role: policy-admin - memory: 64Mi - cpu: 10m - deadline: 120s - -# The image that seeds a Process's Assets onto its volumes before every start -# (spec/v1/14-platform-intent.md#the-seeder): any image with a shell and `cp` -# will do, so one small one serves the estate, and what each step requests. -seeder: - image: busybox - memory: 16Mi - cpu: 10m - -# Things the estate runs and does not deploy, that an Application depends on. A fact -# with an address, resolvable by an edge -- not a hole, so no review date -# (docs/adr/model/0024-dependency-edges-resolve-against-the-union.md). -providers: - - name: stalwart - address: 10.0.0.12 - surfaces: - smtp: 25 - http: 8080 - -# Directories on one node that several projects share, each granted by project, -# read or write (spec/v1/14-platform-intent.md#libraries). A Process mounting one -# is placed on its node and runs with its group; no render re-owns it. -libraries: - media: - node: enschede-t1000-1 - path: /srv/media - gid: 3001 - grants: - notes: write - jellyfin: read - -# What a Process that requires a GPU is handed, by the vendor of the card it -# lands on (spec/v1/14-platform-intent.md#gpus): one share of the device -# resource, and the runtime class that exposes the card to its container. -gpus: - nvidia: - resource: nvidia.com/gpu - runtimeClass: nvidia-cdi - -# The addresses a client off the cluster reaches a raw surface on -# (spec/v1/14-platform-intent.md#l4-addresses), by name. A pool is a range on -# one site's network segment: a Process exposed on it is held to that site, and -# each Service exposed on it takes one address of the range, so a range of one -# address is that address. Both pools sit outside the router's DHCP scope. -l4Addresses: - lan-dns: - kind: pool - site: enschede - range: 192.168.0.98/32 - lan-edge: - kind: pool - site: enschede - range: 192.168.0.99/32 - lan-mqtt: - kind: pool - site: enschede - range: 192.168.0.97/32 - # The public tier's proxy listens on the Frankfurt node's own address. - edge-frankfurt: - kind: node - node: frankfurt-contabo-1 - # A node's own address, at a site with no pool: an exposure on it is a host - # port, and holds its Process to the node. - mail-node: - kind: node - node: frankfurt-contabo-1 - -# The host-privileged agents the nodes run -# (spec/v1/14-platform-intent.md#node-agents). The catalog is closed and its -# privileges are fixed; an entry pins the image and what each copy requests. -# Which nodes run an agent is derived: every node runs node-metrics, a node with -# an nvidia card gpu-device and gpu-metrics, and the nodes of a site with a pool -# l4-speaker, whose controller runs once. -nodeAgents: - gpu-device: { image: nvidia-device-plugin, memory: 64Mi, cpu: 10m } - gpu-metrics: { image: dcgm-exporter, memory: 256Mi, cpu: 50m } - node-metrics: { image: node-exporter, memory: 64Mi, cpu: 20m } - l4-speaker: - image: metallb-speaker - memory: 64Mi - cpu: 20m - controller: { image: metallb-controller, memory: 64Mi, cpu: 10m } - -# The VPN an attached Process's traffic leaves through -# (spec/v1/14-platform-intent.md#vpn): one privileged container the render adds -# beside each attached Process, running this image with these settings. Each -# attached Process reads its own key below the credential prefix, one device per -# Process; the keys are the container's own variables, and it alone reads them. -vpn: - image: gluetun - credential: secret/data/platform/vpn - memory: 128Mi - cpu: 50m - settings: - VPN_SERVICE_PROVIDER: protonvpn - VPN_TYPE: wireguard - SERVER_COUNTRIES: Netherlands - PORT_FORWARD_ONLY: "on" - DOT: "off" - DNS_KEEP_NAMESERVER: "on" -mesh: - enrolled: [coverage, identity] diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/secrets/secrets.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/secrets/secrets.project.yml deleted file mode 100644 index 969433d82..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/secrets/secrets.project.yml +++ /dev/null @@ -1,71 +0,0 @@ -# The Secret Store as Project Intent: the Application the worked Platform -# document's `secretStore` names (spec/v1/14-platform-intent.md#the-secret-store). -# -# Every grant in the estate is read from it, so every Process holding one -# egresses to its `http` surface, and every Application holding one is ordered -# after the unit that materialises the credentials it asks for. - -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -project: secrets # the namespace derives: secrets-system -owner: joris - -applications: - - id: vault - processes: - - name: vault - lifecycle: application - image: vault - runtime: none - provides: - http: 8200 - placement: - memory: 256Mi - cpu: 100m - probes: - readiness: { path: /v1/sys/health, port: 8200 } - liveness: { path: /v1/sys/health, port: 8200 } - startupBudget: 30s - cutover: interrupted - - # The Vault Secrets Operator: every grant's sync object is its, so it reads - # them and writes the Secrets they land in, in every namespace. No agent - # injector and no CSI provider run beside Vault. - - id: vault-secrets-operator - processes: - - name: vault-secrets-operator - lifecycle: application - image: vault-secrets-operator - runtime: none - provides: - metrics: 8080 - health: 8081 - placement: - memory: 128Mi - cpu: 50m - probes: - readiness: { path: /healthz, port: 8081 } - liveness: { path: /healthz, port: 8081 } - startupBudget: 30s - cutover: interrupted - api: - reason: >- - the operator syncs every grant's sync object into its Secret, cluster-wide, and restarts the Processes a rotation names - rules: - - group: secrets.hashicorp.com - objects: [vaultstaticsecrets, vaultstaticsecrets/status, vaultdynamicsecrets, vaultdynamicsecrets/status, vaultauths, vaultauths/status, vaultconnections, vaultconnections/status] - verbs: [get, list, watch, create, update, patch, delete, deletecollection] - - group: core - objects: [secrets] - verbs: [get, list, watch, create, update, patch, delete] - - group: core - objects: [serviceaccounts/token] - verbs: [create] - - group: apps - objects: [deployments, statefulsets, daemonsets] - verbs: [get, list, watch, patch] - - group: core - objects: [events] - verbs: [create, patch] diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/utility/config/adguard/AdGuardHome.yaml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/utility/config/adguard/AdGuardHome.yaml deleted file mode 100644 index f93fb1a37..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/utility/config/adguard/AdGuardHome.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# A stand-in for AdGuard Home's configuration, written for this example: the -# live file is fleet-infra's, and this repository does not copy it. AdGuard -# rewrites the file on every start and stops if it cannot, so the file is -# seeded onto a writable path rather than mounted -# (spec/v1/10-project-intent.md#seeded-assets). -http: - address: 0.0.0.0:3000 -dns: - bind_hosts: [0.0.0.0] - port: 5353 - upstream_dns: - - https://dns.quad9.net/dns-query - bootstrap_dns: [9.9.9.10, 149.112.112.10] -schema_version: 29 diff --git a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/utility/utility.project.yml b/emf/bundles/cli/src/test/resources/stages/parse/estate/input/utility/utility.project.yml deleted file mode 100644 index 61df43a5c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/estate/input/utility/utility.project.yml +++ /dev/null @@ -1,92 +0,0 @@ -# Worked example: utility's DNS resolver, the live case of a Process that -# serves DNS (spec/v1/10-project-intent.md#l4-exposure). -# -# Exercises: a raw surface on a pool. The LAN's devices ask adguard for names -# on port 53, over UDP and TCP, at `lan-dns`, a one-address pool at Enschede. -# Both entries are one Service, so one address answers both protocols. The two -# replicas sit on two nodes, and the pool's address is failover, not load -# sharing: one node announces it, and the other replica takes over when that -# node goes. -# -# Also exercises: a Process that reaches the Kubernetes API holding no rule of -# its own. Headlamp acts on the API with each signed-in user's own token, so it -# needs the way to the API server and nothing else: no Role, no binding, no -# mounted token (spec/v1/10-project-intent.md#kubernetes-api-access). -# -# Also exercises: a Process that serves DNS resolves through the platform's -# upstream nameservers, never the cluster's own DNS, which may be down in -# exactly the outage this resolver exists for. Nothing here says so: an -# exposure on port 53 derives it. - -apiVersion: intent.jorisjonkers.dev/v1 -kind: Project -schemaVersion: 1.0.0 - -project: utility # the namespace derives: utility-system -owner: joris - -applications: - - id: adguard - l4Exposure: - - { address: lan-dns, port: 53, protocol: udp, process: adguard, surface: dns } - - { address: lan-dns, port: 53, protocol: tcp, process: adguard, surface: dns } - processes: - - name: adguard - lifecycle: application - image: adguard - runtime: none - provides: - http: 3000 - dns: 5353 - placement: - memory: 128Mi - cpu: 50m - capabilities: [adguard] - replicas: - count: 2 - reason: the LAN keeps its resolver while one node is down - across: node - # Its work directory, the query log and statistics, holds 66MB live, - # past the platform's one ephemeral size, so it is held in memory at - # its own size and counted toward the Process - # (spec/v1/10-project-intent.md#writable-paths-are-declared-not-exempted). - # It is lost with the pod, as a disk one would be. - writablePaths: [{ path: /opt/adguardhome/work, memory: 128Mi }, /opt/adguardhome/conf] - # AdGuard rewrites its config on every start and stops if it cannot, so - # the config is seeded onto its conf directory before each start rather - # than mounted read-only (spec/v1/10-project-intent.md#seeded-assets). - # The directory is the pod's own: each pod starts from this file. - assets: - - { from: config/adguard/AdGuardHome.yaml, seedAt: /opt/adguardhome/conf/AdGuardHome.yaml } - # Its DNS-over-HTTPS upstream is on the internet. - egress: { to: internet, reason: answers the LAN from a DNS-over-HTTPS upstream } - probes: - readiness: { path: /login.html, port: 3000 } - liveness: { path: /login.html, port: 3000 } - startupBudget: 30s - cutover: continuous - - - id: headlamp - exposure: - - name: lan - host: dashboard.lan.jorisjonkers.dev - audience: lan - routes: - - { path: /, match: prefix, process: headlamp, surface: http } - processes: - - name: headlamp - lifecycle: application - image: headlamp - runtime: none - provides: - http: 4466 - placement: - memory: 128Mi - cpu: 50m - api: - reason: it acts on the API with each signed-in user's own token, and holds nothing of its own - probes: - readiness: { path: /, port: 4466 } - liveness: { path: /, port: 4466 } - startupBudget: 30s - cutover: continuous diff --git a/emf/bundles/cli/src/test/resources/stages/parse/gaps.txt b/emf/bundles/cli/src/test/resources/stages/parse/gaps.txt deleted file mode 100644 index af6ccbd3a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/parse/gaps.txt +++ /dev/null @@ -1,118 +0,0 @@ -ContentPolicy.admin is never used in a parse case's input -ContentPolicy.workflow is never used in a parse case's input -DatabaseEngine.database is never used in a parse case's input -DatabaseGrant is never instantiated in a parse case's input -DatabaseGrant.delivery is never set in a parse case's input -DatabaseGrant.engine is never set in a parse case's input -DatabaseGrant.fileMode is never set in a parse case's input -DatabaseGrant.mountAt is never set in a parse case's input -DatabaseGrant.role is never set in a parse case's input -DatabaseGrant.rotation is never set in a parse case's input -Datastore.etcd is never used in a parse case's input -Engine.valkey is never used in a parse case's input -PolicyController.cni is never used in a parse case's input -PolicyController.none is never used in a parse case's input -SignInMode.token is never used in a parse case's input -platform-intent.schema.json /durability/reconstructible/offCluster is never present in a parse case's input -platform-intent.schema.json /durability/reconstructible/offCluster/credential is never present in a parse case's input -platform-intent.schema.json /durability/reconstructible/offCluster/destination is never present in a parse case's input -platform-intent.schema.json /durability/reconstructible/offCluster/egress is never present in a parse case's input -platform-intent.schema.json /durability/reconstructible/offCluster/egress[]/cidr is never present in a parse case's input -platform-intent.schema.json /durability/reconstructible/offCluster/egress[]/port is never present in a parse case's input -platform-intent.schema.json /durability/reconstructible/offCluster/recipient is never present in a parse case's input -platform-intent.schema.json /durability/reconstructible/retain is never present in a parse case's input -platform-intent.schema.json /durability/reconstructible/schedule is never present in a parse case's input -platform-intent.schema.json /durability/recoverable/offCluster is never present in a parse case's input -platform-intent.schema.json /durability/recoverable/offCluster/credential is never present in a parse case's input -platform-intent.schema.json /durability/recoverable/offCluster/destination is never present in a parse case's input -platform-intent.schema.json /durability/recoverable/offCluster/egress is never present in a parse case's input -platform-intent.schema.json /durability/recoverable/offCluster/egress[]/cidr is never present in a parse case's input -platform-intent.schema.json /durability/recoverable/offCluster/egress[]/port is never present in a parse case's input -platform-intent.schema.json /durability/recoverable/offCluster/recipient is never present in a parse case's input -platform-intent.schema.json /engines/files/catalog is never present in a parse case's input -platform-intent.schema.json /engines/files/catalogSurface is never present in a parse case's input -platform-intent.schema.json /engines/files/surface is never present in a parse case's input -platform-intent.schema.json /engines/mongo/catalog is never present in a parse case's input -platform-intent.schema.json /engines/mongo/catalogSurface is never present in a parse case's input -platform-intent.schema.json /engines/postgres/catalogSurface is never present in a parse case's input -platform-intent.schema.json /engines/rabbitmq/catalog is never present in a parse case's input -platform-intent.schema.json /engines/rabbitmq/catalogSurface is never present in a parse case's input -platform-intent.schema.json /engines/s3/surface is never present in a parse case's input -platform-intent.schema.json /engines/valkey/catalog is never present in a parse case's input -platform-intent.schema.json /engines/valkey/catalogSurface is never present in a parse case's input -project-intent.schema.json /applications[]/assets[]/mountAt is never present in a parse case's input -project-intent.schema.json /applications[]/dependsOn[]/buckets is never present in a parse case's input -project-intent.schema.json /applications[]/dependsOn[]/credentials is never present in a parse case's input -project-intent.schema.json /applications[]/dependsOn[]/credentials/delivery is never present in a parse case's input -project-intent.schema.json /applications[]/dependsOn[]/credentials/fileMode is never present in a parse case's input -project-intent.schema.json /applications[]/dependsOn[]/credentials/mountAt is never present in a parse case's input -project-intent.schema.json /applications[]/dependsOn[]/credentials/rotation is never present in a parse case's input -project-intent.schema.json /applications[]/dependsOn[]/credentials/rotation/maxAge is never present in a parse case's input -project-intent.schema.json /applications[]/dependsOn[]/credentials/rotation/tolerates is never present in a parse case's input -project-intent.schema.json /applications[]/placement/arch is never present in a parse case's input -project-intent.schema.json /applications[]/placement/capabilities is never present in a parse case's input -project-intent.schema.json /applications[]/placement/cpu is never present in a parse case's input -project-intent.schema.json /applications[]/placement/disk is never present in a parse case's input -project-intent.schema.json /applications[]/placement/disk/media is never present in a parse case's input -project-intent.schema.json /applications[]/placement/gpu is never present in a parse case's input -project-intent.schema.json /applications[]/placement/gpu/class is never present in a parse case's input -project-intent.schema.json /applications[]/placement/gpu/memory is never present in a parse case's input -project-intent.schema.json /applications[]/placement/gpu/model is never present in a parse case's input -project-intent.schema.json /applications[]/placement/gpu/vendor is never present in a parse case's input -project-intent.schema.json /applications[]/placement/memory is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/dependsOn[]/credentials/rotation/maxAge is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/dependsOn[]/required is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/secrets[]/keys[]/generate/bytes is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/secrets[]/keys[]/generate/encoding is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/secrets[]/role is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/spawns[]/dependsOn[]/buckets is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/spawns[]/dependsOn[]/credentials is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/spawns[]/dependsOn[]/credentials/delivery is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/spawns[]/dependsOn[]/credentials/fileMode is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/spawns[]/dependsOn[]/credentials/mountAt is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/spawns[]/dependsOn[]/credentials/rotation is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/spawns[]/dependsOn[]/credentials/rotation/maxAge is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/spawns[]/dependsOn[]/credentials/rotation/tolerates is never present in a parse case's input -project-intent.schema.json /applications[]/processes[]/spawns[]/dependsOn[]/required is never present in a parse case's input -project-intent.schema.json /applications[]/secrets[]/engine is never present in a parse case's input -project-intent.schema.json /applications[]/secrets[]/key is never present in a parse case's input -project-intent.schema.json /applications[]/secrets[]/keys[]/generate/adopt is never present in a parse case's input -project-intent.schema.json /applications[]/secrets[]/keys[]/optional is never present in a parse case's input -project-intent.schema.json /applications[]/secrets[]/operations is never present in a parse case's input -project-intent.schema.json /applications[]/secrets[]/role is never present in a parse case's input -project-intent.schema.json /applications[]/secrets[]/rotation/maxAge is never present in a parse case's input -project-intent.schema.json /assets[]/seedAt is never present in a parse case's input -project-intent.schema.json /dependsOn[]/buckets is never present in a parse case's input -project-intent.schema.json /dependsOn[]/credentials is never present in a parse case's input -project-intent.schema.json /dependsOn[]/credentials/delivery is never present in a parse case's input -project-intent.schema.json /dependsOn[]/credentials/fileMode is never present in a parse case's input -project-intent.schema.json /dependsOn[]/credentials/mountAt is never present in a parse case's input -project-intent.schema.json /dependsOn[]/credentials/rotation is never present in a parse case's input -project-intent.schema.json /dependsOn[]/credentials/rotation/maxAge is never present in a parse case's input -project-intent.schema.json /dependsOn[]/credentials/rotation/tolerates is never present in a parse case's input -project-intent.schema.json /placement/arch is never present in a parse case's input -project-intent.schema.json /placement/capabilities is never present in a parse case's input -project-intent.schema.json /placement/cpu is never present in a parse case's input -project-intent.schema.json /placement/disk is never present in a parse case's input -project-intent.schema.json /placement/disk/media is never present in a parse case's input -project-intent.schema.json /placement/gpu is never present in a parse case's input -project-intent.schema.json /placement/gpu/class is never present in a parse case's input -project-intent.schema.json /placement/gpu/memory is never present in a parse case's input -project-intent.schema.json /placement/gpu/model is never present in a parse case's input -project-intent.schema.json /placement/gpu/vendor is never present in a parse case's input -project-intent.schema.json /placement/memory is never present in a parse case's input -project-intent.schema.json /secrets[]/engine is never present in a parse case's input -project-intent.schema.json /secrets[]/fileMode is never present in a parse case's input -project-intent.schema.json /secrets[]/key is never present in a parse case's input -project-intent.schema.json /secrets[]/keys[]/generate is never present in a parse case's input -project-intent.schema.json /secrets[]/keys[]/generate/adopt is never present in a parse case's input -project-intent.schema.json /secrets[]/keys[]/generate/bytes is never present in a parse case's input -project-intent.schema.json /secrets[]/keys[]/generate/encoding is never present in a parse case's input -project-intent.schema.json /secrets[]/keys[]/name is never present in a parse case's input -project-intent.schema.json /secrets[]/keys[]/optional is never present in a parse case's input -project-intent.schema.json /secrets[]/mountAt is never present in a parse case's input -project-intent.schema.json /secrets[]/operations is never present in a parse case's input -project-intent.schema.json /secrets[]/role is never present in a parse case's input -project-intent.schema.json /secrets[]/rotation/maxAge is never present in a parse case's input -project-intent.schema.json /writablePaths[]/memory is never present in a parse case's input -project-intent.schema.json /writablePaths[]/path is never present in a parse case's input diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/networkpolicy.yaml deleted file mode 100644 index 104e1e226..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/networkpolicy.yaml +++ /dev/null @@ -1,117 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: agents-api - namespace: agents-system - labels: - app.kubernetes.io/name: agents-api - app.kubernetes.io/instance: agents-api - app.kubernetes.io/part-of: agents-api - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: agents-api - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/agents-api.http: "true" - ports: - - protocol: TCP - port: 8082 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: agents-system - podSelector: - matchLabels: - deploy-kit.jorisjonkers.dev/spawned-from: agents-api-runner - ports: - - protocol: TCP - port: 8090 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: agents-api-runner - namespace: agents-system - labels: - app.kubernetes.io/name: agents-api - app.kubernetes.io/instance: agents-api - app.kubernetes.io/part-of: agents-api - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - podSelector: - matchLabels: - deploy-kit.jorisjonkers.dev/spawned-from: agents-api-runner - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: agents-system - podSelector: - matchLabels: - app.kubernetes.io/instance: agents-api - ports: - - protocol: TCP - port: 8090 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: agents-system - podSelector: - matchLabels: - app.kubernetes.io/instance: agents-api - ports: - - protocol: TCP - port: 8082 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 - - 100.64.0.0/10 - - 169.254.0.0/16 - - 127.0.0.0/8 diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/rbac.yaml deleted file mode 100644 index 819ced08d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/rbac.yaml +++ /dev/null @@ -1,58 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: agents-api - namespace: agents-system - labels: - app.kubernetes.io/name: agents-api - app.kubernetes.io/instance: agents-api - app.kubernetes.io/part-of: agents-api - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -rules: - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - pods - verbs: - - get - - list - - watch - - create - - delete - - apiGroups: - - "" - resources: - - pods/log - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: agents-api - namespace: agents-system - labels: - app.kubernetes.io/name: agents-api - app.kubernetes.io/instance: agents-api - app.kubernetes.io/part-of: agents-api - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: agents-api -subjects: - - kind: ServiceAccount - name: agents-api - namespace: agents-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/service.yaml deleted file mode 100644 index 6beeb7af2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: agents-api - namespace: agents-system - labels: - app.kubernetes.io/name: agents-api - app.kubernetes.io/instance: agents-api - app.kubernetes.io/part-of: agents-api - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - selector: - app.kubernetes.io/instance: agents-api - ports: - - name: http - port: 8082 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/serviceaccount.yaml deleted file mode 100644 index cc4232cb4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: agents-api - namespace: agents-system - labels: - app.kubernetes.io/name: agents-api - app.kubernetes.io/instance: agents-api - app.kubernetes.io/part-of: agents-api - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/workload.yaml deleted file mode 100644 index 84a831ecd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-api/workload.yaml +++ /dev/null @@ -1,110 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: agents-api - namespace: agents-system - labels: - app.kubernetes.io/name: agents-api - app.kubernetes.io/instance: agents-api - app.kubernetes.io/part-of: agents-api - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - replicas: 0 - strategy: - type: Recreate - progressDeadlineSeconds: 300 - selector: - matchLabels: - app.kubernetes.io/name: agents-api - app.kubernetes.io/instance: agents-api - template: - metadata: - labels: - app.kubernetes.io/name: agents-api - app.kubernetes.io/instance: agents-api - app.kubernetes.io/part-of: agents-api - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm - annotations: - image.jorisjonkers.dev/agents-api: 2.3.0 - spec: - serviceAccountName: agents-api - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: agents-api - image: ghcr.io/jorisjonkers-dev/agents/agents-api@sha256:7a1c3e5b9d2f4a6c8e0b2d4f7e1f3c5a9b2d4f6e8a0c2e4b6d8f5a2c4e6b8d0f - ports: - - name: http - containerPort: 8082 - env: - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: agents-api - - name: PORT - value: "8082" - - name: SPAWN_RUNNER_IMAGE - value: ghcr.io/jorisjonkers-dev/agents/agent-runner@sha256:8b2d4f6e8a0c2e4b6d8f5a2c4e6b8d0f7a1c3e5b9d2f4a6c8e0b2d4f7e1f3c5a - - name: SPAWN_RUNNER_LABELS - value: deploy-kit.jorisjonkers.dev/spawned-from=agents-api-runner,consumes.deploy-kit.jorisjonkers.dev/agents-api.http=true - resources: - requests: - memory: 512Mi - cpu: 100m - limits: - memory: 512Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /actuator/health/readiness - port: 8082 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /actuator/health/liveness - port: 8082 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /actuator/health/liveness - port: 8082 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/configmap.yaml deleted file mode 100644 index 88a185ca6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/configmap.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: agents-ui-external-checks - namespace: agents-system - labels: - app.kubernetes.io/part-of: agents-ui - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - agents-ui-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"agents","name":"agents-ui-public-1","url":"https://agents.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/kustomization.yaml deleted file mode 100644 index 3ecc94ca6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - route-public.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/networkpolicy.yaml deleted file mode 100644 index a85847db5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/networkpolicy.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: agents-ui - namespace: agents-system - labels: - app.kubernetes.io/name: agents-ui - app.kubernetes.io/instance: agents-ui - app.kubernetes.io/part-of: agents-ui - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: agents-ui - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 80 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/agents-ui.http: "true" - ports: - - protocol: TCP - port: 80 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/route-public.yaml deleted file mode 100644 index 09a2c6b24..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/route-public.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: agents-ui-public - namespace: agents-system - labels: - app.kubernetes.io/part-of: agents-ui - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`agents.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: agents-ui - namespace: agents-system - port: 80 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/service.yaml deleted file mode 100644 index a4a8741d9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: agents-ui - namespace: agents-system - labels: - app.kubernetes.io/name: agents-ui - app.kubernetes.io/instance: agents-ui - app.kubernetes.io/part-of: agents-ui - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - selector: - app.kubernetes.io/instance: agents-ui - ports: - - name: http - port: 80 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/serviceaccount.yaml deleted file mode 100644 index 21eb81c7f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: agents-ui - namespace: agents-system - labels: - app.kubernetes.io/name: agents-ui - app.kubernetes.io/instance: agents-ui - app.kubernetes.io/part-of: agents-ui - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/workload.yaml deleted file mode 100644 index 5426e2673..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/agents-ui/workload.yaml +++ /dev/null @@ -1,104 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: agents-ui - namespace: agents-system - labels: - app.kubernetes.io/name: agents-ui - app.kubernetes.io/instance: agents-ui - app.kubernetes.io/part-of: agents-ui - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - replicas: 0 - strategy: - type: Recreate - progressDeadlineSeconds: 720 - selector: - matchLabels: - app.kubernetes.io/name: agents-ui - app.kubernetes.io/instance: agents-ui - template: - metadata: - labels: - app.kubernetes.io/name: agents-ui - app.kubernetes.io/instance: agents-ui - app.kubernetes.io/part-of: agents-ui - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static - annotations: - image.jorisjonkers.dev/agents-ui: 0.19.1 - spec: - serviceAccountName: agents-ui - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 101 - runAsGroup: 101 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: agents-ui - image: ghcr.io/jorisjonkers-dev/agents-ui@sha256:5b41e0ab23e60fbb3f14f42fe5138e6c266aa1bf1289967bfc8a7f9f820bcbc6 - ports: - - name: http - containerPort: 80 - resources: - requests: - memory: 96Mi - cpu: 100m - limits: - memory: 96Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - add: - - NET_BIND_SERVICE - drop: - - ALL - volumeMounts: - - name: writable-var-cache-nginx - mountPath: /var/cache/nginx - - name: writable-var-run - mountPath: /var/run - readinessProbe: - httpGet: - path: / - port: 80 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: / - port: 80 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - volumes: - - name: writable-var-cache-nginx - emptyDir: - sizeLimit: 64Mi - - name: writable-var-run - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/backup.yaml deleted file mode 100644 index 7247a16e9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/backup.yaml +++ /dev/null @@ -1,65 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: hermes-data-backup - namespace: agents-system - labels: - app.kubernetes.io/name: hermes-backup - app.kubernetes.io/instance: hermes-backup - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 15 3 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: hermes-backup - app.kubernetes.io/instance: hermes-backup - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: hermes-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 10000 - runAsGroup: 10000 - fsGroup: 10000 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/file-backup@sha256:2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d - env: - - name: BACKUP_RETAIN - value: "14" - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: hermes-data - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: hermes-data-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/client.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/client.yaml deleted file mode 100644 index fa6b94141..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/client.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: identity.jorisjonkers.dev/v1 -kind: Client -metadata: - name: hermes - labels: - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit -spec: - signIn: native - host: hermes.jorisjonkers.dev - launchUrl: https://hermes.jorisjonkers.dev/ - redirectUris: - - https://hermes.jorisjonkers.dev/auth/callback - credential: pkce - roles: - - user - label: Hermes - description: The agent gateway diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/configmap.yaml deleted file mode 100644 index bbc52dfca..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/configmap.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: hermes-external-checks - namespace: agents-system - labels: - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - hermes-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"agents","name":"hermes-public-1","url":"https://hermes.jorisjonkers.dev/"},{"conditions":["[STATUS] < 500"],"group":"agents","name":"hermes-lan-1","url":"http://hermes.jorisjonkers.dev/"}]} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: hermes-config-yaml-118d92ae7c - namespace: agents-system - labels: - app.kubernetes.io/name: hermes - app.kubernetes.io/instance: hermes - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - config.yaml: | - # A stand-in for hermes's configuration, written for this example: the live - # file is fleet-infra's, and this repository does not copy it. hermes expands - # each ${VAR} below from its own environment as it reads the file, so the file - # holds no secret: the values reach hermes through its env file - # (spec/v1/10-project-intent.md#seeded-assets). - model: - provider: openrouter - default: anthropic/claude-sonnet-4.5 - mcp_servers: - github: - url: https://api.githubcopilot.com/mcp/ - headers: - Authorization: Bearer ${GITHUB_PAT} - context7: - url: https://mcp.context7.com/mcp diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/kustomization.yaml deleted file mode 100644 index 248ccc9ec..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/kustomization.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - client.yaml - - configmap.yaml - - pvc.yaml - - route-lan.yaml - - route-public.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/networkpolicy.yaml deleted file mode 100644 index 8a6dcb23a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/networkpolicy.yaml +++ /dev/null @@ -1,122 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: hermes - namespace: agents-system - labels: - app.kubernetes.io/name: hermes - app.kubernetes.io/instance: hermes - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: hermes - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 9119 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-lan - ports: - - protocol: TCP - port: 9119 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/hermes.dashboard: "true" - ports: - - protocol: TCP - port: 9119 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: agents-system - podSelector: - matchLabels: - app.kubernetes.io/instance: kubernetes-mcp-server - ports: - - protocol: TCP - port: 8080 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 - - 100.64.0.0/10 - - 169.254.0.0/16 - - 127.0.0.0/8 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: hermes-backup - namespace: agents-system - labels: - app.kubernetes.io/name: hermes-backup - app.kubernetes.io/instance: hermes-backup - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: hermes-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/pvc.yaml deleted file mode 100644 index 82aa34584..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/pvc.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: hermes-data - namespace: agents-system - labels: - app.kubernetes.io/name: hermes - app.kubernetes.io/instance: hermes - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: hermes-data-backup - namespace: agents-system - labels: - app.kubernetes.io/name: hermes - app.kubernetes.io/instance: hermes - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/route-lan.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/route-lan.yaml deleted file mode 100644 index 07c3cd6f0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/route-lan.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: hermes-lan - namespace: agents-system - labels: - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-lan -spec: - entryPoints: - - web - routes: - - kind: Rule - match: Host(`hermes.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: hermes - namespace: agents-system - port: 9119 diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/route-public.yaml deleted file mode 100644 index 4cf9e40bd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/route-public.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: hermes-public - namespace: agents-system - labels: - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: 167.86.79.203 - external-dns.alpha.kubernetes.io/cloudflare-proxied: "false" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`hermes.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: hermes - namespace: agents-system - port: 9119 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/service.yaml deleted file mode 100644 index 7d06b53a0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: hermes - namespace: agents-system - labels: - app.kubernetes.io/name: hermes - app.kubernetes.io/instance: hermes - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: hermes - ports: - - name: dashboard - port: 9119 - targetPort: dashboard diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/serviceaccount.yaml deleted file mode 100644 index 980b2c979..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: hermes - namespace: agents-system - labels: - app.kubernetes.io/name: hermes - app.kubernetes.io/instance: hermes - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: hermes-backup - namespace: agents-system - labels: - app.kubernetes.io/name: hermes-backup - app.kubernetes.io/instance: hermes-backup - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/vso.yaml deleted file mode 100644 index c42218636..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/vso.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: hermes - namespace: agents-system - labels: - app.kubernetes.io/name: hermes - app.kubernetes.io/instance: hermes - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: agents-system-hermes - serviceAccount: hermes ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: hermes-agents-hermes - namespace: agents-system - labels: - app.kubernetes.io/name: hermes - app.kubernetes.io/instance: hermes - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: hermes - mount: secret - type: kv-v2 - path: agents/hermes - refreshAfter: 10m - hmacSecretData: true - destination: - name: hermes-agents-hermes - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: hermes diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/workload.yaml deleted file mode 100644 index fc1a50dc3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/hermes/workload.yaml +++ /dev/null @@ -1,229 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: hermes - namespace: agents-system - labels: - app.kubernetes.io/name: hermes - app.kubernetes.io/instance: hermes - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 480 - selector: - matchLabels: - app.kubernetes.io/name: hermes - app.kubernetes.io/instance: hermes - template: - metadata: - labels: - app.kubernetes.io/name: hermes - app.kubernetes.io/instance: hermes - app.kubernetes.io/part-of: hermes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - consumes.deploy-kit.jorisjonkers.dev/kubernetes-mcp-server.mcp: "true" - annotations: - image.jorisjonkers.dev/hermes: 2026.8.31 - image.jorisjonkers.dev/seed: 1.37.0 - spec: - serviceAccountName: hermes - priorityClassName: platform-data - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 10000 - runAsGroup: 10000 - fsGroup: 10000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - initContainers: - - name: seed - image: docker.io/library/busybox@sha256:a7dbc319b1438115a207e11930dc4bb3e643dcb3ec0bdd694bb36cd8fad289ec - command: - - /bin/sh - - -c - - |- - set -eu - umask 077 - mkdir -p '/opt/data' - if [ -e '/opt/data/config.yaml' ]; then cp -p '/opt/data/config.yaml' '/opt/data/config.yaml.superseded'; fi - cp '/seed/hermes-config-yaml-118d92ae7c/config.yaml' '/opt/data/config.yaml.seeding' - chmod 0600 '/opt/data/config.yaml.seeding' - mv '/opt/data/config.yaml.seeding' '/opt/data/config.yaml' - resources: - requests: - memory: 16Mi - cpu: 10m - limits: - memory: 16Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: hermes-config-yaml-118d92ae7c - mountPath: /seed/hermes-config-yaml-118d92ae7c - readOnly: true - - name: hermes-data - mountPath: /opt/data - containers: - - name: hermes - image: docker.io/nousresearch/hermes-agent@sha256:64923faeae267792bf9bf87fe3b4c4869e35004e360c7df01730ad801b74d524 - args: - - gateway - - run - ports: - - name: dashboard - containerPort: 9119 - env: - - name: ANTHROPIC_API_KEY - valueFrom: - secretKeyRef: - name: hermes-agents-hermes - key: anthropic-api-key - optional: true - - name: API_SERVER_ENABLED - value: "false" - - name: GITHUB_PAT - valueFrom: - secretKeyRef: - name: hermes-agents-hermes - key: github-pat - optional: true - - name: HERMES_DASHBOARD - value: "1" - - name: HERMES_DASHBOARD_HOST - value: 0.0.0.0 - - name: HERMES_DASHBOARD_OIDC_CLIENT_ID - value: hermes - - name: HERMES_DASHBOARD_OIDC_ISSUER - value: https://id.jorisjonkers.dev - - name: HERMES_DASHBOARD_OIDC_SCOPES - value: openid profile email - - name: HERMES_DASHBOARD_PORT - value: "9119" - - name: HERMES_DASHBOARD_PUBLIC_URL - value: https://hermes.jorisjonkers.dev - - name: HERMES_SKIP_CONFIG_MIGRATION - value: "false" - - name: HINDSIGHT_API_TOKEN - valueFrom: - secretKeyRef: - name: hermes-agents-hermes - key: hindsight-api-token - optional: true - - name: MEMORY_API_KEY - valueFrom: - secretKeyRef: - name: hermes-agents-hermes - key: memory-api-key - optional: true - - name: OPENAI_API_KEY - valueFrom: - secretKeyRef: - name: hermes-agents-hermes - key: openai-api-key - optional: true - - name: OPENROUTER_API_KEY - valueFrom: - secretKeyRef: - name: hermes-agents-hermes - key: openrouter-api-key - optional: true - - name: OVERLEAF_SESSION - valueFrom: - secretKeyRef: - name: hermes-agents-hermes - key: overleaf-session - optional: true - - name: S6_YES_I_WANT_A_WORLD_WRITABLE_RUN_BECAUSE_KUBERNETES - value: "1" - - name: HOME - value: /tmp - resources: - requests: - memory: 3Gi - cpu: 250m - limits: - memory: 3Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: hermes-data - mountPath: /opt/data - - name: writable-run - mountPath: /run - - name: writable-tmp - mountPath: /tmp - - name: writable-dev-shm - mountPath: /dev/shm - readinessProbe: - httpGet: - path: /api/status - port: 9119 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /api/status - port: 9119 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /api/status - port: 9119 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 24 - volumes: - - name: hermes-data - persistentVolumeClaim: - claimName: hermes-data - - name: hermes-config-yaml-118d92ae7c - configMap: - name: hermes-config-yaml-118d92ae7c - items: - - key: config.yaml - path: config.yaml - - name: writable-run - emptyDir: - sizeLimit: 64Mi - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi - - name: writable-dev-shm - emptyDir: - medium: Memory - sizeLimit: 1Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/canary.yaml deleted file mode 100644 index 6de6583c0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/canary.yaml +++ /dev/null @@ -1,69 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: kubernetes-mcp-server - namespace: agents-system - labels: - app.kubernetes.io/name: kubernetes-mcp-server - app.kubernetes.io/instance: kubernetes-mcp-server - app.kubernetes.io/part-of: kubernetes-mcp-server - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: kubernetes-mcp-server - progressDeadlineSeconds: 180 - service: - port: 8080 - targetPort: mcp - portName: mcp - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: kubernetes-mcp-server - process: kubernetes-mcp-server - revision: sha256:68734b13dd9bd13e73108801924b5f5c1b1c318fcc343a81dacb896c92e91acb - readiness: /healthz - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: kubernetes-mcp-server - process: kubernetes-mcp-server - revision: sha256:68734b13dd9bd13e73108801924b5f5c1b1c318fcc343a81dacb896c92e91acb - readiness: /healthz - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: kubernetes-mcp-server - process: kubernetes-mcp-server - revision: sha256:68734b13dd9bd13e73108801924b5f5c1b1c318fcc343a81dacb896c92e91acb - readiness: /healthz - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: kubernetes-mcp-server - process: kubernetes-mcp-server - revision: sha256:68734b13dd9bd13e73108801924b5f5c1b1c318fcc343a81dacb896c92e91acb - readiness: /healthz - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/configmap.yaml deleted file mode 100644 index 262c78238..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/configmap.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: kubernetes-mcp-server-release-gate - namespace: agents-system - labels: - app.kubernetes.io/part-of: kubernetes-mcp-server - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"180s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"kubernetes-mcp-server","readiness":{"path":"/healthz","port":8080}}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/kustomization.yaml deleted file mode 100644 index f7b15e947..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - rbac.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/networkpolicy.yaml deleted file mode 100644 index c8237986b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/networkpolicy.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: kubernetes-mcp-server - namespace: agents-system - labels: - app.kubernetes.io/name: kubernetes-mcp-server - app.kubernetes.io/instance: kubernetes-mcp-server - app.kubernetes.io/part-of: kubernetes-mcp-server - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: kubernetes-mcp-server - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/kubernetes-mcp-server.mcp: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/rbac.yaml deleted file mode 100644 index 1937d5af8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/rbac.yaml +++ /dev/null @@ -1,110 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: agents-system-kubernetes-mcp-server - labels: - app.kubernetes.io/name: kubernetes-mcp-server - app.kubernetes.io/instance: kubernetes-mcp-server - app.kubernetes.io/part-of: kubernetes-mcp-server - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - pods - - pods/log - - events - - services - - endpoints - - nodes - - namespaces - verbs: - - get - - list - - watch - - apiGroups: - - apps - resources: - - deployments - - statefulsets - - daemonsets - - replicasets - verbs: - - get - - list - - watch - - apiGroups: - - batch - resources: - - jobs - - cronjobs - verbs: - - get - - list - - watch - - apiGroups: - - networking.k8s.io - resources: - - ingresses - - networkpolicies - verbs: - - get - - list - - watch - - apiGroups: - - traefik.io - resources: - - ingressroutes - - middlewares - verbs: - - get - - list - - watch - - apiGroups: - - kustomize.toolkit.fluxcd.io - resources: - - kustomizations - verbs: - - get - - list - - watch - - apiGroups: - - helm.toolkit.fluxcd.io - resources: - - helmreleases - verbs: - - get - - list - - watch - - apiGroups: - - source.toolkit.fluxcd.io - resources: - - gitrepositories - - helmrepositories - - ocirepositories - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: agents-system-kubernetes-mcp-server - labels: - app.kubernetes.io/name: kubernetes-mcp-server - app.kubernetes.io/instance: kubernetes-mcp-server - app.kubernetes.io/part-of: kubernetes-mcp-server - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: agents-system-kubernetes-mcp-server -subjects: - - kind: ServiceAccount - name: kubernetes-mcp-server - namespace: agents-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/serviceaccount.yaml deleted file mode 100644 index e54acb407..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kubernetes-mcp-server - namespace: agents-system - labels: - app.kubernetes.io/name: kubernetes-mcp-server - app.kubernetes.io/instance: kubernetes-mcp-server - app.kubernetes.io/part-of: kubernetes-mcp-server - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/workload.yaml deleted file mode 100644 index 7cf765367..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kubernetes-mcp-server/workload.yaml +++ /dev/null @@ -1,104 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kubernetes-mcp-server - namespace: agents-system - labels: - app.kubernetes.io/name: kubernetes-mcp-server - app.kubernetes.io/instance: kubernetes-mcp-server - app.kubernetes.io/part-of: kubernetes-mcp-server - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 180 - selector: - matchLabels: - app.kubernetes.io/name: kubernetes-mcp-server - app.kubernetes.io/instance: kubernetes-mcp-server - template: - metadata: - labels: - app.kubernetes.io/name: kubernetes-mcp-server - app.kubernetes.io/instance: kubernetes-mcp-server - app.kubernetes.io/part-of: kubernetes-mcp-server - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/kubernetes-mcp-server: 0.0.66 - spec: - serviceAccountName: kubernetes-mcp-server - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: kubernetes-mcp-server - image: quay.io/containers/kubernetes_mcp_server@sha256:6d650f4bd6ac303ad82713c997e73a2d001602f9bf17392c9b9a0e30e29c6423 - args: - - --port=8080 - - --read-only - ports: - - name: mcp - containerPort: 8080 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 4 diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kustomization.yaml deleted file mode 100644 index fd6539c21..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/kustomization.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - agents-api - - agents-ui - - hermes - - kubernetes-mcp-server - - namespace.yaml - - rollout-events - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/namespace.yaml deleted file mode 100644 index 3c01061e2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: agents-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/networkpolicy.yaml deleted file mode 100644 index 5c249c7cf..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: agents-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/rollout-events/alert.yaml deleted file mode 100644 index 610fd5b9e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-agents - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-agents - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-agents - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/rollout-events/provider.yaml deleted file mode 100644 index eb0635913..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-agents - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/configmap.yaml deleted file mode 100644 index eb8c3ea67..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/configmap.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-6ea110f7edda - namespace: agents-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - agents-system-hermes.policy.json: | - {"path":{"secret/data/agents/hermes":{"capabilities":["read"]},"secret/metadata/agents/hermes":{"capabilities":["read"]}}} - agents-system-hermes.role.json: | - {"bound_service_account_names":["hermes"],"bound_service_account_namespaces":["agents-system"],"token_policies":["agents-system-hermes"]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/cronjob.yaml deleted file mode 100644 index ad20476bb..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/cronjob.yaml +++ /dev/null @@ -1,95 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: agents-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-6ea110f7edda - items: - - key: agents-system-hermes.policy.json - path: agents-system-hermes.policy.json - - key: agents-system-hermes.role.json - path: agents-system-hermes.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/job.yaml deleted file mode 100644 index c22d87815..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/job.yaml +++ /dev/null @@ -1,85 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-6ea110f7edda - namespace: agents-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-6ea110f7edda - items: - - key: agents-system-hermes.policy.json - path: agents-system-hermes.policy.json - - key: agents-system-hermes.role.json - path: agents-system-hermes.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/networkpolicy.yaml deleted file mode 100644 index f99ca53e0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: agents-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/policies/agents-system-hermes.policy.json b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/policies/agents-system-hermes.policy.json deleted file mode 100644 index ec85dee85..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/policies/agents-system-hermes.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/agents/hermes": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/agents/hermes": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/policies/agents-system-hermes.role.json b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/policies/agents-system-hermes.role.json deleted file mode 100644 index 2416a1807..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/policies/agents-system-hermes.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "hermes" - ], - "bound_service_account_namespaces": [ - "agents-system" - ], - "token_policies": [ - "agents-system-hermes" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/serviceaccount.yaml deleted file mode 100644 index 7fb91c084..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: agents-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vaultconnection.yaml deleted file mode 100644 index 8f0665b8c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/expected/apps/agents/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: agents-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/agents/oracles b/emf/bundles/cli/src/test/resources/stages/render/agents/oracles deleted file mode 100644 index c2d993e80..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/agents/oracles +++ /dev/null @@ -1,47 +0,0 @@ -apps/agents/agents-api/kustomization.yaml agents/rendered/apps/agents/agents-api/kustomization.yaml -apps/agents/agents-api/networkpolicy.yaml agents/rendered/apps/agents/agents-api/networkpolicy.yaml -apps/agents/agents-api/rbac.yaml agents/rendered/apps/agents/agents-api/rbac.yaml -apps/agents/agents-api/service.yaml agents/rendered/apps/agents/agents-api/service.yaml -apps/agents/agents-api/serviceaccount.yaml agents/rendered/apps/agents/agents-api/serviceaccount.yaml -apps/agents/agents-api/workload.yaml agents/rendered/apps/agents/agents-api/workload.yaml -apps/agents/agents-ui/configmap.yaml agents/rendered/apps/agents/agents-ui/configmap.yaml -apps/agents/agents-ui/kustomization.yaml agents/rendered/apps/agents/agents-ui/kustomization.yaml -apps/agents/agents-ui/networkpolicy.yaml agents/rendered/apps/agents/agents-ui/networkpolicy.yaml -apps/agents/agents-ui/route-public.yaml agents/rendered/apps/agents/agents-ui/route-public.yaml -apps/agents/agents-ui/service.yaml agents/rendered/apps/agents/agents-ui/service.yaml -apps/agents/agents-ui/serviceaccount.yaml agents/rendered/apps/agents/agents-ui/serviceaccount.yaml -apps/agents/agents-ui/workload.yaml agents/rendered/apps/agents/agents-ui/workload.yaml -apps/agents/hermes/backup.yaml agents/rendered/apps/agents/hermes/backup.yaml -apps/agents/hermes/client.yaml agents/rendered/apps/agents/hermes/client.yaml -apps/agents/hermes/configmap.yaml agents/rendered/apps/agents/hermes/configmap.yaml -apps/agents/hermes/kustomization.yaml agents/rendered/apps/agents/hermes/kustomization.yaml -apps/agents/hermes/networkpolicy.yaml agents/rendered/apps/agents/hermes/networkpolicy.yaml -apps/agents/hermes/pvc.yaml agents/rendered/apps/agents/hermes/pvc.yaml -apps/agents/hermes/route-lan.yaml agents/rendered/apps/agents/hermes/route-lan.yaml -apps/agents/hermes/route-public.yaml agents/rendered/apps/agents/hermes/route-public.yaml -apps/agents/hermes/service.yaml agents/rendered/apps/agents/hermes/service.yaml -apps/agents/hermes/serviceaccount.yaml agents/rendered/apps/agents/hermes/serviceaccount.yaml -apps/agents/hermes/vso.yaml agents/rendered/apps/agents/hermes/vso.yaml -apps/agents/hermes/workload.yaml agents/rendered/apps/agents/hermes/workload.yaml -apps/agents/kubernetes-mcp-server/canary.yaml agents/rendered/apps/agents/kubernetes-mcp-server/canary.yaml -apps/agents/kubernetes-mcp-server/configmap.yaml agents/rendered/apps/agents/kubernetes-mcp-server/configmap.yaml -apps/agents/kubernetes-mcp-server/kustomization.yaml agents/rendered/apps/agents/kubernetes-mcp-server/kustomization.yaml -apps/agents/kubernetes-mcp-server/networkpolicy.yaml agents/rendered/apps/agents/kubernetes-mcp-server/networkpolicy.yaml -apps/agents/kubernetes-mcp-server/rbac.yaml agents/rendered/apps/agents/kubernetes-mcp-server/rbac.yaml -apps/agents/kubernetes-mcp-server/serviceaccount.yaml agents/rendered/apps/agents/kubernetes-mcp-server/serviceaccount.yaml -apps/agents/kubernetes-mcp-server/workload.yaml agents/rendered/apps/agents/kubernetes-mcp-server/workload.yaml -apps/agents/kustomization.yaml agents/rendered/apps/agents/kustomization.yaml -apps/agents/namespace.yaml agents/rendered/apps/agents/namespace.yaml -apps/agents/networkpolicy.yaml agents/rendered/apps/agents/networkpolicy.yaml -apps/agents/rollout-events/alert.yaml agents/rendered/apps/agents/rollout-events/alert.yaml -apps/agents/rollout-events/kustomization.yaml agents/rendered/apps/agents/rollout-events/kustomization.yaml -apps/agents/rollout-events/provider.yaml agents/rendered/apps/agents/rollout-events/provider.yaml -apps/agents/vault-policy/configmap.yaml agents/rendered/apps/agents/vault-policy/configmap.yaml -apps/agents/vault-policy/cronjob.yaml agents/rendered/apps/agents/vault-policy/cronjob.yaml -apps/agents/vault-policy/job.yaml agents/rendered/apps/agents/vault-policy/job.yaml -apps/agents/vault-policy/kustomization.yaml agents/rendered/apps/agents/vault-policy/kustomization.yaml -apps/agents/vault-policy/networkpolicy.yaml agents/rendered/apps/agents/vault-policy/networkpolicy.yaml -apps/agents/vault-policy/policies/agents-system-hermes.policy.json agents/rendered/apps/agents/vault-policy/policies/agents-system-hermes.policy.json -apps/agents/vault-policy/policies/agents-system-hermes.role.json agents/rendered/apps/agents/vault-policy/policies/agents-system-hermes.role.json -apps/agents/vault-policy/serviceaccount.yaml agents/rendered/apps/agents/vault-policy/serviceaccount.yaml -apps/agents/vaultconnection.yaml agents/rendered/apps/agents/vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/aliases.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/aliases.yaml deleted file mode 100644 index 388ea9d38..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/aliases.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-postgres - namespace: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: platform-postgres-postgres.estate-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-rabbitmq - namespace: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: platform-rabbitmq-amqp.estate-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-valkey - namespace: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: platform-valkey-redis.estate-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: stalwart - namespace: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: stalwart-smtp.estate-system.svc.cluster.local diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/canary.yaml deleted file mode 100644 index 7cdaf4ee2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/canary.yaml +++ /dev/null @@ -1,176 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: auth-api - autoscalerRef: - apiVersion: autoscaling/v2 - kind: HorizontalPodAutoscaler - name: auth-api - progressDeadlineSeconds: 1920 - service: - port: 8080 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: auth - process: auth-api - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: /api /api/v1/users/register - readiness: /api/actuator/health/readiness - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: auth - process: auth-api - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: /api /api/v1/users/register - readiness: /api/actuator/health/readiness - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: auth - process: auth-api - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: /api /api/v1/users/register - readiness: /api/actuator/health/readiness - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: auth - process: auth-api - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: /api /api/v1/users/register - readiness: /api/actuator/health/readiness - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms ---- -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: auth-api - minReplicas: 2 - maxReplicas: 2 ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: auth-ui - progressDeadlineSeconds: 210 - service: - port: 80 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: auth - process: auth-ui - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: / - readiness: / - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: auth - process: auth-ui - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: / - readiness: / - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: auth - process: auth-ui - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: / - readiness: / - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: auth - process: auth-ui - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: / - readiness: / - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/configmap.yaml deleted file mode 100644 index b67ee6188..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: auth-release-gate - namespace: auth-system - labels: - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"1920s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"checks":["error-rate","latency"],"process":"auth-api","readiness":{"path":"/api/actuator/health/readiness","port":8081}},{"process":"auth-ui","readiness":{"path":"/","port":80}}],"migration":{"identity":"auth-migration","nonTransactional":false,"testedAgainst":"sha256:2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a"}} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: auth-external-checks - namespace: auth-system - labels: - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - auth-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"auth","name":"auth-public-1","url":"https://auth.jorisjonkers.dev/api/v1/users/register"},{"conditions":["[STATUS] < 500"],"group":"auth","name":"auth-public-2","url":"https://auth.jorisjonkers.dev/api"},{"conditions":["[STATUS] < 500"],"group":"auth","name":"auth-public-3","url":"https://auth.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/kustomization.yaml deleted file mode 100644 index 2c2441c0b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/kustomization.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - migration.yaml - - pdb.yaml - - podmonitor.yaml - - route-public.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/migration.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/migration.yaml deleted file mode 100644 index cb5cfcc1b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/migration.yaml +++ /dev/null @@ -1,171 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: auth-migration - namespace: auth-system - labels: - app.kubernetes.io/name: auth-migration - app.kubernetes.io/instance: auth-migration - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: auth-migration-08b008c7a195 - namespace: auth-system - labels: - app.kubernetes.io/name: auth-migration - app.kubernetes.io/instance: auth-migration - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/ssa: IfNotPresent -spec: - suspend: true - backoffLimit: 0 - activeDeadlineSeconds: 600 - template: - metadata: - labels: - app.kubernetes.io/name: auth-migration - app.kubernetes.io/instance: auth-migration - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - annotations: - image.jorisjonkers.dev/migration: 2.3.0 - spec: - serviceAccountName: auth-migration - automountServiceAccountToken: true - restartPolicy: Never - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - containers: - - name: migration - image: ghcr.io/jorisjonkers-dev/auth/auth-migration@sha256:5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7a9b1d3f5c7e - args: - - up - - 08b008c7a195 - env: - - name: DATABASE_HOST - value: postgres.data-system.svc.cluster.local - - name: DATABASE_PORT - value: "5432" - - name: DATABASE_NAME - value: auth_db - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: auth-system-auth-migration - - name: VAULT_CREDENTIALS_PATH - value: database/creds/auth-owner - - name: HOME - value: /tmp - resources: - requests: - memory: 256Mi - cpu: 100m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: scratch - mountPath: /tmp - volumes: - - name: scratch - emptyDir: - sizeLimit: 64Mi ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: auth-migration-down-08b008c7a195 - namespace: auth-system - labels: - app.kubernetes.io/name: auth-migration - app.kubernetes.io/instance: auth-migration - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/ssa: IfNotPresent -spec: - suspend: true - backoffLimit: 0 - activeDeadlineSeconds: 600 - template: - metadata: - labels: - app.kubernetes.io/name: auth-migration - app.kubernetes.io/instance: auth-migration - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - annotations: - image.jorisjonkers.dev/migration: 2.3.0 - spec: - serviceAccountName: auth-migration - automountServiceAccountToken: true - restartPolicy: Never - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - containers: - - name: migration - image: ghcr.io/jorisjonkers-dev/auth/auth-migration@sha256:5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7a9b1d3f5c7e - args: - - down - - 2f4a6c8e0b2d - env: - - name: DATABASE_HOST - value: postgres.data-system.svc.cluster.local - - name: DATABASE_PORT - value: "5432" - - name: DATABASE_NAME - value: auth_db - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: auth-system-auth-migration - - name: VAULT_CREDENTIALS_PATH - value: database/creds/auth-owner - - name: HOME - value: /tmp - resources: - requests: - memory: 256Mi - cpu: 100m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: scratch - mountPath: /tmp - volumes: - - name: scratch - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/networkpolicy.yaml deleted file mode 100644 index 69605586c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/networkpolicy.yaml +++ /dev/null @@ -1,232 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: auth-api - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability-system - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/auth.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - ports: - - protocol: TCP - port: 5432 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: valkey - ports: - - protocol: TCP - port: 6379 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - ports: - - protocol: TCP - port: 5672 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: mail-system - podSelector: - matchLabels: - app.kubernetes.io/instance: stalwart - ports: - - protocol: TCP - port: 25 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: auth-ui - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 80 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/auth.http: "true" - ports: - - protocol: TCP - port: 80 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 80 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: auth-migration - namespace: auth-system - labels: - app.kubernetes.io/name: auth-migration - app.kubernetes.io/instance: auth-migration - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: auth-migration - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - ports: - - protocol: TCP - port: 5432 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/pdb.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/pdb.yaml deleted file mode 100644 index 29a73fa79..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/pdb.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: auth-api-primary diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/podmonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/podmonitor.yaml deleted file mode 100644 index a0d2b1276..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/podmonitor.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: PodMonitor -metadata: - name: auth-api - namespace: auth-system - labels: - release: metrics-stack - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: auth-api - namespaceSelector: - matchNames: - - auth-system - podMetricsEndpoints: - - port: http - path: /api/actuator/prometheus - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/route-public.yaml deleted file mode 100644 index f18b77108..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/route-public.yaml +++ /dev/null @@ -1,68 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: auth-public - namespace: auth-system - labels: - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`auth.jorisjonkers.dev`) && Path(`/api/v1/users/register`) - priority: 999 - middlewares: - - name: security-headers-strict - namespace: edge-system - - name: auth-public-1-rate-limit - namespace: auth-system - services: - - name: auth-api - namespace: auth-system - port: 8080 - - kind: Rule - match: Host(`auth.jorisjonkers.dev`) && PathPrefix(`/api`) - priority: 998 - middlewares: - - name: security-headers-strict - namespace: edge-system - services: - - name: auth-api - namespace: auth-system - port: 8080 - - kind: Rule - match: Host(`auth.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 997 - middlewares: - - name: security-headers-strict - namespace: edge-system - services: - - name: auth-ui - namespace: auth-system - port: 80 - tls: - certResolver: public-frankfurt ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: auth-public-1-rate-limit - namespace: auth-system - labels: - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit -spec: - rateLimit: - average: 10 - period: 1h - burst: 10 - sourceCriterion: - requestHeaderName: CF-Connecting-IP diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/serviceaccount.yaml deleted file mode 100644 index 402c4f525..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/workload.yaml deleted file mode 100644 index 27d0ddb64..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/auth/workload.yaml +++ /dev/null @@ -1,265 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 1920 - selector: - matchLabels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - template: - metadata: - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - consumes.deploy-kit.jorisjonkers.dev/platform-valkey.redis: "true" - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.amqp: "true" - consumes.deploy-kit.jorisjonkers.dev/stalwart.smtp: "true" - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/auth-api: 2.3.0 - spec: - serviceAccountName: auth-api - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - containers: - - name: auth-api - image: ghcr.io/jorisjonkers-dev/auth/auth-api@sha256:3e5a7c9b1d3f5e7a9c1b3d5f7e9a1c3b5d7f9e1a3c5b7d9f1e3a5c7b9d1f3e5a - ports: - - name: http - containerPort: 8080 - env: - - name: AUTH_ISSUER - value: https://auth.jorisjonkers.dev - - name: AUTH_LOGIN_URL - value: https://auth.jorisjonkers.dev/login - - name: CONFIRMATION_URL - value: https://auth.jorisjonkers.dev/confirm - - name: DB_HOST - value: platform-postgres - - name: DB_PORT - value: "5432" - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: MAIL_HOST - value: stalwart - - name: MAIL_PORT - value: "25" - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: auth-api - - name: PORT - value: "8080" - - name: SESSION_COOKIE_SECURE - value: "true" - - name: SPRING_CONFIG_IMPORT - value: vault:// - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_RABBITMQ_HOST - value: platform-rabbitmq - - name: SPRING_RABBITMQ_PORT - value: "5672" - - name: VALKEY_HOST - value: platform-valkey - - name: VALKEY_PORT - value: "6379" - - name: VAULT_AUTHENTICATION - value: KUBERNETES - - name: VAULT_ENABLED - value: "true" - - name: VAULT_KUBERNETES_ROLE - value: auth-system-auth-api - - name: HOME - value: /tmp - resources: - requests: - memory: 768Mi - cpu: 250m - limits: - memory: 768Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-tmp - mountPath: /tmp - readinessProbe: - httpGet: - path: /api/actuator/health/readiness - port: 8081 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /api/actuator/health/liveness - port: 8081 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /api/actuator/health/liveness - port: 8081 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 120 - volumes: - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - template: - metadata: - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/auth-ui: 2.3.0 - spec: - serviceAccountName: auth-ui - priorityClassName: platform-critical-app - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 101 - runAsGroup: 101 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: auth-ui - image: ghcr.io/jorisjonkers-dev/auth/auth-ui@sha256:8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d - ports: - - name: http - containerPort: 80 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - add: - - NET_BIND_SERVICE - drop: - - ALL - volumeMounts: - - name: writable-var-cache-nginx - mountPath: /var/cache/nginx - - name: writable-var-run - mountPath: /var/run - readinessProbe: - httpGet: - path: / - port: 80 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: / - port: 80 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: / - port: 80 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: writable-var-cache-nginx - emptyDir: - sizeLimit: 64Mi - - name: writable-var-run - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/kustomization.yaml deleted file mode 100644 index 5994c89f2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - aliases.yaml - - auth - - namespace.yaml - - rollout-events - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/namespace.yaml deleted file mode 100644 index 375c95b85..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/networkpolicy.yaml deleted file mode 100644 index 0e4c5a823..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/rollout-events/alert.yaml deleted file mode 100644 index 1a87897f6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-auth - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-auth - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-auth - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/rollout-events/provider.yaml deleted file mode 100644 index 9c3f09f4a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-auth - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/configmap.yaml deleted file mode 100644 index 54126b2fc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/configmap.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-e56b08fd2da1 - namespace: auth-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - auth-system-auth-api.policy.json: | - {"path":{"database/creds/auth-data":{"capabilities":["read"]},"secret/data/auth-api":{"capabilities":["read"]},"secret/data/platform/postgres/auth":{"capabilities":["read"]},"secret/metadata/auth-api":{"capabilities":["read"]},"secret/metadata/platform/postgres/auth":{"capabilities":["read"]},"transit/keys/auth-api-jwt":{"capabilities":["read"]},"transit/keys/auth-api-jwt/rotate":{"capabilities":["update"]},"transit/sign/auth-api-jwt":{"capabilities":["update"]}}} - auth-system-auth-api.role.json: | - {"bound_service_account_names":["auth-api"],"bound_service_account_namespaces":["auth-system"],"token_policies":["auth-system-auth-api"]} - auth-system-auth-migration.policy.json: | - {"path":{"database/creds/auth-owner":{"capabilities":["read"]}}} - auth-system-auth-migration.role.json: | - {"bound_service_account_names":["auth-migration"],"bound_service_account_namespaces":["auth-system"],"token_policies":["auth-system-auth-migration"]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/cronjob.yaml deleted file mode 100644 index c2f12552e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/cronjob.yaml +++ /dev/null @@ -1,99 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: auth-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-e56b08fd2da1 - items: - - key: auth-system-auth-api.policy.json - path: auth-system-auth-api.policy.json - - key: auth-system-auth-api.role.json - path: auth-system-auth-api.role.json - - key: auth-system-auth-migration.policy.json - path: auth-system-auth-migration.policy.json - - key: auth-system-auth-migration.role.json - path: auth-system-auth-migration.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/job.yaml deleted file mode 100644 index 0c8da5cc4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/job.yaml +++ /dev/null @@ -1,89 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-e56b08fd2da1 - namespace: auth-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-e56b08fd2da1 - items: - - key: auth-system-auth-api.policy.json - path: auth-system-auth-api.policy.json - - key: auth-system-auth-api.role.json - path: auth-system-auth-api.role.json - - key: auth-system-auth-migration.policy.json - path: auth-system-auth-migration.policy.json - - key: auth-system-auth-migration.role.json - path: auth-system-auth-migration.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/networkpolicy.yaml deleted file mode 100644 index 949ae1390..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: auth-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-api.policy.json b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-api.policy.json deleted file mode 100644 index b7793e400..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-api.policy.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "path": { - "secret/data/platform/postgres/auth": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/postgres/auth": { - "capabilities": [ - "read" - ] - }, - "secret/data/auth-api": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/auth-api": { - "capabilities": [ - "read" - ] - }, - "transit/sign/auth-api-jwt": { - "capabilities": [ - "update" - ] - }, - "transit/keys/auth-api-jwt/rotate": { - "capabilities": [ - "update" - ] - }, - "transit/keys/auth-api-jwt": { - "capabilities": [ - "read" - ] - }, - "database/creds/auth-data": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-api.role.json b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-api.role.json deleted file mode 100644 index 02bd83585..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-api.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "auth-api" - ], - "bound_service_account_namespaces": [ - "auth-system" - ], - "token_policies": [ - "auth-system-auth-api" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.policy.json b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.policy.json deleted file mode 100644 index e33615018..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.policy.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "path": { - "database/creds/auth-owner": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.role.json b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.role.json deleted file mode 100644 index b1e08a895..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "auth-migration" - ], - "bound_service_account_namespaces": [ - "auth-system" - ], - "token_policies": [ - "auth-system-auth-migration" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/serviceaccount.yaml deleted file mode 100644 index 96927b21c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: auth-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vaultconnection.yaml deleted file mode 100644 index a5097ae6a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/apps/auth/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/human-grants/clusterrolebindings.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/human-grants/clusterrolebindings.yaml deleted file mode 100644 index 86311f89c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/human-grants/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: human:oidc:k8s-admin:cluster-admin - labels: - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: oidc:k8s-admin diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/human-grants/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/human-grants/kustomization.yaml deleted file mode 100644 index 029015f5d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/human-grants/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - clusterrolebindings.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/priority-classes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/priority-classes/kustomization.yaml deleted file mode 100644 index 8b06a2f03..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/priority-classes/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/priority-classes/priorityclasses.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/priority-classes/priorityclasses.yaml deleted file mode 100644 index a304512d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/priority-classes/priorityclasses.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-data - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 1000000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "A datastore: it schedules before what reads it." ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-critical-app - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 100000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "The foundation and the Applications the platform names: they keep scheduling under pressure." diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/stable-addresses/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/stable-addresses/kustomization.yaml deleted file mode 100644 index ad77fad11..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/stable-addresses/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - namespace.yaml - - services.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/stable-addresses/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/stable-addresses/namespace.yaml deleted file mode 100644 index 1a599d91f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/stable-addresses/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/stable-addresses/services.yaml b/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/stable-addresses/services.yaml deleted file mode 100644 index 2c743972f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/expected/estate/stable-addresses/services.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-postgres-postgres - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: postgres.data-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-rabbitmq-amqp - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: rabbitmq.data-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-valkey-redis - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: valkey.data-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: stalwart-smtp - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: stalwart.mail-system.svc.cluster.local diff --git a/emf/bundles/cli/src/test/resources/stages/render/auth/oracles b/emf/bundles/cli/src/test/resources/stages/render/auth/oracles deleted file mode 100644 index b37305887..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/auth/oracles +++ /dev/null @@ -1,35 +0,0 @@ -apps/auth/aliases.yaml auth/rendered/apps/auth/aliases.yaml -apps/auth/auth/canary.yaml auth/rendered/apps/auth/auth/canary.yaml -apps/auth/auth/configmap.yaml auth/rendered/apps/auth/auth/configmap.yaml -apps/auth/auth/kustomization.yaml auth/rendered/apps/auth/auth/kustomization.yaml -apps/auth/auth/migration.yaml auth/rendered/apps/auth/auth/migration.yaml -apps/auth/auth/networkpolicy.yaml auth/rendered/apps/auth/auth/networkpolicy.yaml -apps/auth/auth/pdb.yaml auth/rendered/apps/auth/auth/pdb.yaml -apps/auth/auth/podmonitor.yaml auth/rendered/apps/auth/auth/podmonitor.yaml -apps/auth/auth/route-public.yaml auth/rendered/apps/auth/auth/route-public.yaml -apps/auth/auth/serviceaccount.yaml auth/rendered/apps/auth/auth/serviceaccount.yaml -apps/auth/auth/workload.yaml auth/rendered/apps/auth/auth/workload.yaml -apps/auth/kustomization.yaml auth/rendered/apps/auth/kustomization.yaml -apps/auth/namespace.yaml auth/rendered/apps/auth/namespace.yaml -apps/auth/networkpolicy.yaml auth/rendered/apps/auth/networkpolicy.yaml -apps/auth/rollout-events/alert.yaml auth/rendered/apps/auth/rollout-events/alert.yaml -apps/auth/rollout-events/kustomization.yaml auth/rendered/apps/auth/rollout-events/kustomization.yaml -apps/auth/rollout-events/provider.yaml auth/rendered/apps/auth/rollout-events/provider.yaml -apps/auth/vault-policy/configmap.yaml auth/rendered/apps/auth/vault-policy/configmap.yaml -apps/auth/vault-policy/cronjob.yaml auth/rendered/apps/auth/vault-policy/cronjob.yaml -apps/auth/vault-policy/job.yaml auth/rendered/apps/auth/vault-policy/job.yaml -apps/auth/vault-policy/kustomization.yaml auth/rendered/apps/auth/vault-policy/kustomization.yaml -apps/auth/vault-policy/networkpolicy.yaml auth/rendered/apps/auth/vault-policy/networkpolicy.yaml -apps/auth/vault-policy/policies/auth-system-auth-api.policy.json auth/rendered/apps/auth/vault-policy/policies/auth-system-auth-api.policy.json -apps/auth/vault-policy/policies/auth-system-auth-api.role.json auth/rendered/apps/auth/vault-policy/policies/auth-system-auth-api.role.json -apps/auth/vault-policy/policies/auth-system-auth-migration.policy.json auth/rendered/apps/auth/vault-policy/policies/auth-system-auth-migration.policy.json -apps/auth/vault-policy/policies/auth-system-auth-migration.role.json auth/rendered/apps/auth/vault-policy/policies/auth-system-auth-migration.role.json -apps/auth/vault-policy/serviceaccount.yaml auth/rendered/apps/auth/vault-policy/serviceaccount.yaml -apps/auth/vaultconnection.yaml auth/rendered/apps/auth/vaultconnection.yaml -estate/human-grants/clusterrolebindings.yaml platform/rendered/estate/human-grants/clusterrolebindings.yaml -estate/human-grants/kustomization.yaml platform/rendered/estate/human-grants/kustomization.yaml -estate/priority-classes/kustomization.yaml platform/rendered/estate/priority-classes/kustomization.yaml -estate/priority-classes/priorityclasses.yaml platform/rendered/estate/priority-classes/priorityclasses.yaml -estate/stable-addresses/kustomization.yaml auth/rendered/estate/stable-addresses/kustomization.yaml -estate/stable-addresses/namespace.yaml auth/rendered/estate/stable-addresses/namespace.yaml -estate/stable-addresses/services.yaml auth/rendered/estate/stable-addresses/services.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/kustomization.yaml deleted file mode 100644 index 987e82bee..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/kustomization.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - asset-sync - - namespace.yaml - - platform-garage - - platform-mongo - - platform-postgres - - platform-rabbitmq - - platform-valkey - - rollout-events - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/namespace.yaml deleted file mode 100644 index cf7d88ac3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: data-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/networkpolicy.yaml deleted file mode 100644 index efbc30d59..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: data-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/backup.yaml deleted file mode 100644 index cbf43c569..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/backup.yaml +++ /dev/null @@ -1,80 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: postgres-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 45 2 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: postgres-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/postgres-backup@sha256:6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f - env: - - name: BACKUP_RETAIN - value: "90" - - name: BACKUP_OFF_CLUSTER - value: s3://backup-storage/jorisjonkers-dev - - name: BACKUP_OFF_CLUSTER_PATH - value: data/postgres/postgres-data - - name: BACKUP_OFF_CLUSTER_RECIPIENT - value: age1s6v5qrx3mgcgk37gscv8y6z43rssksdct5lx3xk5xrtptjndqvhsnhj7h8 - - name: BACKUP_HOST - value: postgres.data-system.svc.cluster.local - - name: BACKUP_PORT - value: "5432" - envFrom: - - secretRef: - name: postgres-backup-platform-backup-off-cluster - - secretRef: - name: postgres-backup-data-postgres-backup - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: postgres-data - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: postgres-data-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/configmap.yaml deleted file mode 100644 index 7ffa04d4e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/configmap.yaml +++ /dev/null @@ -1,55 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: postgres-postgresql-conf-765c16a293 - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - postgresql.conf: | - # collections/data/platform/config/postgresql.conf - # - # The Asset platform-postgres mounts at /etc/postgresql/postgresql.conf - # (docs/adr/model/0014-file-shaped-configuration-is-an-asset.md). Fully - # static: no placeholder and no derived value, so the file is carried into - # the projection as written, under a name its content digest decides. - - # ------------------------------------------------------------ connections - listen_addresses = '*' - port = 5432 - max_connections = 100 - unix_socket_directories = '/var/run/postgresql' - - # ----------------------------------------------------------------- memory - shared_buffers = 512MB - effective_cache_size = 1536MB - work_mem = 8MB - maintenance_work_mem = 128MB - - # -------------------------------------------------------------------- WAL - wal_level = replica - max_wal_size = 2GB - min_wal_size = 256MB - checkpoint_completion_target = 0.9 - - # -------------------------------------------------------------- extensions - shared_preload_libraries = 'vector' - - # ---------------------------------------------------------------- logging - log_destination = 'stderr' - logging_collector = off - log_min_duration_statement = 1000 - log_line_prefix = '%m [%p] %q%u@%d ' - - # ---------------------------------------------------------------- locale - datestyle = 'iso, mdy' - timezone = 'UTC' - lc_messages = 'en_US.utf8' - default_text_search_config = 'pg_catalog.english' diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/kustomization.yaml deleted file mode 100644 index 5fd130cb5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/kustomization.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - configmap.yaml - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - servicemonitor.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/networkpolicy.yaml deleted file mode 100644 index e09e383ad..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/networkpolicy.yaml +++ /dev/null @@ -1,128 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability-system - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - ports: - - protocol: TCP - port: 9187 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - ports: - - protocol: TCP - port: 5432 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.metrics: "true" - ports: - - protocol: TCP - port: 9187 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres-backup - ports: - - protocol: TCP - port: 5432 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: postgres-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - ports: - - protocol: TCP - port: 5432 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 203.0.113.0/24 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/pvc.yaml deleted file mode 100644 index e7af7a1da..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/pvc.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: postgres-data - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: postgres-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/service.yaml deleted file mode 100644 index bb25a079e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/service.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: postgres - ports: - - name: postgres - port: 5432 - targetPort: postgres - - name: metrics - port: 9187 - targetPort: metrics diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/serviceaccount.yaml deleted file mode 100644 index 579c7347d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: postgres-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/servicemonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/servicemonitor.yaml deleted file mode 100644 index 973c54cbe..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/servicemonitor.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: postgres - namespace: data-system - labels: - release: metrics-stack - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: postgres - namespaceSelector: - matchNames: - - data-system - endpoints: - - port: metrics - path: /metrics - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/vso.yaml deleted file mode 100644 index 3b32d3c59..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/vso.yaml +++ /dev/null @@ -1,114 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-postgres - serviceAccount: postgres ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: postgres-platform-postgres-exporter - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: postgres - mount: secret - type: kv-v2 - path: platform/postgres/exporter - refreshAfter: 10m - hmacSecretData: true - destination: - name: postgres-platform-postgres-exporter - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: postgres ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: postgres-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-postgres-backup - serviceAccount: postgres-backup ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: postgres-backup-platform-backup-off-cluster - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: postgres-backup - mount: secret - type: kv-v2 - path: platform/backup/off-cluster - refreshAfter: 10m - hmacSecretData: true - destination: - name: postgres-backup-platform-backup-off-cluster - create: true - annotations: - flagger.app/config-tracking: disabled ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: postgres-backup-data-postgres-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: postgres-backup - mount: secret - type: kv-v2 - path: data/postgres/backup - refreshAfter: 10m - hmacSecretData: true - destination: - name: postgres-backup-data-postgres-backup - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/workload.yaml deleted file mode 100644 index bcc689338..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-postgres/workload.yaml +++ /dev/null @@ -1,166 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 300 - selector: - matchLabels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - template: - metadata: - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/postgres: 17.2.0 - image.jorisjonkers.dev/postgres-exporter: v0.17.1 - spec: - serviceAccountName: postgres - priorityClassName: platform-data - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: postgres - image: docker.io/pgvector/pgvector@sha256:9c1e3a5b7d9f1c3e5a7b9d1f3c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e - ports: - - name: postgres - containerPort: 5432 - - name: metrics - containerPort: 9187 - env: - - name: DATA_SOURCE_NAME - valueFrom: - secretKeyRef: - name: postgres-platform-postgres-exporter - key: datasource - - name: POSTGRES_DB - value: postgres - - name: POSTGRES_USER - value: postgres - - name: HOME - value: /tmp - resources: - requests: - memory: 2Gi - cpu: 500m - limits: - memory: 2Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: postgres-data - mountPath: /var/lib/postgresql/data - - name: postgres-postgresql-conf-765c16a293 - mountPath: /etc/postgresql/postgresql.conf - subPath: postgresql.conf - readOnly: true - - name: writable-var-run-postgresql - mountPath: /var/run/postgresql - - name: writable-tmp - mountPath: /tmp - readinessProbe: - tcpSocket: - port: 5432 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 5432 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 5432 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 - - name: postgres-exporter - image: quay.io/prometheuscommunity/postgres-exporter@sha256:4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d - env: - - name: DATA_SOURCE_NAME - valueFrom: - secretKeyRef: - name: postgres-platform-postgres-exporter - key: datasource - - name: POSTGRES_DB - value: postgres - - name: POSTGRES_USER - value: postgres - - name: HOME - value: /tmp - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-var-run-postgresql - mountPath: /var/run/postgresql - - name: writable-tmp - mountPath: /tmp - volumes: - - name: postgres-data - persistentVolumeClaim: - claimName: postgres-data - - name: postgres-postgresql-conf-765c16a293 - configMap: - name: postgres-postgresql-conf-765c16a293 - items: - - key: postgresql.conf - path: postgresql.conf - - name: writable-var-run-postgresql - emptyDir: - sizeLimit: 64Mi - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/backup.yaml deleted file mode 100644 index 2c162a569..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/backup.yaml +++ /dev/null @@ -1,72 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: rabbitmq-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 15 3 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: rabbitmq-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/rabbitmq-backup@sha256:a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2 - env: - - name: BACKUP_RETAIN - value: "14" - - name: BACKUP_HOST - value: rabbitmq.data-system.svc.cluster.local - - name: BACKUP_PORT - value: "15672" - envFrom: - - secretRef: - name: rabbitmq-backup-data-rabbitmq-backup - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: rabbitmq-data - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: rabbitmq-data-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/kustomization.yaml deleted file mode 100644 index b098194fe..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/kustomization.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - configmap.yaml - - dashboards.yaml - - pvc.yaml - - route-lan.yaml - - route-management.yaml - - service.yaml - - serviceaccount.yaml - - servicemonitor.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/networkpolicy.yaml deleted file mode 100644 index ff241fb1f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/networkpolicy.yaml +++ /dev/null @@ -1,156 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: rabbitmq - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 15672 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-lan - ports: - - protocol: TCP - port: 15672 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability-system - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - ports: - - protocol: TCP - port: 15692 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.amqp: "true" - ports: - - protocol: TCP - port: 5672 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.management: "true" - ports: - - protocol: TCP - port: 15672 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.metrics: "true" - ports: - - protocol: TCP - port: 15692 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.mqtt: "true" - ports: - - protocol: TCP - port: 1883 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq-backup - ports: - - protocol: TCP - port: 15672 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 1883 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: rabbitmq-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - ports: - - protocol: TCP - port: 15672 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/pvc.yaml deleted file mode 100644 index 7fb2aa3eb..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/pvc.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: rabbitmq-data - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: rabbitmq-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/route-management.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/route-management.yaml deleted file mode 100644 index 71cd6d4d2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/route-management.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: platform-rabbitmq-management - namespace: data-system - labels: - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`rabbitmq.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers - namespace: edge-system - services: - - name: rabbitmq - namespace: data-system - port: 15672 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/service.yaml deleted file mode 100644 index 7c14053a0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/service.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: rabbitmq - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: rabbitmq - ports: - - name: amqp - port: 5672 - targetPort: amqp - - name: management - port: 15672 - targetPort: management - - name: metrics - port: 15692 - targetPort: metrics - - name: mqtt - port: 1883 - targetPort: mqtt ---- -apiVersion: v1 -kind: Service -metadata: - name: rabbitmq-lan-mqtt - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - metallb.io/address-pool: lan-mqtt -spec: - type: LoadBalancer - externalTrafficPolicy: Local - selector: - app.kubernetes.io/instance: rabbitmq - ports: - - name: tcp-1883 - port: 1883 - protocol: TCP - targetPort: 1883 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/serviceaccount.yaml deleted file mode 100644 index 22aa6fb64..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: rabbitmq - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: rabbitmq-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/servicemonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/servicemonitor.yaml deleted file mode 100644 index c7a351189..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/servicemonitor.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: rabbitmq - namespace: data-system - labels: - release: metrics-stack - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - namespaceSelector: - matchNames: - - data-system - endpoints: - - port: metrics - path: /metrics - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/vso.yaml deleted file mode 100644 index a8ee2cce8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/vso.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: rabbitmq-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-rabbitmq-backup - serviceAccount: rabbitmq-backup ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: rabbitmq-backup-data-rabbitmq-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: rabbitmq-backup - mount: secret - type: kv-v2 - path: data/rabbitmq/backup - refreshAfter: 10m - hmacSecretData: true - destination: - name: rabbitmq-backup-data-rabbitmq-backup - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/workload.yaml deleted file mode 100644 index 6e8f4c9b8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-rabbitmq/workload.yaml +++ /dev/null @@ -1,108 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: rabbitmq - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 480 - selector: - matchLabels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - template: - metadata: - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/rabbitmq: 4.0.7 - spec: - serviceAccountName: rabbitmq - priorityClassName: platform-data - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - containers: - - name: rabbitmq - image: docker.io/library/rabbitmq@sha256:2d4f6b8a0c2e4d6f8b0a2c4e6d8f0b2a4c6e8d0f2b4a6c8e0d2f4b6a8c0e2d4f - ports: - - name: amqp - containerPort: 5672 - - name: management - containerPort: 15672 - - name: metrics - containerPort: 15692 - - name: mqtt - containerPort: 1883 - resources: - requests: - memory: 2Gi - cpu: 500m - limits: - memory: 2Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: rabbitmq-data - mountPath: /var/lib/rabbitmq - readinessProbe: - tcpSocket: - port: 5672 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 5672 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 5672 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 24 - volumes: - - name: rabbitmq-data - persistentVolumeClaim: - claimName: rabbitmq-data diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/kustomization.yaml deleted file mode 100644 index 71ff1ac70..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/networkpolicy.yaml deleted file mode 100644 index 47067aa11..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/networkpolicy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: valkey - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: valkey - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-valkey.redis: "true" - ports: - - protocol: TCP - port: 6379 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/pvc.yaml deleted file mode 100644 index 1631b12eb..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/pvc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: valkey-data - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/service.yaml deleted file mode 100644 index ea54c383b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: valkey - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: valkey - ports: - - name: redis - port: 6379 - targetPort: redis diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/serviceaccount.yaml deleted file mode 100644 index b6d570503..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: valkey - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/workload.yaml deleted file mode 100644 index 29bc0d089..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/platform-valkey/workload.yaml +++ /dev/null @@ -1,102 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: valkey - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - template: - metadata: - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/valkey: 8.1.0 - spec: - serviceAccountName: valkey - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: valkey - image: docker.io/valkey/valkey@sha256:6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c - ports: - - name: redis - containerPort: 6379 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: valkey-data - mountPath: /data - readinessProbe: - tcpSocket: - port: 6379 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 6379 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 6379 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: valkey-data - persistentVolumeClaim: - claimName: valkey-data diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/rollout-events/alert.yaml deleted file mode 100644 index 852407496..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-data - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-data - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-data - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/rollout-events/provider.yaml deleted file mode 100644 index 68151d76e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-data - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/configmap.yaml deleted file mode 100644 index 7b16441ef..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/configmap.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-e9176474966e - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - data-system-asset-sync.policy.json: | - {"path":{"secret/data/platform/garage/web-key":{"capabilities":["read"]},"secret/metadata/platform/garage/web-key":{"capabilities":["read"]}}} - data-system-asset-sync.role.json: | - {"bound_service_account_names":["asset-sync"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-asset-sync"]} - data-system-garage.policy.json: | - {"path":{"secret/data/platform/garage":{"capabilities":["read"]},"secret/metadata/platform/garage":{"capabilities":["read"]}}} - data-system-garage.role.json: | - {"bound_service_account_names":["garage"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-garage"]} - data-system-mongo-backup.policy.json: | - {"path":{"secret/data/data/mongo/backup":{"capabilities":["read"]},"secret/data/platform/backup/off-cluster":{"capabilities":["read"]},"secret/metadata/data/mongo/backup":{"capabilities":["read"]},"secret/metadata/platform/backup/off-cluster":{"capabilities":["read"]}}} - data-system-mongo-backup.role.json: | - {"bound_service_account_names":["mongo-backup"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-mongo-backup"]} - data-system-postgres-backup.policy.json: | - {"path":{"secret/data/data/postgres/backup":{"capabilities":["read"]},"secret/data/platform/backup/off-cluster":{"capabilities":["read"]},"secret/metadata/data/postgres/backup":{"capabilities":["read"]},"secret/metadata/platform/backup/off-cluster":{"capabilities":["read"]}}} - data-system-postgres-backup.role.json: | - {"bound_service_account_names":["postgres-backup"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-postgres-backup"]} - data-system-postgres.policy.json: | - {"path":{"secret/data/platform/postgres/exporter":{"capabilities":["read"]},"secret/metadata/platform/postgres/exporter":{"capabilities":["read"]}}} - data-system-postgres.role.json: | - {"bound_service_account_names":["postgres"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-postgres"]} - data-system-rabbitmq-backup.policy.json: | - {"path":{"secret/data/data/rabbitmq/backup":{"capabilities":["read"]},"secret/metadata/data/rabbitmq/backup":{"capabilities":["read"]}}} - data-system-rabbitmq-backup.role.json: | - {"bound_service_account_names":["rabbitmq-backup"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-rabbitmq-backup"]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/cronjob.yaml deleted file mode 100644 index 574012702..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/cronjob.yaml +++ /dev/null @@ -1,115 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-e9176474966e - items: - - key: data-system-asset-sync.policy.json - path: data-system-asset-sync.policy.json - - key: data-system-asset-sync.role.json - path: data-system-asset-sync.role.json - - key: data-system-garage.policy.json - path: data-system-garage.policy.json - - key: data-system-garage.role.json - path: data-system-garage.role.json - - key: data-system-mongo-backup.policy.json - path: data-system-mongo-backup.policy.json - - key: data-system-mongo-backup.role.json - path: data-system-mongo-backup.role.json - - key: data-system-postgres-backup.policy.json - path: data-system-postgres-backup.policy.json - - key: data-system-postgres-backup.role.json - path: data-system-postgres-backup.role.json - - key: data-system-postgres.policy.json - path: data-system-postgres.policy.json - - key: data-system-postgres.role.json - path: data-system-postgres.role.json - - key: data-system-rabbitmq-backup.policy.json - path: data-system-rabbitmq-backup.policy.json - - key: data-system-rabbitmq-backup.role.json - path: data-system-rabbitmq-backup.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/job.yaml deleted file mode 100644 index b7e0cd119..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/job.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-e9176474966e - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-e9176474966e - items: - - key: data-system-asset-sync.policy.json - path: data-system-asset-sync.policy.json - - key: data-system-asset-sync.role.json - path: data-system-asset-sync.role.json - - key: data-system-garage.policy.json - path: data-system-garage.policy.json - - key: data-system-garage.role.json - path: data-system-garage.role.json - - key: data-system-mongo-backup.policy.json - path: data-system-mongo-backup.policy.json - - key: data-system-mongo-backup.role.json - path: data-system-mongo-backup.role.json - - key: data-system-postgres-backup.policy.json - path: data-system-postgres-backup.policy.json - - key: data-system-postgres-backup.role.json - path: data-system-postgres-backup.role.json - - key: data-system-postgres.policy.json - path: data-system-postgres.policy.json - - key: data-system-postgres.role.json - path: data-system-postgres.role.json - - key: data-system-rabbitmq-backup.policy.json - path: data-system-rabbitmq-backup.policy.json - - key: data-system-rabbitmq-backup.role.json - path: data-system-rabbitmq-backup.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/networkpolicy.yaml deleted file mode 100644 index c8cca58b3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json deleted file mode 100644 index 5bb4b204a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "path": { - "secret/data/platform/backup/off-cluster": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/backup/off-cluster": { - "capabilities": [ - "read" - ] - }, - "secret/data/data/postgres/backup": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/data/postgres/backup": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres-backup.role.json b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres-backup.role.json deleted file mode 100644 index 92fc2a159..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres-backup.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "postgres-backup" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-postgres-backup" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres.policy.json b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres.policy.json deleted file mode 100644 index 15c9ba4f6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/platform/postgres/exporter": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/postgres/exporter": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres.role.json b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres.role.json deleted file mode 100644 index e60047242..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-postgres.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "postgres" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-postgres" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json deleted file mode 100644 index dcd53b8c7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/data/rabbitmq/backup": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/data/rabbitmq/backup": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json deleted file mode 100644 index 812e5552c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "rabbitmq-backup" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-rabbitmq-backup" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/serviceaccount.yaml deleted file mode 100644 index 4d4db5b01..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vaultconnection.yaml deleted file mode 100644 index e8ebf385b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/expected/apps/data/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: data-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-full/oracles b/emf/bundles/cli/src/test/resources/stages/render/data-full/oracles deleted file mode 100644 index 4ab29e84d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-full/oracles +++ /dev/null @@ -1,45 +0,0 @@ -apps/data/namespace.yaml data/rendered/apps/data/namespace.yaml -apps/data/kustomization.yaml data/rendered/apps/data/kustomization.yaml -apps/data/networkpolicy.yaml data/rendered/apps/data/networkpolicy.yaml -apps/data/vaultconnection.yaml data/rendered/apps/data/vaultconnection.yaml -apps/data/platform-postgres/kustomization.yaml data/rendered/apps/data/platform-postgres/kustomization.yaml -apps/data/platform-postgres/workload.yaml data/rendered/apps/data/platform-postgres/workload.yaml -apps/data/platform-postgres/service.yaml data/rendered/apps/data/platform-postgres/service.yaml -apps/data/platform-postgres/serviceaccount.yaml data/rendered/apps/data/platform-postgres/serviceaccount.yaml -apps/data/platform-postgres/pvc.yaml data/rendered/apps/data/platform-postgres/pvc.yaml -apps/data/platform-postgres/configmap.yaml data/rendered/apps/data/platform-postgres/configmap.yaml -apps/data/platform-postgres/backup.yaml data/rendered/apps/data/platform-postgres/backup.yaml -apps/data/platform-postgres/servicemonitor.yaml data/rendered/apps/data/platform-postgres/servicemonitor.yaml -apps/data/platform-postgres/vso.yaml data/rendered/apps/data/platform-postgres/vso.yaml -apps/data/platform-postgres/networkpolicy.yaml data/rendered/apps/data/platform-postgres/networkpolicy.yaml -apps/data/platform-rabbitmq/kustomization.yaml data/rendered/apps/data/platform-rabbitmq/kustomization.yaml -apps/data/platform-rabbitmq/route-management.yaml data/rendered/apps/data/platform-rabbitmq/route-management.yaml -apps/data/platform-rabbitmq/workload.yaml data/rendered/apps/data/platform-rabbitmq/workload.yaml -apps/data/platform-rabbitmq/service.yaml data/rendered/apps/data/platform-rabbitmq/service.yaml -apps/data/platform-rabbitmq/serviceaccount.yaml data/rendered/apps/data/platform-rabbitmq/serviceaccount.yaml -apps/data/platform-rabbitmq/pvc.yaml data/rendered/apps/data/platform-rabbitmq/pvc.yaml -apps/data/platform-rabbitmq/backup.yaml data/rendered/apps/data/platform-rabbitmq/backup.yaml -apps/data/platform-rabbitmq/servicemonitor.yaml data/rendered/apps/data/platform-rabbitmq/servicemonitor.yaml -apps/data/platform-rabbitmq/vso.yaml data/rendered/apps/data/platform-rabbitmq/vso.yaml -apps/data/platform-rabbitmq/networkpolicy.yaml data/rendered/apps/data/platform-rabbitmq/networkpolicy.yaml -apps/data/platform-valkey/kustomization.yaml data/rendered/apps/data/platform-valkey/kustomization.yaml -apps/data/platform-valkey/workload.yaml data/rendered/apps/data/platform-valkey/workload.yaml -apps/data/platform-valkey/service.yaml data/rendered/apps/data/platform-valkey/service.yaml -apps/data/platform-valkey/serviceaccount.yaml data/rendered/apps/data/platform-valkey/serviceaccount.yaml -apps/data/platform-valkey/pvc.yaml data/rendered/apps/data/platform-valkey/pvc.yaml -apps/data/platform-valkey/networkpolicy.yaml data/rendered/apps/data/platform-valkey/networkpolicy.yaml -apps/data/vault-policy/policies/data-system-postgres.policy.json data/rendered/apps/data/vault-policy/policies/data-system-postgres.policy.json -apps/data/vault-policy/policies/data-system-postgres.role.json data/rendered/apps/data/vault-policy/policies/data-system-postgres.role.json -apps/data/vault-policy/policies/data-system-postgres-backup.policy.json data/rendered/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json -apps/data/vault-policy/policies/data-system-postgres-backup.role.json data/rendered/apps/data/vault-policy/policies/data-system-postgres-backup.role.json -apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json data/rendered/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json -apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json data/rendered/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json -apps/data/vault-policy/configmap.yaml data/rendered/apps/data/vault-policy/configmap.yaml -apps/data/vault-policy/job.yaml data/rendered/apps/data/vault-policy/job.yaml -apps/data/vault-policy/cronjob.yaml data/rendered/apps/data/vault-policy/cronjob.yaml -apps/data/vault-policy/serviceaccount.yaml data/rendered/apps/data/vault-policy/serviceaccount.yaml -apps/data/vault-policy/networkpolicy.yaml data/rendered/apps/data/vault-policy/networkpolicy.yaml -apps/data/vault-policy/kustomization.yaml data/rendered/apps/data/vault-policy/kustomization.yaml -apps/data/rollout-events/alert.yaml data/rendered/apps/data/rollout-events/alert.yaml -apps/data/rollout-events/provider.yaml data/rendered/apps/data/rollout-events/provider.yaml -apps/data/rollout-events/kustomization.yaml data/rendered/apps/data/rollout-events/kustomization.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/kustomization.yaml deleted file mode 100644 index 1300edca5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/networkpolicy.yaml deleted file mode 100644 index 083f7dabc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/networkpolicy.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: asset-sync - namespace: data-system - labels: - app.kubernetes.io/name: asset-sync - app.kubernetes.io/instance: asset-sync - app.kubernetes.io/part-of: asset-sync - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: asset-sync - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 - - 100.64.0.0/10 - - 169.254.0.0/16 - - 127.0.0.0/8 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/serviceaccount.yaml deleted file mode 100644 index 2b3cb68b3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: asset-sync - namespace: data-system - labels: - app.kubernetes.io/name: asset-sync - app.kubernetes.io/instance: asset-sync - app.kubernetes.io/part-of: asset-sync - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/vso.yaml deleted file mode 100644 index e9b4dd9a9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/vso.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: asset-sync - namespace: data-system - labels: - app.kubernetes.io/name: asset-sync - app.kubernetes.io/instance: asset-sync - app.kubernetes.io/part-of: asset-sync - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-asset-sync - serviceAccount: asset-sync ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: asset-sync-platform-garage-web-key - namespace: data-system - labels: - app.kubernetes.io/name: asset-sync - app.kubernetes.io/instance: asset-sync - app.kubernetes.io/part-of: asset-sync - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: asset-sync - mount: secret - type: kv-v2 - path: platform/garage/web-key - refreshAfter: 10m - hmacSecretData: true - destination: - name: asset-sync-platform-garage-web-key - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/workload.yaml deleted file mode 100644 index 6e372c853..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/asset-sync/workload.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: asset-sync - namespace: data-system - labels: - app.kubernetes.io/name: asset-sync - app.kubernetes.io/instance: asset-sync - app.kubernetes.io/part-of: asset-sync - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "*/15 * * * *" - concurrencyPolicy: Forbid - startingDeadlineSeconds: 300 - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: asset-sync - app.kubernetes.io/instance: asset-sync - app.kubernetes.io/part-of: asset-sync - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/asset-sync: 1.0.0 - spec: - serviceAccountName: asset-sync - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - containers: - - name: asset-sync - image: ghcr.io/jorisjonkers-dev/platform/asset-sync@sha256:5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e - resources: - requests: - memory: 64Mi - cpu: 25m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: secret-asset-sync-platform-garage-web-key - mountPath: /run/secrets/garage - readOnly: true - volumes: - - name: secret-asset-sync-platform-garage-web-key - secret: - secretName: asset-sync-platform-garage-web-key - items: - - key: credentials - path: credentials - defaultMode: 256 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/kustomization.yaml deleted file mode 100644 index 987e82bee..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/kustomization.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - asset-sync - - namespace.yaml - - platform-garage - - platform-mongo - - platform-postgres - - platform-rabbitmq - - platform-valkey - - rollout-events - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/namespace.yaml deleted file mode 100644 index cf7d88ac3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: data-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/networkpolicy.yaml deleted file mode 100644 index efbc30d59..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: data-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/backup.yaml deleted file mode 100644 index c5f60afc0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/backup.yaml +++ /dev/null @@ -1,129 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: garage-snapshots-backup - namespace: data-system - labels: - app.kubernetes.io/name: garage-backup - app.kubernetes.io/instance: garage-backup - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 15 3 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: garage-backup - app.kubernetes.io/instance: garage-backup - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: garage-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/file-backup@sha256:2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d - env: - - name: BACKUP_RETAIN - value: "14" - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: garage-snapshots - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: garage-snapshots-backup ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: garage-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: garage-backup - app.kubernetes.io/instance: garage-backup - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 15 3 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: garage-backup - app.kubernetes.io/instance: garage-backup - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: garage-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/file-backup@sha256:2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d - env: - - name: BACKUP_RETAIN - value: "14" - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: garage-data - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: garage-data-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/configmap.yaml deleted file mode 100644 index 9a542592a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/configmap.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: garage-garage-toml-120c7a969e - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - garage.toml: | - # Garage's own configuration, an Asset: nothing in it is derived. The RPC - # secret and the admin token come from the environment. - metadata_dir = "/var/lib/garage/meta" - data_dir = "/var/lib/garage/data" - db_engine = "lmdb" - - # A consistent copy of the metadata database, which the backup archives in - # place of the live one. - metadata_snapshots_dir = "/var/lib/garage/snapshots" - metadata_auto_snapshot_interval = "6h" - - replication_factor = 1 - rpc_bind_addr = "[::]:3901" - - [s3_api] - s3_region = "garage" - api_bind_addr = "[::]:3900" - - [admin] - api_bind_addr = "[::]:3903" diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/kustomization.yaml deleted file mode 100644 index 759bf5077..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - configmap.yaml - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/networkpolicy.yaml deleted file mode 100644 index b0dbafe56..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/networkpolicy.yaml +++ /dev/null @@ -1,92 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: garage - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: garage - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-garage.s3: "true" - ports: - - protocol: TCP - port: 3900 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-garage.admin: "true" - ports: - - protocol: TCP - port: 3903 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: garage-backup - namespace: data-system - labels: - app.kubernetes.io/name: garage-backup - app.kubernetes.io/instance: garage-backup - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: garage-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/pvc.yaml deleted file mode 100644 index be472abd8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/pvc.yaml +++ /dev/null @@ -1,99 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: garage-meta - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: garage-snapshots - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: garage-snapshots-backup - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: garage-data - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: garage-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/service.yaml deleted file mode 100644 index 01c36cf50..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/service.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: garage - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: garage - ports: - - name: s3 - port: 3900 - targetPort: s3 - - name: admin - port: 3903 - targetPort: admin diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/serviceaccount.yaml deleted file mode 100644 index 41820ee6d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: garage - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: garage-backup - namespace: data-system - labels: - app.kubernetes.io/name: garage-backup - app.kubernetes.io/instance: garage-backup - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/vso.yaml deleted file mode 100644 index df8398f5d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/vso.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: garage - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-garage - serviceAccount: garage ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: garage-platform-garage - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: garage - mount: secret - type: kv-v2 - path: platform/garage - refreshAfter: 10m - hmacSecretData: true - destination: - name: garage-platform-garage - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: garage diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/workload.yaml deleted file mode 100644 index 1b3f0f6c3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-garage/workload.yaml +++ /dev/null @@ -1,131 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: garage - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 300 - selector: - matchLabels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - template: - metadata: - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/garage: 2.3.0 - spec: - serviceAccountName: garage - priorityClassName: platform-data - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - containers: - - name: garage - image: docker.io/dxflrs/garage@sha256:8d0f2b4c6e8a0d2f4b6c8e0a2d4f6b8c0e2a4d6f8b0c2e4a6d8f0b2c4e6a8d0f - ports: - - name: s3 - containerPort: 3900 - - name: admin - containerPort: 3903 - env: - - name: GARAGE_ADMIN_TOKEN - valueFrom: - secretKeyRef: - name: garage-platform-garage - key: admin-token - - name: GARAGE_RPC_SECRET - valueFrom: - secretKeyRef: - name: garage-platform-garage - key: rpc-secret - resources: - requests: - memory: 1Gi - cpu: 200m - limits: - memory: 1Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: garage-meta - mountPath: /var/lib/garage/meta - - name: garage-snapshots - mountPath: /var/lib/garage/snapshots - - name: garage-data - mountPath: /var/lib/garage/data - - name: garage-garage-toml-120c7a969e - mountPath: /etc/garage.toml - subPath: garage.toml - readOnly: true - readinessProbe: - httpGet: - path: /health - port: 3903 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 3900 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 3900 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 - volumes: - - name: garage-meta - persistentVolumeClaim: - claimName: garage-meta - - name: garage-snapshots - persistentVolumeClaim: - claimName: garage-snapshots - - name: garage-data - persistentVolumeClaim: - claimName: garage-data - - name: garage-garage-toml-120c7a969e - configMap: - name: garage-garage-toml-120c7a969e - items: - - key: garage.toml - path: garage.toml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/backup.yaml deleted file mode 100644 index 0f9c7d6b0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/backup.yaml +++ /dev/null @@ -1,80 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: mongo-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 45 2 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.0.0 - spec: - serviceAccountName: mongo-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/mongo-backup@sha256:8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d - env: - - name: BACKUP_RETAIN - value: "90" - - name: BACKUP_OFF_CLUSTER - value: s3://backup-storage/jorisjonkers-dev - - name: BACKUP_OFF_CLUSTER_PATH - value: data/mongo/mongo-data - - name: BACKUP_OFF_CLUSTER_RECIPIENT - value: age1s6v5qrx3mgcgk37gscv8y6z43rssksdct5lx3xk5xrtptjndqvhsnhj7h8 - - name: BACKUP_HOST - value: mongo.data-system.svc.cluster.local - - name: BACKUP_PORT - value: "27017" - envFrom: - - secretRef: - name: mongo-backup-platform-backup-off-cluster - - secretRef: - name: mongo-backup-data-mongo-backup - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: mongo-data - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: mongo-data-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/kustomization.yaml deleted file mode 100644 index 1a2a40343..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/networkpolicy.yaml deleted file mode 100644 index b3c3fc6aa..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/networkpolicy.yaml +++ /dev/null @@ -1,96 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: mongo - namespace: data-system - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: mongo - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-mongo.mongo: "true" - ports: - - protocol: TCP - port: 27017 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: mongo-backup - ports: - - protocol: TCP - port: 27017 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: mongo-backup - namespace: data-system - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: mongo-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: mongo - ports: - - protocol: TCP - port: 27017 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 203.0.113.0/24 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/pvc.yaml deleted file mode 100644 index 98bc72697..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/pvc.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: mongo-data - namespace: data-system - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: mongo-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/service.yaml deleted file mode 100644 index d3bef1e99..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: mongo - namespace: data-system - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: mongo - ports: - - name: mongo - port: 27017 - targetPort: mongo diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/serviceaccount.yaml deleted file mode 100644 index b3f9d29b3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: mongo - namespace: data-system - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: mongo-backup - namespace: data-system - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/vso.yaml deleted file mode 100644 index 36ea571d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/vso.yaml +++ /dev/null @@ -1,68 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: mongo-backup - namespace: data-system - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-mongo-backup - serviceAccount: mongo-backup ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: mongo-backup-platform-backup-off-cluster - namespace: data-system - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: mongo-backup - mount: secret - type: kv-v2 - path: platform/backup/off-cluster - refreshAfter: 10m - hmacSecretData: true - destination: - name: mongo-backup-platform-backup-off-cluster - create: true - annotations: - flagger.app/config-tracking: disabled ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: mongo-backup-data-mongo-backup - namespace: data-system - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: mongo-backup - mount: secret - type: kv-v2 - path: data/mongo/backup - refreshAfter: 10m - hmacSecretData: true - destination: - name: mongo-backup-data-mongo-backup - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/workload.yaml deleted file mode 100644 index 65e92c644..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-mongo/workload.yaml +++ /dev/null @@ -1,120 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: mongo - namespace: data-system - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 300 - selector: - matchLabels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - template: - metadata: - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/mongo: 8.0.15 - spec: - serviceAccountName: mongo - priorityClassName: platform-data - automountServiceAccountToken: false - hostAliases: - - ip: 127.0.0.1 - hostnames: - - mongo.data-system.svc.cluster.local - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: mongo - image: docker.io/library/mongo@sha256:5f7b9d1a3c5e7f9b1d3a5c7e9f1b3d5a7c9e1f3b5d7a9c1e3f5b7d9a1c3e5f7b - ports: - - name: mongo - containerPort: 27017 - env: - - name: HOME - value: /tmp - resources: - requests: - memory: 2Gi - cpu: 200m - limits: - memory: 2Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: mongo-data - mountPath: /data/db - - name: writable-tmp - mountPath: /tmp - - name: writable-data-configdb - mountPath: /data/configdb - readinessProbe: - tcpSocket: - port: 27017 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 27017 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 27017 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 - volumes: - - name: mongo-data - persistentVolumeClaim: - claimName: mongo-data - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi - - name: writable-data-configdb - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/backup.yaml deleted file mode 100644 index cbf43c569..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/backup.yaml +++ /dev/null @@ -1,80 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: postgres-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 45 2 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: postgres-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/postgres-backup@sha256:6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f - env: - - name: BACKUP_RETAIN - value: "90" - - name: BACKUP_OFF_CLUSTER - value: s3://backup-storage/jorisjonkers-dev - - name: BACKUP_OFF_CLUSTER_PATH - value: data/postgres/postgres-data - - name: BACKUP_OFF_CLUSTER_RECIPIENT - value: age1s6v5qrx3mgcgk37gscv8y6z43rssksdct5lx3xk5xrtptjndqvhsnhj7h8 - - name: BACKUP_HOST - value: postgres.data-system.svc.cluster.local - - name: BACKUP_PORT - value: "5432" - envFrom: - - secretRef: - name: postgres-backup-platform-backup-off-cluster - - secretRef: - name: postgres-backup-data-postgres-backup - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: postgres-data - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: postgres-data-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/configmap.yaml deleted file mode 100644 index 7ffa04d4e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/configmap.yaml +++ /dev/null @@ -1,55 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: postgres-postgresql-conf-765c16a293 - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - postgresql.conf: | - # collections/data/platform/config/postgresql.conf - # - # The Asset platform-postgres mounts at /etc/postgresql/postgresql.conf - # (docs/adr/model/0014-file-shaped-configuration-is-an-asset.md). Fully - # static: no placeholder and no derived value, so the file is carried into - # the projection as written, under a name its content digest decides. - - # ------------------------------------------------------------ connections - listen_addresses = '*' - port = 5432 - max_connections = 100 - unix_socket_directories = '/var/run/postgresql' - - # ----------------------------------------------------------------- memory - shared_buffers = 512MB - effective_cache_size = 1536MB - work_mem = 8MB - maintenance_work_mem = 128MB - - # -------------------------------------------------------------------- WAL - wal_level = replica - max_wal_size = 2GB - min_wal_size = 256MB - checkpoint_completion_target = 0.9 - - # -------------------------------------------------------------- extensions - shared_preload_libraries = 'vector' - - # ---------------------------------------------------------------- logging - log_destination = 'stderr' - logging_collector = off - log_min_duration_statement = 1000 - log_line_prefix = '%m [%p] %q%u@%d ' - - # ---------------------------------------------------------------- locale - datestyle = 'iso, mdy' - timezone = 'UTC' - lc_messages = 'en_US.utf8' - default_text_search_config = 'pg_catalog.english' diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/kustomization.yaml deleted file mode 100644 index 5fd130cb5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/kustomization.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - configmap.yaml - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - servicemonitor.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/networkpolicy.yaml deleted file mode 100644 index e09e383ad..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/networkpolicy.yaml +++ /dev/null @@ -1,128 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability-system - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - ports: - - protocol: TCP - port: 9187 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - ports: - - protocol: TCP - port: 5432 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.metrics: "true" - ports: - - protocol: TCP - port: 9187 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres-backup - ports: - - protocol: TCP - port: 5432 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: postgres-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - ports: - - protocol: TCP - port: 5432 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 203.0.113.0/24 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/pvc.yaml deleted file mode 100644 index e7af7a1da..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/pvc.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: postgres-data - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: postgres-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/service.yaml deleted file mode 100644 index bb25a079e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/service.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: postgres - ports: - - name: postgres - port: 5432 - targetPort: postgres - - name: metrics - port: 9187 - targetPort: metrics diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/serviceaccount.yaml deleted file mode 100644 index 579c7347d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: postgres-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/servicemonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/servicemonitor.yaml deleted file mode 100644 index 973c54cbe..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/servicemonitor.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: postgres - namespace: data-system - labels: - release: metrics-stack - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: postgres - namespaceSelector: - matchNames: - - data-system - endpoints: - - port: metrics - path: /metrics - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/vso.yaml deleted file mode 100644 index 3b32d3c59..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/vso.yaml +++ /dev/null @@ -1,114 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-postgres - serviceAccount: postgres ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: postgres-platform-postgres-exporter - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: postgres - mount: secret - type: kv-v2 - path: platform/postgres/exporter - refreshAfter: 10m - hmacSecretData: true - destination: - name: postgres-platform-postgres-exporter - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: postgres ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: postgres-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-postgres-backup - serviceAccount: postgres-backup ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: postgres-backup-platform-backup-off-cluster - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: postgres-backup - mount: secret - type: kv-v2 - path: platform/backup/off-cluster - refreshAfter: 10m - hmacSecretData: true - destination: - name: postgres-backup-platform-backup-off-cluster - create: true - annotations: - flagger.app/config-tracking: disabled ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: postgres-backup-data-postgres-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: postgres-backup - mount: secret - type: kv-v2 - path: data/postgres/backup - refreshAfter: 10m - hmacSecretData: true - destination: - name: postgres-backup-data-postgres-backup - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/workload.yaml deleted file mode 100644 index bcc689338..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-postgres/workload.yaml +++ /dev/null @@ -1,166 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 300 - selector: - matchLabels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - template: - metadata: - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/postgres: 17.2.0 - image.jorisjonkers.dev/postgres-exporter: v0.17.1 - spec: - serviceAccountName: postgres - priorityClassName: platform-data - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: postgres - image: docker.io/pgvector/pgvector@sha256:9c1e3a5b7d9f1c3e5a7b9d1f3c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e - ports: - - name: postgres - containerPort: 5432 - - name: metrics - containerPort: 9187 - env: - - name: DATA_SOURCE_NAME - valueFrom: - secretKeyRef: - name: postgres-platform-postgres-exporter - key: datasource - - name: POSTGRES_DB - value: postgres - - name: POSTGRES_USER - value: postgres - - name: HOME - value: /tmp - resources: - requests: - memory: 2Gi - cpu: 500m - limits: - memory: 2Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: postgres-data - mountPath: /var/lib/postgresql/data - - name: postgres-postgresql-conf-765c16a293 - mountPath: /etc/postgresql/postgresql.conf - subPath: postgresql.conf - readOnly: true - - name: writable-var-run-postgresql - mountPath: /var/run/postgresql - - name: writable-tmp - mountPath: /tmp - readinessProbe: - tcpSocket: - port: 5432 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 5432 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 5432 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 - - name: postgres-exporter - image: quay.io/prometheuscommunity/postgres-exporter@sha256:4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d - env: - - name: DATA_SOURCE_NAME - valueFrom: - secretKeyRef: - name: postgres-platform-postgres-exporter - key: datasource - - name: POSTGRES_DB - value: postgres - - name: POSTGRES_USER - value: postgres - - name: HOME - value: /tmp - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-var-run-postgresql - mountPath: /var/run/postgresql - - name: writable-tmp - mountPath: /tmp - volumes: - - name: postgres-data - persistentVolumeClaim: - claimName: postgres-data - - name: postgres-postgresql-conf-765c16a293 - configMap: - name: postgres-postgresql-conf-765c16a293 - items: - - key: postgresql.conf - path: postgresql.conf - - name: writable-var-run-postgresql - emptyDir: - sizeLimit: 64Mi - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/backup.yaml deleted file mode 100644 index 2c162a569..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/backup.yaml +++ /dev/null @@ -1,72 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: rabbitmq-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 15 3 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: rabbitmq-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/rabbitmq-backup@sha256:a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2 - env: - - name: BACKUP_RETAIN - value: "14" - - name: BACKUP_HOST - value: rabbitmq.data-system.svc.cluster.local - - name: BACKUP_PORT - value: "15672" - envFrom: - - secretRef: - name: rabbitmq-backup-data-rabbitmq-backup - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: rabbitmq-data - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: rabbitmq-data-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/configmap.yaml deleted file mode 100644 index 61d709a82..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/configmap.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: platform-rabbitmq-external-checks - namespace: data-system - labels: - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - platform-rabbitmq-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"data","name":"platform-rabbitmq-management-1","url":"https://rabbitmq.jorisjonkers.dev/"},{"conditions":["[STATUS] < 500"],"group":"data","name":"platform-rabbitmq-lan-1","url":"http://rabbitmq.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/dashboards.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/dashboards.yaml deleted file mode 100644 index b8a621f39..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/dashboards.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaDashboard -metadata: - name: platform-rabbitmq-rabbitmq - namespace: data-system - labels: - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit -spec: - instanceSelector: - matchLabels: - dashboards: grafana - allowCrossNamespaceImport: true - folder: data - json: | - { - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "Prometheus", - "type": "datasource", - "pluginId": "prometheus" - } - ], - "uid": "rabbitmq", - "title": "RabbitMQ", - "tags": ["rabbitmq", "messaging"], - "editable": false, - "refresh": "30s", - "time": { "from": "now-1h", "to": "now" }, - "panels": [ - { - "id": 1, - "title": "Queue Messages (Ready)", - "type": "timeseries", - "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 }, - "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "targets": [ - { "expr": "rabbitmq_queue_messages_ready", "legendFormat": "{{queue}} ready" } - ] - } - ], - "schemaVersion": 39 - } - datasources: - - inputName: DS_PROMETHEUS - datasourceName: prometheus diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/kustomization.yaml deleted file mode 100644 index b098194fe..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/kustomization.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - configmap.yaml - - dashboards.yaml - - pvc.yaml - - route-lan.yaml - - route-management.yaml - - service.yaml - - serviceaccount.yaml - - servicemonitor.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/networkpolicy.yaml deleted file mode 100644 index ff241fb1f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/networkpolicy.yaml +++ /dev/null @@ -1,156 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: rabbitmq - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 15672 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-lan - ports: - - protocol: TCP - port: 15672 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability-system - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - ports: - - protocol: TCP - port: 15692 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.amqp: "true" - ports: - - protocol: TCP - port: 5672 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.management: "true" - ports: - - protocol: TCP - port: 15672 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.metrics: "true" - ports: - - protocol: TCP - port: 15692 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.mqtt: "true" - ports: - - protocol: TCP - port: 1883 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq-backup - ports: - - protocol: TCP - port: 15672 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 1883 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: rabbitmq-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - ports: - - protocol: TCP - port: 15672 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/pvc.yaml deleted file mode 100644 index 7fb2aa3eb..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/pvc.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: rabbitmq-data - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: rabbitmq-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/route-lan.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/route-lan.yaml deleted file mode 100644 index 4f1a917bd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/route-lan.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: platform-rabbitmq-lan - namespace: data-system - labels: - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-lan -spec: - entryPoints: - - web - routes: - - kind: Rule - match: Host(`rabbitmq.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: rabbitmq - namespace: data-system - port: 15672 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/route-management.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/route-management.yaml deleted file mode 100644 index 71cd6d4d2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/route-management.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: platform-rabbitmq-management - namespace: data-system - labels: - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`rabbitmq.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers - namespace: edge-system - services: - - name: rabbitmq - namespace: data-system - port: 15672 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/service.yaml deleted file mode 100644 index 7c14053a0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/service.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: rabbitmq - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: rabbitmq - ports: - - name: amqp - port: 5672 - targetPort: amqp - - name: management - port: 15672 - targetPort: management - - name: metrics - port: 15692 - targetPort: metrics - - name: mqtt - port: 1883 - targetPort: mqtt ---- -apiVersion: v1 -kind: Service -metadata: - name: rabbitmq-lan-mqtt - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - metallb.io/address-pool: lan-mqtt -spec: - type: LoadBalancer - externalTrafficPolicy: Local - selector: - app.kubernetes.io/instance: rabbitmq - ports: - - name: tcp-1883 - port: 1883 - protocol: TCP - targetPort: 1883 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/serviceaccount.yaml deleted file mode 100644 index 22aa6fb64..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: rabbitmq - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: rabbitmq-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/servicemonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/servicemonitor.yaml deleted file mode 100644 index c7a351189..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/servicemonitor.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: rabbitmq - namespace: data-system - labels: - release: metrics-stack - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - namespaceSelector: - matchNames: - - data-system - endpoints: - - port: metrics - path: /metrics - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/vso.yaml deleted file mode 100644 index a8ee2cce8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/vso.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: rabbitmq-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-rabbitmq-backup - serviceAccount: rabbitmq-backup ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: rabbitmq-backup-data-rabbitmq-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: rabbitmq-backup - mount: secret - type: kv-v2 - path: data/rabbitmq/backup - refreshAfter: 10m - hmacSecretData: true - destination: - name: rabbitmq-backup-data-rabbitmq-backup - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/workload.yaml deleted file mode 100644 index 6e8f4c9b8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-rabbitmq/workload.yaml +++ /dev/null @@ -1,108 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: rabbitmq - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 480 - selector: - matchLabels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - template: - metadata: - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/rabbitmq: 4.0.7 - spec: - serviceAccountName: rabbitmq - priorityClassName: platform-data - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - containers: - - name: rabbitmq - image: docker.io/library/rabbitmq@sha256:2d4f6b8a0c2e4d6f8b0a2c4e6d8f0b2a4c6e8d0f2b4a6c8e0d2f4b6a8c0e2d4f - ports: - - name: amqp - containerPort: 5672 - - name: management - containerPort: 15672 - - name: metrics - containerPort: 15692 - - name: mqtt - containerPort: 1883 - resources: - requests: - memory: 2Gi - cpu: 500m - limits: - memory: 2Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: rabbitmq-data - mountPath: /var/lib/rabbitmq - readinessProbe: - tcpSocket: - port: 5672 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 5672 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 5672 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 24 - volumes: - - name: rabbitmq-data - persistentVolumeClaim: - claimName: rabbitmq-data diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/kustomization.yaml deleted file mode 100644 index 71ff1ac70..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/networkpolicy.yaml deleted file mode 100644 index 47067aa11..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/networkpolicy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: valkey - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: valkey - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-valkey.redis: "true" - ports: - - protocol: TCP - port: 6379 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/pvc.yaml deleted file mode 100644 index 1631b12eb..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/pvc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: valkey-data - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/service.yaml deleted file mode 100644 index ea54c383b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: valkey - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: valkey - ports: - - name: redis - port: 6379 - targetPort: redis diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/serviceaccount.yaml deleted file mode 100644 index b6d570503..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: valkey - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/workload.yaml deleted file mode 100644 index 29bc0d089..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/platform-valkey/workload.yaml +++ /dev/null @@ -1,102 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: valkey - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - template: - metadata: - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/valkey: 8.1.0 - spec: - serviceAccountName: valkey - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: valkey - image: docker.io/valkey/valkey@sha256:6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c - ports: - - name: redis - containerPort: 6379 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: valkey-data - mountPath: /data - readinessProbe: - tcpSocket: - port: 6379 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 6379 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 6379 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: valkey-data - persistentVolumeClaim: - claimName: valkey-data diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/rollout-events/alert.yaml deleted file mode 100644 index 852407496..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-data - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-data - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-data - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/rollout-events/provider.yaml deleted file mode 100644 index 68151d76e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-data - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/configmap.yaml deleted file mode 100644 index 7b16441ef..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/configmap.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-e9176474966e - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - data-system-asset-sync.policy.json: | - {"path":{"secret/data/platform/garage/web-key":{"capabilities":["read"]},"secret/metadata/platform/garage/web-key":{"capabilities":["read"]}}} - data-system-asset-sync.role.json: | - {"bound_service_account_names":["asset-sync"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-asset-sync"]} - data-system-garage.policy.json: | - {"path":{"secret/data/platform/garage":{"capabilities":["read"]},"secret/metadata/platform/garage":{"capabilities":["read"]}}} - data-system-garage.role.json: | - {"bound_service_account_names":["garage"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-garage"]} - data-system-mongo-backup.policy.json: | - {"path":{"secret/data/data/mongo/backup":{"capabilities":["read"]},"secret/data/platform/backup/off-cluster":{"capabilities":["read"]},"secret/metadata/data/mongo/backup":{"capabilities":["read"]},"secret/metadata/platform/backup/off-cluster":{"capabilities":["read"]}}} - data-system-mongo-backup.role.json: | - {"bound_service_account_names":["mongo-backup"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-mongo-backup"]} - data-system-postgres-backup.policy.json: | - {"path":{"secret/data/data/postgres/backup":{"capabilities":["read"]},"secret/data/platform/backup/off-cluster":{"capabilities":["read"]},"secret/metadata/data/postgres/backup":{"capabilities":["read"]},"secret/metadata/platform/backup/off-cluster":{"capabilities":["read"]}}} - data-system-postgres-backup.role.json: | - {"bound_service_account_names":["postgres-backup"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-postgres-backup"]} - data-system-postgres.policy.json: | - {"path":{"secret/data/platform/postgres/exporter":{"capabilities":["read"]},"secret/metadata/platform/postgres/exporter":{"capabilities":["read"]}}} - data-system-postgres.role.json: | - {"bound_service_account_names":["postgres"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-postgres"]} - data-system-rabbitmq-backup.policy.json: | - {"path":{"secret/data/data/rabbitmq/backup":{"capabilities":["read"]},"secret/metadata/data/rabbitmq/backup":{"capabilities":["read"]}}} - data-system-rabbitmq-backup.role.json: | - {"bound_service_account_names":["rabbitmq-backup"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-rabbitmq-backup"]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/cronjob.yaml deleted file mode 100644 index 574012702..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/cronjob.yaml +++ /dev/null @@ -1,115 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-e9176474966e - items: - - key: data-system-asset-sync.policy.json - path: data-system-asset-sync.policy.json - - key: data-system-asset-sync.role.json - path: data-system-asset-sync.role.json - - key: data-system-garage.policy.json - path: data-system-garage.policy.json - - key: data-system-garage.role.json - path: data-system-garage.role.json - - key: data-system-mongo-backup.policy.json - path: data-system-mongo-backup.policy.json - - key: data-system-mongo-backup.role.json - path: data-system-mongo-backup.role.json - - key: data-system-postgres-backup.policy.json - path: data-system-postgres-backup.policy.json - - key: data-system-postgres-backup.role.json - path: data-system-postgres-backup.role.json - - key: data-system-postgres.policy.json - path: data-system-postgres.policy.json - - key: data-system-postgres.role.json - path: data-system-postgres.role.json - - key: data-system-rabbitmq-backup.policy.json - path: data-system-rabbitmq-backup.policy.json - - key: data-system-rabbitmq-backup.role.json - path: data-system-rabbitmq-backup.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/job.yaml deleted file mode 100644 index b7e0cd119..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/job.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-e9176474966e - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-e9176474966e - items: - - key: data-system-asset-sync.policy.json - path: data-system-asset-sync.policy.json - - key: data-system-asset-sync.role.json - path: data-system-asset-sync.role.json - - key: data-system-garage.policy.json - path: data-system-garage.policy.json - - key: data-system-garage.role.json - path: data-system-garage.role.json - - key: data-system-mongo-backup.policy.json - path: data-system-mongo-backup.policy.json - - key: data-system-mongo-backup.role.json - path: data-system-mongo-backup.role.json - - key: data-system-postgres-backup.policy.json - path: data-system-postgres-backup.policy.json - - key: data-system-postgres-backup.role.json - path: data-system-postgres-backup.role.json - - key: data-system-postgres.policy.json - path: data-system-postgres.policy.json - - key: data-system-postgres.role.json - path: data-system-postgres.role.json - - key: data-system-rabbitmq-backup.policy.json - path: data-system-rabbitmq-backup.policy.json - - key: data-system-rabbitmq-backup.role.json - path: data-system-rabbitmq-backup.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/networkpolicy.yaml deleted file mode 100644 index c8cca58b3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-asset-sync.policy.json b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-asset-sync.policy.json deleted file mode 100644 index c37c02871..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-asset-sync.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/platform/garage/web-key": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/garage/web-key": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-asset-sync.role.json b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-asset-sync.role.json deleted file mode 100644 index 98679d81f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-asset-sync.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "asset-sync" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-asset-sync" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-garage.policy.json b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-garage.policy.json deleted file mode 100644 index ce342e581..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-garage.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/platform/garage": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/garage": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-garage.role.json b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-garage.role.json deleted file mode 100644 index 056988d39..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-garage.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "garage" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-garage" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-mongo-backup.policy.json b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-mongo-backup.policy.json deleted file mode 100644 index 48737a6d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-mongo-backup.policy.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "path": { - "secret/data/platform/backup/off-cluster": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/backup/off-cluster": { - "capabilities": [ - "read" - ] - }, - "secret/data/data/mongo/backup": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/data/mongo/backup": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-mongo-backup.role.json b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-mongo-backup.role.json deleted file mode 100644 index dcebd1594..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-mongo-backup.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "mongo-backup" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-mongo-backup" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json deleted file mode 100644 index 5bb4b204a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "path": { - "secret/data/platform/backup/off-cluster": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/backup/off-cluster": { - "capabilities": [ - "read" - ] - }, - "secret/data/data/postgres/backup": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/data/postgres/backup": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres-backup.role.json b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres-backup.role.json deleted file mode 100644 index 92fc2a159..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres-backup.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "postgres-backup" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-postgres-backup" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres.policy.json b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres.policy.json deleted file mode 100644 index 15c9ba4f6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/platform/postgres/exporter": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/postgres/exporter": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres.role.json b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres.role.json deleted file mode 100644 index e60047242..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-postgres.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "postgres" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-postgres" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json deleted file mode 100644 index dcd53b8c7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/data/rabbitmq/backup": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/data/rabbitmq/backup": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json deleted file mode 100644 index 812e5552c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "rabbitmq-backup" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-rabbitmq-backup" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/serviceaccount.yaml deleted file mode 100644 index 4d4db5b01..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vaultconnection.yaml deleted file mode 100644 index e8ebf385b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/expected/apps/data/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: data-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/data-main/oracles b/emf/bundles/cli/src/test/resources/stages/render/data-main/oracles deleted file mode 100644 index 59eb97e61..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/data-main/oracles +++ /dev/null @@ -1,76 +0,0 @@ -apps/data/asset-sync/kustomization.yaml data/rendered/apps/data/asset-sync/kustomization.yaml -apps/data/asset-sync/networkpolicy.yaml data/rendered/apps/data/asset-sync/networkpolicy.yaml -apps/data/asset-sync/serviceaccount.yaml data/rendered/apps/data/asset-sync/serviceaccount.yaml -apps/data/asset-sync/vso.yaml data/rendered/apps/data/asset-sync/vso.yaml -apps/data/asset-sync/workload.yaml data/rendered/apps/data/asset-sync/workload.yaml -apps/data/kustomization.yaml data/rendered/apps/data/kustomization.yaml -apps/data/namespace.yaml data/rendered/apps/data/namespace.yaml -apps/data/networkpolicy.yaml data/rendered/apps/data/networkpolicy.yaml -apps/data/platform-garage/backup.yaml data/rendered/apps/data/platform-garage/backup.yaml -apps/data/platform-garage/configmap.yaml data/rendered/apps/data/platform-garage/configmap.yaml -apps/data/platform-garage/kustomization.yaml data/rendered/apps/data/platform-garage/kustomization.yaml -apps/data/platform-garage/networkpolicy.yaml data/rendered/apps/data/platform-garage/networkpolicy.yaml -apps/data/platform-garage/pvc.yaml data/rendered/apps/data/platform-garage/pvc.yaml -apps/data/platform-garage/service.yaml data/rendered/apps/data/platform-garage/service.yaml -apps/data/platform-garage/serviceaccount.yaml data/rendered/apps/data/platform-garage/serviceaccount.yaml -apps/data/platform-garage/vso.yaml data/rendered/apps/data/platform-garage/vso.yaml -apps/data/platform-garage/workload.yaml data/rendered/apps/data/platform-garage/workload.yaml -apps/data/platform-mongo/backup.yaml data/rendered/apps/data/platform-mongo/backup.yaml -apps/data/platform-mongo/kustomization.yaml data/rendered/apps/data/platform-mongo/kustomization.yaml -apps/data/platform-mongo/networkpolicy.yaml data/rendered/apps/data/platform-mongo/networkpolicy.yaml -apps/data/platform-mongo/pvc.yaml data/rendered/apps/data/platform-mongo/pvc.yaml -apps/data/platform-mongo/service.yaml data/rendered/apps/data/platform-mongo/service.yaml -apps/data/platform-mongo/serviceaccount.yaml data/rendered/apps/data/platform-mongo/serviceaccount.yaml -apps/data/platform-mongo/vso.yaml data/rendered/apps/data/platform-mongo/vso.yaml -apps/data/platform-mongo/workload.yaml data/rendered/apps/data/platform-mongo/workload.yaml -apps/data/platform-postgres/backup.yaml data/rendered/apps/data/platform-postgres/backup.yaml -apps/data/platform-postgres/configmap.yaml data/rendered/apps/data/platform-postgres/configmap.yaml -apps/data/platform-postgres/kustomization.yaml data/rendered/apps/data/platform-postgres/kustomization.yaml -apps/data/platform-postgres/networkpolicy.yaml data/rendered/apps/data/platform-postgres/networkpolicy.yaml -apps/data/platform-postgres/pvc.yaml data/rendered/apps/data/platform-postgres/pvc.yaml -apps/data/platform-postgres/service.yaml data/rendered/apps/data/platform-postgres/service.yaml -apps/data/platform-postgres/serviceaccount.yaml data/rendered/apps/data/platform-postgres/serviceaccount.yaml -apps/data/platform-postgres/servicemonitor.yaml data/rendered/apps/data/platform-postgres/servicemonitor.yaml -apps/data/platform-postgres/vso.yaml data/rendered/apps/data/platform-postgres/vso.yaml -apps/data/platform-postgres/workload.yaml data/rendered/apps/data/platform-postgres/workload.yaml -apps/data/platform-rabbitmq/backup.yaml data/rendered/apps/data/platform-rabbitmq/backup.yaml -apps/data/platform-rabbitmq/configmap.yaml data/rendered/apps/data/platform-rabbitmq/configmap.yaml -apps/data/platform-rabbitmq/dashboards.yaml data/rendered/apps/data/platform-rabbitmq/dashboards.yaml -apps/data/platform-rabbitmq/kustomization.yaml data/rendered/apps/data/platform-rabbitmq/kustomization.yaml -apps/data/platform-rabbitmq/networkpolicy.yaml data/rendered/apps/data/platform-rabbitmq/networkpolicy.yaml -apps/data/platform-rabbitmq/pvc.yaml data/rendered/apps/data/platform-rabbitmq/pvc.yaml -apps/data/platform-rabbitmq/route-lan.yaml data/rendered/apps/data/platform-rabbitmq/route-lan.yaml -apps/data/platform-rabbitmq/route-management.yaml data/rendered/apps/data/platform-rabbitmq/route-management.yaml -apps/data/platform-rabbitmq/service.yaml data/rendered/apps/data/platform-rabbitmq/service.yaml -apps/data/platform-rabbitmq/serviceaccount.yaml data/rendered/apps/data/platform-rabbitmq/serviceaccount.yaml -apps/data/platform-rabbitmq/servicemonitor.yaml data/rendered/apps/data/platform-rabbitmq/servicemonitor.yaml -apps/data/platform-rabbitmq/vso.yaml data/rendered/apps/data/platform-rabbitmq/vso.yaml -apps/data/platform-rabbitmq/workload.yaml data/rendered/apps/data/platform-rabbitmq/workload.yaml -apps/data/platform-valkey/kustomization.yaml data/rendered/apps/data/platform-valkey/kustomization.yaml -apps/data/platform-valkey/networkpolicy.yaml data/rendered/apps/data/platform-valkey/networkpolicy.yaml -apps/data/platform-valkey/pvc.yaml data/rendered/apps/data/platform-valkey/pvc.yaml -apps/data/platform-valkey/service.yaml data/rendered/apps/data/platform-valkey/service.yaml -apps/data/platform-valkey/serviceaccount.yaml data/rendered/apps/data/platform-valkey/serviceaccount.yaml -apps/data/platform-valkey/workload.yaml data/rendered/apps/data/platform-valkey/workload.yaml -apps/data/rollout-events/alert.yaml data/rendered/apps/data/rollout-events/alert.yaml -apps/data/rollout-events/kustomization.yaml data/rendered/apps/data/rollout-events/kustomization.yaml -apps/data/rollout-events/provider.yaml data/rendered/apps/data/rollout-events/provider.yaml -apps/data/vault-policy/configmap.yaml data/rendered/apps/data/vault-policy/configmap.yaml -apps/data/vault-policy/cronjob.yaml data/rendered/apps/data/vault-policy/cronjob.yaml -apps/data/vault-policy/job.yaml data/rendered/apps/data/vault-policy/job.yaml -apps/data/vault-policy/kustomization.yaml data/rendered/apps/data/vault-policy/kustomization.yaml -apps/data/vault-policy/networkpolicy.yaml data/rendered/apps/data/vault-policy/networkpolicy.yaml -apps/data/vault-policy/policies/data-system-asset-sync.policy.json data/rendered/apps/data/vault-policy/policies/data-system-asset-sync.policy.json -apps/data/vault-policy/policies/data-system-asset-sync.role.json data/rendered/apps/data/vault-policy/policies/data-system-asset-sync.role.json -apps/data/vault-policy/policies/data-system-garage.policy.json data/rendered/apps/data/vault-policy/policies/data-system-garage.policy.json -apps/data/vault-policy/policies/data-system-garage.role.json data/rendered/apps/data/vault-policy/policies/data-system-garage.role.json -apps/data/vault-policy/policies/data-system-mongo-backup.policy.json data/rendered/apps/data/vault-policy/policies/data-system-mongo-backup.policy.json -apps/data/vault-policy/policies/data-system-mongo-backup.role.json data/rendered/apps/data/vault-policy/policies/data-system-mongo-backup.role.json -apps/data/vault-policy/policies/data-system-postgres-backup.policy.json data/rendered/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json -apps/data/vault-policy/policies/data-system-postgres-backup.role.json data/rendered/apps/data/vault-policy/policies/data-system-postgres-backup.role.json -apps/data/vault-policy/policies/data-system-postgres.policy.json data/rendered/apps/data/vault-policy/policies/data-system-postgres.policy.json -apps/data/vault-policy/policies/data-system-postgres.role.json data/rendered/apps/data/vault-policy/policies/data-system-postgres.role.json -apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json data/rendered/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json -apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json data/rendered/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json -apps/data/vault-policy/serviceaccount.yaml data/rendered/apps/data/vault-policy/serviceaccount.yaml -apps/data/vaultconnection.yaml data/rendered/apps/data/vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/networkpolicy.yaml deleted file mode 100644 index 8d07aedcd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/networkpolicy.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: collector - namespace: delivery-system - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: collector - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/collector.http: "true" - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/rbac.yaml deleted file mode 100644 index a4474cbe2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/rbac.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: delivery-system-collector - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - persistentvolumes - - persistentvolumeclaims - - pods - verbs: - - get - - list ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: delivery-system-collector - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: delivery-system-collector -subjects: - - kind: ServiceAccount - name: collector - namespace: delivery-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/service.yaml deleted file mode 100644 index 0e2aa1f96..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: collector - namespace: delivery-system - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: collector - ports: - - name: http - port: 8080 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/serviceaccount.yaml deleted file mode 100644 index 8f989217c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: collector - namespace: delivery-system - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/workload.yaml deleted file mode 100644 index 565d8b443..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/collector/workload.yaml +++ /dev/null @@ -1,98 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: collector - namespace: delivery-system - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 150 - selector: - matchLabels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - template: - metadata: - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/collector: 1.0.0 - spec: - serviceAccountName: collector - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: collector - image: ghcr.io/jorisjonkers-dev/delivery/collector@sha256:7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e7b9d - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /readyz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /fresh - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /fresh - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 2 diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/networkpolicy.yaml deleted file mode 100644 index fafff2c79..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/networkpolicy.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: flagger - namespace: delivery-system - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: flagger - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/flagger.http: "true" - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/rbac.yaml deleted file mode 100644 index 68334f066..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/rbac.yaml +++ /dev/null @@ -1,94 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: delivery-system-flagger - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - flagger.app - resources: - - canaries - - canaries/status - verbs: - - get - - list - - watch - - update - - patch - - apiGroups: - - apps - resources: - - deployments - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - autoscaling - resources: - - horizontalpodautoscalers - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - "" - resources: - - services - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - "" - resources: - - secrets - verbs: - - get - - apiGroups: - - "" - resources: - - events - verbs: - - create - - update - - patch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: delivery-system-flagger - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: delivery-system-flagger -subjects: - - kind: ServiceAccount - name: flagger - namespace: delivery-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/service.yaml deleted file mode 100644 index d8a64dd99..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: flagger - namespace: delivery-system - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: flagger - ports: - - name: http - port: 8080 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/serviceaccount.yaml deleted file mode 100644 index 674218776..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: flagger - namespace: delivery-system - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/workload.yaml deleted file mode 100644 index 38dc3293c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/flagger/workload.yaml +++ /dev/null @@ -1,112 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: flagger - namespace: delivery-system - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - template: - metadata: - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - consumes.deploy-kit.jorisjonkers.dev/release-gate.http: "true" - annotations: - image.jorisjonkers.dev/flagger: 1.41.0 - spec: - serviceAccountName: flagger - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 10001 - runAsGroup: 10001 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: flagger - image: ghcr.io/fluxcd/flagger@sha256:5d1b8f3e7a2c9d4b6e0f1a3c5e7b9d2f4a6c8e0b1d3f5a7c9e2b4d6f8a0c1e3b - ports: - - name: http - containerPort: 8080 - env: - - name: HOME - value: /tmp - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-tmp - mountPath: /tmp - readinessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/kustomization.yaml deleted file mode 100644 index 765f75ad8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - collector - - flagger - - namespace.yaml - - release-gate - - reporter - - rollout-events diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/namespace.yaml deleted file mode 100644 index 4b797d4c2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: delivery-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/networkpolicy.yaml deleted file mode 100644 index 31bd709f7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: delivery-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/kustomization.yaml deleted file mode 100644 index 53001dc91..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - servicemonitor.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/networkpolicy.yaml deleted file mode 100644 index 2765b7ae9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/networkpolicy.yaml +++ /dev/null @@ -1,64 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: release-gate - namespace: delivery-system - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability-system - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/release-gate.http: "true" - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/rbac.yaml deleted file mode 100644 index dbf5581c7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/rbac.yaml +++ /dev/null @@ -1,113 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: release-gate - namespace: delivery-system - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - configmaps - verbs: - - create - - update ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: release-gate - namespace: delivery-system - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: release-gate -subjects: - - kind: ServiceAccount - name: release-gate - namespace: delivery-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: delivery-system-release-gate - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - apiGroups: - - "" - resources: - - pods - verbs: - - list - - apiGroups: - - apps - resources: - - deployments - verbs: - - get - - apiGroups: - - batch - resources: - - jobs - verbs: - - list - - patch - - apiGroups: - - flagger.app - resources: - - canaries - verbs: - - get - - apiGroups: - - secrets.hashicorp.com - resources: - - vaultauths - - vaultstaticsecrets - - vaultdynamicsecrets - verbs: - - list - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: delivery-system-release-gate - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: delivery-system-release-gate -subjects: - - kind: ServiceAccount - name: release-gate - namespace: delivery-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/service.yaml deleted file mode 100644 index 647c16cf5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: release-gate - namespace: delivery-system - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: release-gate - ports: - - name: http - port: 8080 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/serviceaccount.yaml deleted file mode 100644 index d60bd49f1..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: release-gate - namespace: delivery-system - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/servicemonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/servicemonitor.yaml deleted file mode 100644 index 3c5e4b1cd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/servicemonitor.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: release-gate - namespace: delivery-system - labels: - release: metrics-stack - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: release-gate - namespaceSelector: - matchNames: - - delivery-system - endpoints: - - port: http - path: /metrics - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/workload.yaml deleted file mode 100644 index 4d9294410..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/release-gate/workload.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: release-gate - namespace: delivery-system - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 - progressDeadlineSeconds: 150 - selector: - matchLabels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - template: - metadata: - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/release-gate: 1.0.0 - spec: - serviceAccountName: release-gate - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: release-gate - image: ghcr.io/jorisjonkers-dev/delivery/release-gate@sha256:3e7a9c1d5b2f8e4a6c0d9b7e5f3a1c8d6e4b2a0f9c7e5d3b1a8f6e4c2d0b9a7e - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 64Mi - cpu: 25m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /readyz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 2 diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/networkpolicy.yaml deleted file mode 100644 index 9eaf95d10..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/networkpolicy.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: reporter - namespace: delivery-system - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: reporter - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/reporter.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: flux-system - podSelector: - matchLabels: - app: notification-controller - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/rbac.yaml deleted file mode 100644 index 8b0dcef60..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/rbac.yaml +++ /dev/null @@ -1,48 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: delivery-system-reporter - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - kustomize.toolkit.fluxcd.io - resources: - - kustomizations - verbs: - - get - - list - - watch - - apiGroups: - - flagger.app - resources: - - canaries - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: delivery-system-reporter - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: delivery-system-reporter -subjects: - - kind: ServiceAccount - name: reporter - namespace: delivery-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/service.yaml deleted file mode 100644 index 82daacef8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: reporter - namespace: delivery-system - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: reporter - ports: - - name: http - port: 8080 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/serviceaccount.yaml deleted file mode 100644 index 43955743a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: reporter - namespace: delivery-system - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/workload.yaml deleted file mode 100644 index 73cc075db..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/reporter/workload.yaml +++ /dev/null @@ -1,98 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: reporter - namespace: delivery-system - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 150 - selector: - matchLabels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - template: - metadata: - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/reporter: 1.0.0 - spec: - serviceAccountName: reporter - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: reporter - image: ghcr.io/jorisjonkers-dev/delivery/reporter@sha256:4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /readyz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 2 diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/rollout-events/alert.yaml deleted file mode 100644 index 7397d5331..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-delivery - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-delivery - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-delivery - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/rollout-events/provider.yaml deleted file mode 100644 index a711aecf6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/expected/apps/delivery/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-delivery - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/delivery/oracles b/emf/bundles/cli/src/test/resources/stages/render/delivery/oracles deleted file mode 100644 index 3b1e9c9bd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/delivery/oracles +++ /dev/null @@ -1,31 +0,0 @@ -apps/delivery/collector/kustomization.yaml delivery/rendered/apps/delivery/collector/kustomization.yaml -apps/delivery/collector/networkpolicy.yaml delivery/rendered/apps/delivery/collector/networkpolicy.yaml -apps/delivery/collector/rbac.yaml delivery/rendered/apps/delivery/collector/rbac.yaml -apps/delivery/collector/service.yaml delivery/rendered/apps/delivery/collector/service.yaml -apps/delivery/collector/serviceaccount.yaml delivery/rendered/apps/delivery/collector/serviceaccount.yaml -apps/delivery/collector/workload.yaml delivery/rendered/apps/delivery/collector/workload.yaml -apps/delivery/flagger/kustomization.yaml delivery/rendered/apps/delivery/flagger/kustomization.yaml -apps/delivery/flagger/networkpolicy.yaml delivery/rendered/apps/delivery/flagger/networkpolicy.yaml -apps/delivery/flagger/rbac.yaml delivery/rendered/apps/delivery/flagger/rbac.yaml -apps/delivery/flagger/service.yaml delivery/rendered/apps/delivery/flagger/service.yaml -apps/delivery/flagger/serviceaccount.yaml delivery/rendered/apps/delivery/flagger/serviceaccount.yaml -apps/delivery/flagger/workload.yaml delivery/rendered/apps/delivery/flagger/workload.yaml -apps/delivery/kustomization.yaml delivery/rendered/apps/delivery/kustomization.yaml -apps/delivery/namespace.yaml delivery/rendered/apps/delivery/namespace.yaml -apps/delivery/networkpolicy.yaml delivery/rendered/apps/delivery/networkpolicy.yaml -apps/delivery/release-gate/kustomization.yaml delivery/rendered/apps/delivery/release-gate/kustomization.yaml -apps/delivery/release-gate/networkpolicy.yaml delivery/rendered/apps/delivery/release-gate/networkpolicy.yaml -apps/delivery/release-gate/rbac.yaml delivery/rendered/apps/delivery/release-gate/rbac.yaml -apps/delivery/release-gate/service.yaml delivery/rendered/apps/delivery/release-gate/service.yaml -apps/delivery/release-gate/serviceaccount.yaml delivery/rendered/apps/delivery/release-gate/serviceaccount.yaml -apps/delivery/release-gate/servicemonitor.yaml delivery/rendered/apps/delivery/release-gate/servicemonitor.yaml -apps/delivery/release-gate/workload.yaml delivery/rendered/apps/delivery/release-gate/workload.yaml -apps/delivery/reporter/kustomization.yaml delivery/rendered/apps/delivery/reporter/kustomization.yaml -apps/delivery/reporter/networkpolicy.yaml delivery/rendered/apps/delivery/reporter/networkpolicy.yaml -apps/delivery/reporter/rbac.yaml delivery/rendered/apps/delivery/reporter/rbac.yaml -apps/delivery/reporter/service.yaml delivery/rendered/apps/delivery/reporter/service.yaml -apps/delivery/reporter/serviceaccount.yaml delivery/rendered/apps/delivery/reporter/serviceaccount.yaml -apps/delivery/reporter/workload.yaml delivery/rendered/apps/delivery/reporter/workload.yaml -apps/delivery/rollout-events/alert.yaml delivery/rendered/apps/delivery/rollout-events/alert.yaml -apps/delivery/rollout-events/kustomization.yaml delivery/rendered/apps/delivery/rollout-events/kustomization.yaml -apps/delivery/rollout-events/provider.yaml delivery/rendered/apps/delivery/rollout-events/provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/networkpolicy.yaml deleted file mode 100644 index c4e2c8296..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/networkpolicy.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: external-dns - namespace: edge-system - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: external-dns - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/external-dns.metrics: "true" - ports: - - protocol: TCP - port: 7979 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 - - 100.64.0.0/10 - - 169.254.0.0/16 - - 127.0.0.0/8 diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/rbac.yaml deleted file mode 100644 index a4c8710e6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/rbac.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: edge-system-external-dns - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - services - - endpoints - - pods - - nodes - verbs: - - get - - list - - watch - - apiGroups: - - traefik.io - resources: - - ingressroutes - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: edge-system-external-dns - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: edge-system-external-dns -subjects: - - kind: ServiceAccount - name: external-dns - namespace: edge-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/service.yaml deleted file mode 100644 index 27c9b1f66..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: external-dns - namespace: edge-system - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: external-dns - ports: - - name: metrics - port: 7979 - targetPort: metrics diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/serviceaccount.yaml deleted file mode 100644 index d8c0d292b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: external-dns - namespace: edge-system - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/workload.yaml deleted file mode 100644 index de42378e3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/external-dns/workload.yaml +++ /dev/null @@ -1,98 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: external-dns - namespace: edge-system - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - template: - metadata: - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/external-dns: 0.15.1 - spec: - serviceAccountName: external-dns - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: external-dns - image: registry.k8s.io/external-dns/external-dns@sha256:32d7bec08ad97a73bf55e6bd4a434206f5eefb0b15adc05453203c72788fcd5d - ports: - - name: metrics - containerPort: 7979 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /healthz - port: 7979 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 7979 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 7979 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/kustomization.yaml deleted file mode 100644 index 6f8f417b2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - external-dns - - namespace.yaml - - rollout-events - - traefik-lan - - traefik-public - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/namespace.yaml deleted file mode 100644 index 77b7404fd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: edge-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/networkpolicy.yaml deleted file mode 100644 index 2dd44709d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: edge-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/rollout-events/alert.yaml deleted file mode 100644 index 65fb45021..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-edge - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-edge - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-edge - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/rollout-events/provider.yaml deleted file mode 100644 index 5c6e94255..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-edge - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/kustomization.yaml deleted file mode 100644 index dcff559e8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - middlewares.yaml - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/middlewares.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/middlewares.yaml deleted file mode 100644 index 2feb68e69..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/middlewares.yaml +++ /dev/null @@ -1,85 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: forward-auth - namespace: edge-system - labels: - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit -spec: - forwardAuth: - address: http://identity-http.estate-system.svc.cluster.local:8080/gate/forward - trustForwardHeader: true ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: security-headers - namespace: edge-system - labels: - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit -spec: - headers: - contentTypeNosniff: true - frameDeny: true - referrerPolicy: strict-origin-when-cross-origin - permissionsPolicy: camera=(), microphone=(), geolocation=() - stsSeconds: 31536000 - stsIncludeSubdomains: true ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: security-headers-strict - namespace: edge-system - labels: - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit -spec: - headers: - contentTypeNosniff: true - frameDeny: true - referrerPolicy: strict-origin-when-cross-origin - permissionsPolicy: camera=(), microphone=(), geolocation=() - stsSeconds: 31536000 - stsIncludeSubdomains: true - contentSecurityPolicy: default-src 'self' ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: security-headers-admin - namespace: edge-system - labels: - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit -spec: - headers: - contentTypeNosniff: true - frameDeny: true - referrerPolicy: strict-origin-when-cross-origin - permissionsPolicy: camera=(), microphone=(), geolocation=() - stsSeconds: 31536000 - stsIncludeSubdomains: true - contentSecurityPolicy: default-src 'self'; style-src 'self' 'unsafe-inline' ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: security-headers-workflow - namespace: edge-system - labels: - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit -spec: - headers: - contentTypeNosniff: true - frameDeny: true - referrerPolicy: strict-origin-when-cross-origin - permissionsPolicy: camera=(), microphone=(), geolocation=() - stsSeconds: 31536000 - stsIncludeSubdomains: true - contentSecurityPolicy: "default-src 'self'; connect-src 'self' https:" diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/networkpolicy.yaml deleted file mode 100644 index 982df596d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/networkpolicy.yaml +++ /dev/null @@ -1,63 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: traefik-lan - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-lan - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/traefik-lan.web: "true" - ports: - - protocol: TCP - port: 8000 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/traefik-lan.admin: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 8000 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/rbac.yaml deleted file mode 100644 index 39863bcc1..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/rbac.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: edge-system-traefik-lan - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - services - - secrets - - nodes - - configmaps - - namespaces - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - pods - verbs: - - get - - apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - list - - watch - - apiGroups: - - traefik.io - resources: - - ingressroutes - - ingressroutetcps - - ingressrouteudps - - middlewares - - middlewaretcps - - serverstransports - - serverstransporttcps - - tlsoptions - - tlsstores - - traefikservices - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: edge-system-traefik-lan - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: edge-system-traefik-lan -subjects: - - kind: ServiceAccount - name: traefik-lan - namespace: edge-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/service.yaml deleted file mode 100644 index b4234d63e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/service.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: traefik-lan - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: traefik-lan - ports: - - name: web - port: 8000 - targetPort: web - - name: admin - port: 8080 - targetPort: admin ---- -apiVersion: v1 -kind: Service -metadata: - name: traefik-lan-lan-edge - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - metallb.io/address-pool: lan-edge -spec: - type: LoadBalancer - externalTrafficPolicy: Local - selector: - app.kubernetes.io/instance: traefik-lan - ports: - - name: tcp-80 - port: 80 - protocol: TCP - targetPort: 8000 diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/serviceaccount.yaml deleted file mode 100644 index d2f1eb7fd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: traefik-lan - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/workload.yaml deleted file mode 100644 index 593b5d5f3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-lan/workload.yaml +++ /dev/null @@ -1,123 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: traefik-lan - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 - progressDeadlineSeconds: 180 - selector: - matchLabels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - template: - metadata: - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/traefik-lan: v3.3.4 - spec: - serviceAccountName: traefik-lan - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - containers: - - name: traefik-lan - image: docker.io/library/traefik@sha256:1f3d5b7a9c2e4f6a8b0d1c3e5f7a9b2d4c6e8f0a1b3d5c7e9f2a4b6d8c0e1f3a - args: - - --entryPoints.web.address=:8000/tcp - - --entryPoints.traefik.address=:8080/tcp - - --ping=true - - --ping.entryPoint=traefik - - --metrics.prometheus=true - - --metrics.prometheus.entryPoint=traefik - - --providers.kubernetescrd=true - - --providers.kubernetescrd.ingressClass=traefik-lan - - --providers.kubernetescrd.allowCrossNamespace=true - - --providers.kubernetescrd.allowEmptyServices=true - - --log.format=json - - --accesslog=true - - --accesslog.format=json - ports: - - name: web - containerPort: 8000 - - name: admin - containerPort: 8080 - env: - - name: HOME - value: /tmp - resources: - requests: - memory: 128Mi - cpu: 50m - limits: - memory: 128Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-tmp - mountPath: /tmp - readinessProbe: - httpGet: - path: /ping - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /ping - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /ping - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 4 - volumes: - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/kustomization.yaml deleted file mode 100644 index 7c8d9a8d3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pvc.yaml - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/networkpolicy.yaml deleted file mode 100644 index e8a1bb48a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/networkpolicy.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: traefik-public - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/traefik-public.web: "true" - ports: - - protocol: TCP - port: 8000 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/traefik-public.websecure: "true" - ports: - - protocol: TCP - port: 8443 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/traefik-public.admin: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 8000 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 8443 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 - - 100.64.0.0/10 - - 169.254.0.0/16 - - 127.0.0.0/8 diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/pvc.yaml deleted file mode 100644 index 4bdd73b2b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/pvc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: traefik-public-acme - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 16Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/rbac.yaml deleted file mode 100644 index 1a07940e7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/rbac.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: edge-system-traefik-public - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - services - - secrets - - nodes - - configmaps - - namespaces - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - pods - verbs: - - get - - apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - list - - watch - - apiGroups: - - traefik.io - resources: - - ingressroutes - - ingressroutetcps - - ingressrouteudps - - middlewares - - middlewaretcps - - serverstransports - - serverstransporttcps - - tlsoptions - - tlsstores - - traefikservices - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: edge-system-traefik-public - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: edge-system-traefik-public -subjects: - - kind: ServiceAccount - name: traefik-public - namespace: edge-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/service.yaml deleted file mode 100644 index 9baef1217..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/service.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: traefik-public - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: traefik-public - ports: - - name: web - port: 8000 - targetPort: web - - name: websecure - port: 8443 - targetPort: websecure - - name: admin - port: 8080 - targetPort: admin diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/serviceaccount.yaml deleted file mode 100644 index 214e655f9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: traefik-public - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/vso.yaml deleted file mode 100644 index 8296cca2e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/vso.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: traefik-public - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: edge-system-traefik-public - serviceAccount: traefik-public ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: traefik-public-platform-cloudflare - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: traefik-public - mount: secret - type: kv-v2 - path: platform/cloudflare - refreshAfter: 10m - hmacSecretData: true - destination: - name: traefik-public-platform-cloudflare - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: traefik-public diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/workload.yaml deleted file mode 100644 index cc6f444e4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/traefik-public/workload.yaml +++ /dev/null @@ -1,142 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: traefik-public - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 - progressDeadlineSeconds: 180 - selector: - matchLabels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - template: - metadata: - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/traefik-public: v3.3.4 - spec: - serviceAccountName: traefik-public - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - fsGroup: 65532 - fsGroupChangePolicy: OnRootMismatch - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - containers: - - name: traefik-public - image: docker.io/library/traefik@sha256:1f3d5b7a9c2e4f6a8b0d1c3e5f7a9b2d4c6e8f0a1b3d5c7e9f2a4b6d8c0e1f3a - args: - - --entryPoints.web.address=:8000/tcp - - --entryPoints.websecure.address=:8443/tcp - - --entryPoints.websecure.http.tls=true - - --entryPoints.traefik.address=:8080/tcp - - --ping=true - - --ping.entryPoint=traefik - - --metrics.prometheus=true - - --metrics.prometheus.entryPoint=traefik - - --providers.kubernetescrd=true - - --providers.kubernetescrd.ingressClass=traefik-public - - --providers.kubernetescrd.allowCrossNamespace=true - - --providers.kubernetescrd.allowEmptyServices=true - - --certificatesresolvers.public-frankfurt.acme.email=hostmaster@jorisjonkers.dev - - --certificatesresolvers.public-frankfurt.acme.storage=/acme/public-frankfurt.json - - --certificatesresolvers.public-frankfurt.acme.dnschallenge.provider=cloudflare - - --log.format=json - - --accesslog=true - - --accesslog.format=json - ports: - - name: web - containerPort: 8000 - hostPort: 80 - - name: websecure - containerPort: 8443 - hostPort: 443 - - name: admin - containerPort: 8080 - env: - - name: CF_DNS_API_TOKEN - valueFrom: - secretKeyRef: - name: traefik-public-platform-cloudflare - key: CF_DNS_API_TOKEN - - name: HOME - value: /tmp - resources: - requests: - memory: 128Mi - cpu: 50m - limits: - memory: 128Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: traefik-public-acme - mountPath: /acme - - name: writable-tmp - mountPath: /tmp - readinessProbe: - httpGet: - path: /ping - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /ping - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /ping - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 4 - volumes: - - name: traefik-public-acme - persistentVolumeClaim: - claimName: traefik-public-acme - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/configmap.yaml deleted file mode 100644 index 940d5787f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/configmap.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-4397ac2bab13 - namespace: edge-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - edge-system-traefik-public.policy.json: | - {"path":{"secret/data/platform/cloudflare":{"capabilities":["read"]},"secret/metadata/platform/cloudflare":{"capabilities":["read"]}}} - edge-system-traefik-public.role.json: | - {"bound_service_account_names":["traefik-public"],"bound_service_account_namespaces":["edge-system"],"token_policies":["edge-system-traefik-public"]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/cronjob.yaml deleted file mode 100644 index 968d7ce89..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/cronjob.yaml +++ /dev/null @@ -1,95 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: edge-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-4397ac2bab13 - items: - - key: edge-system-traefik-public.policy.json - path: edge-system-traefik-public.policy.json - - key: edge-system-traefik-public.role.json - path: edge-system-traefik-public.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/job.yaml deleted file mode 100644 index 76a1851c6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/job.yaml +++ /dev/null @@ -1,85 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-4397ac2bab13 - namespace: edge-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-4397ac2bab13 - items: - - key: edge-system-traefik-public.policy.json - path: edge-system-traefik-public.policy.json - - key: edge-system-traefik-public.role.json - path: edge-system-traefik-public.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/networkpolicy.yaml deleted file mode 100644 index 7b95dcb4c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: edge-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.policy.json b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.policy.json deleted file mode 100644 index 9c33e44a9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/platform/cloudflare": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/cloudflare": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.role.json b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.role.json deleted file mode 100644 index b1900753c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "traefik-public" - ], - "bound_service_account_namespaces": [ - "edge-system" - ], - "token_policies": [ - "edge-system-traefik-public" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/serviceaccount.yaml deleted file mode 100644 index 4a75f0272..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: edge-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vaultconnection.yaml deleted file mode 100644 index 0d5cfead4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/apps/edge/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: edge-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/human-grants/clusterrolebindings.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/human-grants/clusterrolebindings.yaml deleted file mode 100644 index 86311f89c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/human-grants/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: human:oidc:k8s-admin:cluster-admin - labels: - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: oidc:k8s-admin diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/human-grants/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/human-grants/kustomization.yaml deleted file mode 100644 index 029015f5d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/human-grants/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - clusterrolebindings.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/priority-classes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/priority-classes/kustomization.yaml deleted file mode 100644 index 8b06a2f03..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/priority-classes/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/priority-classes/priorityclasses.yaml b/emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/priority-classes/priorityclasses.yaml deleted file mode 100644 index a304512d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/expected/estate/priority-classes/priorityclasses.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-data - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 1000000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "A datastore: it schedules before what reads it." ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-critical-app - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 100000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "The foundation and the Applications the platform names: they keep scheduling under pressure." diff --git a/emf/bundles/cli/src/test/resources/stages/render/edge/oracles b/emf/bundles/cli/src/test/resources/stages/render/edge/oracles deleted file mode 100644 index 164132c60..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/edge/oracles +++ /dev/null @@ -1,40 +0,0 @@ -apps/edge/external-dns/kustomization.yaml edge/rendered/apps/edge/external-dns/kustomization.yaml -apps/edge/external-dns/networkpolicy.yaml edge/rendered/apps/edge/external-dns/networkpolicy.yaml -apps/edge/external-dns/rbac.yaml edge/rendered/apps/edge/external-dns/rbac.yaml -apps/edge/external-dns/service.yaml edge/rendered/apps/edge/external-dns/service.yaml -apps/edge/external-dns/serviceaccount.yaml edge/rendered/apps/edge/external-dns/serviceaccount.yaml -apps/edge/external-dns/workload.yaml edge/rendered/apps/edge/external-dns/workload.yaml -apps/edge/kustomization.yaml edge/rendered/apps/edge/kustomization.yaml -apps/edge/namespace.yaml edge/rendered/apps/edge/namespace.yaml -apps/edge/networkpolicy.yaml edge/rendered/apps/edge/networkpolicy.yaml -apps/edge/rollout-events/alert.yaml edge/rendered/apps/edge/rollout-events/alert.yaml -apps/edge/rollout-events/kustomization.yaml edge/rendered/apps/edge/rollout-events/kustomization.yaml -apps/edge/rollout-events/provider.yaml edge/rendered/apps/edge/rollout-events/provider.yaml -apps/edge/traefik-lan/kustomization.yaml edge/rendered/apps/edge/traefik-lan/kustomization.yaml -apps/edge/traefik-lan/middlewares.yaml edge/rendered/apps/edge/traefik-lan/middlewares.yaml -apps/edge/traefik-lan/networkpolicy.yaml edge/rendered/apps/edge/traefik-lan/networkpolicy.yaml -apps/edge/traefik-lan/rbac.yaml edge/rendered/apps/edge/traefik-lan/rbac.yaml -apps/edge/traefik-lan/service.yaml edge/rendered/apps/edge/traefik-lan/service.yaml -apps/edge/traefik-lan/serviceaccount.yaml edge/rendered/apps/edge/traefik-lan/serviceaccount.yaml -apps/edge/traefik-lan/workload.yaml edge/rendered/apps/edge/traefik-lan/workload.yaml -apps/edge/traefik-public/kustomization.yaml edge/rendered/apps/edge/traefik-public/kustomization.yaml -apps/edge/traefik-public/networkpolicy.yaml edge/rendered/apps/edge/traefik-public/networkpolicy.yaml -apps/edge/traefik-public/pvc.yaml edge/rendered/apps/edge/traefik-public/pvc.yaml -apps/edge/traefik-public/rbac.yaml edge/rendered/apps/edge/traefik-public/rbac.yaml -apps/edge/traefik-public/service.yaml edge/rendered/apps/edge/traefik-public/service.yaml -apps/edge/traefik-public/serviceaccount.yaml edge/rendered/apps/edge/traefik-public/serviceaccount.yaml -apps/edge/traefik-public/vso.yaml edge/rendered/apps/edge/traefik-public/vso.yaml -apps/edge/traefik-public/workload.yaml edge/rendered/apps/edge/traefik-public/workload.yaml -apps/edge/vault-policy/configmap.yaml edge/rendered/apps/edge/vault-policy/configmap.yaml -apps/edge/vault-policy/cronjob.yaml edge/rendered/apps/edge/vault-policy/cronjob.yaml -apps/edge/vault-policy/job.yaml edge/rendered/apps/edge/vault-policy/job.yaml -apps/edge/vault-policy/kustomization.yaml edge/rendered/apps/edge/vault-policy/kustomization.yaml -apps/edge/vault-policy/networkpolicy.yaml edge/rendered/apps/edge/vault-policy/networkpolicy.yaml -apps/edge/vault-policy/policies/edge-system-traefik-public.policy.json edge/rendered/apps/edge/vault-policy/policies/edge-system-traefik-public.policy.json -apps/edge/vault-policy/policies/edge-system-traefik-public.role.json edge/rendered/apps/edge/vault-policy/policies/edge-system-traefik-public.role.json -apps/edge/vault-policy/serviceaccount.yaml edge/rendered/apps/edge/vault-policy/serviceaccount.yaml -apps/edge/vaultconnection.yaml edge/rendered/apps/edge/vaultconnection.yaml -estate/human-grants/clusterrolebindings.yaml platform/rendered/estate/human-grants/clusterrolebindings.yaml -estate/human-grants/kustomization.yaml platform/rendered/estate/human-grants/kustomization.yaml -estate/priority-classes/kustomization.yaml platform/rendered/estate/priority-classes/kustomization.yaml -estate/priority-classes/priorityclasses.yaml platform/rendered/estate/priority-classes/priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/aliases.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/aliases.yaml deleted file mode 100644 index 388ea9d38..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/aliases.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-postgres - namespace: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: platform-postgres-postgres.estate-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-rabbitmq - namespace: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: platform-rabbitmq-amqp.estate-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-valkey - namespace: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: platform-valkey-redis.estate-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: stalwart - namespace: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: stalwart-smtp.estate-system.svc.cluster.local diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/canary.yaml deleted file mode 100644 index 7cdaf4ee2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/canary.yaml +++ /dev/null @@ -1,176 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: auth-api - autoscalerRef: - apiVersion: autoscaling/v2 - kind: HorizontalPodAutoscaler - name: auth-api - progressDeadlineSeconds: 1920 - service: - port: 8080 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: auth - process: auth-api - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: /api /api/v1/users/register - readiness: /api/actuator/health/readiness - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: auth - process: auth-api - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: /api /api/v1/users/register - readiness: /api/actuator/health/readiness - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: auth - process: auth-api - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: /api /api/v1/users/register - readiness: /api/actuator/health/readiness - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: auth - process: auth-api - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: /api /api/v1/users/register - readiness: /api/actuator/health/readiness - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms ---- -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: auth-api - minReplicas: 2 - maxReplicas: 2 ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: auth-ui - progressDeadlineSeconds: 210 - service: - port: 80 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: auth - process: auth-ui - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: / - readiness: / - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: auth - process: auth-ui - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: / - readiness: / - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: auth - process: auth-ui - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: / - readiness: / - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: auth - process: auth-ui - revision: sha256:08b008c7a1958d1108992d6404c9dcf96ee298beaee25ddba0095a89e42187d0 - paths: / - readiness: / - hostnames: auth.jorisjonkers.dev - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/configmap.yaml deleted file mode 100644 index b67ee6188..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: auth-release-gate - namespace: auth-system - labels: - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"1920s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"checks":["error-rate","latency"],"process":"auth-api","readiness":{"path":"/api/actuator/health/readiness","port":8081}},{"process":"auth-ui","readiness":{"path":"/","port":80}}],"migration":{"identity":"auth-migration","nonTransactional":false,"testedAgainst":"sha256:2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a"}} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: auth-external-checks - namespace: auth-system - labels: - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - auth-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"auth","name":"auth-public-1","url":"https://auth.jorisjonkers.dev/api/v1/users/register"},{"conditions":["[STATUS] < 500"],"group":"auth","name":"auth-public-2","url":"https://auth.jorisjonkers.dev/api"},{"conditions":["[STATUS] < 500"],"group":"auth","name":"auth-public-3","url":"https://auth.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/kustomization.yaml deleted file mode 100644 index 2c2441c0b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/kustomization.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - migration.yaml - - pdb.yaml - - podmonitor.yaml - - route-public.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/migration.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/migration.yaml deleted file mode 100644 index cb5cfcc1b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/migration.yaml +++ /dev/null @@ -1,171 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: auth-migration - namespace: auth-system - labels: - app.kubernetes.io/name: auth-migration - app.kubernetes.io/instance: auth-migration - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: auth-migration-08b008c7a195 - namespace: auth-system - labels: - app.kubernetes.io/name: auth-migration - app.kubernetes.io/instance: auth-migration - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/ssa: IfNotPresent -spec: - suspend: true - backoffLimit: 0 - activeDeadlineSeconds: 600 - template: - metadata: - labels: - app.kubernetes.io/name: auth-migration - app.kubernetes.io/instance: auth-migration - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - annotations: - image.jorisjonkers.dev/migration: 2.3.0 - spec: - serviceAccountName: auth-migration - automountServiceAccountToken: true - restartPolicy: Never - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - containers: - - name: migration - image: ghcr.io/jorisjonkers-dev/auth/auth-migration@sha256:5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7a9b1d3f5c7e - args: - - up - - 08b008c7a195 - env: - - name: DATABASE_HOST - value: postgres.data-system.svc.cluster.local - - name: DATABASE_PORT - value: "5432" - - name: DATABASE_NAME - value: auth_db - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: auth-system-auth-migration - - name: VAULT_CREDENTIALS_PATH - value: database/creds/auth-owner - - name: HOME - value: /tmp - resources: - requests: - memory: 256Mi - cpu: 100m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: scratch - mountPath: /tmp - volumes: - - name: scratch - emptyDir: - sizeLimit: 64Mi ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: auth-migration-down-08b008c7a195 - namespace: auth-system - labels: - app.kubernetes.io/name: auth-migration - app.kubernetes.io/instance: auth-migration - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/ssa: IfNotPresent -spec: - suspend: true - backoffLimit: 0 - activeDeadlineSeconds: 600 - template: - metadata: - labels: - app.kubernetes.io/name: auth-migration - app.kubernetes.io/instance: auth-migration - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - annotations: - image.jorisjonkers.dev/migration: 2.3.0 - spec: - serviceAccountName: auth-migration - automountServiceAccountToken: true - restartPolicy: Never - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - containers: - - name: migration - image: ghcr.io/jorisjonkers-dev/auth/auth-migration@sha256:5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7a9b1d3f5c7e - args: - - down - - 2f4a6c8e0b2d - env: - - name: DATABASE_HOST - value: postgres.data-system.svc.cluster.local - - name: DATABASE_PORT - value: "5432" - - name: DATABASE_NAME - value: auth_db - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: auth-system-auth-migration - - name: VAULT_CREDENTIALS_PATH - value: database/creds/auth-owner - - name: HOME - value: /tmp - resources: - requests: - memory: 256Mi - cpu: 100m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: scratch - mountPath: /tmp - volumes: - - name: scratch - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/networkpolicy.yaml deleted file mode 100644 index 69605586c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/networkpolicy.yaml +++ /dev/null @@ -1,232 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: auth-api - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability-system - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/auth.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - ports: - - protocol: TCP - port: 5432 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: valkey - ports: - - protocol: TCP - port: 6379 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - ports: - - protocol: TCP - port: 5672 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: mail-system - podSelector: - matchLabels: - app.kubernetes.io/instance: stalwart - ports: - - protocol: TCP - port: 25 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: auth-ui - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 80 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/auth.http: "true" - ports: - - protocol: TCP - port: 80 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 80 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: auth-migration - namespace: auth-system - labels: - app.kubernetes.io/name: auth-migration - app.kubernetes.io/instance: auth-migration - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: auth-migration - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - ports: - - protocol: TCP - port: 5432 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/pdb.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/pdb.yaml deleted file mode 100644 index 29a73fa79..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/pdb.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: auth-api-primary diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/podmonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/podmonitor.yaml deleted file mode 100644 index a0d2b1276..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/podmonitor.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: PodMonitor -metadata: - name: auth-api - namespace: auth-system - labels: - release: metrics-stack - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: auth-api - namespaceSelector: - matchNames: - - auth-system - podMetricsEndpoints: - - port: http - path: /api/actuator/prometheus - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/route-public.yaml deleted file mode 100644 index f18b77108..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/route-public.yaml +++ /dev/null @@ -1,68 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: auth-public - namespace: auth-system - labels: - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`auth.jorisjonkers.dev`) && Path(`/api/v1/users/register`) - priority: 999 - middlewares: - - name: security-headers-strict - namespace: edge-system - - name: auth-public-1-rate-limit - namespace: auth-system - services: - - name: auth-api - namespace: auth-system - port: 8080 - - kind: Rule - match: Host(`auth.jorisjonkers.dev`) && PathPrefix(`/api`) - priority: 998 - middlewares: - - name: security-headers-strict - namespace: edge-system - services: - - name: auth-api - namespace: auth-system - port: 8080 - - kind: Rule - match: Host(`auth.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 997 - middlewares: - - name: security-headers-strict - namespace: edge-system - services: - - name: auth-ui - namespace: auth-system - port: 80 - tls: - certResolver: public-frankfurt ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: auth-public-1-rate-limit - namespace: auth-system - labels: - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit -spec: - rateLimit: - average: 10 - period: 1h - burst: 10 - sourceCriterion: - requestHeaderName: CF-Connecting-IP diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/serviceaccount.yaml deleted file mode 100644 index 402c4f525..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/workload.yaml deleted file mode 100644 index 27d0ddb64..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/auth/workload.yaml +++ /dev/null @@ -1,265 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: auth-api - namespace: auth-system - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 1920 - selector: - matchLabels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - template: - metadata: - labels: - app.kubernetes.io/name: auth-api - app.kubernetes.io/instance: auth-api - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: jvm - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - consumes.deploy-kit.jorisjonkers.dev/platform-valkey.redis: "true" - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.amqp: "true" - consumes.deploy-kit.jorisjonkers.dev/stalwart.smtp: "true" - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/auth-api: 2.3.0 - spec: - serviceAccountName: auth-api - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - containers: - - name: auth-api - image: ghcr.io/jorisjonkers-dev/auth/auth-api@sha256:3e5a7c9b1d3f5e7a9c1b3d5f7e9a1c3b5d7f9e1a3c5b7d9f1e3a5c7b9d1f3e5a - ports: - - name: http - containerPort: 8080 - env: - - name: AUTH_ISSUER - value: https://auth.jorisjonkers.dev - - name: AUTH_LOGIN_URL - value: https://auth.jorisjonkers.dev/login - - name: CONFIRMATION_URL - value: https://auth.jorisjonkers.dev/confirm - - name: DB_HOST - value: platform-postgres - - name: DB_PORT - value: "5432" - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: MAIL_HOST - value: stalwart - - name: MAIL_PORT - value: "25" - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: auth-api - - name: PORT - value: "8080" - - name: SESSION_COOKIE_SECURE - value: "true" - - name: SPRING_CONFIG_IMPORT - value: vault:// - - name: SPRING_PROFILES_ACTIVE - value: prod - - name: SPRING_RABBITMQ_HOST - value: platform-rabbitmq - - name: SPRING_RABBITMQ_PORT - value: "5672" - - name: VALKEY_HOST - value: platform-valkey - - name: VALKEY_PORT - value: "6379" - - name: VAULT_AUTHENTICATION - value: KUBERNETES - - name: VAULT_ENABLED - value: "true" - - name: VAULT_KUBERNETES_ROLE - value: auth-system-auth-api - - name: HOME - value: /tmp - resources: - requests: - memory: 768Mi - cpu: 250m - limits: - memory: 768Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-tmp - mountPath: /tmp - readinessProbe: - httpGet: - path: /api/actuator/health/readiness - port: 8081 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /api/actuator/health/liveness - port: 8081 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /api/actuator/health/liveness - port: 8081 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 120 - volumes: - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: auth-ui - namespace: auth-system - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - template: - metadata: - labels: - app.kubernetes.io/name: auth-ui - app.kubernetes.io/instance: auth-ui - app.kubernetes.io/part-of: auth - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: static - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/auth-ui: 2.3.0 - spec: - serviceAccountName: auth-ui - priorityClassName: platform-critical-app - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 101 - runAsGroup: 101 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: auth-ui - image: ghcr.io/jorisjonkers-dev/auth/auth-ui@sha256:8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d - ports: - - name: http - containerPort: 80 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - add: - - NET_BIND_SERVICE - drop: - - ALL - volumeMounts: - - name: writable-var-cache-nginx - mountPath: /var/cache/nginx - - name: writable-var-run - mountPath: /var/run - readinessProbe: - httpGet: - path: / - port: 80 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: / - port: 80 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: / - port: 80 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: writable-var-cache-nginx - emptyDir: - sizeLimit: 64Mi - - name: writable-var-run - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/kustomization.yaml deleted file mode 100644 index 5994c89f2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - aliases.yaml - - auth - - namespace.yaml - - rollout-events - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/namespace.yaml deleted file mode 100644 index 375c95b85..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/networkpolicy.yaml deleted file mode 100644 index 0e4c5a823..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/rollout-events/alert.yaml deleted file mode 100644 index 1a87897f6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-auth - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-auth - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-auth - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/rollout-events/provider.yaml deleted file mode 100644 index 9c3f09f4a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-auth - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/configmap.yaml deleted file mode 100644 index 54126b2fc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/configmap.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-e56b08fd2da1 - namespace: auth-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - auth-system-auth-api.policy.json: | - {"path":{"database/creds/auth-data":{"capabilities":["read"]},"secret/data/auth-api":{"capabilities":["read"]},"secret/data/platform/postgres/auth":{"capabilities":["read"]},"secret/metadata/auth-api":{"capabilities":["read"]},"secret/metadata/platform/postgres/auth":{"capabilities":["read"]},"transit/keys/auth-api-jwt":{"capabilities":["read"]},"transit/keys/auth-api-jwt/rotate":{"capabilities":["update"]},"transit/sign/auth-api-jwt":{"capabilities":["update"]}}} - auth-system-auth-api.role.json: | - {"bound_service_account_names":["auth-api"],"bound_service_account_namespaces":["auth-system"],"token_policies":["auth-system-auth-api"]} - auth-system-auth-migration.policy.json: | - {"path":{"database/creds/auth-owner":{"capabilities":["read"]}}} - auth-system-auth-migration.role.json: | - {"bound_service_account_names":["auth-migration"],"bound_service_account_namespaces":["auth-system"],"token_policies":["auth-system-auth-migration"]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/cronjob.yaml deleted file mode 100644 index c2f12552e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/cronjob.yaml +++ /dev/null @@ -1,99 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: auth-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-e56b08fd2da1 - items: - - key: auth-system-auth-api.policy.json - path: auth-system-auth-api.policy.json - - key: auth-system-auth-api.role.json - path: auth-system-auth-api.role.json - - key: auth-system-auth-migration.policy.json - path: auth-system-auth-migration.policy.json - - key: auth-system-auth-migration.role.json - path: auth-system-auth-migration.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/job.yaml deleted file mode 100644 index 0c8da5cc4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/job.yaml +++ /dev/null @@ -1,89 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-e56b08fd2da1 - namespace: auth-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-e56b08fd2da1 - items: - - key: auth-system-auth-api.policy.json - path: auth-system-auth-api.policy.json - - key: auth-system-auth-api.role.json - path: auth-system-auth-api.role.json - - key: auth-system-auth-migration.policy.json - path: auth-system-auth-migration.policy.json - - key: auth-system-auth-migration.role.json - path: auth-system-auth-migration.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/networkpolicy.yaml deleted file mode 100644 index 949ae1390..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: auth-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-api.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-api.policy.json deleted file mode 100644 index b7793e400..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-api.policy.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "path": { - "secret/data/platform/postgres/auth": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/postgres/auth": { - "capabilities": [ - "read" - ] - }, - "secret/data/auth-api": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/auth-api": { - "capabilities": [ - "read" - ] - }, - "transit/sign/auth-api-jwt": { - "capabilities": [ - "update" - ] - }, - "transit/keys/auth-api-jwt/rotate": { - "capabilities": [ - "update" - ] - }, - "transit/keys/auth-api-jwt": { - "capabilities": [ - "read" - ] - }, - "database/creds/auth-data": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-api.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-api.role.json deleted file mode 100644 index 02bd83585..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-api.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "auth-api" - ], - "bound_service_account_namespaces": [ - "auth-system" - ], - "token_policies": [ - "auth-system-auth-api" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.policy.json deleted file mode 100644 index e33615018..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.policy.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "path": { - "database/creds/auth-owner": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.role.json deleted file mode 100644 index b1e08a895..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/policies/auth-system-auth-migration.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "auth-migration" - ], - "bound_service_account_namespaces": [ - "auth-system" - ], - "token_policies": [ - "auth-system-auth-migration" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/serviceaccount.yaml deleted file mode 100644 index 96927b21c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: auth-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vaultconnection.yaml deleted file mode 100644 index a5097ae6a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/auth/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: auth-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/kustomization.yaml deleted file mode 100644 index 1300edca5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/networkpolicy.yaml deleted file mode 100644 index 083f7dabc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/networkpolicy.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: asset-sync - namespace: data-system - labels: - app.kubernetes.io/name: asset-sync - app.kubernetes.io/instance: asset-sync - app.kubernetes.io/part-of: asset-sync - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: asset-sync - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 - - 100.64.0.0/10 - - 169.254.0.0/16 - - 127.0.0.0/8 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/serviceaccount.yaml deleted file mode 100644 index 2b3cb68b3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: asset-sync - namespace: data-system - labels: - app.kubernetes.io/name: asset-sync - app.kubernetes.io/instance: asset-sync - app.kubernetes.io/part-of: asset-sync - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/vso.yaml deleted file mode 100644 index e9b4dd9a9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/vso.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: asset-sync - namespace: data-system - labels: - app.kubernetes.io/name: asset-sync - app.kubernetes.io/instance: asset-sync - app.kubernetes.io/part-of: asset-sync - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-asset-sync - serviceAccount: asset-sync ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: asset-sync-platform-garage-web-key - namespace: data-system - labels: - app.kubernetes.io/name: asset-sync - app.kubernetes.io/instance: asset-sync - app.kubernetes.io/part-of: asset-sync - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: asset-sync - mount: secret - type: kv-v2 - path: platform/garage/web-key - refreshAfter: 10m - hmacSecretData: true - destination: - name: asset-sync-platform-garage-web-key - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/workload.yaml deleted file mode 100644 index 6e372c853..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/asset-sync/workload.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: asset-sync - namespace: data-system - labels: - app.kubernetes.io/name: asset-sync - app.kubernetes.io/instance: asset-sync - app.kubernetes.io/part-of: asset-sync - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "*/15 * * * *" - concurrencyPolicy: Forbid - startingDeadlineSeconds: 300 - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: asset-sync - app.kubernetes.io/instance: asset-sync - app.kubernetes.io/part-of: asset-sync - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/asset-sync: 1.0.0 - spec: - serviceAccountName: asset-sync - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - containers: - - name: asset-sync - image: ghcr.io/jorisjonkers-dev/platform/asset-sync@sha256:5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e - resources: - requests: - memory: 64Mi - cpu: 25m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: secret-asset-sync-platform-garage-web-key - mountPath: /run/secrets/garage - readOnly: true - volumes: - - name: secret-asset-sync-platform-garage-web-key - secret: - secretName: asset-sync-platform-garage-web-key - items: - - key: credentials - path: credentials - defaultMode: 256 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/kustomization.yaml deleted file mode 100644 index 987e82bee..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/kustomization.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - asset-sync - - namespace.yaml - - platform-garage - - platform-mongo - - platform-postgres - - platform-rabbitmq - - platform-valkey - - rollout-events - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/namespace.yaml deleted file mode 100644 index cf7d88ac3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: data-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/networkpolicy.yaml deleted file mode 100644 index efbc30d59..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: data-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/backup.yaml deleted file mode 100644 index c5f60afc0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/backup.yaml +++ /dev/null @@ -1,129 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: garage-snapshots-backup - namespace: data-system - labels: - app.kubernetes.io/name: garage-backup - app.kubernetes.io/instance: garage-backup - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 15 3 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: garage-backup - app.kubernetes.io/instance: garage-backup - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: garage-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/file-backup@sha256:2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d - env: - - name: BACKUP_RETAIN - value: "14" - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: garage-snapshots - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: garage-snapshots-backup ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: garage-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: garage-backup - app.kubernetes.io/instance: garage-backup - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 15 3 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: garage-backup - app.kubernetes.io/instance: garage-backup - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: garage-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/file-backup@sha256:2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d - env: - - name: BACKUP_RETAIN - value: "14" - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: garage-data - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: garage-data-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/configmap.yaml deleted file mode 100644 index 9a542592a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/configmap.yaml +++ /dev/null @@ -1,36 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: garage-garage-toml-120c7a969e - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - garage.toml: | - # Garage's own configuration, an Asset: nothing in it is derived. The RPC - # secret and the admin token come from the environment. - metadata_dir = "/var/lib/garage/meta" - data_dir = "/var/lib/garage/data" - db_engine = "lmdb" - - # A consistent copy of the metadata database, which the backup archives in - # place of the live one. - metadata_snapshots_dir = "/var/lib/garage/snapshots" - metadata_auto_snapshot_interval = "6h" - - replication_factor = 1 - rpc_bind_addr = "[::]:3901" - - [s3_api] - s3_region = "garage" - api_bind_addr = "[::]:3900" - - [admin] - api_bind_addr = "[::]:3903" diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/garage-catalog-networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/garage-catalog-networkpolicy.yaml deleted file mode 100644 index cf7b5568d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/garage-catalog-networkpolicy.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: garage-catalog - namespace: data-system - labels: - app.kubernetes.io/name: garage-catalog - app.kubernetes.io/instance: garage-catalog - app.kubernetes.io/part-of: garage-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: garage-catalog - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: garage - ports: - - protocol: TCP - port: 3903 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/garage-catalog.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/garage-catalog.yaml deleted file mode 100644 index 9c04b75e8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/garage-catalog.yaml +++ /dev/null @@ -1,205 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: garage-catalog - namespace: data-system - labels: - app.kubernetes.io/name: garage-catalog - app.kubernetes.io/instance: garage-catalog - app.kubernetes.io/part-of: garage-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: garage-catalog-3b4fd9d75003 - namespace: data-system - labels: - app.kubernetes.io/name: garage-catalog - app.kubernetes.io/instance: garage-catalog - app.kubernetes.io/part-of: garage-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - catalog.json: | - {"admin":{"path":"secret/data/data/garage/catalog","token":"token"},"host":"garage.data-system.svc.cluster.local","keys":[{"buckets":["knowledge-platform-assets"],"name":"knowledge-platform","path":"secret/data/knowledge-platform/garage/s3"}],"port":3903} ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: garage-catalog-3b4fd9d75003 - namespace: data-system - labels: - app.kubernetes.io/name: garage-catalog - app.kubernetes.io/instance: garage-catalog - app.kubernetes.io/part-of: garage-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: garage-catalog - app.kubernetes.io/instance: garage-catalog - app.kubernetes.io/part-of: garage-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - consumes.deploy-kit.jorisjonkers.dev/platform-garage.admin: "true" - annotations: - image.jorisjonkers.dev/garage-catalog: 1.0.0 - spec: - serviceAccountName: garage-catalog - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: garage-catalog - image: ghcr.io/jorisjonkers-dev/delivery/garage-catalog@sha256:3c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: data-system-garage-catalog - - name: CATALOG_FILE - value: /catalog/catalog.json - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: catalog - mountPath: /catalog - readOnly: true - volumes: - - name: catalog - configMap: - name: garage-catalog-3b4fd9d75003 - items: - - key: catalog.json - path: catalog.json ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: garage-catalog - namespace: data-system - labels: - app.kubernetes.io/name: garage-catalog - app.kubernetes.io/instance: garage-catalog - app.kubernetes.io/part-of: garage-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: garage-catalog - app.kubernetes.io/instance: garage-catalog - app.kubernetes.io/part-of: garage-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: garage-catalog - app.kubernetes.io/instance: garage-catalog - app.kubernetes.io/part-of: garage-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - consumes.deploy-kit.jorisjonkers.dev/platform-garage.admin: "true" - annotations: - image.jorisjonkers.dev/garage-catalog: 1.0.0 - spec: - serviceAccountName: garage-catalog - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: garage-catalog - image: ghcr.io/jorisjonkers-dev/delivery/garage-catalog@sha256:3c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: data-system-garage-catalog - - name: CATALOG_FILE - value: /catalog/catalog.json - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: catalog - mountPath: /catalog - readOnly: true - volumes: - - name: catalog - configMap: - name: garage-catalog-3b4fd9d75003 - items: - - key: catalog.json - path: catalog.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/kustomization.yaml deleted file mode 100644 index 6b8543f92..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/kustomization.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - configmap.yaml - - garage-catalog.yaml - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/networkpolicy.yaml deleted file mode 100644 index b0dbafe56..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/networkpolicy.yaml +++ /dev/null @@ -1,92 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: garage - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: garage - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-garage.s3: "true" - ports: - - protocol: TCP - port: 3900 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-garage.admin: "true" - ports: - - protocol: TCP - port: 3903 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: garage-backup - namespace: data-system - labels: - app.kubernetes.io/name: garage-backup - app.kubernetes.io/instance: garage-backup - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: garage-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/pvc.yaml deleted file mode 100644 index be472abd8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/pvc.yaml +++ /dev/null @@ -1,99 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: garage-meta - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: garage-snapshots - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: garage-snapshots-backup - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 4Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: garage-data - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: garage-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/service.yaml deleted file mode 100644 index 01c36cf50..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/service.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: garage - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: garage - ports: - - name: s3 - port: 3900 - targetPort: s3 - - name: admin - port: 3903 - targetPort: admin diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/serviceaccount.yaml deleted file mode 100644 index 41820ee6d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: garage - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: garage-backup - namespace: data-system - labels: - app.kubernetes.io/name: garage-backup - app.kubernetes.io/instance: garage-backup - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/vso.yaml deleted file mode 100644 index df8398f5d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/vso.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: garage - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-garage - serviceAccount: garage ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: garage-platform-garage - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: garage - mount: secret - type: kv-v2 - path: platform/garage - refreshAfter: 10m - hmacSecretData: true - destination: - name: garage-platform-garage - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: garage diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/workload.yaml deleted file mode 100644 index 1b3f0f6c3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-garage/workload.yaml +++ /dev/null @@ -1,131 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: garage - namespace: data-system - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 300 - selector: - matchLabels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - template: - metadata: - labels: - app.kubernetes.io/name: garage - app.kubernetes.io/instance: garage - app.kubernetes.io/part-of: platform-garage - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/garage: 2.3.0 - spec: - serviceAccountName: garage - priorityClassName: platform-data - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - containers: - - name: garage - image: docker.io/dxflrs/garage@sha256:8d0f2b4c6e8a0d2f4b6c8e0a2d4f6b8c0e2a4d6f8b0c2e4a6d8f0b2c4e6a8d0f - ports: - - name: s3 - containerPort: 3900 - - name: admin - containerPort: 3903 - env: - - name: GARAGE_ADMIN_TOKEN - valueFrom: - secretKeyRef: - name: garage-platform-garage - key: admin-token - - name: GARAGE_RPC_SECRET - valueFrom: - secretKeyRef: - name: garage-platform-garage - key: rpc-secret - resources: - requests: - memory: 1Gi - cpu: 200m - limits: - memory: 1Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: garage-meta - mountPath: /var/lib/garage/meta - - name: garage-snapshots - mountPath: /var/lib/garage/snapshots - - name: garage-data - mountPath: /var/lib/garage/data - - name: garage-garage-toml-120c7a969e - mountPath: /etc/garage.toml - subPath: garage.toml - readOnly: true - readinessProbe: - httpGet: - path: /health - port: 3903 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 3900 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 3900 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 - volumes: - - name: garage-meta - persistentVolumeClaim: - claimName: garage-meta - - name: garage-snapshots - persistentVolumeClaim: - claimName: garage-snapshots - - name: garage-data - persistentVolumeClaim: - claimName: garage-data - - name: garage-garage-toml-120c7a969e - configMap: - name: garage-garage-toml-120c7a969e - items: - - key: garage.toml - path: garage.toml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/backup.yaml deleted file mode 100644 index 0f9c7d6b0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/backup.yaml +++ /dev/null @@ -1,80 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: mongo-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 45 2 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.0.0 - spec: - serviceAccountName: mongo-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/mongo-backup@sha256:8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d - env: - - name: BACKUP_RETAIN - value: "90" - - name: BACKUP_OFF_CLUSTER - value: s3://backup-storage/jorisjonkers-dev - - name: BACKUP_OFF_CLUSTER_PATH - value: data/mongo/mongo-data - - name: BACKUP_OFF_CLUSTER_RECIPIENT - value: age1s6v5qrx3mgcgk37gscv8y6z43rssksdct5lx3xk5xrtptjndqvhsnhj7h8 - - name: BACKUP_HOST - value: mongo.data-system.svc.cluster.local - - name: BACKUP_PORT - value: "27017" - envFrom: - - secretRef: - name: mongo-backup-platform-backup-off-cluster - - secretRef: - name: mongo-backup-data-mongo-backup - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: mongo-data - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: mongo-data-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/kustomization.yaml deleted file mode 100644 index 1a2a40343..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/networkpolicy.yaml deleted file mode 100644 index b3c3fc6aa..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/networkpolicy.yaml +++ /dev/null @@ -1,96 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: mongo - namespace: data-system - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: mongo - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-mongo.mongo: "true" - ports: - - protocol: TCP - port: 27017 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: mongo-backup - ports: - - protocol: TCP - port: 27017 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: mongo-backup - namespace: data-system - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: mongo-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: mongo - ports: - - protocol: TCP - port: 27017 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 203.0.113.0/24 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/pvc.yaml deleted file mode 100644 index 98bc72697..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/pvc.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: mongo-data - namespace: data-system - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: mongo-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/service.yaml deleted file mode 100644 index d3bef1e99..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: mongo - namespace: data-system - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: mongo - ports: - - name: mongo - port: 27017 - targetPort: mongo diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/serviceaccount.yaml deleted file mode 100644 index b3f9d29b3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: mongo - namespace: data-system - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: mongo-backup - namespace: data-system - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/vso.yaml deleted file mode 100644 index 36ea571d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/vso.yaml +++ /dev/null @@ -1,68 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: mongo-backup - namespace: data-system - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-mongo-backup - serviceAccount: mongo-backup ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: mongo-backup-platform-backup-off-cluster - namespace: data-system - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: mongo-backup - mount: secret - type: kv-v2 - path: platform/backup/off-cluster - refreshAfter: 10m - hmacSecretData: true - destination: - name: mongo-backup-platform-backup-off-cluster - create: true - annotations: - flagger.app/config-tracking: disabled ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: mongo-backup-data-mongo-backup - namespace: data-system - labels: - app.kubernetes.io/name: mongo-backup - app.kubernetes.io/instance: mongo-backup - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: mongo-backup - mount: secret - type: kv-v2 - path: data/mongo/backup - refreshAfter: 10m - hmacSecretData: true - destination: - name: mongo-backup-data-mongo-backup - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/workload.yaml deleted file mode 100644 index 65e92c644..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-mongo/workload.yaml +++ /dev/null @@ -1,120 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: mongo - namespace: data-system - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 300 - selector: - matchLabels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - template: - metadata: - labels: - app.kubernetes.io/name: mongo - app.kubernetes.io/instance: mongo - app.kubernetes.io/part-of: platform-mongo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/mongo: 8.0.15 - spec: - serviceAccountName: mongo - priorityClassName: platform-data - automountServiceAccountToken: false - hostAliases: - - ip: 127.0.0.1 - hostnames: - - mongo.data-system.svc.cluster.local - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: mongo - image: docker.io/library/mongo@sha256:5f7b9d1a3c5e7f9b1d3a5c7e9f1b3d5a7c9e1f3b5d7a9c1e3f5b7d9a1c3e5f7b - ports: - - name: mongo - containerPort: 27017 - env: - - name: HOME - value: /tmp - resources: - requests: - memory: 2Gi - cpu: 200m - limits: - memory: 2Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: mongo-data - mountPath: /data/db - - name: writable-tmp - mountPath: /tmp - - name: writable-data-configdb - mountPath: /data/configdb - readinessProbe: - tcpSocket: - port: 27017 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 27017 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 27017 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 - volumes: - - name: mongo-data - persistentVolumeClaim: - claimName: mongo-data - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi - - name: writable-data-configdb - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/backup.yaml deleted file mode 100644 index cbf43c569..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/backup.yaml +++ /dev/null @@ -1,80 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: postgres-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 45 2 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: postgres-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/postgres-backup@sha256:6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f - env: - - name: BACKUP_RETAIN - value: "90" - - name: BACKUP_OFF_CLUSTER - value: s3://backup-storage/jorisjonkers-dev - - name: BACKUP_OFF_CLUSTER_PATH - value: data/postgres/postgres-data - - name: BACKUP_OFF_CLUSTER_RECIPIENT - value: age1s6v5qrx3mgcgk37gscv8y6z43rssksdct5lx3xk5xrtptjndqvhsnhj7h8 - - name: BACKUP_HOST - value: postgres.data-system.svc.cluster.local - - name: BACKUP_PORT - value: "5432" - envFrom: - - secretRef: - name: postgres-backup-platform-backup-off-cluster - - secretRef: - name: postgres-backup-data-postgres-backup - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: postgres-data - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: postgres-data-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/configmap.yaml deleted file mode 100644 index 7ffa04d4e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/configmap.yaml +++ /dev/null @@ -1,55 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: postgres-postgresql-conf-765c16a293 - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - postgresql.conf: | - # collections/data/platform/config/postgresql.conf - # - # The Asset platform-postgres mounts at /etc/postgresql/postgresql.conf - # (docs/adr/model/0014-file-shaped-configuration-is-an-asset.md). Fully - # static: no placeholder and no derived value, so the file is carried into - # the projection as written, under a name its content digest decides. - - # ------------------------------------------------------------ connections - listen_addresses = '*' - port = 5432 - max_connections = 100 - unix_socket_directories = '/var/run/postgresql' - - # ----------------------------------------------------------------- memory - shared_buffers = 512MB - effective_cache_size = 1536MB - work_mem = 8MB - maintenance_work_mem = 128MB - - # -------------------------------------------------------------------- WAL - wal_level = replica - max_wal_size = 2GB - min_wal_size = 256MB - checkpoint_completion_target = 0.9 - - # -------------------------------------------------------------- extensions - shared_preload_libraries = 'vector' - - # ---------------------------------------------------------------- logging - log_destination = 'stderr' - logging_collector = off - log_min_duration_statement = 1000 - log_line_prefix = '%m [%p] %q%u@%d ' - - # ---------------------------------------------------------------- locale - datestyle = 'iso, mdy' - timezone = 'UTC' - lc_messages = 'en_US.utf8' - default_text_search_config = 'pg_catalog.english' diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/kustomization.yaml deleted file mode 100644 index 757c0ec0c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/kustomization.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - configmap.yaml - - postgres-catalog.yaml - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - servicemonitor.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/networkpolicy.yaml deleted file mode 100644 index e09e383ad..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/networkpolicy.yaml +++ /dev/null @@ -1,128 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability-system - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - ports: - - protocol: TCP - port: 9187 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - ports: - - protocol: TCP - port: 5432 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.metrics: "true" - ports: - - protocol: TCP - port: 9187 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres-backup - ports: - - protocol: TCP - port: 5432 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: postgres-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - ports: - - protocol: TCP - port: 5432 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 203.0.113.0/24 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/postgres-catalog-networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/postgres-catalog-networkpolicy.yaml deleted file mode 100644 index 540bb2eb6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/postgres-catalog-networkpolicy.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: postgres-catalog - namespace: data-system - labels: - app.kubernetes.io/name: postgres-catalog - app.kubernetes.io/instance: postgres-catalog - app.kubernetes.io/part-of: postgres-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres-catalog - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - ports: - - protocol: TCP - port: 5432 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/postgres-catalog.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/postgres-catalog.yaml deleted file mode 100644 index 40992ddf0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/postgres-catalog.yaml +++ /dev/null @@ -1,205 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: postgres-catalog - namespace: data-system - labels: - app.kubernetes.io/name: postgres-catalog - app.kubernetes.io/instance: postgres-catalog - app.kubernetes.io/part-of: postgres-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: postgres-catalog-45f8d58834d0 - namespace: data-system - labels: - app.kubernetes.io/name: postgres-catalog - app.kubernetes.io/instance: postgres-catalog - app.kubernetes.io/part-of: postgres-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - catalog.json: | - {"admin":{"password":"password","path":"secret/data/data/postgres/catalog","user":"user"},"connection":"postgres","databases":[{"data":"auth-data","name":"auth_db","owner":"auth-owner"},{"data":"knowledge-data","name":"knowledge_db","owner":"knowledge-owner"},{"data":"knowledge-platform-data","name":"knowledge-platform_db","owner":"knowledge-platform-owner"}],"host":"postgres.data-system.svc.cluster.local","port":5432} ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: postgres-catalog-45f8d58834d0 - namespace: data-system - labels: - app.kubernetes.io/name: postgres-catalog - app.kubernetes.io/instance: postgres-catalog - app.kubernetes.io/part-of: postgres-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: postgres-catalog - app.kubernetes.io/instance: postgres-catalog - app.kubernetes.io/part-of: postgres-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - annotations: - image.jorisjonkers.dev/postgres-catalog: 1.0.0 - spec: - serviceAccountName: postgres-catalog - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: postgres-catalog - image: ghcr.io/jorisjonkers-dev/delivery/postgres-catalog@sha256:7e9a1c3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: data-system-postgres-catalog - - name: CATALOG_FILE - value: /catalog/catalog.json - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: catalog - mountPath: /catalog - readOnly: true - volumes: - - name: catalog - configMap: - name: postgres-catalog-45f8d58834d0 - items: - - key: catalog.json - path: catalog.json ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: postgres-catalog - namespace: data-system - labels: - app.kubernetes.io/name: postgres-catalog - app.kubernetes.io/instance: postgres-catalog - app.kubernetes.io/part-of: postgres-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: postgres-catalog - app.kubernetes.io/instance: postgres-catalog - app.kubernetes.io/part-of: postgres-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: postgres-catalog - app.kubernetes.io/instance: postgres-catalog - app.kubernetes.io/part-of: postgres-catalog - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - annotations: - image.jorisjonkers.dev/postgres-catalog: 1.0.0 - spec: - serviceAccountName: postgres-catalog - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: postgres-catalog - image: ghcr.io/jorisjonkers-dev/delivery/postgres-catalog@sha256:7e9a1c3b5d7f9a1c3e5b7d9f1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: data-system-postgres-catalog - - name: CATALOG_FILE - value: /catalog/catalog.json - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: catalog - mountPath: /catalog - readOnly: true - volumes: - - name: catalog - configMap: - name: postgres-catalog-45f8d58834d0 - items: - - key: catalog.json - path: catalog.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/pvc.yaml deleted file mode 100644 index e7af7a1da..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/pvc.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: postgres-data - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: postgres-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/service.yaml deleted file mode 100644 index bb25a079e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/service.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: postgres - ports: - - name: postgres - port: 5432 - targetPort: postgres - - name: metrics - port: 9187 - targetPort: metrics diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/serviceaccount.yaml deleted file mode 100644 index 579c7347d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: postgres-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/servicemonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/servicemonitor.yaml deleted file mode 100644 index 973c54cbe..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/servicemonitor.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: postgres - namespace: data-system - labels: - release: metrics-stack - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: postgres - namespaceSelector: - matchNames: - - data-system - endpoints: - - port: metrics - path: /metrics - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/vso.yaml deleted file mode 100644 index ebf8f573e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/vso.yaml +++ /dev/null @@ -1,141 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-postgres - serviceAccount: postgres ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: postgres-data-system-exporter - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: postgres - mount: secret - type: kv-v2 - path: data-system/exporter - refreshAfter: 10m - hmacSecretData: true - destination: - name: postgres-data-system-exporter - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: postgres ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: postgres-platform-postgres-exporter - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: postgres - mount: secret - type: kv-v2 - path: platform/postgres/exporter - refreshAfter: 10m - hmacSecretData: true - destination: - name: postgres-platform-postgres-exporter - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: postgres ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: postgres-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-postgres-backup - serviceAccount: postgres-backup ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: postgres-backup-platform-backup-off-cluster - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: postgres-backup - mount: secret - type: kv-v2 - path: platform/backup/off-cluster - refreshAfter: 10m - hmacSecretData: true - destination: - name: postgres-backup-platform-backup-off-cluster - create: true - annotations: - flagger.app/config-tracking: disabled ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: postgres-backup-data-postgres-backup - namespace: data-system - labels: - app.kubernetes.io/name: postgres-backup - app.kubernetes.io/instance: postgres-backup - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: postgres-backup - mount: secret - type: kv-v2 - path: data/postgres/backup - refreshAfter: 10m - hmacSecretData: true - destination: - name: postgres-backup-data-postgres-backup - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/workload.yaml deleted file mode 100644 index 0dc12caa8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-postgres/workload.yaml +++ /dev/null @@ -1,179 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: postgres - namespace: data-system - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 300 - selector: - matchLabels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - template: - metadata: - labels: - app.kubernetes.io/name: postgres - app.kubernetes.io/instance: postgres - app.kubernetes.io/part-of: platform-postgres - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/postgres: 17.2.0 - image.jorisjonkers.dev/postgres-exporter: v0.17.1 - spec: - serviceAccountName: postgres - priorityClassName: platform-data - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: postgres - image: docker.io/pgvector/pgvector@sha256:9c1e3a5b7d9f1c3e5a7b9d1f3c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e - ports: - - name: postgres - containerPort: 5432 - - name: metrics - containerPort: 9187 - env: - - name: DATA_SOURCE_NAME - valueFrom: - secretKeyRef: - name: postgres-platform-postgres-exporter - key: datasource - - name: POSTGRES_DB - value: postgres - - name: POSTGRES_USER - value: postgres - - name: HOME - value: /tmp - resources: - requests: - memory: 2Gi - cpu: 500m - limits: - memory: 2Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: postgres-data - mountPath: /var/lib/postgresql/data - - name: postgres-postgresql-conf-765c16a293 - mountPath: /etc/postgresql/postgresql.conf - subPath: postgresql.conf - readOnly: true - - name: writable-var-run-postgresql - mountPath: /var/run/postgresql - - name: writable-tmp - mountPath: /tmp - - name: secret-postgres-data-system-exporter - mountPath: /run/secrets - readOnly: true - readinessProbe: - tcpSocket: - port: 5432 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 5432 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 5432 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 - - name: postgres-exporter - image: quay.io/prometheuscommunity/postgres-exporter@sha256:4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2e4b6d - env: - - name: DATA_SOURCE_NAME - valueFrom: - secretKeyRef: - name: postgres-platform-postgres-exporter - key: datasource - - name: POSTGRES_DB - value: postgres - - name: POSTGRES_USER - value: postgres - - name: HOME - value: /tmp - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-var-run-postgresql - mountPath: /var/run/postgresql - - name: writable-tmp - mountPath: /tmp - - name: secret-postgres-data-system-exporter - mountPath: /run/secrets - readOnly: true - volumes: - - name: postgres-data - persistentVolumeClaim: - claimName: postgres-data - - name: postgres-postgresql-conf-765c16a293 - configMap: - name: postgres-postgresql-conf-765c16a293 - items: - - key: postgresql.conf - path: postgresql.conf - - name: writable-var-run-postgresql - emptyDir: - sizeLimit: 64Mi - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi - - name: secret-postgres-data-system-exporter - secret: - secretName: postgres-data-system-exporter - items: - - key: datasource - path: exporter - defaultMode: 256 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/backup.yaml deleted file mode 100644 index 2c162a569..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/backup.yaml +++ /dev/null @@ -1,72 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: rabbitmq-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 15 3 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: rabbitmq-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/rabbitmq-backup@sha256:a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f8a0c2 - env: - - name: BACKUP_RETAIN - value: "14" - - name: BACKUP_HOST - value: rabbitmq.data-system.svc.cluster.local - - name: BACKUP_PORT - value: "15672" - envFrom: - - secretRef: - name: rabbitmq-backup-data-rabbitmq-backup - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: rabbitmq-data - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: rabbitmq-data-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/configmap.yaml deleted file mode 100644 index f4f01a0ac..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/configmap.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: platform-rabbitmq-external-checks - namespace: data-system - labels: - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - platform-rabbitmq-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"data","name":"platform-rabbitmq-management-1","url":"https://rabbitmq.jorisjonkers.dev/"},{"conditions":["[STATUS] < 500"],"group":"data","name":"platform-rabbitmq-lan-1","url":"https://rabbitmq.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/dashboards.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/dashboards.yaml deleted file mode 100644 index b8a621f39..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/dashboards.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: GrafanaDashboard -metadata: - name: platform-rabbitmq-rabbitmq - namespace: data-system - labels: - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit -spec: - instanceSelector: - matchLabels: - dashboards: grafana - allowCrossNamespaceImport: true - folder: data - json: | - { - "__inputs": [ - { - "name": "DS_PROMETHEUS", - "label": "Prometheus", - "type": "datasource", - "pluginId": "prometheus" - } - ], - "uid": "rabbitmq", - "title": "RabbitMQ", - "tags": ["rabbitmq", "messaging"], - "editable": false, - "refresh": "30s", - "time": { "from": "now-1h", "to": "now" }, - "panels": [ - { - "id": 1, - "title": "Queue Messages (Ready)", - "type": "timeseries", - "gridPos": { "h": 8, "w": 12, "x": 0, "y": 0 }, - "datasource": { "type": "prometheus", "uid": "${DS_PROMETHEUS}" }, - "targets": [ - { "expr": "rabbitmq_queue_messages_ready", "legendFormat": "{{queue}} ready" } - ] - } - ], - "schemaVersion": 39 - } - datasources: - - inputName: DS_PROMETHEUS - datasourceName: prometheus diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/kustomization.yaml deleted file mode 100644 index b098194fe..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/kustomization.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - configmap.yaml - - dashboards.yaml - - pvc.yaml - - route-lan.yaml - - route-management.yaml - - service.yaml - - serviceaccount.yaml - - servicemonitor.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/networkpolicy.yaml deleted file mode 100644 index ff241fb1f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/networkpolicy.yaml +++ /dev/null @@ -1,156 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: rabbitmq - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 15672 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-lan - ports: - - protocol: TCP - port: 15672 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability-system - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - ports: - - protocol: TCP - port: 15692 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.amqp: "true" - ports: - - protocol: TCP - port: 5672 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.management: "true" - ports: - - protocol: TCP - port: 15672 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.metrics: "true" - ports: - - protocol: TCP - port: 15692 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-rabbitmq.mqtt: "true" - ports: - - protocol: TCP - port: 1883 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq-backup - ports: - - protocol: TCP - port: 15672 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 1883 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: rabbitmq-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - ports: - - protocol: TCP - port: 15672 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/pvc.yaml deleted file mode 100644 index 7fb2aa3eb..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/pvc.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: rabbitmq-data - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: rabbitmq-data-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/route-lan.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/route-lan.yaml deleted file mode 100644 index ec355af5d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/route-lan.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: platform-rabbitmq-lan - namespace: data-system - labels: - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-lan -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`rabbitmq.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: rabbitmq - namespace: data-system - port: 15672 - tls: {} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/route-management.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/route-management.yaml deleted file mode 100644 index 71cd6d4d2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/route-management.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: platform-rabbitmq-management - namespace: data-system - labels: - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`rabbitmq.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers - namespace: edge-system - services: - - name: rabbitmq - namespace: data-system - port: 15672 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/service.yaml deleted file mode 100644 index 7c14053a0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/service.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: rabbitmq - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: rabbitmq - ports: - - name: amqp - port: 5672 - targetPort: amqp - - name: management - port: 15672 - targetPort: management - - name: metrics - port: 15692 - targetPort: metrics - - name: mqtt - port: 1883 - targetPort: mqtt ---- -apiVersion: v1 -kind: Service -metadata: - name: rabbitmq-lan-mqtt - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - metallb.io/address-pool: lan-mqtt -spec: - type: LoadBalancer - externalTrafficPolicy: Local - selector: - app.kubernetes.io/instance: rabbitmq - ports: - - name: tcp-1883 - port: 1883 - protocol: TCP - targetPort: 1883 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/serviceaccount.yaml deleted file mode 100644 index 22aa6fb64..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: rabbitmq - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: rabbitmq-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/servicemonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/servicemonitor.yaml deleted file mode 100644 index 8b4cd3017..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/servicemonitor.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: rabbitmq - namespace: data-system - labels: - release: metrics-stack - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - namespaceSelector: - matchNames: - - data-system - endpoints: - - port: metrics - path: /metrics - interval: 30s - scrapeTimeout: 10s - honorLabels: true diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/vso.yaml deleted file mode 100644 index a8ee2cce8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/vso.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: rabbitmq-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: data-system-rabbitmq-backup - serviceAccount: rabbitmq-backup ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: rabbitmq-backup-data-rabbitmq-backup - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq-backup - app.kubernetes.io/instance: rabbitmq-backup - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: rabbitmq-backup - mount: secret - type: kv-v2 - path: data/rabbitmq/backup - refreshAfter: 10m - hmacSecretData: true - destination: - name: rabbitmq-backup-data-rabbitmq-backup - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/workload.yaml deleted file mode 100644 index 6e8f4c9b8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-rabbitmq/workload.yaml +++ /dev/null @@ -1,108 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: rabbitmq - namespace: data-system - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 480 - selector: - matchLabels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - template: - metadata: - labels: - app.kubernetes.io/name: rabbitmq - app.kubernetes.io/instance: rabbitmq - app.kubernetes.io/part-of: platform-rabbitmq - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/rabbitmq: 4.0.7 - spec: - serviceAccountName: rabbitmq - priorityClassName: platform-data - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 999 - fsGroup: 999 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - containers: - - name: rabbitmq - image: docker.io/library/rabbitmq@sha256:2d4f6b8a0c2e4d6f8b0a2c4e6d8f0b2a4c6e8d0f2b4a6c8e0d2f4b6a8c0e2d4f - ports: - - name: amqp - containerPort: 5672 - - name: management - containerPort: 15672 - - name: metrics - containerPort: 15692 - - name: mqtt - containerPort: 1883 - resources: - requests: - memory: 2Gi - cpu: 500m - limits: - memory: 2Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: rabbitmq-data - mountPath: /var/lib/rabbitmq - readinessProbe: - tcpSocket: - port: 5672 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 5672 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 5672 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 24 - volumes: - - name: rabbitmq-data - persistentVolumeClaim: - claimName: rabbitmq-data diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/kustomization.yaml deleted file mode 100644 index 71ff1ac70..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/networkpolicy.yaml deleted file mode 100644 index 47067aa11..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/networkpolicy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: valkey - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: valkey - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/platform-valkey.redis: "true" - ports: - - protocol: TCP - port: 6379 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/pvc.yaml deleted file mode 100644 index 1631b12eb..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/pvc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: valkey-data - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/service.yaml deleted file mode 100644 index ea54c383b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: valkey - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: valkey - ports: - - name: redis - port: 6379 - targetPort: redis diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/serviceaccount.yaml deleted file mode 100644 index b6d570503..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: valkey - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/workload.yaml deleted file mode 100644 index 29bc0d089..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/platform-valkey/workload.yaml +++ /dev/null @@ -1,102 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: valkey - namespace: data-system - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - template: - metadata: - labels: - app.kubernetes.io/name: valkey - app.kubernetes.io/instance: valkey - app.kubernetes.io/part-of: platform-valkey - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/valkey: 8.1.0 - spec: - serviceAccountName: valkey - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 999 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: valkey - image: docker.io/valkey/valkey@sha256:6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c - ports: - - name: redis - containerPort: 6379 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: valkey-data - mountPath: /data - readinessProbe: - tcpSocket: - port: 6379 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 6379 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 6379 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: valkey-data - persistentVolumeClaim: - claimName: valkey-data diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/rollout-events/alert.yaml deleted file mode 100644 index 852407496..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-data - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-data - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-data - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/rollout-events/provider.yaml deleted file mode 100644 index 68151d76e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-data - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/configmap.yaml deleted file mode 100644 index 1bf71f707..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/configmap.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-27616ea716cd - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - data-system-asset-sync.policy.json: | - {"path":{"secret/data/platform/garage/web-key":{"capabilities":["read"]},"secret/metadata/platform/garage/web-key":{"capabilities":["read"]}}} - data-system-asset-sync.role.json: | - {"bound_service_account_names":["asset-sync"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-asset-sync"]} - data-system-garage-catalog.policy.json: | - {"path":{"secret/data/data/garage/catalog":{"capabilities":["read"]},"secret/data/knowledge-platform/garage/s3":{"capabilities":["create","read","update"]},"secret/metadata/data/garage/catalog":{"capabilities":["read"]}}} - data-system-garage-catalog.role.json: | - {"bound_service_account_names":["garage-catalog"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-garage-catalog"]} - data-system-garage.policy.json: | - {"path":{"secret/data/platform/garage":{"capabilities":["read"]},"secret/metadata/platform/garage":{"capabilities":["read"]}}} - data-system-garage.role.json: | - {"bound_service_account_names":["garage"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-garage"]} - data-system-mongo-backup.policy.json: | - {"path":{"secret/data/data/mongo/backup":{"capabilities":["read"]},"secret/data/platform/backup/off-cluster":{"capabilities":["read"]},"secret/metadata/data/mongo/backup":{"capabilities":["read"]},"secret/metadata/platform/backup/off-cluster":{"capabilities":["read"]}}} - data-system-mongo-backup.role.json: | - {"bound_service_account_names":["mongo-backup"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-mongo-backup"]} - data-system-postgres-backup.policy.json: | - {"path":{"secret/data/data/postgres/backup":{"capabilities":["read"]},"secret/data/platform/backup/off-cluster":{"capabilities":["read"]},"secret/metadata/data/postgres/backup":{"capabilities":["read"]},"secret/metadata/platform/backup/off-cluster":{"capabilities":["read"]}}} - data-system-postgres-backup.role.json: | - {"bound_service_account_names":["postgres-backup"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-postgres-backup"]} - data-system-postgres-catalog.policy.json: | - {"path":{"database/roles/auth-data":{"capabilities":["create","read","update"]},"database/roles/auth-owner":{"capabilities":["create","read","update"]},"database/roles/knowledge-data":{"capabilities":["create","read","update"]},"database/roles/knowledge-owner":{"capabilities":["create","read","update"]},"database/roles/knowledge-platform-data":{"capabilities":["create","read","update"]},"database/roles/knowledge-platform-owner":{"capabilities":["create","read","update"]},"secret/data/data/postgres/catalog":{"capabilities":["read"]},"secret/metadata/data/postgres/catalog":{"capabilities":["read"]}}} - data-system-postgres-catalog.role.json: | - {"bound_service_account_names":["postgres-catalog"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-postgres-catalog"]} - data-system-postgres.policy.json: | - {"path":{"secret/data/data-system/exporter":{"capabilities":["read"]},"secret/data/platform/postgres/exporter":{"capabilities":["read"]},"secret/metadata/data-system/exporter":{"capabilities":["read"]},"secret/metadata/platform/postgres/exporter":{"capabilities":["read"]}}} - data-system-postgres.role.json: | - {"bound_service_account_names":["postgres"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-postgres"]} - data-system-rabbitmq-backup.policy.json: | - {"path":{"secret/data/data/rabbitmq/backup":{"capabilities":["read"]},"secret/metadata/data/rabbitmq/backup":{"capabilities":["read"]}}} - data-system-rabbitmq-backup.role.json: | - {"bound_service_account_names":["rabbitmq-backup"],"bound_service_account_namespaces":["data-system"],"token_policies":["data-system-rabbitmq-backup"]} - data-system.generated.json: | - {"keys":[{"adopt":{"key":"datasource","path":"secret/data/platform/postgres/exporter"},"bytes":32,"encoding":"hex","key":"datasource","path":"secret/data/data-system/exporter"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/cronjob.yaml deleted file mode 100644 index 071b09d22..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/cronjob.yaml +++ /dev/null @@ -1,125 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-27616ea716cd - items: - - key: data-system-asset-sync.policy.json - path: data-system-asset-sync.policy.json - - key: data-system-asset-sync.role.json - path: data-system-asset-sync.role.json - - key: data-system-garage-catalog.policy.json - path: data-system-garage-catalog.policy.json - - key: data-system-garage-catalog.role.json - path: data-system-garage-catalog.role.json - - key: data-system-garage.policy.json - path: data-system-garage.policy.json - - key: data-system-garage.role.json - path: data-system-garage.role.json - - key: data-system-mongo-backup.policy.json - path: data-system-mongo-backup.policy.json - - key: data-system-mongo-backup.role.json - path: data-system-mongo-backup.role.json - - key: data-system-postgres-backup.policy.json - path: data-system-postgres-backup.policy.json - - key: data-system-postgres-backup.role.json - path: data-system-postgres-backup.role.json - - key: data-system-postgres-catalog.policy.json - path: data-system-postgres-catalog.policy.json - - key: data-system-postgres-catalog.role.json - path: data-system-postgres-catalog.role.json - - key: data-system-postgres.policy.json - path: data-system-postgres.policy.json - - key: data-system-postgres.role.json - path: data-system-postgres.role.json - - key: data-system-rabbitmq-backup.policy.json - path: data-system-rabbitmq-backup.policy.json - - key: data-system-rabbitmq-backup.role.json - path: data-system-rabbitmq-backup.role.json - - key: data-system.generated.json - path: data-system.generated.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/job.yaml deleted file mode 100644 index 7f896da91..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/job.yaml +++ /dev/null @@ -1,115 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-27616ea716cd - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-27616ea716cd - items: - - key: data-system-asset-sync.policy.json - path: data-system-asset-sync.policy.json - - key: data-system-asset-sync.role.json - path: data-system-asset-sync.role.json - - key: data-system-garage-catalog.policy.json - path: data-system-garage-catalog.policy.json - - key: data-system-garage-catalog.role.json - path: data-system-garage-catalog.role.json - - key: data-system-garage.policy.json - path: data-system-garage.policy.json - - key: data-system-garage.role.json - path: data-system-garage.role.json - - key: data-system-mongo-backup.policy.json - path: data-system-mongo-backup.policy.json - - key: data-system-mongo-backup.role.json - path: data-system-mongo-backup.role.json - - key: data-system-postgres-backup.policy.json - path: data-system-postgres-backup.policy.json - - key: data-system-postgres-backup.role.json - path: data-system-postgres-backup.role.json - - key: data-system-postgres-catalog.policy.json - path: data-system-postgres-catalog.policy.json - - key: data-system-postgres-catalog.role.json - path: data-system-postgres-catalog.role.json - - key: data-system-postgres.policy.json - path: data-system-postgres.policy.json - - key: data-system-postgres.role.json - path: data-system-postgres.role.json - - key: data-system-rabbitmq-backup.policy.json - path: data-system-rabbitmq-backup.policy.json - - key: data-system-rabbitmq-backup.role.json - path: data-system-rabbitmq-backup.role.json - - key: data-system.generated.json - path: data-system.generated.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/networkpolicy.yaml deleted file mode 100644 index c8cca58b3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-asset-sync.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-asset-sync.policy.json deleted file mode 100644 index c37c02871..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-asset-sync.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/platform/garage/web-key": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/garage/web-key": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-asset-sync.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-asset-sync.role.json deleted file mode 100644 index 98679d81f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-asset-sync.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "asset-sync" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-asset-sync" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage-catalog.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage-catalog.policy.json deleted file mode 100644 index 6ca829330..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage-catalog.policy.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "path": { - "secret/data/data/garage/catalog": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/data/garage/catalog": { - "capabilities": [ - "read" - ] - }, - "secret/data/knowledge-platform/garage/s3": { - "capabilities": [ - "create", - "read", - "update" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage-catalog.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage-catalog.role.json deleted file mode 100644 index 3688fb663..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage-catalog.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "garage-catalog" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-garage-catalog" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage.policy.json deleted file mode 100644 index ce342e581..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/platform/garage": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/garage": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage.role.json deleted file mode 100644 index 056988d39..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-garage.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "garage" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-garage" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-mongo-backup.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-mongo-backup.policy.json deleted file mode 100644 index 48737a6d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-mongo-backup.policy.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "path": { - "secret/data/platform/backup/off-cluster": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/backup/off-cluster": { - "capabilities": [ - "read" - ] - }, - "secret/data/data/mongo/backup": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/data/mongo/backup": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-mongo-backup.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-mongo-backup.role.json deleted file mode 100644 index dcebd1594..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-mongo-backup.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "mongo-backup" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-mongo-backup" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json deleted file mode 100644 index 5bb4b204a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-backup.policy.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "path": { - "secret/data/platform/backup/off-cluster": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/backup/off-cluster": { - "capabilities": [ - "read" - ] - }, - "secret/data/data/postgres/backup": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/data/postgres/backup": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-backup.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-backup.role.json deleted file mode 100644 index 92fc2a159..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-backup.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "postgres-backup" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-postgres-backup" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-catalog.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-catalog.policy.json deleted file mode 100644 index 39635394e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-catalog.policy.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "path": { - "secret/data/data/postgres/catalog": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/data/postgres/catalog": { - "capabilities": [ - "read" - ] - }, - "database/roles/auth-owner": { - "capabilities": [ - "create", - "read", - "update" - ] - }, - "database/roles/auth-data": { - "capabilities": [ - "create", - "read", - "update" - ] - }, - "database/roles/knowledge-owner": { - "capabilities": [ - "create", - "read", - "update" - ] - }, - "database/roles/knowledge-data": { - "capabilities": [ - "create", - "read", - "update" - ] - }, - "database/roles/knowledge-platform-owner": { - "capabilities": [ - "create", - "read", - "update" - ] - }, - "database/roles/knowledge-platform-data": { - "capabilities": [ - "create", - "read", - "update" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-catalog.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-catalog.role.json deleted file mode 100644 index 63bf13bbf..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres-catalog.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "postgres-catalog" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-postgres-catalog" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres.policy.json deleted file mode 100644 index e09babd91..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres.policy.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "path": { - "secret/data/data-system/exporter": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/data-system/exporter": { - "capabilities": [ - "read" - ] - }, - "secret/data/platform/postgres/exporter": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/postgres/exporter": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres.role.json deleted file mode 100644 index e60047242..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-postgres.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "postgres" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-postgres" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json deleted file mode 100644 index dcd53b8c7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/data/rabbitmq/backup": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/data/rabbitmq/backup": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json deleted file mode 100644 index 812e5552c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system-rabbitmq-backup.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "rabbitmq-backup" - ], - "bound_service_account_namespaces": [ - "data-system" - ], - "token_policies": [ - "data-system-rabbitmq-backup" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system.generated.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system.generated.json deleted file mode 100644 index c608bd1f7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/policies/data-system.generated.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "keys": [ - { - "path": "secret/data/data-system/exporter", - "key": "datasource", - "bytes": 32, - "encoding": "hex", - "adopt": { - "path": "secret/data/platform/postgres/exporter", - "key": "datasource" - } - } - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/serviceaccount.yaml deleted file mode 100644 index 4d4db5b01..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: data-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vaultconnection.yaml deleted file mode 100644 index e8ebf385b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/data/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: data-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/networkpolicy.yaml deleted file mode 100644 index 8d07aedcd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/networkpolicy.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: collector - namespace: delivery-system - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: collector - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/collector.http: "true" - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/rbac.yaml deleted file mode 100644 index a4474cbe2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/rbac.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: delivery-system-collector - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - persistentvolumes - - persistentvolumeclaims - - pods - verbs: - - get - - list ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: delivery-system-collector - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: delivery-system-collector -subjects: - - kind: ServiceAccount - name: collector - namespace: delivery-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/service.yaml deleted file mode 100644 index 0e2aa1f96..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: collector - namespace: delivery-system - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: collector - ports: - - name: http - port: 8080 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/serviceaccount.yaml deleted file mode 100644 index 8f989217c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: collector - namespace: delivery-system - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/workload.yaml deleted file mode 100644 index 565d8b443..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/collector/workload.yaml +++ /dev/null @@ -1,98 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: collector - namespace: delivery-system - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 150 - selector: - matchLabels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - template: - metadata: - labels: - app.kubernetes.io/name: collector - app.kubernetes.io/instance: collector - app.kubernetes.io/part-of: collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/collector: 1.0.0 - spec: - serviceAccountName: collector - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: collector - image: ghcr.io/jorisjonkers-dev/delivery/collector@sha256:7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c5e7b9d - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /readyz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /fresh - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /fresh - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 2 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/networkpolicy.yaml deleted file mode 100644 index fafff2c79..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/networkpolicy.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: flagger - namespace: delivery-system - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: flagger - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/flagger.http: "true" - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/rbac.yaml deleted file mode 100644 index 68334f066..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/rbac.yaml +++ /dev/null @@ -1,94 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: delivery-system-flagger - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - flagger.app - resources: - - canaries - - canaries/status - verbs: - - get - - list - - watch - - update - - patch - - apiGroups: - - apps - resources: - - deployments - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - autoscaling - resources: - - horizontalpodautoscalers - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - "" - resources: - - services - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - "" - resources: - - secrets - verbs: - - get - - apiGroups: - - "" - resources: - - events - verbs: - - create - - update - - patch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: delivery-system-flagger - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: delivery-system-flagger -subjects: - - kind: ServiceAccount - name: flagger - namespace: delivery-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/service.yaml deleted file mode 100644 index d8a64dd99..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: flagger - namespace: delivery-system - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: flagger - ports: - - name: http - port: 8080 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/serviceaccount.yaml deleted file mode 100644 index 674218776..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: flagger - namespace: delivery-system - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/workload.yaml deleted file mode 100644 index 38dc3293c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/flagger/workload.yaml +++ /dev/null @@ -1,112 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: flagger - namespace: delivery-system - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - template: - metadata: - labels: - app.kubernetes.io/name: flagger - app.kubernetes.io/instance: flagger - app.kubernetes.io/part-of: flagger - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - consumes.deploy-kit.jorisjonkers.dev/release-gate.http: "true" - annotations: - image.jorisjonkers.dev/flagger: 1.41.0 - spec: - serviceAccountName: flagger - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 10001 - runAsGroup: 10001 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: flagger - image: ghcr.io/fluxcd/flagger@sha256:5d1b8f3e7a2c9d4b6e0f1a3c5e7b9d2f4a6c8e0b1d3f5a7c9e2b4d6f8a0c1e3b - ports: - - name: http - containerPort: 8080 - env: - - name: HOME - value: /tmp - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-tmp - mountPath: /tmp - readinessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/kustomization.yaml deleted file mode 100644 index 765f75ad8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - collector - - flagger - - namespace.yaml - - release-gate - - reporter - - rollout-events diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/namespace.yaml deleted file mode 100644 index 4b797d4c2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: delivery-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/networkpolicy.yaml deleted file mode 100644 index 31bd709f7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: delivery-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/kustomization.yaml deleted file mode 100644 index 53001dc91..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - servicemonitor.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/networkpolicy.yaml deleted file mode 100644 index 2765b7ae9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/networkpolicy.yaml +++ /dev/null @@ -1,64 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: release-gate - namespace: delivery-system - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability-system - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/release-gate.http: "true" - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/rbac.yaml deleted file mode 100644 index dbf5581c7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/rbac.yaml +++ /dev/null @@ -1,113 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: release-gate - namespace: delivery-system - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - configmaps - verbs: - - create - - update ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: release-gate - namespace: delivery-system - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: release-gate -subjects: - - kind: ServiceAccount - name: release-gate - namespace: delivery-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: delivery-system-release-gate - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - apiGroups: - - "" - resources: - - pods - verbs: - - list - - apiGroups: - - apps - resources: - - deployments - verbs: - - get - - apiGroups: - - batch - resources: - - jobs - verbs: - - list - - patch - - apiGroups: - - flagger.app - resources: - - canaries - verbs: - - get - - apiGroups: - - secrets.hashicorp.com - resources: - - vaultauths - - vaultstaticsecrets - - vaultdynamicsecrets - verbs: - - list - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: delivery-system-release-gate - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: delivery-system-release-gate -subjects: - - kind: ServiceAccount - name: release-gate - namespace: delivery-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/service.yaml deleted file mode 100644 index 647c16cf5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: release-gate - namespace: delivery-system - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: release-gate - ports: - - name: http - port: 8080 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/serviceaccount.yaml deleted file mode 100644 index d60bd49f1..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: release-gate - namespace: delivery-system - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/servicemonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/servicemonitor.yaml deleted file mode 100644 index 3c5e4b1cd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/servicemonitor.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: release-gate - namespace: delivery-system - labels: - release: metrics-stack - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: release-gate - namespaceSelector: - matchNames: - - delivery-system - endpoints: - - port: http - path: /metrics - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/workload.yaml deleted file mode 100644 index 4d9294410..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/release-gate/workload.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: release-gate - namespace: delivery-system - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 - progressDeadlineSeconds: 150 - selector: - matchLabels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - template: - metadata: - labels: - app.kubernetes.io/name: release-gate - app.kubernetes.io/instance: release-gate - app.kubernetes.io/part-of: release-gate - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/release-gate: 1.0.0 - spec: - serviceAccountName: release-gate - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: release-gate - image: ghcr.io/jorisjonkers-dev/delivery/release-gate@sha256:3e7a9c1d5b2f8e4a6c0d9b7e5f3a1c8d6e4b2a0f9c7e5d3b1a8f6e4c2d0b9a7e - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 64Mi - cpu: 25m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /readyz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 2 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/networkpolicy.yaml deleted file mode 100644 index 9eaf95d10..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/networkpolicy.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: reporter - namespace: delivery-system - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: reporter - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/reporter.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: flux-system - podSelector: - matchLabels: - app: notification-controller - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/rbac.yaml deleted file mode 100644 index 8b0dcef60..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/rbac.yaml +++ /dev/null @@ -1,48 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: delivery-system-reporter - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - kustomize.toolkit.fluxcd.io - resources: - - kustomizations - verbs: - - get - - list - - watch - - apiGroups: - - flagger.app - resources: - - canaries - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: delivery-system-reporter - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: delivery-system-reporter -subjects: - - kind: ServiceAccount - name: reporter - namespace: delivery-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/service.yaml deleted file mode 100644 index 82daacef8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: reporter - namespace: delivery-system - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: reporter - ports: - - name: http - port: 8080 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/serviceaccount.yaml deleted file mode 100644 index 43955743a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: reporter - namespace: delivery-system - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/workload.yaml deleted file mode 100644 index 73cc075db..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/reporter/workload.yaml +++ /dev/null @@ -1,98 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: reporter - namespace: delivery-system - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 150 - selector: - matchLabels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - template: - metadata: - labels: - app.kubernetes.io/name: reporter - app.kubernetes.io/instance: reporter - app.kubernetes.io/part-of: reporter - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/reporter: 1.0.0 - spec: - serviceAccountName: reporter - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: reporter - image: ghcr.io/jorisjonkers-dev/delivery/reporter@sha256:4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d6f - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /readyz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 2 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/rollout-events/alert.yaml deleted file mode 100644 index 7397d5331..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-delivery - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-delivery - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-delivery - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/rollout-events/provider.yaml deleted file mode 100644 index a711aecf6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/delivery/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-delivery - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/networkpolicy.yaml deleted file mode 100644 index c4e2c8296..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/networkpolicy.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: external-dns - namespace: edge-system - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: external-dns - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/external-dns.metrics: "true" - ports: - - protocol: TCP - port: 7979 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 - - 100.64.0.0/10 - - 169.254.0.0/16 - - 127.0.0.0/8 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/rbac.yaml deleted file mode 100644 index a4c8710e6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/rbac.yaml +++ /dev/null @@ -1,51 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: edge-system-external-dns - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - services - - endpoints - - pods - - nodes - verbs: - - get - - list - - watch - - apiGroups: - - traefik.io - resources: - - ingressroutes - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: edge-system-external-dns - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: edge-system-external-dns -subjects: - - kind: ServiceAccount - name: external-dns - namespace: edge-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/service.yaml deleted file mode 100644 index 27c9b1f66..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: external-dns - namespace: edge-system - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: external-dns - ports: - - name: metrics - port: 7979 - targetPort: metrics diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/serviceaccount.yaml deleted file mode 100644 index d8c0d292b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: external-dns - namespace: edge-system - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/workload.yaml deleted file mode 100644 index de42378e3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/external-dns/workload.yaml +++ /dev/null @@ -1,98 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: external-dns - namespace: edge-system - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - template: - metadata: - labels: - app.kubernetes.io/name: external-dns - app.kubernetes.io/instance: external-dns - app.kubernetes.io/part-of: external-dns - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/external-dns: 0.15.1 - spec: - serviceAccountName: external-dns - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: external-dns - image: registry.k8s.io/external-dns/external-dns@sha256:32d7bec08ad97a73bf55e6bd4a434206f5eefb0b15adc05453203c72788fcd5d - ports: - - name: metrics - containerPort: 7979 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /healthz - port: 7979 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 7979 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 7979 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/kustomization.yaml deleted file mode 100644 index 6f8f417b2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - external-dns - - namespace.yaml - - rollout-events - - traefik-lan - - traefik-public - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/namespace.yaml deleted file mode 100644 index 77b7404fd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: edge-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/networkpolicy.yaml deleted file mode 100644 index 2dd44709d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: edge-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/rollout-events/alert.yaml deleted file mode 100644 index 65fb45021..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-edge - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-edge - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-edge - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/rollout-events/provider.yaml deleted file mode 100644 index 5c6e94255..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-edge - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/kustomization.yaml deleted file mode 100644 index eaa8f012c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - middlewares.yaml - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - tlsstore.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/middlewares.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/middlewares.yaml deleted file mode 100644 index 2feb68e69..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/middlewares.yaml +++ /dev/null @@ -1,85 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: forward-auth - namespace: edge-system - labels: - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit -spec: - forwardAuth: - address: http://identity-http.estate-system.svc.cluster.local:8080/gate/forward - trustForwardHeader: true ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: security-headers - namespace: edge-system - labels: - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit -spec: - headers: - contentTypeNosniff: true - frameDeny: true - referrerPolicy: strict-origin-when-cross-origin - permissionsPolicy: camera=(), microphone=(), geolocation=() - stsSeconds: 31536000 - stsIncludeSubdomains: true ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: security-headers-strict - namespace: edge-system - labels: - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit -spec: - headers: - contentTypeNosniff: true - frameDeny: true - referrerPolicy: strict-origin-when-cross-origin - permissionsPolicy: camera=(), microphone=(), geolocation=() - stsSeconds: 31536000 - stsIncludeSubdomains: true - contentSecurityPolicy: default-src 'self' ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: security-headers-admin - namespace: edge-system - labels: - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit -spec: - headers: - contentTypeNosniff: true - frameDeny: true - referrerPolicy: strict-origin-when-cross-origin - permissionsPolicy: camera=(), microphone=(), geolocation=() - stsSeconds: 31536000 - stsIncludeSubdomains: true - contentSecurityPolicy: default-src 'self'; style-src 'self' 'unsafe-inline' ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: security-headers-workflow - namespace: edge-system - labels: - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit -spec: - headers: - contentTypeNosniff: true - frameDeny: true - referrerPolicy: strict-origin-when-cross-origin - permissionsPolicy: camera=(), microphone=(), geolocation=() - stsSeconds: 31536000 - stsIncludeSubdomains: true - contentSecurityPolicy: "default-src 'self'; connect-src 'self' https:" diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/networkpolicy.yaml deleted file mode 100644 index e0a7e267f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/networkpolicy.yaml +++ /dev/null @@ -1,79 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: traefik-lan - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-lan - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/traefik-lan.web: "true" - ports: - - protocol: TCP - port: 8000 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/traefik-lan.websecure: "true" - ports: - - protocol: TCP - port: 8443 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/traefik-lan.admin: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 8000 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 8443 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/rbac.yaml deleted file mode 100644 index 39863bcc1..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/rbac.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: edge-system-traefik-lan - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - services - - secrets - - nodes - - configmaps - - namespaces - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - pods - verbs: - - get - - apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - list - - watch - - apiGroups: - - traefik.io - resources: - - ingressroutes - - ingressroutetcps - - ingressrouteudps - - middlewares - - middlewaretcps - - serverstransports - - serverstransporttcps - - tlsoptions - - tlsstores - - traefikservices - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: edge-system-traefik-lan - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: edge-system-traefik-lan -subjects: - - kind: ServiceAccount - name: traefik-lan - namespace: edge-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/service.yaml deleted file mode 100644 index b3e7b7cfa..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/service.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: traefik-lan - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: traefik-lan - ports: - - name: web - port: 8000 - targetPort: web - - name: websecure - port: 8443 - targetPort: websecure - - name: admin - port: 8080 - targetPort: admin ---- -apiVersion: v1 -kind: Service -metadata: - name: traefik-lan-lan-edge - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - metallb.io/address-pool: lan-edge -spec: - type: LoadBalancer - externalTrafficPolicy: Local - selector: - app.kubernetes.io/instance: traefik-lan - ports: - - name: tcp-80 - port: 80 - protocol: TCP - targetPort: 8000 - - name: tcp-443 - port: 443 - protocol: TCP - targetPort: 8443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/serviceaccount.yaml deleted file mode 100644 index d2f1eb7fd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: traefik-lan - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/tlsstore.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/tlsstore.yaml deleted file mode 100644 index 3e66f3ccd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/tlsstore.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: TLSStore -metadata: - name: default - namespace: edge-system - labels: - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit -spec: - defaultCertificate: - secretName: traefik-lan-platform-tls-wildcard diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/vso.yaml deleted file mode 100644 index a20b5c39c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/vso.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: traefik-lan - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: edge-system-traefik-lan - serviceAccount: traefik-lan ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: traefik-lan-platform-tls-wildcard - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: traefik-lan - mount: secret - type: kv-v2 - path: platform/tls/wildcard - refreshAfter: 10m - hmacSecretData: true - destination: - name: traefik-lan-platform-tls-wildcard - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/workload.yaml deleted file mode 100644 index c36636cb4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-lan/workload.yaml +++ /dev/null @@ -1,127 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: traefik-lan - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 - progressDeadlineSeconds: 180 - selector: - matchLabels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - template: - metadata: - labels: - app.kubernetes.io/name: traefik-lan - app.kubernetes.io/instance: traefik-lan - app.kubernetes.io/part-of: traefik-lan - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/traefik-lan: v3.3.4 - spec: - serviceAccountName: traefik-lan - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - containers: - - name: traefik-lan - image: docker.io/library/traefik@sha256:1f3d5b7a9c2e4f6a8b0d1c3e5f7a9b2d4c6e8f0a1b3d5c7e9f2a4b6d8c0e1f3a - args: - - --entryPoints.web.address=:8000/tcp - - --entryPoints.websecure.address=:8443/tcp - - --entryPoints.websecure.http.tls=true - - --entryPoints.traefik.address=:8080/tcp - - --ping=true - - --ping.entryPoint=traefik - - --metrics.prometheus=true - - --metrics.prometheus.entryPoint=traefik - - --providers.kubernetescrd=true - - --providers.kubernetescrd.ingressClass=traefik-lan - - --providers.kubernetescrd.allowCrossNamespace=true - - --providers.kubernetescrd.allowEmptyServices=true - - --log.format=json - - --accesslog=true - - --accesslog.format=json - ports: - - name: web - containerPort: 8000 - - name: websecure - containerPort: 8443 - - name: admin - containerPort: 8080 - env: - - name: HOME - value: /tmp - resources: - requests: - memory: 128Mi - cpu: 50m - limits: - memory: 128Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-tmp - mountPath: /tmp - readinessProbe: - httpGet: - path: /ping - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /ping - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /ping - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 4 - volumes: - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/kustomization.yaml deleted file mode 100644 index 7c8d9a8d3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pvc.yaml - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/networkpolicy.yaml deleted file mode 100644 index e8a1bb48a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/networkpolicy.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: traefik-public - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/traefik-public.web: "true" - ports: - - protocol: TCP - port: 8000 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/traefik-public.websecure: "true" - ports: - - protocol: TCP - port: 8443 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/traefik-public.admin: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 8000 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 8443 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 - - 100.64.0.0/10 - - 169.254.0.0/16 - - 127.0.0.0/8 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/pvc.yaml deleted file mode 100644 index 4bdd73b2b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/pvc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: traefik-public-acme - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 16Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/rbac.yaml deleted file mode 100644 index 1a07940e7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/rbac.yaml +++ /dev/null @@ -1,75 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: edge-system-traefik-public - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - services - - secrets - - nodes - - configmaps - - namespaces - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - pods - verbs: - - get - - apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - list - - watch - - apiGroups: - - traefik.io - resources: - - ingressroutes - - ingressroutetcps - - ingressrouteudps - - middlewares - - middlewaretcps - - serverstransports - - serverstransporttcps - - tlsoptions - - tlsstores - - traefikservices - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: edge-system-traefik-public - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: edge-system-traefik-public -subjects: - - kind: ServiceAccount - name: traefik-public - namespace: edge-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/service.yaml deleted file mode 100644 index 9baef1217..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/service.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: traefik-public - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: traefik-public - ports: - - name: web - port: 8000 - targetPort: web - - name: websecure - port: 8443 - targetPort: websecure - - name: admin - port: 8080 - targetPort: admin diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/serviceaccount.yaml deleted file mode 100644 index 214e655f9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: traefik-public - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/vso.yaml deleted file mode 100644 index 8296cca2e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/vso.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: traefik-public - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: edge-system-traefik-public - serviceAccount: traefik-public ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: traefik-public-platform-cloudflare - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: traefik-public - mount: secret - type: kv-v2 - path: platform/cloudflare - refreshAfter: 10m - hmacSecretData: true - destination: - name: traefik-public-platform-cloudflare - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: traefik-public diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/workload.yaml deleted file mode 100644 index cc6f444e4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/traefik-public/workload.yaml +++ /dev/null @@ -1,142 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: traefik-public - namespace: edge-system - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 - progressDeadlineSeconds: 180 - selector: - matchLabels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - template: - metadata: - labels: - app.kubernetes.io/name: traefik-public - app.kubernetes.io/instance: traefik-public - app.kubernetes.io/part-of: traefik-public - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/traefik-public: v3.3.4 - spec: - serviceAccountName: traefik-public - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - fsGroup: 65532 - fsGroupChangePolicy: OnRootMismatch - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - containers: - - name: traefik-public - image: docker.io/library/traefik@sha256:1f3d5b7a9c2e4f6a8b0d1c3e5f7a9b2d4c6e8f0a1b3d5c7e9f2a4b6d8c0e1f3a - args: - - --entryPoints.web.address=:8000/tcp - - --entryPoints.websecure.address=:8443/tcp - - --entryPoints.websecure.http.tls=true - - --entryPoints.traefik.address=:8080/tcp - - --ping=true - - --ping.entryPoint=traefik - - --metrics.prometheus=true - - --metrics.prometheus.entryPoint=traefik - - --providers.kubernetescrd=true - - --providers.kubernetescrd.ingressClass=traefik-public - - --providers.kubernetescrd.allowCrossNamespace=true - - --providers.kubernetescrd.allowEmptyServices=true - - --certificatesresolvers.public-frankfurt.acme.email=hostmaster@jorisjonkers.dev - - --certificatesresolvers.public-frankfurt.acme.storage=/acme/public-frankfurt.json - - --certificatesresolvers.public-frankfurt.acme.dnschallenge.provider=cloudflare - - --log.format=json - - --accesslog=true - - --accesslog.format=json - ports: - - name: web - containerPort: 8000 - hostPort: 80 - - name: websecure - containerPort: 8443 - hostPort: 443 - - name: admin - containerPort: 8080 - env: - - name: CF_DNS_API_TOKEN - valueFrom: - secretKeyRef: - name: traefik-public-platform-cloudflare - key: CF_DNS_API_TOKEN - - name: HOME - value: /tmp - resources: - requests: - memory: 128Mi - cpu: 50m - limits: - memory: 128Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: traefik-public-acme - mountPath: /acme - - name: writable-tmp - mountPath: /tmp - readinessProbe: - httpGet: - path: /ping - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /ping - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /ping - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 4 - volumes: - - name: traefik-public-acme - persistentVolumeClaim: - claimName: traefik-public-acme - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/configmap.yaml deleted file mode 100644 index 0e07cd26a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/configmap.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-4201b3c4846b - namespace: edge-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - edge-system-traefik-lan.policy.json: | - {"path":{"secret/data/platform/tls/wildcard":{"capabilities":["read"]},"secret/metadata/platform/tls/wildcard":{"capabilities":["read"]}}} - edge-system-traefik-lan.role.json: | - {"bound_service_account_names":["traefik-lan"],"bound_service_account_namespaces":["edge-system"],"token_policies":["edge-system-traefik-lan"]} - edge-system-traefik-public.policy.json: | - {"path":{"secret/data/platform/cloudflare":{"capabilities":["read"]},"secret/metadata/platform/cloudflare":{"capabilities":["read"]}}} - edge-system-traefik-public.role.json: | - {"bound_service_account_names":["traefik-public"],"bound_service_account_namespaces":["edge-system"],"token_policies":["edge-system-traefik-public"]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/cronjob.yaml deleted file mode 100644 index 160f7abfa..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/cronjob.yaml +++ /dev/null @@ -1,99 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: edge-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-4201b3c4846b - items: - - key: edge-system-traefik-lan.policy.json - path: edge-system-traefik-lan.policy.json - - key: edge-system-traefik-lan.role.json - path: edge-system-traefik-lan.role.json - - key: edge-system-traefik-public.policy.json - path: edge-system-traefik-public.policy.json - - key: edge-system-traefik-public.role.json - path: edge-system-traefik-public.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/job.yaml deleted file mode 100644 index e8c1d1950..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/job.yaml +++ /dev/null @@ -1,89 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-4201b3c4846b - namespace: edge-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-4201b3c4846b - items: - - key: edge-system-traefik-lan.policy.json - path: edge-system-traefik-lan.policy.json - - key: edge-system-traefik-lan.role.json - path: edge-system-traefik-lan.role.json - - key: edge-system-traefik-public.policy.json - path: edge-system-traefik-public.policy.json - - key: edge-system-traefik-public.role.json - path: edge-system-traefik-public.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/networkpolicy.yaml deleted file mode 100644 index 7b95dcb4c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: edge-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-lan.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-lan.policy.json deleted file mode 100644 index 250e4b2e3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-lan.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/platform/tls/wildcard": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/tls/wildcard": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-lan.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-lan.role.json deleted file mode 100644 index 2f071ce25..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-lan.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "traefik-lan" - ], - "bound_service_account_namespaces": [ - "edge-system" - ], - "token_policies": [ - "edge-system-traefik-lan" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.policy.json deleted file mode 100644 index 9c33e44a9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/platform/cloudflare": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/cloudflare": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.role.json deleted file mode 100644 index b1900753c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/policies/edge-system-traefik-public.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "traefik-public" - ], - "bound_service_account_namespaces": [ - "edge-system" - ], - "token_policies": [ - "edge-system-traefik-public" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/serviceaccount.yaml deleted file mode 100644 index 4a75f0272..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: edge-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vaultconnection.yaml deleted file mode 100644 index 0d5cfead4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/edge/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: edge-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/canary.yaml deleted file mode 100644 index 6b46573d8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/canary.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: identity - namespace: identity-system - labels: - app.kubernetes.io/name: identity - app.kubernetes.io/instance: identity - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: identity - progressDeadlineSeconds: 210 - service: - port: 8080 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: identity - process: identity - revision: sha256:04f21489fa0baf215c3c144f3de73f8ef87c180b2b796d5b1ed058e6766df332 - paths: / - readiness: /health/ready - hostnames: id.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: identity - process: identity - revision: sha256:04f21489fa0baf215c3c144f3de73f8ef87c180b2b796d5b1ed058e6766df332 - paths: / - readiness: /health/ready - hostnames: id.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: identity - process: identity - revision: sha256:04f21489fa0baf215c3c144f3de73f8ef87c180b2b796d5b1ed058e6766df332 - paths: / - readiness: /health/ready - hostnames: id.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: identity - process: identity - revision: sha256:04f21489fa0baf215c3c144f3de73f8ef87c180b2b796d5b1ed058e6766df332 - paths: / - readiness: /health/ready - hostnames: id.jorisjonkers.dev - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/configmap.yaml deleted file mode 100644 index d094a2099..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: identity-release-gate - namespace: identity-system - labels: - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"210s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"identity","readiness":{"path":"/health/ready","port":8080}}]} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: identity-external-checks - namespace: identity-system - labels: - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - identity-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"identity","name":"identity-public-1","url":"https://id.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/kustomization.yaml deleted file mode 100644 index d929a4c8c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - route-public.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/networkpolicy.yaml deleted file mode 100644 index f4bfe8d4e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/networkpolicy.yaml +++ /dev/null @@ -1,73 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: identity - namespace: identity-system - labels: - app.kubernetes.io/name: identity - app.kubernetes.io/instance: identity - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: identity - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/identity.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/route-public.yaml deleted file mode 100644 index d3453fde5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/route-public.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: identity-public - namespace: identity-system - labels: - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`id.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers-strict - namespace: edge-system - services: - - name: identity - namespace: identity-system - port: 8080 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/serviceaccount.yaml deleted file mode 100644 index 721c040f0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: identity - namespace: identity-system - labels: - app.kubernetes.io/name: identity - app.kubernetes.io/instance: identity - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/workload.yaml deleted file mode 100644 index 4a8f42163..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/identity/workload.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: identity - namespace: identity-system - labels: - app.kubernetes.io/name: identity - app.kubernetes.io/instance: identity - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: identity - app.kubernetes.io/instance: identity - template: - metadata: - labels: - app.kubernetes.io/name: identity - app.kubernetes.io/instance: identity - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/identity: 1.0.0 - spec: - serviceAccountName: identity - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: identity - image: ghcr.io/jorisjonkers-dev/identity/identity@sha256:1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /health/ready - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /health/live - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /health/live - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/kustomization.yaml deleted file mode 100644 index b1f0d0bc2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - identity - - namespace.yaml - - portal - - rollout-events - - vault-policy - - vaultconnection.yaml - - whoami diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/namespace.yaml deleted file mode 100644 index d0194e6b5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: identity-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/networkpolicy.yaml deleted file mode 100644 index d2a9cee18..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: identity-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/canary.yaml deleted file mode 100644 index 95e1be1ad..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/canary.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: portal - namespace: identity-system - labels: - app.kubernetes.io/name: portal - app.kubernetes.io/instance: portal - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: portal - progressDeadlineSeconds: 720 - service: - port: 8080 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: portal - process: portal - revision: sha256:64c8b50827e7d3454a00eab6bcaa99051bd59849546fdb68a99e77c1e0730752 - paths: / - readiness: / - hostnames: home.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: portal - process: portal - revision: sha256:64c8b50827e7d3454a00eab6bcaa99051bd59849546fdb68a99e77c1e0730752 - paths: / - readiness: / - hostnames: home.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: portal - process: portal - revision: sha256:64c8b50827e7d3454a00eab6bcaa99051bd59849546fdb68a99e77c1e0730752 - paths: / - readiness: / - hostnames: home.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: portal - process: portal - revision: sha256:64c8b50827e7d3454a00eab6bcaa99051bd59849546fdb68a99e77c1e0730752 - paths: / - readiness: / - hostnames: home.jorisjonkers.dev - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/client.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/client.yaml deleted file mode 100644 index 8335ea2e1..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/client.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: identity.jorisjonkers.dev/v1 -kind: Client -metadata: - name: portal - labels: - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit -spec: - signIn: native - host: home.jorisjonkers.dev - launchUrl: https://home.jorisjonkers.dev/apps - redirectUris: - - https://home.jorisjonkers.dev/callback - - https://home.jorisjonkers.dev/silent-renew - credential: pkce - roles: - - user - label: Home - description: Every application you can open diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/configmap.yaml deleted file mode 100644 index 09d6cdf2e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: portal-release-gate - namespace: identity-system - labels: - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"720s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"portal","readiness":{"path":"/","port":8080}}],"protectedBy":"portal","protectedPath":"/api/me"} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: portal-external-checks - namespace: identity-system - labels: - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - portal-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"identity","name":"portal-public-1","url":"https://home.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/kustomization.yaml deleted file mode 100644 index d7ffa4502..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - client.yaml - - configmap.yaml - - route-public.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/networkpolicy.yaml deleted file mode 100644 index 6cfa89637..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/networkpolicy.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: portal - namespace: identity-system - labels: - app.kubernetes.io/name: portal - app.kubernetes.io/instance: portal - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: portal - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/portal.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/route-public.yaml deleted file mode 100644 index a4dea9056..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/route-public.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: portal-public - namespace: identity-system - labels: - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`home.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: portal - namespace: identity-system - port: 8080 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/serviceaccount.yaml deleted file mode 100644 index 24aa46346..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: portal - namespace: identity-system - labels: - app.kubernetes.io/name: portal - app.kubernetes.io/instance: portal - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/workload.yaml deleted file mode 100644 index 64e275230..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/portal/workload.yaml +++ /dev/null @@ -1,85 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: portal - namespace: identity-system - labels: - app.kubernetes.io/name: portal - app.kubernetes.io/instance: portal - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 720 - selector: - matchLabels: - app.kubernetes.io/name: portal - app.kubernetes.io/instance: portal - template: - metadata: - labels: - app.kubernetes.io/name: portal - app.kubernetes.io/instance: portal - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/portal: 1.0.0 - spec: - serviceAccountName: portal - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 101 - runAsGroup: 101 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: portal - image: ghcr.io/jorisjonkers-dev/identity/portal@sha256:3d5f7b9c1e3a5d7f9b1c3e5a7d9f1b3c5e7a9d1f3b5c7e9a1d3f5b7c9e1a3d5f - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: / - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/rollout-events/alert.yaml deleted file mode 100644 index d8329e6a5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-identity - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-identity - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-identity - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/rollout-events/provider.yaml deleted file mode 100644 index bd8b41d35..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-identity - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/configmap.yaml deleted file mode 100644 index a409b2807..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/configmap.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-32b517bea9bc - namespace: identity-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - identity-system-identity.policy.json: | - {"path":{"secret/data/observability-system/grafana/client":{"capabilities":["create","read","update"]}}} - identity-system-identity.role.json: | - {"bound_service_account_names":["identity"],"bound_service_account_namespaces":["identity-system"],"token_policies":["identity-system-identity"]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/cronjob.yaml deleted file mode 100644 index b79d7770a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/cronjob.yaml +++ /dev/null @@ -1,95 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: identity-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-32b517bea9bc - items: - - key: identity-system-identity.policy.json - path: identity-system-identity.policy.json - - key: identity-system-identity.role.json - path: identity-system-identity.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/job.yaml deleted file mode 100644 index ead322874..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/job.yaml +++ /dev/null @@ -1,85 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-32b517bea9bc - namespace: identity-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-32b517bea9bc - items: - - key: identity-system-identity.policy.json - path: identity-system-identity.policy.json - - key: identity-system-identity.role.json - path: identity-system-identity.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/networkpolicy.yaml deleted file mode 100644 index 1ebf448fb..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: identity-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/policies/identity-system-identity.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/policies/identity-system-identity.policy.json deleted file mode 100644 index 7af4460ca..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/policies/identity-system-identity.policy.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "path": { - "secret/data/observability-system/grafana/client": { - "capabilities": [ - "create", - "read", - "update" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/policies/identity-system-identity.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/policies/identity-system-identity.role.json deleted file mode 100644 index 5c84b04f0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/policies/identity-system-identity.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "identity" - ], - "bound_service_account_namespaces": [ - "identity-system" - ], - "token_policies": [ - "identity-system-identity" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/serviceaccount.yaml deleted file mode 100644 index dc5042ee9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: identity-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vaultconnection.yaml deleted file mode 100644 index e81c48a1d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: identity-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/canary.yaml deleted file mode 100644 index f5ba83003..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/canary.yaml +++ /dev/null @@ -1,100 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: whoami - namespace: identity-system - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: whoami - autoscalerRef: - apiVersion: autoscaling/v2 - kind: HorizontalPodAutoscaler - name: whoami - progressDeadlineSeconds: 720 - service: - port: 8080 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: whoami - process: whoami - revision: sha256:4bd7748a66e3d3e1e858c651aee85898bfa851f2677711385cec86360e573960 - paths: / /health - readiness: /health - hostnames: whoami.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: whoami - process: whoami - revision: sha256:4bd7748a66e3d3e1e858c651aee85898bfa851f2677711385cec86360e573960 - paths: / /health - readiness: /health - hostnames: whoami.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: whoami - process: whoami - revision: sha256:4bd7748a66e3d3e1e858c651aee85898bfa851f2677711385cec86360e573960 - paths: / /health - readiness: /health - hostnames: whoami.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: whoami - process: whoami - revision: sha256:4bd7748a66e3d3e1e858c651aee85898bfa851f2677711385cec86360e573960 - paths: / /health - readiness: /health - hostnames: whoami.jorisjonkers.dev - errorRate: 1% - latency: 500ms ---- -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: whoami - namespace: identity-system - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: whoami - minReplicas: 2 - maxReplicas: 2 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/client.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/client.yaml deleted file mode 100644 index 300f20fa7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/client.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: identity.jorisjonkers.dev/v1 -kind: Client -metadata: - name: whoami - labels: - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit -spec: - signIn: gated - host: whoami.jorisjonkers.dev - launchUrl: https://whoami.jorisjonkers.dev/ - iconUrl: https://whoami.jorisjonkers.dev/favicon.ico - roles: - - user - label: Who am I diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/configmap.yaml deleted file mode 100644 index bdd07e6e3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: whoami-release-gate - namespace: identity-system - labels: - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"720s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"whoami","readiness":{"path":"/health","port":8080}}]} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: whoami-external-checks - namespace: identity-system - labels: - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - whoami-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"identity","name":"whoami-public-1","url":"https://whoami.jorisjonkers.dev/"},{"conditions":["[STATUS] < 500"],"group":"identity","name":"whoami-public-2","url":"https://whoami.jorisjonkers.dev/health"},{"conditions":["[STATUS] < 500"],"group":"identity","name":"whoami-public-3","url":"https://whoami.jorisjonkers.dev/.auth/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/kustomization.yaml deleted file mode 100644 index a0a5e59fc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - client.yaml - - configmap.yaml - - pdb.yaml - - route-public.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/networkpolicy.yaml deleted file mode 100644 index 6b2b90b3b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/networkpolicy.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: whoami - namespace: identity-system - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: whoami - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/whoami.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/pdb.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/pdb.yaml deleted file mode 100644 index 088f77749..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/pdb.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: whoami - namespace: identity-system - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: whoami-primary diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/route-public.yaml deleted file mode 100644 index fe4a0dc33..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/route-public.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: whoami-public - namespace: identity-system - labels: - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`whoami.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 997 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers - namespace: edge-system - services: - - name: whoami - namespace: identity-system - port: 8080 - - kind: Rule - match: Host(`whoami.jorisjonkers.dev`) && Path(`/health`) - priority: 999 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: whoami - namespace: identity-system - port: 8080 - - kind: Rule - match: Host(`whoami.jorisjonkers.dev`) && PathPrefix(`/.auth/`) - priority: 998 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: identity - namespace: identity-system - port: 8080 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/serviceaccount.yaml deleted file mode 100644 index 0fff0b40c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: whoami - namespace: identity-system - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/workload.yaml deleted file mode 100644 index ec303d844..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/identity/whoami/workload.yaml +++ /dev/null @@ -1,93 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: whoami - namespace: identity-system - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 720 - selector: - matchLabels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - template: - metadata: - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/whoami: v1.11.0 - spec: - serviceAccountName: whoami - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: - app.kubernetes.io/instance: whoami - matchLabelKeys: - - pod-template-hash - topologyKey: kubernetes.io/hostname - containers: - - name: whoami - image: docker.io/traefik/whoami@sha256:4e6a8c0d2f4b6e8a0c2d4f6b8e0a2c4d6f8b0e2a4c6d8f0b2e4a6c8d0f2b4e6a - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 32Mi - cpu: 10m - limits: - memory: 32Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /health - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/kustomization.yaml deleted file mode 100644 index baa07a1f8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - namespace.yaml - - rollout-events - - stalwart diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/namespace.yaml deleted file mode 100644 index bad1e8aab..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: mail-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/networkpolicy.yaml deleted file mode 100644 index 24062cbf6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: mail-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/rollout-events/alert.yaml deleted file mode 100644 index fc4e6781b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-mail - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-mail - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-mail - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/rollout-events/provider.yaml deleted file mode 100644 index 7aa26ed60..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-mail - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/configmap.yaml deleted file mode 100644 index 0e6644630..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/configmap.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: stalwart-external-checks - namespace: mail-system - labels: - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - stalwart-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"mail","name":"stalwart-admin-1","url":"https://mail.jorisjonkers.dev/"},{"conditions":["[STATUS] < 500"],"group":"mail","name":"stalwart-admin-2","url":"https://mail.jorisjonkers.dev/"}]} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: stalwart-manifest-json-f1813d8cee - namespace: mail-system - labels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - manifest.json: | - { - "domains": [{ "name": "jorisjonkers.dev" }], - "accounts": [{ "name": "postmaster", "domain": "jorisjonkers.dev" }] - } diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/kustomization.yaml deleted file mode 100644 index 14279eb51..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - route-admin.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/networkpolicy.yaml deleted file mode 100644 index 18284dda8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/networkpolicy.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: stalwart - namespace: mail-system - labels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: stalwart - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/stalwart.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/stalwart.smtp: "true" - ports: - - protocol: TCP - port: 25 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/stalwart.imaps: "true" - ports: - - protocol: TCP - port: 993 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 25 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 993 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/route-admin.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/route-admin.yaml deleted file mode 100644 index d5a55f2af..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/route-admin.yaml +++ /dev/null @@ -1,60 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: stalwart-admin - namespace: mail-system - labels: - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`mail.jorisjonkers.dev`) && Path(`/`) - priority: 999 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers - namespace: edge-system - - name: stalwart-admin-1-redirect - namespace: mail-system - services: - - name: stalwart - namespace: mail-system - port: 8080 - - kind: Rule - match: Host(`mail.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 998 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers - namespace: edge-system - services: - - name: stalwart - namespace: mail-system - port: 8080 - tls: - certResolver: public-frankfurt ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: stalwart-admin-1-redirect - namespace: mail-system - labels: - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit -spec: - redirectRegex: - regex: ^(https?://[^/]+)(/.*)?$ - replacement: ${1}/admin/ - permanent: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/service.yaml deleted file mode 100644 index c84bdb505..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/service.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: stalwart - namespace: mail-system - labels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: stalwart - ports: - - name: http - port: 8080 - targetPort: http - - name: smtp - port: 25 - targetPort: smtp - - name: imaps - port: 993 - targetPort: imaps diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/serviceaccount.yaml deleted file mode 100644 index 46c95a780..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: stalwart - namespace: mail-system - labels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/workload.yaml deleted file mode 100644 index 6bf90a0e3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/mail/stalwart/workload.yaml +++ /dev/null @@ -1,148 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: stalwart - namespace: mail-system - labels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 300 - selector: - matchLabels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - template: - metadata: - labels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/stalwart: v0.16.0 - image.jorisjonkers.dev/stalwart-apply: 0.22.0 - spec: - serviceAccountName: stalwart - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 2000 - runAsGroup: 2000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - containers: - - name: stalwart - image: docker.io/stalwartlabs/stalwart@sha256:5a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f7e1f3c5a9b2d4f6e8a0c2e4b6d8f - ports: - - name: http - containerPort: 8080 - - name: smtp - containerPort: 25 - hostPort: 25 - - name: imaps - containerPort: 993 - hostPort: 993 - - name: tcp-2525 - containerPort: 25 - hostPort: 2525 - protocol: TCP - env: - - name: HOME - value: /tmp - resources: - requests: - memory: 512Mi - cpu: 100m - limits: - memory: 512Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - add: - - NET_BIND_SERVICE - drop: - - ALL - volumeMounts: - - name: stalwart-manifest-json-f1813d8cee - mountPath: /etc/stalwart-provisioner/manifest.json - subPath: manifest.json - readOnly: true - - name: writable-tmp - mountPath: /tmp - readinessProbe: - httpGet: - path: /healthz/ready - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz/live - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz/live - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 - - name: stalwart-apply - image: ghcr.io/jorisjonkers-dev/stalwart-provisioner@sha256:7d1f3b5a9c2e4f6b8d0a2c4e6f8b1d3a5c7e9f2b4d6a8c0e2f4b6d8a1c3e5f7b - env: - - name: HOME - value: /tmp - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: stalwart-manifest-json-f1813d8cee - mountPath: /etc/stalwart-provisioner/manifest.json - subPath: manifest.json - readOnly: true - - name: writable-tmp - mountPath: /tmp - volumes: - - name: stalwart-manifest-json-f1813d8cee - configMap: - name: stalwart-manifest-json-f1813d8cee - items: - - key: manifest.json - path: manifest.json - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/configmap.yaml deleted file mode 100644 index fa710c897..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/configmap.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: gpu-device - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-device - app.kubernetes.io/part-of: node -data: - config.yaml: | - version: v1 - sharing: - timeSlicing: - resources: - - name: nvidia.com/gpu - replicas: 4 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/kustomization.yaml deleted file mode 100644 index 4f85ca4f3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/serviceaccount.yaml deleted file mode 100644 index cfc1175b0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/serviceaccount.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: gpu-device - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-device - app.kubernetes.io/part-of: node diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/workload.yaml deleted file mode 100644 index 39c28453d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-device/workload.yaml +++ /dev/null @@ -1,84 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: gpu-device - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-device - app.kubernetes.io/part-of: node -spec: - selector: - matchLabels: - app.kubernetes.io/name: gpu-device - updateStrategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - template: - metadata: - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-device - app.kubernetes.io/part-of: node - spec: - serviceAccountName: gpu-device - automountServiceAccountToken: false - priorityClassName: system-node-critical - securityContext: - seccompProfile: - type: RuntimeDefault - hostPID: true - runtimeClassName: nvidia-cdi - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-gtx-960m-1 - containers: - - name: gpu-device - image: nvcr.io/nvidia/k8s-device-plugin@sha256:eeaf499dbb6f09bb79d95f788d3d87ca6ffa0ae36ed63210d5672e08ba266ff4 - env: - - name: CONFIG_FILE - value: /config/config.yaml - - name: DEVICE_ID_STRATEGY - value: index - - name: FAIL_ON_INIT_ERROR - value: "true" - - name: NVIDIA_VISIBLE_DEVICES - value: all - - name: PASS_DEVICE_SPECS - value: "true" - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - privileged: true - volumeMounts: - - name: device-plugins - mountPath: /var/lib/kubelet/device-plugins - - name: cdi - mountPath: /var/run/cdi - - name: config - mountPath: /config - readOnly: true - volumes: - - name: device-plugins - hostPath: - path: /var/lib/kubelet/device-plugins - - name: cdi - hostPath: - path: /var/run/cdi - - name: config - configMap: - name: gpu-device diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-metrics/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-metrics/kustomization.yaml deleted file mode 100644 index 341f80291..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-metrics/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-metrics/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-metrics/serviceaccount.yaml deleted file mode 100644 index 435e6a618..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-metrics/serviceaccount.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: gpu-metrics - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-metrics - app.kubernetes.io/part-of: node diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-metrics/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-metrics/workload.yaml deleted file mode 100644 index 41d1cfad6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/gpu-metrics/workload.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: gpu-metrics - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-metrics - app.kubernetes.io/part-of: node -spec: - selector: - matchLabels: - app.kubernetes.io/name: gpu-metrics - updateStrategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - template: - metadata: - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-metrics - app.kubernetes.io/part-of: node - spec: - serviceAccountName: gpu-metrics - automountServiceAccountToken: false - priorityClassName: system-node-critical - securityContext: - seccompProfile: - type: RuntimeDefault - runtimeClassName: nvidia-cdi - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-gtx-960m-1 - containers: - - name: gpu-metrics - image: nvcr.io/nvidia/k8s/dcgm-exporter@sha256:6faf8666aeffe3aa674aa33eb59433addf6b8d5ec267ac1a096892d1ffab6a0b - env: - - name: DCGM_EXPORTER_KUBERNETES - value: "true" - - name: DCGM_EXPORTER_LISTEN - value: :9400 - ports: - - name: metrics - containerPort: 9400 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - nvidia.com/gpu: "1" - securityContext: - runAsNonRoot: false - runAsUser: 0 - capabilities: - add: - - SYS_ADMIN - drop: - - ALL - volumeMounts: - - name: pod-resources - mountPath: /var/lib/kubelet/pod-resources - readOnly: true - volumes: - - name: pod-resources - hostPath: - path: /var/lib/kubelet/pod-resources diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/kustomization.yaml deleted file mode 100644 index 352e35872..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - gpu-device - - gpu-metrics - - l4-speaker - - namespace.yaml - - node-metrics - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/kustomization.yaml deleted file mode 100644 index ec636d7b6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pools.yaml - - rbac.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/pools.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/pools.yaml deleted file mode 100644 index 2ca6a7d8e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/pools.yaml +++ /dev/null @@ -1,103 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: metallb.io/v1beta1 -kind: IPAddressPool -metadata: - name: lan-dns - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - addresses: - - 192.168.0.98/32 - autoAssign: false ---- -apiVersion: metallb.io/v1beta1 -kind: L2Advertisement -metadata: - name: lan-dns - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - ipAddressPools: - - lan-dns - nodeSelectors: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 ---- -apiVersion: metallb.io/v1beta1 -kind: IPAddressPool -metadata: - name: lan-edge - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - addresses: - - 192.168.0.99/32 - autoAssign: false ---- -apiVersion: metallb.io/v1beta1 -kind: L2Advertisement -metadata: - name: lan-edge - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - ipAddressPools: - - lan-edge - nodeSelectors: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 ---- -apiVersion: metallb.io/v1beta1 -kind: IPAddressPool -metadata: - name: lan-mqtt - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - addresses: - - 192.168.0.97/32 - autoAssign: false ---- -apiVersion: metallb.io/v1beta1 -kind: L2Advertisement -metadata: - name: lan-mqtt - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - ipAddressPools: - - lan-mqtt - nodeSelectors: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/rbac.yaml deleted file mode 100644 index e82f896cf..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/rbac.yaml +++ /dev/null @@ -1,258 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: node:l4-speaker - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -rules: - - apiGroups: - - "" - resources: - - services - - endpoints - - nodes - - namespaces - - pods - verbs: - - get - - list - - watch - - apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - apiGroups: - - metallb.io - resources: - - ipaddresspools - - l2advertisements - - bgppeers - - bgpadvertisements - - communities - - bfdprofiles - - servicel2statuses - verbs: - - get - - list - - watch - - apiGroups: - - metallb.io - resources: - - servicel2statuses - - servicel2statuses/status - verbs: - - create - - delete - - update - - patch - - apiGroups: - - metallb.io - resources: - - configurationstates - - configurationstates/status - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: node:l4-speaker - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: node:l4-speaker -subjects: - - kind: ServiceAccount - name: l4-speaker - namespace: node-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: l4-speaker - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -rules: - - apiGroups: - - "" - resources: - - secrets - - configmaps - verbs: - - get - - list - - watch - - apiGroups: - - metallb.io - resources: - - servicebgpstatuses - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: l4-speaker - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: l4-speaker -subjects: - - kind: ServiceAccount - name: l4-speaker - namespace: node-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: node:l4-controller - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node -rules: - - apiGroups: - - "" - resources: - - services - - namespaces - - nodes - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - services/status - verbs: - - update - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - apiGroups: - - metallb.io - resources: - - ipaddresspools - - l2advertisements - - bgppeers - - bgpadvertisements - - communities - - bfdprofiles - verbs: - - get - - list - - watch - - apiGroups: - - metallb.io - resources: - - ipaddresspools/status - verbs: - - update - - apiGroups: - - metallb.io - resources: - - configurationstates - - configurationstates/status - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: node:l4-controller - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: node:l4-controller -subjects: - - kind: ServiceAccount - name: l4-controller - namespace: node-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: l4-controller - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node -rules: - - apiGroups: - - "" - resources: - - secrets - - configmaps - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: l4-controller - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: l4-controller -subjects: - - kind: ServiceAccount - name: l4-controller - namespace: node-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/serviceaccount.yaml deleted file mode 100644 index a4924f9ca..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/serviceaccount.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: l4-speaker - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: l4-controller - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/vso.yaml deleted file mode 100644 index 818d055e9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/vso.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: l4-speaker - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: node-system-l4-speaker - serviceAccount: l4-speaker ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: l4-speaker-memberlist - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -spec: - vaultAuthRef: l4-speaker - mount: secret - type: kv-v2 - path: node-system/l4-speaker - refreshAfter: 10m - hmacSecretData: true - destination: - name: l4-speaker-memberlist - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: DaemonSet - name: l4-speaker diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/workload.yaml deleted file mode 100644 index 2cc2330f4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/l4-speaker/workload.yaml +++ /dev/null @@ -1,172 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: l4-speaker - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -spec: - selector: - matchLabels: - app.kubernetes.io/name: l4-speaker - updateStrategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - template: - metadata: - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node - spec: - serviceAccountName: l4-speaker - automountServiceAccountToken: true - priorityClassName: system-node-critical - securityContext: - seccompProfile: - type: RuntimeDefault - hostNetwork: true - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - containers: - - name: l4-speaker - image: quay.io/metallb/speaker@sha256:a2de24e2d206541cb9f101b66876944ecd5a2f19d1783d674e982bfb829defbe - args: - - --port=7472 - - --namespace=node-system - - --log-level=info - env: - - name: METALLB_NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: METALLB_HOST - valueFrom: - fieldRef: - fieldPath: status.hostIP - - name: METALLB_POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: METALLB_ML_BIND_ADDR - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: METALLB_ML_LABELS - value: app.kubernetes.io/name=l4-speaker - - name: METALLB_ML_BIND_PORT - value: "7946" - - name: METALLB_ML_SECRET_KEY_PATH - value: /etc/ml_secret_key - ports: - - name: metrics - containerPort: 7472 - resources: - requests: - memory: 64Mi - cpu: 20m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - add: - - NET_RAW - drop: - - ALL - volumeMounts: - - name: memberlist - mountPath: /etc/ml_secret_key - readOnly: true - volumes: - - name: memberlist - secret: - secretName: l4-speaker-memberlist ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: l4-controller - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node -spec: - replicas: 1 - strategy: - type: Recreate - selector: - matchLabels: - app.kubernetes.io/name: l4-controller - template: - metadata: - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node - spec: - serviceAccountName: l4-controller - automountServiceAccountToken: true - priorityClassName: system-cluster-critical - securityContext: - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - containers: - - name: l4-controller - image: quay.io/metallb/controller@sha256:8bd722cbf5d88cf8b9c82fed1ab069dc1a2f8e5ee383dcf57e49c359ee9d27a3 - args: - - --port=7472 - - --namespace=node-system - - --webhook-mode=disabled - - --log-level=info - ports: - - name: metrics - containerPort: 7472 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/namespace.yaml deleted file mode 100644 index 765a84e8c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/node-metrics/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/node-metrics/kustomization.yaml deleted file mode 100644 index 341f80291..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/node-metrics/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/node-metrics/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/node-metrics/serviceaccount.yaml deleted file mode 100644 index 0619d464b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/node-metrics/serviceaccount.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: node-metrics - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: node-metrics - app.kubernetes.io/part-of: node diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/node-metrics/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/node-metrics/workload.yaml deleted file mode 100644 index 0450606ab..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/node-metrics/workload.yaml +++ /dev/null @@ -1,94 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: node-metrics - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: node-metrics - app.kubernetes.io/part-of: node -spec: - selector: - matchLabels: - app.kubernetes.io/name: node-metrics - updateStrategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - template: - metadata: - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: node-metrics - app.kubernetes.io/part-of: node - spec: - serviceAccountName: node-metrics - automountServiceAccountToken: false - priorityClassName: system-node-critical - securityContext: - seccompProfile: - type: RuntimeDefault - hostNetwork: true - hostPID: true - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: node-metrics - image: quay.io/prometheus/node-exporter@sha256:2303824a4e3dc61fe3195d1a6e978029d4774876cc9aba9d2c60ef85eb96a845 - args: - - --path.procfs=/host/proc - - --path.sysfs=/host/sys - - --path.rootfs=/host/root - - --web.listen-address=:9100 - ports: - - name: metrics - containerPort: 9100 - resources: - requests: - memory: 64Mi - cpu: 20m - limits: - memory: 64Mi - securityContext: - runAsNonRoot: true - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: proc - mountPath: /host/proc - readOnly: true - - name: sys - mountPath: /host/sys - readOnly: true - - name: root - mountPath: /host/root - readOnly: true - mountPropagation: HostToContainer - volumes: - - name: proc - hostPath: - path: /proc - - name: sys - hostPath: - path: /sys - - name: root - hostPath: - path: / diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/configmap.yaml deleted file mode 100644 index fdfc2d0f0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/configmap.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-7aef94bb1eca - namespace: node-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - node-system-l4-speaker.policy.json: | - {"path":{"secret/data/node-system/l4-speaker":{"capabilities":["read"]},"secret/metadata/node-system/l4-speaker":{"capabilities":["read"]}}} - node-system-l4-speaker.role.json: | - {"bound_service_account_names":["l4-speaker"],"bound_service_account_namespaces":["node-system"],"token_policies":["node-system-l4-speaker"]} - node-system.generated.json: | - {"keys":[{"bytes":32,"encoding":"hex","key":"secretkey","path":"secret/data/node-system/l4-speaker"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/cronjob.yaml deleted file mode 100644 index 3e22eefe4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/cronjob.yaml +++ /dev/null @@ -1,97 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: node-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-7aef94bb1eca - items: - - key: node-system-l4-speaker.policy.json - path: node-system-l4-speaker.policy.json - - key: node-system-l4-speaker.role.json - path: node-system-l4-speaker.role.json - - key: node-system.generated.json - path: node-system.generated.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/job.yaml deleted file mode 100644 index 90e609c8b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/job.yaml +++ /dev/null @@ -1,87 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-7aef94bb1eca - namespace: node-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-7aef94bb1eca - items: - - key: node-system-l4-speaker.policy.json - path: node-system-l4-speaker.policy.json - - key: node-system-l4-speaker.role.json - path: node-system-l4-speaker.role.json - - key: node-system.generated.json - path: node-system.generated.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/networkpolicy.yaml deleted file mode 100644 index 27afd3c8f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: node-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/policies/node-system-l4-speaker.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/policies/node-system-l4-speaker.policy.json deleted file mode 100644 index 5bf7b5987..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/policies/node-system-l4-speaker.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/node-system/l4-speaker": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/node-system/l4-speaker": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/policies/node-system-l4-speaker.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/policies/node-system-l4-speaker.role.json deleted file mode 100644 index d6b3f7f11..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/policies/node-system-l4-speaker.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "l4-speaker" - ], - "bound_service_account_namespaces": [ - "node-system" - ], - "token_policies": [ - "node-system-l4-speaker" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/policies/node-system.generated.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/policies/node-system.generated.json deleted file mode 100644 index 962733633..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/policies/node-system.generated.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "keys": [ - { - "path": "secret/data/node-system/l4-speaker", - "key": "secretkey", - "bytes": 32, - "encoding": "hex" - } - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/serviceaccount.yaml deleted file mode 100644 index 4c5d4e8e6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: node-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vaultconnection.yaml deleted file mode 100644 index 592e2b05e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/node/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/kustomization.yaml deleted file mode 100644 index ce1528686..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - libraries.yaml - - namespace.yaml - - notes - - rollout-events diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/libraries.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/libraries.yaml deleted file mode 100644 index b666a6052..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/libraries.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolume -metadata: - name: notes-system-media - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - capacity: - storage: 1Gi - volumeMode: Filesystem - accessModes: - - ReadWriteOnce - persistentVolumeReclaimPolicy: Retain - storageClassName: "" - claimRef: - namespace: notes-system - name: library-media - local: - path: /srv/media - nodeAffinity: - required: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: library-media - namespace: notes-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - storageClassName: "" - volumeName: notes-system-media - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/namespace.yaml deleted file mode 100644 index 91bd05009..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: notes-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/networkpolicy.yaml deleted file mode 100644 index 2f0471623..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: notes-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/canary.yaml deleted file mode 100644 index 8c83e7a2d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/canary.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: notes-api - namespace: notes-system - labels: - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: notes-api - progressDeadlineSeconds: 180 - service: - port: 8080 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: notes - process: notes-api - revision: sha256:2b25f8cbaf62431045cc22614d91a135ce897bc27a977a56a029ead0880c82aa - paths: / - readiness: /healthz/ready - hostnames: notes.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: notes - process: notes-api - revision: sha256:2b25f8cbaf62431045cc22614d91a135ce897bc27a977a56a029ead0880c82aa - paths: / - readiness: /healthz/ready - hostnames: notes.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: notes - process: notes-api - revision: sha256:2b25f8cbaf62431045cc22614d91a135ce897bc27a977a56a029ead0880c82aa - paths: / - readiness: /healthz/ready - hostnames: notes.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: notes - process: notes-api - revision: sha256:2b25f8cbaf62431045cc22614d91a135ce897bc27a977a56a029ead0880c82aa - paths: / - readiness: /healthz/ready - hostnames: notes.jorisjonkers.dev - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/configmap.yaml deleted file mode 100644 index c2d3cc129..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: notes-release-gate - namespace: notes-system - labels: - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"180s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"checks":["error-rate","latency"],"process":"notes-api","readiness":{"path":"/healthz/ready","port":8080}}]} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: notes-external-checks - namespace: notes-system - labels: - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - notes-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"notes","name":"notes-public-1","url":"https://notes.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/kustomization.yaml deleted file mode 100644 index fdbf82ca2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - podmonitor.yaml - - route-public.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/networkpolicy.yaml deleted file mode 100644 index a3d5d3020..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/networkpolicy.yaml +++ /dev/null @@ -1,71 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: notes-api - namespace: notes-system - labels: - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: notes-api - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability-system - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/notes.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/podmonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/podmonitor.yaml deleted file mode 100644 index 1f1448bef..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/podmonitor.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: PodMonitor -metadata: - name: notes-api - namespace: notes-system - labels: - release: metrics-stack - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: notes-api - namespaceSelector: - matchNames: - - notes-system - podMetricsEndpoints: - - port: http - path: /metrics - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/route-public.yaml deleted file mode 100644 index ea74d8a92..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/route-public.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: notes-public - namespace: notes-system - labels: - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`notes.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers-strict - namespace: edge-system - services: - - name: notes-api - namespace: notes-system - port: 8080 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/serviceaccount.yaml deleted file mode 100644 index 80be8eb59..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: notes-api - namespace: notes-system - labels: - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/workload.yaml deleted file mode 100644 index 44927babf..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/notes/workload.yaml +++ /dev/null @@ -1,119 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: notes-api - namespace: notes-system - labels: - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 180 - selector: - matchLabels: - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - template: - metadata: - labels: - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/notes-api: 1.4.0 - spec: - serviceAccountName: notes-api - automountServiceAccountToken: false - runtimeClassName: nvidia-cdi - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - supplementalGroups: - - 3001 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - containers: - - name: notes-api - image: ghcr.io/jorisjonkers-dev/notes/notes-api@sha256:9c1e5a4b7d2f8e3a6b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a - ports: - - name: http - containerPort: 8080 - env: - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: NODE_ENV - value: production - - name: NOTES_PAGE_SIZE - value: "50" - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: notes-api - - name: PORT - value: "8080" - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - nvidia.com/gpu: "1" - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: library-media - mountPath: /attachments - subPath: Notes - readinessProbe: - httpGet: - path: /healthz/ready - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz/live - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz/live - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 4 - volumes: - - name: library-media - persistentVolumeClaim: - claimName: library-media diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/rollout-events/alert.yaml deleted file mode 100644 index 9a88e3438..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-notes - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-notes - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-notes - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/rollout-events/provider.yaml deleted file mode 100644 index 6c9ffcb42..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/notes/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-notes - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/alertmanagerconfig.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/alertmanagerconfig.yaml deleted file mode 100644 index ade3319a2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/alertmanagerconfig.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1alpha1 -kind: AlertmanagerConfig -metadata: - name: estate-alerts - namespace: observability-system - labels: - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit -spec: - route: - receiver: "null" - groupBy: - - alertname - - namespace - groupWait: 1m - groupInterval: 5m - repeatInterval: 12h - routes: - - matchers: - - name: severity - value: critical - receiver: discord - repeatInterval: 4h - - matchers: - - name: severity - value: warning - receiver: discord - repeatInterval: 12h - receivers: - - name: "null" - - name: discord - discordConfigs: - - apiURL: - name: alertmanager-platform-alertmanager-discord - key: webhook-url - sendResolved: true diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/kustomization.yaml deleted file mode 100644 index 4223c5585..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alertmanagerconfig.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/networkpolicy.yaml deleted file mode 100644 index 825f5496d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/networkpolicy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: alertmanager - namespace: observability-system - labels: - app.kubernetes.io/name: alertmanager - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: alertmanager - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/alertmanager.http: "true" - ports: - - protocol: TCP - port: 9093 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/service.yaml deleted file mode 100644 index 349be1ae9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: alertmanager - namespace: observability-system - labels: - app.kubernetes.io/name: alertmanager - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: alertmanager - ports: - - name: http - port: 9093 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/serviceaccount.yaml deleted file mode 100644 index ac12eae56..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: alertmanager - namespace: observability-system - labels: - app.kubernetes.io/name: alertmanager - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/vso.yaml deleted file mode 100644 index 09c3fde20..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/vso.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: alertmanager - namespace: observability-system - labels: - app.kubernetes.io/name: alertmanager - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: observability-system-alertmanager - serviceAccount: alertmanager ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: alertmanager-platform-alertmanager-discord - namespace: observability-system - labels: - app.kubernetes.io/name: alertmanager - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: alertmanager - mount: secret - type: kv-v2 - path: platform/alertmanager-discord - refreshAfter: 10m - hmacSecretData: true - destination: - name: alertmanager-platform-alertmanager-discord - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/workload.yaml deleted file mode 100644 index 77fa163d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alertmanager/workload.yaml +++ /dev/null @@ -1,96 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: Alertmanager -metadata: - name: alertmanager - namespace: observability-system - labels: - app.kubernetes.io/name: alertmanager - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - image: quay.io/prometheus/alertmanager@sha256:4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f7e1f3c5a9b2d4f6e8a0c2e4b6d8f5a2c - version: v0.28.1 - replicas: 1 - serviceAccountName: alertmanager - automountServiceAccountToken: false - podMetadata: - labels: - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/alertmanager: v0.28.1 - portName: http - securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - resources: - requests: - memory: 128Mi - cpu: 50m - limits: - memory: 128Mi - containers: - - name: alertmanager - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-alertmanager - mountPath: /alertmanager - readinessProbe: - httpGet: - path: /-/ready - port: 9093 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /-/healthy - port: 9093 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /-/healthy - port: 9093 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: writable-alertmanager - emptyDir: - sizeLimit: 64Mi - alertmanagerConfigSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - alertmanagerConfigMatcherStrategy: - type: None diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/canary.yaml deleted file mode 100644 index 9ce5ed044..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/canary.yaml +++ /dev/null @@ -1,69 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: alloy - namespace: observability-system - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: alloy - progressDeadlineSeconds: 210 - service: - port: 12345 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: alloy - process: alloy - revision: sha256:85d70bd1e948612d073b7f7cf90001f9bcecdc701d30c544ab7453d485384115 - readiness: /-/ready - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: alloy - process: alloy - revision: sha256:85d70bd1e948612d073b7f7cf90001f9bcecdc701d30c544ab7453d485384115 - readiness: /-/ready - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: alloy - process: alloy - revision: sha256:85d70bd1e948612d073b7f7cf90001f9bcecdc701d30c544ab7453d485384115 - readiness: /-/ready - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: alloy - process: alloy - revision: sha256:85d70bd1e948612d073b7f7cf90001f9bcecdc701d30c544ab7453d485384115 - readiness: /-/ready - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/configmap.yaml deleted file mode 100644 index 876e71832..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/configmap.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: alloy-release-gate - namespace: observability-system - labels: - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"210s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"alloy","readiness":{"path":"/-/ready","port":12345}}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/kustomization.yaml deleted file mode 100644 index f7b15e947..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - rbac.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/networkpolicy.yaml deleted file mode 100644 index 8c9d7d222..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/networkpolicy.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: alloy - namespace: observability-system - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: alloy - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/alloy.http: "true" - ports: - - protocol: TCP - port: 12345 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 12345 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/rbac.yaml deleted file mode 100644 index 62a735885..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/rbac.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-alloy - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - pods - - pods/log - - namespaces - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-alloy - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-alloy -subjects: - - kind: ServiceAccount - name: alloy - namespace: observability-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/serviceaccount.yaml deleted file mode 100644 index ee68ebfbc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: alloy - namespace: observability-system - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/workload.yaml deleted file mode 100644 index 08b2153c9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/alloy/workload.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: alloy - namespace: observability-system - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - template: - metadata: - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/alloy: 1.7.1 - spec: - serviceAccountName: alloy - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 473 - runAsGroup: 473 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: alloy - image: docker.io/grafana/alloy@sha256:65d9d6c5c7c2d5c29e38b777edf8da1dbd764f67deeeaa230724967cafe4e684 - ports: - - name: http - containerPort: 12345 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /-/ready - port: 12345 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /-/ready - port: 12345 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /-/ready - port: 12345 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/networkpolicy.yaml deleted file mode 100644 index f04393ce4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/networkpolicy.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: gatus - namespace: observability-system - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: gatus - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/gatus.http: "true" - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/rbac.yaml deleted file mode 100644 index b54aa0e0a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/rbac.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-gatus - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-gatus - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-gatus -subjects: - - kind: ServiceAccount - name: gatus - namespace: observability-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/service.yaml deleted file mode 100644 index fa623df78..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: gatus - namespace: observability-system - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: gatus - ports: - - name: http - port: 8080 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/serviceaccount.yaml deleted file mode 100644 index e9f00d112..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: gatus - namespace: observability-system - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/workload.yaml deleted file mode 100644 index 33e8a5923..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/gatus/workload.yaml +++ /dev/null @@ -1,113 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: gatus - namespace: observability-system - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - template: - metadata: - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/checks: 1.0.0 - image.jorisjonkers.dev/gatus: 5.17.0 - spec: - serviceAccountName: gatus - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: gatus - image: ghcr.io/twin/gatus@sha256:421c15f697f7992eb00e61643a4284e8d2f57bcc2eabea3639459fa1040add33 - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 64Mi - cpu: 20m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /health - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /health - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /health - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - - name: checks - image: ghcr.io/jorisjonkers-dev/platform/gatus-checks@sha256:a542f60b6e21372a737b4f4dd62c5fd41d76939818b57b0ebb46b650f29dcd5a - resources: - requests: - memory: 32Mi - cpu: 10m - limits: - memory: 32Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/networkpolicy.yaml deleted file mode 100644 index 5cad1efcc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/networkpolicy.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: grafana-operator - namespace: observability-system - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: grafana-operator - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/grafana-operator.metrics: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/grafana-operator.health: "true" - ports: - - protocol: TCP - port: 8081 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/rbac.yaml deleted file mode 100644 index e552a630c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/rbac.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-grafana-operator - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - grafana.integreatly.org - resources: - - grafanas - - grafanas/status - - grafanadashboards - - grafanadashboards/status - verbs: - - get - - list - - watch - - update - - patch - - apiGroups: - - "" - resources: - - configmaps - - secrets - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-grafana-operator - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-grafana-operator -subjects: - - kind: ServiceAccount - name: grafana-operator - namespace: observability-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/service.yaml deleted file mode 100644 index 90c56dc8a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/service.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: grafana-operator - namespace: observability-system - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: grafana-operator - ports: - - name: metrics - port: 8080 - targetPort: metrics - - name: health - port: 8081 - targetPort: health diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/serviceaccount.yaml deleted file mode 100644 index 699ca11dd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: grafana-operator - namespace: observability-system - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/workload.yaml deleted file mode 100644 index 548fa4071..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana-operator/workload.yaml +++ /dev/null @@ -1,100 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: grafana-operator - namespace: observability-system - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - template: - metadata: - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/grafana-operator: 5.17.0 - spec: - serviceAccountName: grafana-operator - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: grafana-operator - image: ghcr.io/grafana/grafana-operator@sha256:5689f1966f7e00acd0cdcff38ae0fc49d66469b384af9139412d645439937c2d - ports: - - name: metrics - containerPort: 8080 - - name: health - containerPort: 8081 - resources: - requests: - memory: 64Mi - cpu: 20m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /healthz - port: 8081 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 8081 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 8081 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/canary.yaml deleted file mode 100644 index 70d184684..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/canary.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: grafana - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: grafana - progressDeadlineSeconds: 210 - service: - port: 3000 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: grafana - process: grafana - revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - paths: / - readiness: /api/health - hostnames: grafana.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: grafana - process: grafana - revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - paths: / - readiness: /api/health - hostnames: grafana.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: grafana - process: grafana - revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - paths: / - readiness: /api/health - hostnames: grafana.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: grafana - process: grafana - revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - paths: / - readiness: /api/health - hostnames: grafana.jorisjonkers.dev - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/client.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/client.yaml deleted file mode 100644 index a5d856f6b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/client.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: identity.jorisjonkers.dev/v1 -kind: Client -metadata: - name: grafana - labels: - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit -spec: - signIn: native - host: grafana.jorisjonkers.dev - launchUrl: https://grafana.jorisjonkers.dev/ - iconUrl: https://grafana.jorisjonkers.dev/public/img/grafana_icon.svg - redirectUris: - - https://grafana.jorisjonkers.dev/login/generic_oauth - credential: secret - secretPath: secret/data/observability-system/grafana/client - roles: - - user - - viewer - - editor - - admin - label: Grafana - description: Metrics and dashboards diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/configmap.yaml deleted file mode 100644 index 5957d2a66..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: grafana-release-gate - namespace: observability-system - labels: - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"210s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"grafana","readiness":{"path":"/api/health","port":3000}}],"protectedBy":"grafana","protectedPath":"/api/user"} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: grafana-external-checks - namespace: observability-system - labels: - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - grafana-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"observability","name":"grafana-public-1","url":"https://grafana.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/grafana.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/grafana.yaml deleted file mode 100644 index 430e042a2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/grafana.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: Grafana -metadata: - name: grafana - namespace: observability-system - labels: - dashboards: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit -spec: - external: - url: http://grafana.observability-system:3000 - adminUser: - name: grafana-observability-system-grafana-admin - key: user - adminPassword: - name: grafana-observability-system-grafana-admin - key: password diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/kustomization.yaml deleted file mode 100644 index 1781af062..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/kustomization.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - client.yaml - - configmap.yaml - - grafana.yaml - - route-public.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/networkpolicy.yaml deleted file mode 100644 index e2e976985..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/networkpolicy.yaml +++ /dev/null @@ -1,73 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: grafana - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: grafana - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 3000 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/grafana.http: "true" - ports: - - protocol: TCP - port: 3000 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 3000 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/route-public.yaml deleted file mode 100644 index 4899f0bd6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/route-public.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: grafana-public - namespace: observability-system - labels: - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`grafana.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: grafana - namespace: observability-system - port: 3000 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/serviceaccount.yaml deleted file mode 100644 index cb88e0bec..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: grafana - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/vso.yaml deleted file mode 100644 index 6e22d6778..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/vso.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: grafana - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - estate.jorisjonkers.dev/revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: observability-system-grafana - serviceAccount: grafana ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: grafana-observability-system-grafana-client - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - estate.jorisjonkers.dev/revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - vaultAuthRef: grafana - mount: secret - type: kv-v2 - path: observability-system/grafana/client - refreshAfter: 10m - hmacSecretData: true - destination: - name: grafana-observability-system-grafana-client - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: grafana-primary ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: grafana-observability-system-grafana-admin - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - estate.jorisjonkers.dev/revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - vaultAuthRef: grafana - mount: secret - type: kv-v2 - path: observability-system/grafana-admin - refreshAfter: 10m - hmacSecretData: true - destination: - name: grafana-observability-system-grafana-admin - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: grafana-primary diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/workload.yaml deleted file mode 100644 index 71f98580e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/grafana/workload.yaml +++ /dev/null @@ -1,126 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: grafana - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - template: - metadata: - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/grafana: 12.2.0 - spec: - serviceAccountName: grafana - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 472 - runAsGroup: 472 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: grafana - image: docker.io/grafana/grafana@sha256:2c4e6a8b0d2f4c6e8a0b2d4f6c8e0a2b4d6f8c0e2a4b6d8f0c2e4a6b8d0f2c4e - ports: - - name: http - containerPort: 3000 - env: - - name: GF_AUTH_DISABLE_LOGIN_FORM - value: "true" - - name: GF_AUTH_GENERIC_OAUTH_API_URL - value: https://id.jorisjonkers.dev/userinfo - - name: GF_AUTH_GENERIC_OAUTH_AUTH_URL - value: https://id.jorisjonkers.dev/oauth2/authorize - - name: GF_AUTH_GENERIC_OAUTH_CLIENT_ID - value: grafana - - name: GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: grafana-observability-system-grafana-client - key: secret - - name: GF_AUTH_GENERIC_OAUTH_ENABLED - value: "true" - - name: GF_AUTH_GENERIC_OAUTH_NAME - value: jorisjonkers.dev - - name: GF_AUTH_GENERIC_OAUTH_SCOPES - value: openid,profile,email - - name: GF_AUTH_GENERIC_OAUTH_TOKEN_URL - value: https://id.jorisjonkers.dev/oauth2/token - - name: GF_SECURITY_ADMIN_PASSWORD - valueFrom: - secretKeyRef: - name: grafana-observability-system-grafana-admin - key: password - - name: GF_SECURITY_ADMIN_USER - valueFrom: - secretKeyRef: - name: grafana-observability-system-grafana-admin - key: user - - name: GF_SERVER_ROOT_URL - value: https://grafana.jorisjonkers.dev - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-var-lib-grafana - mountPath: /var/lib/grafana - readinessProbe: - httpGet: - path: /api/health - port: 3000 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - volumes: - - name: writable-var-lib-grafana - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/canary.yaml deleted file mode 100644 index 883a33420..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/canary.yaml +++ /dev/null @@ -1,69 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: kube-state-metrics - namespace: observability-system - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: kube-state-metrics - progressDeadlineSeconds: 210 - service: - port: 8080 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: kube-state-metrics - process: kube-state-metrics - revision: sha256:2193c1c60acedf71736b49fb4c5a7d1cab725c5a383d968c13bc29fa1c28c22a - readiness: /livez - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: kube-state-metrics - process: kube-state-metrics - revision: sha256:2193c1c60acedf71736b49fb4c5a7d1cab725c5a383d968c13bc29fa1c28c22a - readiness: /livez - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: kube-state-metrics - process: kube-state-metrics - revision: sha256:2193c1c60acedf71736b49fb4c5a7d1cab725c5a383d968c13bc29fa1c28c22a - readiness: /livez - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: kube-state-metrics - process: kube-state-metrics - revision: sha256:2193c1c60acedf71736b49fb4c5a7d1cab725c5a383d968c13bc29fa1c28c22a - readiness: /livez - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/configmap.yaml deleted file mode 100644 index e1a596bd6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/configmap.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: kube-state-metrics-release-gate - namespace: observability-system - labels: - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"210s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"kube-state-metrics","readiness":{"path":"/livez","port":8080}}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/kustomization.yaml deleted file mode 100644 index f7b15e947..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - rbac.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/networkpolicy.yaml deleted file mode 100644 index c4f64ce16..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/networkpolicy.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: kube-state-metrics - namespace: observability-system - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: kube-state-metrics - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/kube-state-metrics.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/kube-state-metrics.telemetry: "true" - ports: - - protocol: TCP - port: 8081 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/rbac.yaml deleted file mode 100644 index 3dae2a0b3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/rbac.yaml +++ /dev/null @@ -1,62 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-kube-state-metrics - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - pods - - nodes - - namespaces - - services - - persistentvolumeclaims - - persistentvolumes - verbs: - - list - - watch - - apiGroups: - - apps - resources: - - deployments - - statefulsets - - daemonsets - - replicasets - verbs: - - list - - watch - - apiGroups: - - batch - resources: - - jobs - - cronjobs - verbs: - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-kube-state-metrics - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-kube-state-metrics -subjects: - - kind: ServiceAccount - name: kube-state-metrics - namespace: observability-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/serviceaccount.yaml deleted file mode 100644 index 71ced0f35..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-state-metrics - namespace: observability-system - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/workload.yaml deleted file mode 100644 index 6585074c2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kube-state-metrics/workload.yaml +++ /dev/null @@ -1,103 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-state-metrics - namespace: observability-system - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - template: - metadata: - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/kube-state-metrics: 2.15.0 - spec: - serviceAccountName: kube-state-metrics - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: kube-state-metrics - image: registry.k8s.io/kube-state-metrics/kube-state-metrics@sha256:6e9bea4d3f394ba14fe405f6027d4d2187f751814702d595a0f68a9cc679171c - ports: - - name: http - containerPort: 8080 - - name: telemetry - containerPort: 8081 - resources: - requests: - memory: 128Mi - cpu: 20m - limits: - memory: 128Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /livez - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /livez - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /livez - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kustomization.yaml deleted file mode 100644 index a4190489c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/kustomization.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alertmanager - - alloy - - gatus - - grafana - - grafana-operator - - kube-state-metrics - - loki - - namespace.yaml - - otel-collector - - prometheus - - prometheus-operator - - pyroscope - - rollout-events - - tempo - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/kustomization.yaml deleted file mode 100644 index 71ff1ac70..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/networkpolicy.yaml deleted file mode 100644 index 99ad9a385..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/networkpolicy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: loki - namespace: observability-system - labels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - app.kubernetes.io/part-of: loki - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: loki - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/loki.http: "true" - ports: - - protocol: TCP - port: 3100 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/pvc.yaml deleted file mode 100644 index 4f237993e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/pvc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: loki - namespace: observability-system - labels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - app.kubernetes.io/part-of: loki - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/service.yaml deleted file mode 100644 index ae39e9764..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: loki - namespace: observability-system - labels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - app.kubernetes.io/part-of: loki - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: loki - ports: - - name: http - port: 3100 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/serviceaccount.yaml deleted file mode 100644 index ae5fb1af7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: loki - namespace: observability-system - labels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - app.kubernetes.io/part-of: loki - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/workload.yaml deleted file mode 100644 index 9b421e986..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/loki/workload.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: loki - namespace: observability-system - labels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - app.kubernetes.io/part-of: loki - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - template: - metadata: - labels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - app.kubernetes.io/part-of: loki - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/loki: 3.4.2 - spec: - serviceAccountName: loki - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 10001 - runAsGroup: 10001 - fsGroup: 10001 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: loki - image: docker.io/grafana/loki@sha256:982945308d3682d16636fd628c314e293499e99c00120acd9b693f5ab16e1648 - ports: - - name: http - containerPort: 3100 - resources: - requests: - memory: 512Mi - cpu: 100m - limits: - memory: 512Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: loki - mountPath: /loki - readinessProbe: - httpGet: - path: /ready - port: 3100 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /ready - port: 3100 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /ready - port: 3100 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: loki - persistentVolumeClaim: - claimName: loki diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/namespace.yaml deleted file mode 100644 index 443be6782..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: observability-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/networkpolicy.yaml deleted file mode 100644 index 2848c1891..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: observability-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/canary.yaml deleted file mode 100644 index fba37a553..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/canary.yaml +++ /dev/null @@ -1,69 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: otel-collector - namespace: observability-system - labels: - app.kubernetes.io/name: otel-collector - app.kubernetes.io/instance: otel-collector - app.kubernetes.io/part-of: otel-collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: otel-collector - progressDeadlineSeconds: 180 - service: - port: 4317 - targetPort: otlp - portName: otlp - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: otel-collector - process: otel-collector - revision: sha256:4bcdab7f158cf8d299aa2970116d870a1dd481e1a861082d99409a4d43d4fe29 - readiness: / - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: otel-collector - process: otel-collector - revision: sha256:4bcdab7f158cf8d299aa2970116d870a1dd481e1a861082d99409a4d43d4fe29 - readiness: / - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: otel-collector - process: otel-collector - revision: sha256:4bcdab7f158cf8d299aa2970116d870a1dd481e1a861082d99409a4d43d4fe29 - readiness: / - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: otel-collector - process: otel-collector - revision: sha256:4bcdab7f158cf8d299aa2970116d870a1dd481e1a861082d99409a4d43d4fe29 - readiness: / - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/configmap.yaml deleted file mode 100644 index fc5ef55b2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/configmap.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: otel-collector-release-gate - namespace: observability-system - labels: - app.kubernetes.io/part-of: otel-collector - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"180s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"otel-collector","readiness":{"path":"/","port":13133}}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/kustomization.yaml deleted file mode 100644 index 058323d97..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/networkpolicy.yaml deleted file mode 100644 index a71195006..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/networkpolicy.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: otel-collector - namespace: observability-system - labels: - app.kubernetes.io/name: otel-collector - app.kubernetes.io/instance: otel-collector - app.kubernetes.io/part-of: otel-collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: otel-collector - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/otel-collector.otlp: "true" - ports: - - protocol: TCP - port: 4317 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/otel-collector.health: "true" - ports: - - protocol: TCP - port: 13133 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 4317 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/serviceaccount.yaml deleted file mode 100644 index 0ece166ed..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: otel-collector - namespace: observability-system - labels: - app.kubernetes.io/name: otel-collector - app.kubernetes.io/instance: otel-collector - app.kubernetes.io/part-of: otel-collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/workload.yaml deleted file mode 100644 index b5db56ccd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/otel-collector/workload.yaml +++ /dev/null @@ -1,103 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: otel-collector - namespace: observability-system - labels: - app.kubernetes.io/name: otel-collector - app.kubernetes.io/instance: otel-collector - app.kubernetes.io/part-of: otel-collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 180 - selector: - matchLabels: - app.kubernetes.io/name: otel-collector - app.kubernetes.io/instance: otel-collector - template: - metadata: - labels: - app.kubernetes.io/name: otel-collector - app.kubernetes.io/instance: otel-collector - app.kubernetes.io/part-of: otel-collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/otel-collector: 0.120.0 - spec: - serviceAccountName: otel-collector - priorityClassName: platform-critical-app - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 10001 - runAsGroup: 10001 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: otel-collector - image: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib@sha256:8e2c4a6f0b1d3e5a7c9f2b4d6e8a0c1f3b5d7e9a2c4f6b8d0e1a3c5f7b9d2e4a - ports: - - name: otlp - containerPort: 4317 - - name: health - containerPort: 13133 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: / - port: 13133 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: / - port: 13133 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: / - port: 13133 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 4 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/networkpolicy.yaml deleted file mode 100644 index 8043b819d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/networkpolicy.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: prometheus-operator - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus-operator - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/prometheus-operator.http: "true" - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/rbac.yaml deleted file mode 100644 index 68ed9dc1a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/rbac.yaml +++ /dev/null @@ -1,79 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-prometheus-operator - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - monitoring.coreos.com - resources: - - prometheuses - - prometheuses/status - - alertmanagers - - alertmanagers/status - - servicemonitors - - podmonitors - - prometheusrules - - alertmanagerconfigs - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - "" - resources: - - services - - endpoints - - pods - - nodes - - namespaces - - configmaps - - secrets - verbs: - - get - - list - - watch - - create - - update - - delete - - apiGroups: - - apps - resources: - - statefulsets - verbs: - - get - - list - - watch - - create - - update - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-prometheus-operator - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-prometheus-operator -subjects: - - kind: ServiceAccount - name: prometheus-operator - namespace: observability-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/service.yaml deleted file mode 100644 index ff0be2b1d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: prometheus-operator - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: prometheus-operator - ports: - - name: http - port: 8080 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/serviceaccount.yaml deleted file mode 100644 index eb2f601cf..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: prometheus-operator - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/workload.yaml deleted file mode 100644 index ad76cecae..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus-operator/workload.yaml +++ /dev/null @@ -1,98 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: prometheus-operator - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - template: - metadata: - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/prometheus-operator: 0.81.0 - spec: - serviceAccountName: prometheus-operator - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: prometheus-operator - image: quay.io/prometheus-operator/prometheus-operator@sha256:b32bec04dd57ec4c604c3f72b7103224b6006922536099eb5e92c017524819c6 - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 128Mi - cpu: 50m - limits: - memory: 128Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/alertrules.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/alertrules.yaml deleted file mode 100644 index f6337e6d1..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/alertrules.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: PrometheusRule -metadata: - name: prometheus-platform - namespace: observability-system - labels: - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - groups: - - name: platform - rules: - - alert: JobFailed - expr: kube_job_status_failed > 0 - for: 5m - labels: - severity: warning - annotations: - summary: Job {{ $labels.namespace }}/{{ $labels.job_name }} failed - - alert: TargetDown - expr: up == 0 - for: 10m - labels: - severity: critical - annotations: - summary: "{{ $labels.job }} on {{ $labels.instance }} is down" - - name: breadth - interval: 1m - limit: 10 - rules: - - record: breadth:up:sum - expr: | - sum(up) - by (job) - labels: {} - annotations: - paged: false - runbook: null - note: say "up" diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/flux-podmonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/flux-podmonitor.yaml deleted file mode 100644 index 81c18ed94..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/flux-podmonitor.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: PodMonitor -metadata: - name: flux-controllers - namespace: observability-system - labels: - release: metrics-stack - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - jobLabel: app - selector: - matchLabels: - app.kubernetes.io/part-of: flux - namespaceSelector: - matchNames: - - flux-system - podMetricsEndpoints: - - portNumber: 8080 - path: /metrics - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/k3s-monitors.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/k3s-monitors.yaml deleted file mode 100644 index 95daf5369..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/k3s-monitors.yaml +++ /dev/null @@ -1,261 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Secret -metadata: - name: prometheus-token - namespace: observability-system - labels: - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/service-account.name: prometheus -type: kubernetes.io/service-account-token ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-prometheus-k3s - labels: - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -rules: - - apiGroups: - - "" - resources: - - nodes - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - nodes/metrics - verbs: - - get - - nonResourceURLs: - - /metrics - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-prometheus-k3s - labels: - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-prometheus-k3s -subjects: - - kind: ServiceAccount - name: prometheus - namespace: observability-system ---- -apiVersion: monitoring.coreos.com/v1alpha1 -kind: ScrapeConfig -metadata: - name: kubelet - namespace: observability-system - labels: - release: metrics-stack - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - jobName: kubelet - kubernetesSDConfigs: - - role: Node - scheme: HTTPS - metricsPath: /metrics - scrapeInterval: 30s - scrapeTimeout: 10s - honorLabels: true - honorTimestamps: true - authorization: - type: Bearer - credentials: - name: prometheus-token - key: token - tlsConfig: - insecureSkipVerify: true - relabelings: - - sourceLabels: - - __address__ - regex: (.+):\d+ - replacement: $1:10250 - targetLabel: __address__ - - sourceLabels: - - __meta_kubernetes_node_name - targetLabel: node - - sourceLabels: - - __metrics_path__ - targetLabel: metrics_path ---- -apiVersion: monitoring.coreos.com/v1alpha1 -kind: ScrapeConfig -metadata: - name: kubelet-cadvisor - namespace: observability-system - labels: - release: metrics-stack - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - jobName: kubelet - kubernetesSDConfigs: - - role: Node - scheme: HTTPS - metricsPath: /metrics/cadvisor - scrapeInterval: 30s - scrapeTimeout: 10s - honorLabels: true - honorTimestamps: true - authorization: - type: Bearer - credentials: - name: prometheus-token - key: token - tlsConfig: - insecureSkipVerify: true - relabelings: - - sourceLabels: - - __address__ - regex: (.+):\d+ - replacement: $1:10250 - targetLabel: __address__ - - sourceLabels: - - __meta_kubernetes_node_name - targetLabel: node - - sourceLabels: - - __metrics_path__ - targetLabel: metrics_path - metricRelabelings: - - action: drop - sourceLabels: - - __name__ - regex: container_cpu_(cfs_throttled_seconds_total|load_average_10s|system_seconds_total|user_seconds_total) - - action: drop - sourceLabels: - - __name__ - regex: container_fs_(io_current|io_time_seconds_total|io_time_weighted_seconds_total|reads_merged_total|sector_reads_total|sector_writes_total|writes_merged_total) - - action: drop - sourceLabels: - - __name__ - regex: container_memory_(mapped_file|swap) - - action: drop - sourceLabels: - - __name__ - regex: container_(file_descriptors|tasks_state|threads_max) - - action: drop - sourceLabels: - - __name__ - regex: container_spec.* ---- -apiVersion: monitoring.coreos.com/v1alpha1 -kind: ScrapeConfig -metadata: - name: kubelet-probes - namespace: observability-system - labels: - release: metrics-stack - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - jobName: kubelet - kubernetesSDConfigs: - - role: Node - scheme: HTTPS - metricsPath: /metrics/probes - scrapeInterval: 30s - scrapeTimeout: 10s - honorLabels: true - honorTimestamps: true - authorization: - type: Bearer - credentials: - name: prometheus-token - key: token - tlsConfig: - insecureSkipVerify: true - relabelings: - - sourceLabels: - - __address__ - regex: (.+):\d+ - replacement: $1:10250 - targetLabel: __address__ - - sourceLabels: - - __meta_kubernetes_node_name - targetLabel: node - - sourceLabels: - - __metrics_path__ - targetLabel: metrics_path ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: apiserver - namespace: observability-system - labels: - release: metrics-stack - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - jobLabel: component - selector: - matchLabels: - component: apiserver - provider: kubernetes - namespaceSelector: - matchNames: - - default - endpoints: - - port: https - scheme: https - interval: 30s - scrapeTimeout: 10s - authorization: - type: Bearer - credentials: - name: prometheus-token - key: token - tlsConfig: - ca: - configMap: - name: kube-root-ca.crt - key: ca.crt - serverName: kube-apiserver - metricRelabelings: - - action: drop - sourceLabels: - - __name__ - - le - regex: (etcd_request|apiserver_request_slo|apiserver_request_sli|apiserver_request)_duration_seconds_bucket;(0\.15|0\.2|0\.3|0\.35|0\.4|0\.45|0\.6|0\.7|0\.8|0\.9|1\.25|1\.5|1\.75|2|3|3\.5|4|4\.5|6|7|8|9|15|20|40|45|50)(\.0)? ---- -apiVersion: monitoring.coreos.com/v1 -kind: PodMonitor -metadata: - name: coredns - namespace: observability-system - labels: - release: metrics-stack - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - jobLabel: k8s-app - selector: - matchLabels: - k8s-app: kube-dns - namespaceSelector: - matchNames: - - kube-system - podMetricsEndpoints: - - portNumber: 9153 - path: /metrics - interval: 30s - scrapeTimeout: 10s - relabelings: - - targetLabel: job - replacement: coredns diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/kustomization.yaml deleted file mode 100644 index e89f5ac02..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alertrules.yaml - - flux-podmonitor.yaml - - k3s-monitors.yaml - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/networkpolicy.yaml deleted file mode 100644 index 6b34cf599..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/networkpolicy.yaml +++ /dev/null @@ -1,131 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: prometheus - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus - app.kubernetes.io/instance: prometheus - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/prometheus.http: "true" - ports: - - protocol: TCP - port: 9090 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: auth-system - podSelector: - matchLabels: - app.kubernetes.io/instance: auth-api - ports: - - protocol: UDP - port: 8080 - - protocol: TCP - port: 8080 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - ports: - - protocol: UDP - port: 9187 - - protocol: TCP - port: 9187 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - ports: - - protocol: UDP - port: 15692 - - protocol: TCP - port: 15692 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: UDP - port: 8080 - - protocol: TCP - port: 8080 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: knowledge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: knowledge-api - ports: - - protocol: UDP - port: 8080 - - protocol: TCP - port: 8080 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: notes-system - podSelector: - matchLabels: - app.kubernetes.io/instance: notes-api - ports: - - protocol: UDP - port: 8080 - - protocol: TCP - port: 8080 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: flux-system - podSelector: - matchLabels: - app.kubernetes.io/part-of: flux - ports: - - protocol: UDP - port: 8080 - - protocol: TCP - port: 8080 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/rbac.yaml deleted file mode 100644 index ce695861b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/rbac.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-prometheus - labels: - app.kubernetes.io/name: prometheus - app.kubernetes.io/instance: prometheus - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - services - - endpoints - - pods - verbs: - - get - - list - - watch - - apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-prometheus - labels: - app.kubernetes.io/name: prometheus - app.kubernetes.io/instance: prometheus - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-prometheus -subjects: - - kind: ServiceAccount - name: prometheus - namespace: observability-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/service.yaml deleted file mode 100644 index 664b3e9e9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: prometheus - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus - app.kubernetes.io/instance: prometheus - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: prometheus - ports: - - name: http - port: 9090 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/serviceaccount.yaml deleted file mode 100644 index 02907a2e8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: prometheus - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus - app.kubernetes.io/instance: prometheus - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/workload.yaml deleted file mode 100644 index 48c6409c5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/prometheus/workload.yaml +++ /dev/null @@ -1,127 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: Prometheus -metadata: - name: prometheus - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus - app.kubernetes.io/instance: prometheus - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - image: quay.io/prometheus/prometheus@sha256:4c6e8a0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c - version: v3.2.1 - replicas: 1 - serviceAccountName: prometheus - automountServiceAccountToken: true - priorityClassName: platform-critical-app - podMetadata: - labels: - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/prometheus: v3.2.1 - portName: http - securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - resources: - requests: - memory: 512Mi - cpu: 100m - limits: - memory: 512Mi - containers: - - name: prometheus - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-prometheus - mountPath: /prometheus - readinessProbe: - httpGet: - path: /-/ready - port: 9090 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /-/healthy - port: 9090 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /-/healthy - port: 9090 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 - volumes: - - name: writable-prometheus - emptyDir: - sizeLimit: 64Mi - additionalArgs: - - name: log.level - value: info - - name: query.max-concurrency - scrapeInterval: 30s - scrapeTimeout: 10s - evaluationInterval: 30s - serviceMonitorSelector: - matchLabels: - release: metrics-stack - serviceMonitorNamespaceSelector: {} - podMonitorSelector: - matchLabels: - release: metrics-stack - podMonitorNamespaceSelector: {} - scrapeConfigSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - scrapeConfigNamespaceSelector: {} - ruleSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - ruleNamespaceSelector: {} - alerting: - alertmanagers: - - namespace: observability-system - name: alertmanager - port: http - apiVersion: v2 - retention: 15d - retentionSize: 10GB - enableRemoteWriteReceiver: true - enableFeatures: - - exemplar-storage - - native-histograms diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/kustomization.yaml deleted file mode 100644 index 71ff1ac70..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/networkpolicy.yaml deleted file mode 100644 index 533e9fb90..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/networkpolicy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: pyroscope - namespace: observability-system - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - app.kubernetes.io/part-of: pyroscope - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: pyroscope - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/pyroscope.http: "true" - ports: - - protocol: TCP - port: 4040 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/pvc.yaml deleted file mode 100644 index ad4ae728f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/pvc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: pyroscope - namespace: observability-system - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - app.kubernetes.io/part-of: pyroscope - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/service.yaml deleted file mode 100644 index ed5318969..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: pyroscope - namespace: observability-system - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - app.kubernetes.io/part-of: pyroscope - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: pyroscope - ports: - - name: http - port: 4040 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/serviceaccount.yaml deleted file mode 100644 index 8ef5955a6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: pyroscope - namespace: observability-system - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - app.kubernetes.io/part-of: pyroscope - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/workload.yaml deleted file mode 100644 index 78b3d69d8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/pyroscope/workload.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pyroscope - namespace: observability-system - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - app.kubernetes.io/part-of: pyroscope - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - template: - metadata: - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - app.kubernetes.io/part-of: pyroscope - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/pyroscope: 1.12.0 - spec: - serviceAccountName: pyroscope - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 10001 - runAsGroup: 10001 - fsGroup: 10001 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: pyroscope - image: docker.io/grafana/pyroscope@sha256:af2bcaf32f82481f3d0138ebd1f99ba2ca96ac6104acac0a10ee9b193e5df2af - ports: - - name: http - containerPort: 4040 - resources: - requests: - memory: 512Mi - cpu: 100m - limits: - memory: 512Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: pyroscope - mountPath: /data - readinessProbe: - httpGet: - path: /ready - port: 4040 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /ready - port: 4040 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /ready - port: 4040 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: pyroscope - persistentVolumeClaim: - claimName: pyroscope diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/rollout-events/alert.yaml deleted file mode 100644 index 9446756a6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-observability - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-observability - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-observability - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/rollout-events/provider.yaml deleted file mode 100644 index 7ee2e7582..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-observability - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/kustomization.yaml deleted file mode 100644 index 71ff1ac70..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/networkpolicy.yaml deleted file mode 100644 index 46d0b765d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/networkpolicy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: tempo - namespace: observability-system - labels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - app.kubernetes.io/part-of: tempo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: tempo - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/tempo.http: "true" - ports: - - protocol: TCP - port: 3200 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/pvc.yaml deleted file mode 100644 index 9f0838def..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/pvc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: tempo - namespace: observability-system - labels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - app.kubernetes.io/part-of: tempo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/service.yaml deleted file mode 100644 index f351b8ad3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: tempo - namespace: observability-system - labels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - app.kubernetes.io/part-of: tempo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: tempo - ports: - - name: http - port: 3200 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/serviceaccount.yaml deleted file mode 100644 index 603601cc9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: tempo - namespace: observability-system - labels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - app.kubernetes.io/part-of: tempo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/workload.yaml deleted file mode 100644 index ee18b6ac6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/tempo/workload.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: tempo - namespace: observability-system - labels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - app.kubernetes.io/part-of: tempo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - template: - metadata: - labels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - app.kubernetes.io/part-of: tempo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/tempo: 2.7.1 - spec: - serviceAccountName: tempo - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 10001 - runAsGroup: 10001 - fsGroup: 10001 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: tempo - image: docker.io/grafana/tempo@sha256:8d6546721a1d106cf8d27f7326ebae7e83c1592aeb7479b8f7ec9d8d700d464f - ports: - - name: http - containerPort: 3200 - resources: - requests: - memory: 512Mi - cpu: 100m - limits: - memory: 512Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: tempo - mountPath: /var/tempo - readinessProbe: - httpGet: - path: /ready - port: 3200 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /ready - port: 3200 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /ready - port: 3200 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: tempo - persistentVolumeClaim: - claimName: tempo diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/configmap.yaml deleted file mode 100644 index dbb63d095..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/configmap.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-b2e608d67c17 - namespace: observability-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - observability-system-alertmanager.policy.json: | - {"path":{"secret/data/platform/alertmanager-discord":{"capabilities":["read"]},"secret/metadata/platform/alertmanager-discord":{"capabilities":["read"]}}} - observability-system-alertmanager.role.json: | - {"bound_service_account_names":["alertmanager"],"bound_service_account_namespaces":["observability-system"],"token_policies":["observability-system-alertmanager"]} - observability-system-grafana.policy.json: | - {"path":{"secret/data/observability-system/grafana-admin":{"capabilities":["read"]},"secret/data/observability-system/grafana/client":{"capabilities":["read"]},"secret/metadata/observability-system/grafana-admin":{"capabilities":["read"]},"secret/metadata/observability-system/grafana/client":{"capabilities":["read"]}}} - observability-system-grafana.role.json: | - {"bound_service_account_names":["grafana"],"bound_service_account_namespaces":["observability-system"],"token_policies":["observability-system-grafana"]} - observability-system.generated.json: | - {"keys":[{"bytes":32,"encoding":"hex","key":"password","path":"secret/data/observability-system/grafana-admin"},{"bytes":32,"encoding":"hex","key":"user","path":"secret/data/observability-system/grafana-admin"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/cronjob.yaml deleted file mode 100644 index f69abddcf..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/cronjob.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: observability-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-b2e608d67c17 - items: - - key: observability-system-alertmanager.policy.json - path: observability-system-alertmanager.policy.json - - key: observability-system-alertmanager.role.json - path: observability-system-alertmanager.role.json - - key: observability-system-grafana.policy.json - path: observability-system-grafana.policy.json - - key: observability-system-grafana.role.json - path: observability-system-grafana.role.json - - key: observability-system.generated.json - path: observability-system.generated.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/job.yaml deleted file mode 100644 index 66757a228..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/job.yaml +++ /dev/null @@ -1,91 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-b2e608d67c17 - namespace: observability-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-b2e608d67c17 - items: - - key: observability-system-alertmanager.policy.json - path: observability-system-alertmanager.policy.json - - key: observability-system-alertmanager.role.json - path: observability-system-alertmanager.role.json - - key: observability-system-grafana.policy.json - path: observability-system-grafana.policy.json - - key: observability-system-grafana.role.json - path: observability-system-grafana.role.json - - key: observability-system.generated.json - path: observability-system.generated.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/networkpolicy.yaml deleted file mode 100644 index 00bbfd21f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: observability-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.policy.json deleted file mode 100644 index 56db5c5f8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/platform/alertmanager-discord": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/alertmanager-discord": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.role.json deleted file mode 100644 index b63e93039..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "alertmanager" - ], - "bound_service_account_namespaces": [ - "observability-system" - ], - "token_policies": [ - "observability-system-alertmanager" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-grafana.policy.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-grafana.policy.json deleted file mode 100644 index 30a55dec1..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-grafana.policy.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "path": { - "secret/data/observability-system/grafana/client": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/observability-system/grafana/client": { - "capabilities": [ - "read" - ] - }, - "secret/data/observability-system/grafana-admin": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/observability-system/grafana-admin": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-grafana.role.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-grafana.role.json deleted file mode 100644 index 5a3890685..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system-grafana.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "grafana" - ], - "bound_service_account_namespaces": [ - "observability-system" - ], - "token_policies": [ - "observability-system-grafana" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system.generated.json b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system.generated.json deleted file mode 100644 index ca961387e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/policies/observability-system.generated.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "keys": [ - { - "path": "secret/data/observability-system/grafana-admin", - "key": "password", - "bytes": 32, - "encoding": "hex" - }, - { - "path": "secret/data/observability-system/grafana-admin", - "key": "user", - "bytes": 32, - "encoding": "hex" - } - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/serviceaccount.yaml deleted file mode 100644 index c09926c15..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: observability-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vaultconnection.yaml deleted file mode 100644 index 39db9c968..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/apps/observability/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: observability-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/human-grants/clusterrolebindings.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/human-grants/clusterrolebindings.yaml deleted file mode 100644 index 31e6e799d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/human-grants/clusterrolebindings.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: human:oidc:k8s-operators:admin - labels: - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: admin -subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: oidc:k8s-operators ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: human:oidc:k8s-developers:edit - labels: - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: edit -subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: oidc:k8s-developers ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: human:oidc:k8s-readers:view - labels: - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: view -subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: oidc:k8s-readers ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: human:oidc:k8s-admin:cluster-admin - labels: - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: oidc:k8s-admin diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/human-grants/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/human-grants/kustomization.yaml deleted file mode 100644 index 029015f5d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/human-grants/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - clusterrolebindings.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/priority-classes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/priority-classes/kustomization.yaml deleted file mode 100644 index 8b06a2f03..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/priority-classes/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/priority-classes/priorityclasses.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/priority-classes/priorityclasses.yaml deleted file mode 100644 index a304512d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/priority-classes/priorityclasses.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-data - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 1000000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "A datastore: it schedules before what reads it." ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-critical-app - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 100000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "The foundation and the Applications the platform names: they keep scheduling under pressure." diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/stable-addresses/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/stable-addresses/kustomization.yaml deleted file mode 100644 index ad77fad11..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/stable-addresses/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - namespace.yaml - - services.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/stable-addresses/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/stable-addresses/namespace.yaml deleted file mode 100644 index 1a599d91f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/stable-addresses/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/stable-addresses/services.yaml b/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/stable-addresses/services.yaml deleted file mode 100644 index a62906c81..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/estate/expected/estate/stable-addresses/services.yaml +++ /dev/null @@ -1,56 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-postgres-postgres - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: postgres.data-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-rabbitmq-amqp - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: rabbitmq.data-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-valkey-redis - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: valkey.data-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: release-gate-http - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: release-gate.delivery-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: stalwart-smtp - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: stalwart.mail-system.svc.cluster.local diff --git a/emf/bundles/cli/src/test/resources/stages/render/gaps.txt b/emf/bundles/cli/src/test/resources/stages/render/gaps.txt deleted file mode 100644 index 908a4fddd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/gaps.txt +++ /dev/null @@ -1,9 +0,0 @@ -ControllerKind.statefulSet is never used in a render case's input -IndexFile.namespace is never set in a render case's input -ResolvedClient.backChannelLogoutUri is never set in a render case's input -ResolvedPlacement.boundTo is never set in a render case's input -ResolvedPlacement.from is never set in a render case's input -ResolvedProcess.command is never set in a render case's input -ResolvedSidecar.arguments is never set in a render case's input -ResolvedSidecar.command is never set in a render case's input -WorkloadFile.disruptionBudget is never set in a render case's input diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/canary.yaml deleted file mode 100644 index 6b46573d8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/canary.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: identity - namespace: identity-system - labels: - app.kubernetes.io/name: identity - app.kubernetes.io/instance: identity - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: identity - progressDeadlineSeconds: 210 - service: - port: 8080 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: identity - process: identity - revision: sha256:04f21489fa0baf215c3c144f3de73f8ef87c180b2b796d5b1ed058e6766df332 - paths: / - readiness: /health/ready - hostnames: id.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: identity - process: identity - revision: sha256:04f21489fa0baf215c3c144f3de73f8ef87c180b2b796d5b1ed058e6766df332 - paths: / - readiness: /health/ready - hostnames: id.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: identity - process: identity - revision: sha256:04f21489fa0baf215c3c144f3de73f8ef87c180b2b796d5b1ed058e6766df332 - paths: / - readiness: /health/ready - hostnames: id.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: identity - process: identity - revision: sha256:04f21489fa0baf215c3c144f3de73f8ef87c180b2b796d5b1ed058e6766df332 - paths: / - readiness: /health/ready - hostnames: id.jorisjonkers.dev - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/configmap.yaml deleted file mode 100644 index d094a2099..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: identity-release-gate - namespace: identity-system - labels: - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"210s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"identity","readiness":{"path":"/health/ready","port":8080}}]} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: identity-external-checks - namespace: identity-system - labels: - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - identity-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"identity","name":"identity-public-1","url":"https://id.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/kustomization.yaml deleted file mode 100644 index d929a4c8c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - route-public.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/networkpolicy.yaml deleted file mode 100644 index f4bfe8d4e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/networkpolicy.yaml +++ /dev/null @@ -1,73 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: identity - namespace: identity-system - labels: - app.kubernetes.io/name: identity - app.kubernetes.io/instance: identity - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: identity - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/identity.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/route-public.yaml deleted file mode 100644 index d3453fde5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/route-public.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: identity-public - namespace: identity-system - labels: - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`id.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers-strict - namespace: edge-system - services: - - name: identity - namespace: identity-system - port: 8080 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/serviceaccount.yaml deleted file mode 100644 index 721c040f0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: identity - namespace: identity-system - labels: - app.kubernetes.io/name: identity - app.kubernetes.io/instance: identity - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/workload.yaml deleted file mode 100644 index 4a8f42163..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/identity/workload.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: identity - namespace: identity-system - labels: - app.kubernetes.io/name: identity - app.kubernetes.io/instance: identity - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: identity - app.kubernetes.io/instance: identity - template: - metadata: - labels: - app.kubernetes.io/name: identity - app.kubernetes.io/instance: identity - app.kubernetes.io/part-of: identity - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/identity: 1.0.0 - spec: - serviceAccountName: identity - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: identity - image: ghcr.io/jorisjonkers-dev/identity/identity@sha256:1a3c5e7b9d1f3a5c7e9b1d3f5a7c9e1b3d5f7a9c1e3b5d7f9a1c3e5b7d9f1a3c - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /health/ready - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /health/live - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /health/live - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/kustomization.yaml deleted file mode 100644 index b1f0d0bc2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - identity - - namespace.yaml - - portal - - rollout-events - - vault-policy - - vaultconnection.yaml - - whoami diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/namespace.yaml deleted file mode 100644 index d0194e6b5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: identity-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/networkpolicy.yaml deleted file mode 100644 index d2a9cee18..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: identity-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/canary.yaml deleted file mode 100644 index 95e1be1ad..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/canary.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: portal - namespace: identity-system - labels: - app.kubernetes.io/name: portal - app.kubernetes.io/instance: portal - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: portal - progressDeadlineSeconds: 720 - service: - port: 8080 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: portal - process: portal - revision: sha256:64c8b50827e7d3454a00eab6bcaa99051bd59849546fdb68a99e77c1e0730752 - paths: / - readiness: / - hostnames: home.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: portal - process: portal - revision: sha256:64c8b50827e7d3454a00eab6bcaa99051bd59849546fdb68a99e77c1e0730752 - paths: / - readiness: / - hostnames: home.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: portal - process: portal - revision: sha256:64c8b50827e7d3454a00eab6bcaa99051bd59849546fdb68a99e77c1e0730752 - paths: / - readiness: / - hostnames: home.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: portal - process: portal - revision: sha256:64c8b50827e7d3454a00eab6bcaa99051bd59849546fdb68a99e77c1e0730752 - paths: / - readiness: / - hostnames: home.jorisjonkers.dev - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/client.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/client.yaml deleted file mode 100644 index 8335ea2e1..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/client.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: identity.jorisjonkers.dev/v1 -kind: Client -metadata: - name: portal - labels: - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit -spec: - signIn: native - host: home.jorisjonkers.dev - launchUrl: https://home.jorisjonkers.dev/apps - redirectUris: - - https://home.jorisjonkers.dev/callback - - https://home.jorisjonkers.dev/silent-renew - credential: pkce - roles: - - user - label: Home - description: Every application you can open diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/configmap.yaml deleted file mode 100644 index 09d6cdf2e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: portal-release-gate - namespace: identity-system - labels: - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"720s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"portal","readiness":{"path":"/","port":8080}}],"protectedBy":"portal","protectedPath":"/api/me"} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: portal-external-checks - namespace: identity-system - labels: - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - portal-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"identity","name":"portal-public-1","url":"https://home.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/kustomization.yaml deleted file mode 100644 index d7ffa4502..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - client.yaml - - configmap.yaml - - route-public.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/networkpolicy.yaml deleted file mode 100644 index 6cfa89637..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/networkpolicy.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: portal - namespace: identity-system - labels: - app.kubernetes.io/name: portal - app.kubernetes.io/instance: portal - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: portal - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/portal.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/route-public.yaml deleted file mode 100644 index a4dea9056..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/route-public.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: portal-public - namespace: identity-system - labels: - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`home.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: portal - namespace: identity-system - port: 8080 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/serviceaccount.yaml deleted file mode 100644 index 24aa46346..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: portal - namespace: identity-system - labels: - app.kubernetes.io/name: portal - app.kubernetes.io/instance: portal - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/workload.yaml deleted file mode 100644 index 64e275230..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/portal/workload.yaml +++ /dev/null @@ -1,85 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: portal - namespace: identity-system - labels: - app.kubernetes.io/name: portal - app.kubernetes.io/instance: portal - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 720 - selector: - matchLabels: - app.kubernetes.io/name: portal - app.kubernetes.io/instance: portal - template: - metadata: - labels: - app.kubernetes.io/name: portal - app.kubernetes.io/instance: portal - app.kubernetes.io/part-of: portal - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/portal: 1.0.0 - spec: - serviceAccountName: portal - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 101 - runAsGroup: 101 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: portal - image: ghcr.io/jorisjonkers-dev/identity/portal@sha256:3d5f7b9c1e3a5d7f9b1c3e5a7d9f1b3c5e7a9d1f3b5c7e9a1d3f5b7c9e1a3d5f - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: / - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/rollout-events/alert.yaml deleted file mode 100644 index d8329e6a5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-identity - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-identity - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-identity - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/rollout-events/provider.yaml deleted file mode 100644 index bd8b41d35..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-identity - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/configmap.yaml deleted file mode 100644 index a409b2807..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/configmap.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-32b517bea9bc - namespace: identity-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - identity-system-identity.policy.json: | - {"path":{"secret/data/observability-system/grafana/client":{"capabilities":["create","read","update"]}}} - identity-system-identity.role.json: | - {"bound_service_account_names":["identity"],"bound_service_account_namespaces":["identity-system"],"token_policies":["identity-system-identity"]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/cronjob.yaml deleted file mode 100644 index b79d7770a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/cronjob.yaml +++ /dev/null @@ -1,95 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: identity-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-32b517bea9bc - items: - - key: identity-system-identity.policy.json - path: identity-system-identity.policy.json - - key: identity-system-identity.role.json - path: identity-system-identity.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/job.yaml deleted file mode 100644 index ead322874..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/job.yaml +++ /dev/null @@ -1,85 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-32b517bea9bc - namespace: identity-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-32b517bea9bc - items: - - key: identity-system-identity.policy.json - path: identity-system-identity.policy.json - - key: identity-system-identity.role.json - path: identity-system-identity.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/networkpolicy.yaml deleted file mode 100644 index 1ebf448fb..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: identity-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/policies/identity-system-identity.policy.json b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/policies/identity-system-identity.policy.json deleted file mode 100644 index 7af4460ca..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/policies/identity-system-identity.policy.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "path": { - "secret/data/observability-system/grafana/client": { - "capabilities": [ - "create", - "read", - "update" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/policies/identity-system-identity.role.json b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/policies/identity-system-identity.role.json deleted file mode 100644 index 5c84b04f0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/policies/identity-system-identity.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "identity" - ], - "bound_service_account_namespaces": [ - "identity-system" - ], - "token_policies": [ - "identity-system-identity" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/serviceaccount.yaml deleted file mode 100644 index dc5042ee9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: identity-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vaultconnection.yaml deleted file mode 100644 index e81c48a1d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: identity-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/canary.yaml deleted file mode 100644 index f5ba83003..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/canary.yaml +++ /dev/null @@ -1,100 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: whoami - namespace: identity-system - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: whoami - autoscalerRef: - apiVersion: autoscaling/v2 - kind: HorizontalPodAutoscaler - name: whoami - progressDeadlineSeconds: 720 - service: - port: 8080 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: whoami - process: whoami - revision: sha256:4bd7748a66e3d3e1e858c651aee85898bfa851f2677711385cec86360e573960 - paths: / /health - readiness: /health - hostnames: whoami.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: whoami - process: whoami - revision: sha256:4bd7748a66e3d3e1e858c651aee85898bfa851f2677711385cec86360e573960 - paths: / /health - readiness: /health - hostnames: whoami.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: whoami - process: whoami - revision: sha256:4bd7748a66e3d3e1e858c651aee85898bfa851f2677711385cec86360e573960 - paths: / /health - readiness: /health - hostnames: whoami.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: whoami - process: whoami - revision: sha256:4bd7748a66e3d3e1e858c651aee85898bfa851f2677711385cec86360e573960 - paths: / /health - readiness: /health - hostnames: whoami.jorisjonkers.dev - errorRate: 1% - latency: 500ms ---- -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: whoami - namespace: identity-system - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: whoami - minReplicas: 2 - maxReplicas: 2 diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/client.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/client.yaml deleted file mode 100644 index 300f20fa7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/client.yaml +++ /dev/null @@ -1,17 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: identity.jorisjonkers.dev/v1 -kind: Client -metadata: - name: whoami - labels: - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit -spec: - signIn: gated - host: whoami.jorisjonkers.dev - launchUrl: https://whoami.jorisjonkers.dev/ - iconUrl: https://whoami.jorisjonkers.dev/favicon.ico - roles: - - user - label: Who am I diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/configmap.yaml deleted file mode 100644 index bdd07e6e3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: whoami-release-gate - namespace: identity-system - labels: - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"720s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"whoami","readiness":{"path":"/health","port":8080}}]} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: whoami-external-checks - namespace: identity-system - labels: - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - whoami-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"identity","name":"whoami-public-1","url":"https://whoami.jorisjonkers.dev/"},{"conditions":["[STATUS] < 500"],"group":"identity","name":"whoami-public-2","url":"https://whoami.jorisjonkers.dev/health"},{"conditions":["[STATUS] < 500"],"group":"identity","name":"whoami-public-3","url":"https://whoami.jorisjonkers.dev/.auth/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/kustomization.yaml deleted file mode 100644 index a0a5e59fc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - client.yaml - - configmap.yaml - - pdb.yaml - - route-public.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/networkpolicy.yaml deleted file mode 100644 index 6b2b90b3b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/networkpolicy.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: whoami - namespace: identity-system - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: whoami - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/whoami.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/pdb.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/pdb.yaml deleted file mode 100644 index 088f77749..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/pdb.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: whoami - namespace: identity-system - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: whoami-primary diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/route-public.yaml deleted file mode 100644 index fe4a0dc33..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/route-public.yaml +++ /dev/null @@ -1,52 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: whoami-public - namespace: identity-system - labels: - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`whoami.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 997 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers - namespace: edge-system - services: - - name: whoami - namespace: identity-system - port: 8080 - - kind: Rule - match: Host(`whoami.jorisjonkers.dev`) && Path(`/health`) - priority: 999 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: whoami - namespace: identity-system - port: 8080 - - kind: Rule - match: Host(`whoami.jorisjonkers.dev`) && PathPrefix(`/.auth/`) - priority: 998 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: identity - namespace: identity-system - port: 8080 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/serviceaccount.yaml deleted file mode 100644 index 0fff0b40c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: whoami - namespace: identity-system - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/workload.yaml deleted file mode 100644 index ec303d844..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/apps/identity/whoami/workload.yaml +++ /dev/null @@ -1,93 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: whoami - namespace: identity-system - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 720 - selector: - matchLabels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - template: - metadata: - labels: - app.kubernetes.io/name: whoami - app.kubernetes.io/instance: whoami - app.kubernetes.io/part-of: whoami - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/whoami: v1.11.0 - spec: - serviceAccountName: whoami - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: - app.kubernetes.io/instance: whoami - matchLabelKeys: - - pod-template-hash - topologyKey: kubernetes.io/hostname - containers: - - name: whoami - image: docker.io/traefik/whoami@sha256:4e6a8c0d2f4b6e8a0c2d4f6b8e0a2c4d6f8b0e2a4c6d8f0b2e4a6c8d0f2b4e6a - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 32Mi - cpu: 10m - limits: - memory: 32Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /health - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/human-grants/clusterrolebindings.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/human-grants/clusterrolebindings.yaml deleted file mode 100644 index 86311f89c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/human-grants/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: human:oidc:k8s-admin:cluster-admin - labels: - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: oidc:k8s-admin diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/human-grants/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/human-grants/kustomization.yaml deleted file mode 100644 index 029015f5d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/human-grants/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - clusterrolebindings.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/priority-classes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/priority-classes/kustomization.yaml deleted file mode 100644 index 8b06a2f03..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/priority-classes/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/priority-classes/priorityclasses.yaml b/emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/priority-classes/priorityclasses.yaml deleted file mode 100644 index a304512d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/expected/estate/priority-classes/priorityclasses.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-data - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 1000000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "A datastore: it schedules before what reads it." ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-critical-app - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 100000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "The foundation and the Applications the platform names: they keep scheduling under pressure." diff --git a/emf/bundles/cli/src/test/resources/stages/render/identity/oracles b/emf/bundles/cli/src/test/resources/stages/render/identity/oracles deleted file mode 100644 index e65ad5831..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/identity/oracles +++ /dev/null @@ -1,43 +0,0 @@ -apps/identity/identity/canary.yaml identity/rendered/apps/identity/identity/canary.yaml -apps/identity/identity/configmap.yaml identity/rendered/apps/identity/identity/configmap.yaml -apps/identity/identity/kustomization.yaml identity/rendered/apps/identity/identity/kustomization.yaml -apps/identity/identity/networkpolicy.yaml identity/rendered/apps/identity/identity/networkpolicy.yaml -apps/identity/identity/route-public.yaml identity/rendered/apps/identity/identity/route-public.yaml -apps/identity/identity/serviceaccount.yaml identity/rendered/apps/identity/identity/serviceaccount.yaml -apps/identity/identity/workload.yaml identity/rendered/apps/identity/identity/workload.yaml -apps/identity/kustomization.yaml identity/rendered/apps/identity/kustomization.yaml -apps/identity/namespace.yaml identity/rendered/apps/identity/namespace.yaml -apps/identity/networkpolicy.yaml identity/rendered/apps/identity/networkpolicy.yaml -apps/identity/portal/canary.yaml identity/rendered/apps/identity/portal/canary.yaml -apps/identity/portal/client.yaml identity/rendered/apps/identity/portal/client.yaml -apps/identity/portal/configmap.yaml identity/rendered/apps/identity/portal/configmap.yaml -apps/identity/portal/kustomization.yaml identity/rendered/apps/identity/portal/kustomization.yaml -apps/identity/portal/networkpolicy.yaml identity/rendered/apps/identity/portal/networkpolicy.yaml -apps/identity/portal/route-public.yaml identity/rendered/apps/identity/portal/route-public.yaml -apps/identity/portal/serviceaccount.yaml identity/rendered/apps/identity/portal/serviceaccount.yaml -apps/identity/portal/workload.yaml identity/rendered/apps/identity/portal/workload.yaml -apps/identity/rollout-events/alert.yaml identity/rendered/apps/identity/rollout-events/alert.yaml -apps/identity/rollout-events/kustomization.yaml identity/rendered/apps/identity/rollout-events/kustomization.yaml -apps/identity/rollout-events/provider.yaml identity/rendered/apps/identity/rollout-events/provider.yaml -apps/identity/vault-policy/configmap.yaml identity/rendered/apps/identity/vault-policy/configmap.yaml -apps/identity/vault-policy/cronjob.yaml identity/rendered/apps/identity/vault-policy/cronjob.yaml -apps/identity/vault-policy/job.yaml identity/rendered/apps/identity/vault-policy/job.yaml -apps/identity/vault-policy/kustomization.yaml identity/rendered/apps/identity/vault-policy/kustomization.yaml -apps/identity/vault-policy/networkpolicy.yaml identity/rendered/apps/identity/vault-policy/networkpolicy.yaml -apps/identity/vault-policy/policies/identity-system-identity.policy.json identity/rendered/apps/identity/vault-policy/policies/identity-system-identity.policy.json -apps/identity/vault-policy/policies/identity-system-identity.role.json identity/rendered/apps/identity/vault-policy/policies/identity-system-identity.role.json -apps/identity/vault-policy/serviceaccount.yaml identity/rendered/apps/identity/vault-policy/serviceaccount.yaml -apps/identity/vaultconnection.yaml identity/rendered/apps/identity/vaultconnection.yaml -apps/identity/whoami/canary.yaml identity/rendered/apps/identity/whoami/canary.yaml -apps/identity/whoami/client.yaml identity/rendered/apps/identity/whoami/client.yaml -apps/identity/whoami/configmap.yaml identity/rendered/apps/identity/whoami/configmap.yaml -apps/identity/whoami/kustomization.yaml identity/rendered/apps/identity/whoami/kustomization.yaml -apps/identity/whoami/networkpolicy.yaml identity/rendered/apps/identity/whoami/networkpolicy.yaml -apps/identity/whoami/pdb.yaml identity/rendered/apps/identity/whoami/pdb.yaml -apps/identity/whoami/route-public.yaml identity/rendered/apps/identity/whoami/route-public.yaml -apps/identity/whoami/serviceaccount.yaml identity/rendered/apps/identity/whoami/serviceaccount.yaml -apps/identity/whoami/workload.yaml identity/rendered/apps/identity/whoami/workload.yaml -estate/human-grants/clusterrolebindings.yaml platform/rendered/estate/human-grants/clusterrolebindings.yaml -estate/human-grants/kustomization.yaml platform/rendered/estate/human-grants/kustomization.yaml -estate/priority-classes/kustomization.yaml platform/rendered/estate/priority-classes/kustomization.yaml -estate/priority-classes/priorityclasses.yaml platform/rendered/estate/priority-classes/priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/aliases.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/aliases.yaml deleted file mode 100644 index 1afa23a6f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/aliases.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-garage - namespace: knowledge-platform-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: platform-garage-s3.estate-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-postgres - namespace: knowledge-platform-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: platform-postgres-postgres.estate-system.svc.cluster.local diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/configmap.yaml deleted file mode 100644 index 179289962..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/configmap.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: basic-memory-external-checks - namespace: knowledge-platform-system - labels: - app.kubernetes.io/part-of: basic-memory - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - basic-memory-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"knowledge-platform","name":"basic-memory-mcp-1","url":"https://memory-mcp.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/kustomization.yaml deleted file mode 100644 index c8123d92b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - pvc.yaml - - route-mcp.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/networkpolicy.yaml deleted file mode 100644 index ce636d39f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/networkpolicy.yaml +++ /dev/null @@ -1,63 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: basic-memory - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: basic-memory - app.kubernetes.io/instance: basic-memory - app.kubernetes.io/part-of: basic-memory - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: basic-memory - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8000 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/basic-memory.mcp: "true" - ports: - - protocol: TCP - port: 8000 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/pvc.yaml deleted file mode 100644 index 8d55f8434..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/pvc.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: basic-memory-vault - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: basic-memory - app.kubernetes.io/instance: basic-memory - app.kubernetes.io/part-of: basic-memory - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 5Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: basic-memory-config - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: basic-memory - app.kubernetes.io/instance: basic-memory - app.kubernetes.io/part-of: basic-memory - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 2Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/route-mcp.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/route-mcp.yaml deleted file mode 100644 index 613d46312..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/route-mcp.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: basic-memory-mcp - namespace: knowledge-platform-system - labels: - app.kubernetes.io/part-of: basic-memory - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`memory-mcp.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers-strict - namespace: edge-system - services: - - name: basic-memory - namespace: knowledge-platform-system - port: 8000 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/service.yaml deleted file mode 100644 index 908452f04..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: basic-memory - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: basic-memory - app.kubernetes.io/instance: basic-memory - app.kubernetes.io/part-of: basic-memory - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - selector: - app.kubernetes.io/instance: basic-memory - ports: - - name: mcp - port: 8000 - targetPort: mcp diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/serviceaccount.yaml deleted file mode 100644 index 6e4131e41..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: basic-memory - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: basic-memory - app.kubernetes.io/instance: basic-memory - app.kubernetes.io/part-of: basic-memory - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/vso.yaml deleted file mode 100644 index 0a57fc55f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/vso.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: basic-memory - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: basic-memory - app.kubernetes.io/instance: basic-memory - app.kubernetes.io/part-of: basic-memory - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: knowledge-platform-system-basic-memory - serviceAccount: basic-memory ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: basic-memory-knowledge-system-vault-deploy-key - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: basic-memory - app.kubernetes.io/instance: basic-memory - app.kubernetes.io/part-of: basic-memory - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - vaultAuthRef: basic-memory - mount: secret - type: kv-v2 - path: knowledge-system/vault-deploy-key - refreshAfter: 10m - hmacSecretData: true - destination: - name: basic-memory-knowledge-system-vault-deploy-key - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: basic-memory diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/workload.yaml deleted file mode 100644 index eba070270..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/basic-memory/workload.yaml +++ /dev/null @@ -1,313 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: basic-memory - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: basic-memory - app.kubernetes.io/instance: basic-memory - app.kubernetes.io/part-of: basic-memory - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 480 - selector: - matchLabels: - app.kubernetes.io/name: basic-memory - app.kubernetes.io/instance: basic-memory - template: - metadata: - labels: - app.kubernetes.io/name: basic-memory - app.kubernetes.io/instance: basic-memory - app.kubernetes.io/part-of: basic-memory - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python - annotations: - image.jorisjonkers.dev/basic-memory: v0.14.2 - image.jorisjonkers.dev/git-clone: 1.0.0 - image.jorisjonkers.dev/git-sync: 1.0.0 - spec: - serviceAccountName: basic-memory - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - initContainers: - - name: git-clone - image: ghcr.io/jorisjonkers-dev/knowledge/basic-memory-git-sync@sha256:7507f69d7e903da30006f07d84091d892dfa42c359c125cccaec05506af36e50 - env: - - name: BASIC_MEMORY_CONFIG_DIR - value: /app/.basic-memory - - name: BASIC_MEMORY_DEFAULT_PROJECT - value: main - - name: BASIC_MEMORY_DISABLE_PERMALINKS - value: "true" - - name: BASIC_MEMORY_ENSURE_FRONTMATTER_ON_SYNC - value: "false" - - name: BASIC_MEMORY_HOME - value: /vault - - name: BASIC_MEMORY_LOG_LEVEL - value: INFO - - name: BASIC_MEMORY_PROJECT_ROOT - value: /vault - - name: BASIC_MEMORY_SEMANTIC_EMBEDDING_CACHE_DIR - value: /app/.basic-memory/fastembed - - name: BASIC_MEMORY_SYNC_CHANGES - value: "true" - - name: BASIC_MEMORY_SYNC_DELAY - value: "1000" - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: GIT_CONFIG_COUNT - value: "1" - - name: GIT_CONFIG_KEY_0 - value: safe.directory - - name: GIT_CONFIG_VALUE_0 - value: /vault - - name: LOG_LEVEL - value: INFO - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: basic-memory - - name: POLL_SECONDS - value: "10" - - name: PORT - value: "8000" - - name: PUSH - value: "true" - - name: VAULT_AUTHOR_EMAIL - value: basicmemory@knowledge.local - - name: VAULT_AUTHOR_NAME - value: basic-memory-vault - - name: VAULT_BRANCH - value: main - - name: VAULT_CLONE_URL - value: git@github.com:JorisJonkers-dev/knowledge-vault.git - - name: VAULT_DIR - value: /vault - - name: VAULT_SSH_KEY_PATH - value: /run/secrets/knowledge-vault/id_ed25519 - resources: - requests: - memory: 64Mi - cpu: 50m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: basic-memory-vault - mountPath: /vault - - name: secret-basic-memory-knowledge-system-vault-deploy-key - mountPath: /run/secrets/knowledge-vault - readOnly: true - containers: - - name: basic-memory - image: ghcr.io/basicmachines-co/basic-memory@sha256:939f1173d96626c280763e14622f2381d49fbbb7db17cae2e832f4f639405643 - ports: - - name: mcp - containerPort: 8000 - env: - - name: BASIC_MEMORY_CONFIG_DIR - value: /app/.basic-memory - - name: BASIC_MEMORY_DEFAULT_PROJECT - value: main - - name: BASIC_MEMORY_DISABLE_PERMALINKS - value: "true" - - name: BASIC_MEMORY_ENSURE_FRONTMATTER_ON_SYNC - value: "false" - - name: BASIC_MEMORY_HOME - value: /vault - - name: BASIC_MEMORY_LOG_LEVEL - value: INFO - - name: BASIC_MEMORY_PROJECT_ROOT - value: /vault - - name: BASIC_MEMORY_SEMANTIC_EMBEDDING_CACHE_DIR - value: /app/.basic-memory/fastembed - - name: BASIC_MEMORY_SYNC_CHANGES - value: "true" - - name: BASIC_MEMORY_SYNC_DELAY - value: "1000" - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: GIT_CONFIG_COUNT - value: "1" - - name: GIT_CONFIG_KEY_0 - value: safe.directory - - name: GIT_CONFIG_VALUE_0 - value: /vault - - name: LOG_LEVEL - value: INFO - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: basic-memory - - name: POLL_SECONDS - value: "10" - - name: PORT - value: "8000" - - name: PUSH - value: "true" - - name: VAULT_AUTHOR_EMAIL - value: basicmemory@knowledge.local - - name: VAULT_AUTHOR_NAME - value: basic-memory-vault - - name: VAULT_BRANCH - value: main - - name: VAULT_CLONE_URL - value: git@github.com:JorisJonkers-dev/knowledge-vault.git - - name: VAULT_DIR - value: /vault - - name: VAULT_SSH_KEY_PATH - value: /run/secrets/knowledge-vault/id_ed25519 - resources: - requests: - memory: 1Gi - cpu: 500m - limits: - memory: 1Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: basic-memory-vault - mountPath: /vault - - name: basic-memory-config - mountPath: /app/.basic-memory - - name: secret-basic-memory-knowledge-system-vault-deploy-key - mountPath: /run/secrets/knowledge-vault - readOnly: true - readinessProbe: - tcpSocket: - port: 8000 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 8000 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 8000 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 24 - - name: git-sync - image: ghcr.io/jorisjonkers-dev/knowledge/basic-memory-git-sync@sha256:7507f69d7e903da30006f07d84091d892dfa42c359c125cccaec05506af36e50 - env: - - name: BASIC_MEMORY_CONFIG_DIR - value: /app/.basic-memory - - name: BASIC_MEMORY_DEFAULT_PROJECT - value: main - - name: BASIC_MEMORY_DISABLE_PERMALINKS - value: "true" - - name: BASIC_MEMORY_ENSURE_FRONTMATTER_ON_SYNC - value: "false" - - name: BASIC_MEMORY_HOME - value: /vault - - name: BASIC_MEMORY_LOG_LEVEL - value: INFO - - name: BASIC_MEMORY_PROJECT_ROOT - value: /vault - - name: BASIC_MEMORY_SEMANTIC_EMBEDDING_CACHE_DIR - value: /app/.basic-memory/fastembed - - name: BASIC_MEMORY_SYNC_CHANGES - value: "true" - - name: BASIC_MEMORY_SYNC_DELAY - value: "1000" - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: GIT_CONFIG_COUNT - value: "1" - - name: GIT_CONFIG_KEY_0 - value: safe.directory - - name: GIT_CONFIG_VALUE_0 - value: /vault - - name: LOG_LEVEL - value: INFO - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: basic-memory - - name: POLL_SECONDS - value: "10" - - name: PORT - value: "8000" - - name: PUSH - value: "true" - - name: VAULT_AUTHOR_EMAIL - value: basicmemory@knowledge.local - - name: VAULT_AUTHOR_NAME - value: basic-memory-vault - - name: VAULT_BRANCH - value: main - - name: VAULT_CLONE_URL - value: git@github.com:JorisJonkers-dev/knowledge-vault.git - - name: VAULT_DIR - value: /vault - - name: VAULT_SSH_KEY_PATH - value: /run/secrets/knowledge-vault/id_ed25519 - resources: - requests: - memory: 64Mi - cpu: 50m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: basic-memory-vault - mountPath: /vault - - name: secret-basic-memory-knowledge-system-vault-deploy-key - mountPath: /run/secrets/knowledge-vault - readOnly: true - volumes: - - name: basic-memory-vault - persistentVolumeClaim: - claimName: basic-memory-vault - - name: basic-memory-config - persistentVolumeClaim: - claimName: basic-memory-config - - name: secret-basic-memory-knowledge-system-vault-deploy-key - secret: - secretName: basic-memory-knowledge-system-vault-deploy-key - items: - - key: private_key - path: id_ed25519 - defaultMode: 256 diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/backup.yaml deleted file mode 100644 index b56fcfb32..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/backup.yaml +++ /dev/null @@ -1,74 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: docling-serve-archive-backup - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: docling-serve-backup - app.kubernetes.io/instance: docling-serve-backup - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 45 2 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: docling-serve-backup - app.kubernetes.io/instance: docling-serve-backup - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: docling-serve-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/file-backup@sha256:2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d - env: - - name: BACKUP_RETAIN - value: "90" - - name: BACKUP_OFF_CLUSTER - value: s3://backup-storage/jorisjonkers-dev - - name: BACKUP_OFF_CLUSTER_PATH - value: knowledge-platform/docling-serve/docling-serve-archive - - name: BACKUP_OFF_CLUSTER_RECIPIENT - value: age1s6v5qrx3mgcgk37gscv8y6z43rssksdct5lx3xk5xrtptjndqvhsnhj7h8 - envFrom: - - secretRef: - name: docling-serve-backup-platform-backup-off-cluster - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: docling-serve-archive - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: docling-serve-archive-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/kustomization.yaml deleted file mode 100644 index 1a2a40343..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/networkpolicy.yaml deleted file mode 100644 index 96959972a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/networkpolicy.yaml +++ /dev/null @@ -1,76 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: docling-serve - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: docling-serve - app.kubernetes.io/instance: docling-serve - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: docling-serve - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/docling-serve.http: "true" - ports: - - protocol: TCP - port: 8000 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: docling-serve-backup - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: docling-serve-backup - app.kubernetes.io/instance: docling-serve-backup - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: docling-serve-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 203.0.113.0/24 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/pvc.yaml deleted file mode 100644 index 25a9656b5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/pvc.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: docling-serve-archive - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: docling-serve - app.kubernetes.io/instance: docling-serve - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: docling-serve-archive-backup - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: docling-serve - app.kubernetes.io/instance: docling-serve - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/service.yaml deleted file mode 100644 index e82b733d0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: docling-serve - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: docling-serve - app.kubernetes.io/instance: docling-serve - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - selector: - app.kubernetes.io/instance: docling-serve - ports: - - name: http - port: 8000 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/serviceaccount.yaml deleted file mode 100644 index a33977b66..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: docling-serve - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: docling-serve - app.kubernetes.io/instance: docling-serve - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: docling-serve-backup - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: docling-serve-backup - app.kubernetes.io/instance: docling-serve-backup - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/vso.yaml deleted file mode 100644 index 611549fa1..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/vso.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: docling-serve-backup - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: docling-serve-backup - app.kubernetes.io/instance: docling-serve-backup - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: knowledge-platform-system-docling-serve-backup - serviceAccount: docling-serve-backup ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: docling-serve-backup-platform-backup-off-cluster - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: docling-serve-backup - app.kubernetes.io/instance: docling-serve-backup - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: docling-serve-backup - mount: secret - type: kv-v2 - path: platform/backup/off-cluster - refreshAfter: 10m - hmacSecretData: true - destination: - name: docling-serve-backup-platform-backup-off-cluster - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/workload.yaml deleted file mode 100644 index 2ed57f10d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/docling-serve/workload.yaml +++ /dev/null @@ -1,113 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: docling-serve - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: docling-serve - app.kubernetes.io/instance: docling-serve - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 480 - selector: - matchLabels: - app.kubernetes.io/name: docling-serve - app.kubernetes.io/instance: docling-serve - template: - metadata: - labels: - app.kubernetes.io/name: docling-serve - app.kubernetes.io/instance: docling-serve - app.kubernetes.io/part-of: docling-serve - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python - annotations: - image.jorisjonkers.dev/docling-serve: v1.5.0 - spec: - serviceAccountName: docling-serve - priorityClassName: platform-data - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - containers: - - name: docling-serve - image: ghcr.io/docling-project/docling-serve@sha256:5d1a649d48b5715e23ec4906bb0624632b1971a1d975a4bc57d0f723114c7c6e - ports: - - name: http - containerPort: 8000 - env: - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: docling-serve - - name: PORT - value: "8000" - - name: UVICORN_HOST - value: 0.0.0.0 - - name: UVICORN_PORT - value: "8000" - resources: - requests: - memory: 1Gi - cpu: 500m - limits: - memory: 1Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: docling-serve-archive - mountPath: /archive - readinessProbe: - httpGet: - path: /health - port: 8000 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /health - port: 8000 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /health - port: 8000 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 24 - volumes: - - name: docling-serve-archive - persistentVolumeClaim: - claimName: docling-serve-archive diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/kustomization.yaml deleted file mode 100644 index 71ff1ac70..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/networkpolicy.yaml deleted file mode 100644 index 9716364db..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/networkpolicy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: hindsight-tei-embedding - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-tei-embedding - app.kubernetes.io/instance: hindsight-tei-embedding - app.kubernetes.io/part-of: hindsight-embedding - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: hindsight-tei-embedding - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/hindsight-embedding.embeddings: "true" - ports: - - protocol: TCP - port: 8091 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/pvc.yaml deleted file mode 100644 index f71d14f5d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/pvc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: hindsight-tei-model-cache - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-tei-embedding - app.kubernetes.io/instance: hindsight-tei-embedding - app.kubernetes.io/part-of: hindsight-embedding - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 8Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/service.yaml deleted file mode 100644 index 400d8ff75..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: hindsight-tei-embedding - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-tei-embedding - app.kubernetes.io/instance: hindsight-tei-embedding - app.kubernetes.io/part-of: hindsight-embedding - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: hindsight-tei-embedding - ports: - - name: embeddings - port: 8091 - targetPort: embeddings diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/serviceaccount.yaml deleted file mode 100644 index 4e22cb5cd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: hindsight-tei-embedding - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-tei-embedding - app.kubernetes.io/instance: hindsight-tei-embedding - app.kubernetes.io/part-of: hindsight-embedding - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/workload.yaml deleted file mode 100644 index bc9588a7a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight-embedding/workload.yaml +++ /dev/null @@ -1,109 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: hindsight-tei-embedding - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-tei-embedding - app.kubernetes.io/instance: hindsight-tei-embedding - app.kubernetes.io/part-of: hindsight-embedding - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 1020 - selector: - matchLabels: - app.kubernetes.io/name: hindsight-tei-embedding - app.kubernetes.io/instance: hindsight-tei-embedding - template: - metadata: - labels: - app.kubernetes.io/name: hindsight-tei-embedding - app.kubernetes.io/instance: hindsight-tei-embedding - app.kubernetes.io/part-of: hindsight-embedding - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/hindsight-tei-embedding: 1.7.0 - spec: - serviceAccountName: hindsight-tei-embedding - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - containers: - - name: hindsight-tei-embedding - image: ghcr.io/huggingface/text-embeddings-inference@sha256:8de25e75ce39617f17f2f6c77d60a4f75b65e779ed5005420eb1400072a15c1c - ports: - - name: embeddings - containerPort: 8091 - env: - - name: MAX_CLIENT_BATCH_SIZE - value: "256" - - name: PAYLOAD_LIMIT - value: "10000000" - - name: PORT - value: "8091" - resources: - requests: - memory: 6Gi - cpu: 500m - limits: - memory: 6Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: hindsight-tei-model-cache - mountPath: /data - readinessProbe: - httpGet: - path: /health - port: 8091 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /health - port: 8091 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /health - port: 8091 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 60 - volumes: - - name: hindsight-tei-model-cache - persistentVolumeClaim: - claimName: hindsight-tei-model-cache diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/canary.yaml deleted file mode 100644 index 5b72dd943..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/canary.yaml +++ /dev/null @@ -1,149 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: hindsight-api - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-api - app.kubernetes.io/instance: hindsight-api - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: hindsight-api - progressDeadlineSeconds: 480 - service: - port: 8888 - targetPort: api - portName: api - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: hindsight - process: hindsight-api - revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - paths: / - readiness: /health - hostnames: memory-api.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: hindsight - process: hindsight-api - revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - paths: / - readiness: /health - hostnames: memory-api.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: hindsight - process: hindsight-api - revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - paths: / - readiness: /health - hostnames: memory-api.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: hindsight - process: hindsight-api - revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - paths: / - readiness: /health - hostnames: memory-api.jorisjonkers.dev - errorRate: 1% - latency: 500ms ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: hindsight-control-plane - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-control-plane - app.kubernetes.io/instance: hindsight-control-plane - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: hindsight-control-plane - progressDeadlineSeconds: 300 - service: - port: 3000 - targetPort: console - portName: console - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: hindsight - process: hindsight-control-plane - revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - paths: / - hostnames: memory.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: hindsight - process: hindsight-control-plane - revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - paths: / - hostnames: memory.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: hindsight - process: hindsight-control-plane - revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - paths: / - hostnames: memory.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: hindsight - process: hindsight-control-plane - revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - paths: / - hostnames: memory.jorisjonkers.dev - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/configmap.yaml deleted file mode 100644 index a91789f07..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: hindsight-release-gate - namespace: knowledge-platform-system - labels: - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"480s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"checks":["error-rate","latency"],"process":"hindsight-api","readiness":{"path":"/health","port":8888},"waitsFor":[{"application":"hindsight-embedding","process":"hindsight-tei-embedding"}]},{"checks":["error-rate","latency"],"process":"hindsight-control-plane","readiness":{"tcp":3000}}]} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: hindsight-external-checks - namespace: knowledge-platform-system - labels: - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - hindsight-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"knowledge-platform","name":"hindsight-console-1","url":"https://memory.jorisjonkers.dev/"},{"conditions":["[STATUS] < 500"],"group":"knowledge-platform","name":"hindsight-api-1","url":"https://memory-api.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/kustomization.yaml deleted file mode 100644 index 057e365db..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/kustomization.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - route-api.yaml - - route-console.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/networkpolicy.yaml deleted file mode 100644 index cfef73022..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/networkpolicy.yaml +++ /dev/null @@ -1,235 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: hindsight-api - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-api - app.kubernetes.io/instance: hindsight-api - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: hindsight-api - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8888 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/hindsight.api: "true" - ports: - - protocol: TCP - port: 8888 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8888 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - ports: - - protocol: TCP - port: 5432 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: knowledge-platform-system - podSelector: - matchLabels: - app.kubernetes.io/instance: hindsight-tei-embedding - ports: - - protocol: TCP - port: 8091 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: hindsight-worker - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-worker - app.kubernetes.io/instance: hindsight-worker - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: hindsight-worker - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/hindsight.worker: "true" - ports: - - protocol: TCP - port: 8889 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - ports: - - protocol: TCP - port: 5432 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: knowledge-platform-system - podSelector: - matchLabels: - app.kubernetes.io/instance: hindsight-tei-embedding - ports: - - protocol: TCP - port: 8091 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: hindsight-control-plane - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-control-plane - app.kubernetes.io/instance: hindsight-control-plane - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: hindsight-control-plane - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 3000 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/hindsight.console: "true" - ports: - - protocol: TCP - port: 3000 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 3000 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: knowledge-platform-system - podSelector: - matchLabels: - app.kubernetes.io/instance: hindsight-api - ports: - - protocol: TCP - port: 8888 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/route-api.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/route-api.yaml deleted file mode 100644 index 220d7069d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/route-api.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: hindsight-api - namespace: knowledge-platform-system - labels: - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`memory-api.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers-strict - namespace: edge-system - services: - - name: hindsight-api - namespace: knowledge-platform-system - port: 8888 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/route-console.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/route-console.yaml deleted file mode 100644 index 7c190ec82..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/route-console.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: hindsight-console - namespace: knowledge-platform-system - labels: - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`memory.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers-strict - namespace: edge-system - services: - - name: hindsight-control-plane - namespace: knowledge-platform-system - port: 3000 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/service.yaml deleted file mode 100644 index 116f5c742..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: hindsight-worker - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-worker - app.kubernetes.io/instance: hindsight-worker - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - selector: - app.kubernetes.io/instance: hindsight-worker - ports: - - name: worker - port: 8889 - targetPort: worker diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/serviceaccount.yaml deleted file mode 100644 index 68cb6dda6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/serviceaccount.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: hindsight-api - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-api - app.kubernetes.io/instance: hindsight-api - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: hindsight-worker - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-worker - app.kubernetes.io/instance: hindsight-worker - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: hindsight-control-plane - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-control-plane - app.kubernetes.io/instance: hindsight-control-plane - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/vso.yaml deleted file mode 100644 index 1955b3227..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/vso.yaml +++ /dev/null @@ -1,159 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: hindsight-api - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-api - app.kubernetes.io/instance: hindsight-api - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python - annotations: - estate.jorisjonkers.dev/revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: knowledge-platform-system-hindsight-api - serviceAccount: hindsight-api ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: hindsight-api-platform-hindsight - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-api - app.kubernetes.io/instance: hindsight-api - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python - annotations: - estate.jorisjonkers.dev/revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - vaultAuthRef: hindsight-api - mount: secret - type: kv-v2 - path: platform/hindsight - refreshAfter: 10m - hmacSecretData: true - destination: - name: hindsight-api-platform-hindsight - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: hindsight-api-primary ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultDynamicSecret -metadata: - name: hindsight-api-database-creds-knowledge-platform-owner - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-api - app.kubernetes.io/instance: hindsight-api - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python - annotations: - estate.jorisjonkers.dev/revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - vaultAuthRef: hindsight-api - mount: database - path: creds/knowledge-platform-owner - destination: - name: hindsight-api-database-creds-knowledge-platform-owner - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: hindsight-api-primary ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: hindsight-worker - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-worker - app.kubernetes.io/instance: hindsight-worker - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python - annotations: - estate.jorisjonkers.dev/revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: knowledge-platform-system-hindsight-worker - serviceAccount: hindsight-worker ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: hindsight-worker-platform-hindsight - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-worker - app.kubernetes.io/instance: hindsight-worker - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python - annotations: - estate.jorisjonkers.dev/revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - vaultAuthRef: hindsight-worker - mount: secret - type: kv-v2 - path: platform/hindsight - refreshAfter: 10m - hmacSecretData: true - destination: - name: hindsight-worker-platform-hindsight - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: hindsight-worker ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultDynamicSecret -metadata: - name: hindsight-worker-database-creds-knowledge-platform-owner - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-worker - app.kubernetes.io/instance: hindsight-worker - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python - annotations: - estate.jorisjonkers.dev/revision: sha256:e764c96d9622f87d54cc76f57aba5ed612c1fd501ba0e21d4f5da348355d5f67 - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - vaultAuthRef: hindsight-worker - mount: database - path: creds/knowledge-platform-owner - destination: - name: hindsight-worker-database-creds-knowledge-platform-owner - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: hindsight-worker diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/workload.yaml deleted file mode 100644 index 7072b8531..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/hindsight/workload.yaml +++ /dev/null @@ -1,391 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: hindsight-api - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-api - app.kubernetes.io/instance: hindsight-api - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 480 - selector: - matchLabels: - app.kubernetes.io/name: hindsight-api - app.kubernetes.io/instance: hindsight-api - template: - metadata: - labels: - app.kubernetes.io/name: hindsight-api - app.kubernetes.io/instance: hindsight-api - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - consumes.deploy-kit.jorisjonkers.dev/hindsight-embedding.embeddings: "true" - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/hindsight-api: 0.4.0 - spec: - serviceAccountName: hindsight-api - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - containers: - - name: hindsight-api - image: ghcr.io/vectorize-io/hindsight-api@sha256:7b14a1f4062252992d0176758753615e0a2071d9a269995be007be223ab01812 - ports: - - name: api - containerPort: 8888 - env: - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: HINDSIGHT_API_EMBEDDINGS_PROVIDER - value: tei - - name: HINDSIGHT_API_LLM_API_KEY - valueFrom: - secretKeyRef: - name: hindsight-api-platform-hindsight - key: llm-api-key - - name: HINDSIGHT_API_LLM_BASE_URL - value: https://eu.openrouter.ai/api/v1 - - name: HINDSIGHT_API_LLM_MODEL - value: mistralai/mistral-small-2603 - - name: HINDSIGHT_API_LLM_PROVIDER - value: openai - - name: HINDSIGHT_API_PORT - value: "8888" - - name: HINDSIGHT_API_WORKER_ENABLED - value: "false" - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: hindsight-api - - name: PGPASSWORD - valueFrom: - secretKeyRef: - name: hindsight-api-database-creds-knowledge-platform-owner - key: password - - name: PGUSER - valueFrom: - secretKeyRef: - name: hindsight-api-database-creds-knowledge-platform-owner - key: username - - name: PORT - value: "8888" - resources: - requests: - memory: 1Gi - cpu: 500m - limits: - memory: 1Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /health - port: 8888 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /health/live - port: 8888 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /health/live - port: 8888 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 24 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: hindsight-worker - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-worker - app.kubernetes.io/instance: hindsight-worker - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python -spec: - replicas: 0 - strategy: - type: Recreate - progressDeadlineSeconds: 480 - selector: - matchLabels: - app.kubernetes.io/name: hindsight-worker - app.kubernetes.io/instance: hindsight-worker - template: - metadata: - labels: - app.kubernetes.io/name: hindsight-worker - app.kubernetes.io/instance: hindsight-worker - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: python - consumes.deploy-kit.jorisjonkers.dev/platform-postgres.postgres: "true" - consumes.deploy-kit.jorisjonkers.dev/hindsight-embedding.embeddings: "true" - annotations: - image.jorisjonkers.dev/hindsight-worker: 0.4.0 - spec: - serviceAccountName: hindsight-worker - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - containers: - - name: hindsight-worker - image: ghcr.io/vectorize-io/hindsight-api@sha256:7b14a1f4062252992d0176758753615e0a2071d9a269995be007be223ab01812 - ports: - - name: worker - containerPort: 8889 - env: - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: HINDSIGHT_API_EMBEDDINGS_PROVIDER - value: tei - - name: HINDSIGHT_API_LLM_API_KEY - valueFrom: - secretKeyRef: - name: hindsight-worker-platform-hindsight - key: llm-api-key - - name: HINDSIGHT_API_LLM_BASE_URL - value: https://eu.openrouter.ai/api/v1 - - name: HINDSIGHT_API_LLM_MODEL - value: mistralai/mistral-small-2603 - - name: HINDSIGHT_API_LLM_PROVIDER - value: openai - - name: HINDSIGHT_API_PORT - value: "8889" - - name: HINDSIGHT_API_WORKER_BATCH_SIZE - value: "10" - - name: HINDSIGHT_API_WORKER_HTTP_PORT - value: "8889" - - name: HINDSIGHT_API_WORKER_MAX_RETRIES - value: "3" - - name: HINDSIGHT_API_WORKER_POLL_INTERVAL_MS - value: "500" - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: hindsight-worker - - name: PORT - value: "8889" - resources: - requests: - memory: 1Gi - cpu: 500m - limits: - memory: 1Gi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: secret-hindsight-worker-database-creds-knowledge-platform-owner - mountPath: /run/secrets/database - readOnly: true - readinessProbe: - httpGet: - path: /health - port: 8889 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /health/live - port: 8889 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /health/live - port: 8889 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 24 - volumes: - - name: secret-hindsight-worker-database-creds-knowledge-platform-owner - secret: - secretName: hindsight-worker-database-creds-knowledge-platform-owner - items: - - key: username - path: username - - key: password - path: password - defaultMode: 256 ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: hindsight-control-plane - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: hindsight-control-plane - app.kubernetes.io/instance: hindsight-control-plane - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 300 - selector: - matchLabels: - app.kubernetes.io/name: hindsight-control-plane - app.kubernetes.io/instance: hindsight-control-plane - template: - metadata: - labels: - app.kubernetes.io/name: hindsight-control-plane - app.kubernetes.io/instance: hindsight-control-plane - app.kubernetes.io/part-of: hindsight - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node - consumes.deploy-kit.jorisjonkers.dev/hindsight.api: "true" - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/hindsight-control-plane: 0.4.0 - spec: - serviceAccountName: hindsight-control-plane - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - containers: - - name: hindsight-control-plane - image: ghcr.io/vectorize-io/hindsight-control-plane@sha256:d9bf57083f7cb0a53ee5011bdfde6aae2490dbf5c360d2d1bff10473b45eb112 - ports: - - name: console - containerPort: 3000 - env: - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: HINDSIGHT_CP_HOSTNAME - value: 0.0.0.0 - - name: HINDSIGHT_CP_PORT - value: "3000" - - name: NODE_ENV - value: production - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: hindsight-control-plane - - name: PORT - value: "3000" - resources: - requests: - memory: 512Mi - cpu: 250m - limits: - memory: 512Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - tcpSocket: - port: 3000 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - tcpSocket: - port: 3000 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - tcpSocket: - port: 3000 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/backup.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/backup.yaml deleted file mode 100644 index f399225f5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/backup.yaml +++ /dev/null @@ -1,65 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: karakeep-data-backup - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep-backup - app.kubernetes.io/instance: karakeep-backup - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: 15 3 * * * - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - app.kubernetes.io/name: karakeep-backup - app.kubernetes.io/instance: karakeep-backup - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/backup: 1.2.0 - spec: - serviceAccountName: karakeep-backup - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: ghcr.io/jorisjonkers-dev/platform/file-backup@sha256:2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f6a8c0e2b4d - env: - - name: BACKUP_RETAIN - value: "14" - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: karakeep-data - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: karakeep-data-backup diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/configmap.yaml deleted file mode 100644 index 693a0e57a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/configmap.yaml +++ /dev/null @@ -1,14 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: karakeep-external-checks - namespace: knowledge-platform-system - labels: - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - karakeep-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"knowledge-platform","name":"karakeep-public-1","url":"https://karakeep.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/kustomization.yaml deleted file mode 100644 index 5c390322e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/kustomization.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - backup.yaml - - configmap.yaml - - pvc.yaml - - route-public.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/networkpolicy.yaml deleted file mode 100644 index df2b07a3a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/networkpolicy.yaml +++ /dev/null @@ -1,112 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: karakeep - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: karakeep - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 3000 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/karakeep.http: "true" - ports: - - protocol: TCP - port: 3000 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: garage - ports: - - protocol: TCP - port: 3900 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 - - 100.64.0.0/10 - - 169.254.0.0/16 - - 127.0.0.0/8 ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: karakeep-backup - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep-backup - app.kubernetes.io/instance: karakeep-backup - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: karakeep-backup - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/pvc.yaml deleted file mode 100644 index bd959c598..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/pvc.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: karakeep-data - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: karakeep-data-backup - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 50Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: karakeep-meili - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 5Gi ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: meilisearch-data - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/route-public.yaml deleted file mode 100644 index a8fa1532b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/route-public.yaml +++ /dev/null @@ -1,32 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: karakeep-public - namespace: knowledge-platform-system - labels: - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`karakeep.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers-strict - namespace: edge-system - services: - - name: karakeep - namespace: knowledge-platform-system - port: 3000 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/service.yaml deleted file mode 100644 index 6357cc669..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: karakeep - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - selector: - app.kubernetes.io/instance: karakeep - ports: - - name: http - port: 3000 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/serviceaccount.yaml deleted file mode 100644 index c0cf28017..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/serviceaccount.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: karakeep - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: karakeep-backup - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep-backup - app.kubernetes.io/instance: karakeep-backup - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/vso.yaml deleted file mode 100644 index 4e2dedef0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/vso.yaml +++ /dev/null @@ -1,95 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: karakeep - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: knowledge-platform-system-karakeep - serviceAccount: karakeep ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: karakeep-platform-karakeep - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - vaultAuthRef: karakeep - mount: secret - type: kv-v2 - path: platform/karakeep - refreshAfter: 10m - hmacSecretData: true - destination: - name: karakeep-platform-karakeep - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: karakeep ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: karakeep-knowledge-platform-garage-s3 - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - vaultAuthRef: karakeep - mount: secret - type: kv-v2 - path: knowledge-platform/garage/s3 - refreshAfter: 10m - hmacSecretData: true - destination: - name: karakeep-knowledge-platform-garage-s3 - create: true - annotations: - flagger.app/config-tracking: disabled ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: karakeep-vpn-platform-vpn-knowledge-platform-karakeep - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - vaultAuthRef: karakeep - mount: secret - type: kv-v2 - path: platform/vpn/knowledge-platform-karakeep - refreshAfter: 10m - hmacSecretData: true - destination: - name: karakeep-vpn-platform-vpn-knowledge-platform-karakeep - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/workload.yaml deleted file mode 100644 index a49ff9f36..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/karakeep/workload.yaml +++ /dev/null @@ -1,383 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: karakeep - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 720 - selector: - matchLabels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - template: - metadata: - labels: - app.kubernetes.io/name: karakeep - app.kubernetes.io/instance: karakeep - app.kubernetes.io/part-of: karakeep - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node - consumes.deploy-kit.jorisjonkers.dev/platform-garage.s3: "true" - annotations: - image.jorisjonkers.dev/chrome: 124.0.6367.78 - image.jorisjonkers.dev/karakeep: 0.33.2 - image.jorisjonkers.dev/meilisearch: v1.41.0 - image.jorisjonkers.dev/vpn: v3.40.0 - spec: - serviceAccountName: karakeep - priorityClassName: platform-data - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - fsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - initContainers: - - name: vpn - image: docker.io/qmcgaw/gluetun@sha256:7e1f3c5a9b2d4f6e8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f - restartPolicy: Always - env: - - name: DNS_KEEP_NAMESERVER - value: "on" - - name: DOT - value: "off" - - name: FIREWALL_INPUT_PORTS - value: "3000" - - name: PORT_FORWARD_ONLY - value: "on" - - name: SERVER_COUNTRIES - value: Netherlands - - name: VPN_PORT_FORWARDING - value: "off" - - name: VPN_SERVICE_PROVIDER - value: protonvpn - - name: VPN_TYPE - value: wireguard - envFrom: - - secretRef: - name: karakeep-vpn-platform-vpn-knowledge-platform-karakeep - resources: - requests: - memory: 128Mi - cpu: 50m - limits: - memory: 128Mi - securityContext: - runAsNonRoot: false - runAsUser: 0 - runAsGroup: 0 - capabilities: - add: - - NET_ADMIN - - NET_RAW - startupProbe: - exec: - command: - - /gluetun-entrypoint - - healthcheck - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 60 - volumeMounts: - - name: vpn - mountPath: /run/vpn - containers: - - name: karakeep - image: ghcr.io/karakeep-app/karakeep@sha256:3d57623bf031f32a0597a3ebe0cd869bff6ba181c02ebc90fac492458bcfd4a4 - ports: - - name: http - containerPort: 3000 - env: - - name: ASSET_STORE_S3_ACCESS_KEY_ID - valueFrom: - secretKeyRef: - name: karakeep-knowledge-platform-garage-s3 - key: access-key-id - - name: ASSET_STORE_S3_BUCKET - value: knowledge-platform-assets - - name: ASSET_STORE_S3_ENDPOINT - value: http://platform-garage:3900 - - name: ASSET_STORE_S3_FORCE_PATH_STYLE - value: "true" - - name: ASSET_STORE_S3_REGION - value: garage - - name: ASSET_STORE_S3_SECRET_ACCESS_KEY - valueFrom: - secretKeyRef: - name: karakeep-knowledge-platform-garage-s3 - key: secret-access-key - - name: BROWSER_WEB_URL - value: http://localhost:9222 - - name: DATA_DIR - value: /data - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: INFERENCE_CONTEXT_LENGTH - value: "2048" - - name: INFERENCE_ENABLE_AUTO_SUMMARIZATION - value: "true" - - name: INFERENCE_ENABLE_AUTO_TAGGING - value: "true" - - name: INFERENCE_TEXT_MODEL - value: mistralai/mistral-small-2603 - - name: MEILI_ADDR - value: http://localhost:7700 - - name: MEILI_MASTER_KEY - valueFrom: - secretKeyRef: - name: karakeep-platform-karakeep - key: meili-master-key - - name: MEILI_NO_ANALYTICS - value: "true" - - name: NEXTAUTH_SECRET - valueFrom: - secretKeyRef: - name: karakeep-platform-karakeep - key: nextauth-secret - - name: NEXTAUTH_URL - value: https://karakeep.jorisjonkers.dev - - name: OPENAI_API_BASE - value: https://eu.openrouter.ai/api/v1 - - name: OPENAI_API_KEY - valueFrom: - secretKeyRef: - name: karakeep-platform-karakeep - key: openrouter-api-key - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: karakeep - - name: PORT - value: "3000" - resources: - requests: - memory: 512Mi - cpu: 200m - limits: - memory: 512Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: karakeep-data - mountPath: /data - - name: karakeep-meili - mountPath: /meili_data - - name: meilisearch-data - mountPath: /meili_data - readinessProbe: - httpGet: - path: /api/health - port: 3000 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /api/health - port: 3000 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /api/health - port: 3000 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 40 - - name: meilisearch - image: getmeili/meilisearch@sha256:860fa4baed04ae1c235de870edab0c8006227546dea1bbb6411fbfc5e27cf1db - env: - - name: ASSET_STORE_S3_ACCESS_KEY_ID - valueFrom: - secretKeyRef: - name: karakeep-knowledge-platform-garage-s3 - key: access-key-id - - name: ASSET_STORE_S3_BUCKET - value: knowledge-platform-assets - - name: ASSET_STORE_S3_ENDPOINT - value: http://platform-garage:3900 - - name: ASSET_STORE_S3_FORCE_PATH_STYLE - value: "true" - - name: ASSET_STORE_S3_REGION - value: garage - - name: ASSET_STORE_S3_SECRET_ACCESS_KEY - valueFrom: - secretKeyRef: - name: karakeep-knowledge-platform-garage-s3 - key: secret-access-key - - name: BROWSER_WEB_URL - value: http://localhost:9222 - - name: DATA_DIR - value: /data - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: INFERENCE_CONTEXT_LENGTH - value: "2048" - - name: INFERENCE_ENABLE_AUTO_SUMMARIZATION - value: "true" - - name: INFERENCE_ENABLE_AUTO_TAGGING - value: "true" - - name: INFERENCE_TEXT_MODEL - value: mistralai/mistral-small-2603 - - name: MEILI_ADDR - value: http://localhost:7700 - - name: MEILI_MASTER_KEY - valueFrom: - secretKeyRef: - name: karakeep-platform-karakeep - key: meili-master-key - - name: MEILI_NO_ANALYTICS - value: "true" - - name: NEXTAUTH_SECRET - valueFrom: - secretKeyRef: - name: karakeep-platform-karakeep - key: nextauth-secret - - name: NEXTAUTH_URL - value: https://karakeep.jorisjonkers.dev - - name: OPENAI_API_BASE - value: https://eu.openrouter.ai/api/v1 - - name: OPENAI_API_KEY - valueFrom: - secretKeyRef: - name: karakeep-platform-karakeep - key: openrouter-api-key - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: karakeep - - name: PORT - value: "3000" - resources: - requests: - memory: 256Mi - cpu: 100m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: karakeep-meili - mountPath: /meili_data - - name: chrome - image: ghcr.io/karakeep-app/karakeep-chrome@sha256:5b19bbb160e9ff60681a3abd97e1c4ec9f64212301410de658c3900ab7ef31e7 - env: - - name: ASSET_STORE_S3_ACCESS_KEY_ID - valueFrom: - secretKeyRef: - name: karakeep-knowledge-platform-garage-s3 - key: access-key-id - - name: ASSET_STORE_S3_BUCKET - value: knowledge-platform-assets - - name: ASSET_STORE_S3_ENDPOINT - value: http://platform-garage:3900 - - name: ASSET_STORE_S3_FORCE_PATH_STYLE - value: "true" - - name: ASSET_STORE_S3_REGION - value: garage - - name: ASSET_STORE_S3_SECRET_ACCESS_KEY - valueFrom: - secretKeyRef: - name: karakeep-knowledge-platform-garage-s3 - key: secret-access-key - - name: BROWSER_WEB_URL - value: http://localhost:9222 - - name: DATA_DIR - value: /data - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: INFERENCE_CONTEXT_LENGTH - value: "2048" - - name: INFERENCE_ENABLE_AUTO_SUMMARIZATION - value: "true" - - name: INFERENCE_ENABLE_AUTO_TAGGING - value: "true" - - name: INFERENCE_TEXT_MODEL - value: mistralai/mistral-small-2603 - - name: MEILI_ADDR - value: http://localhost:7700 - - name: MEILI_MASTER_KEY - valueFrom: - secretKeyRef: - name: karakeep-platform-karakeep - key: meili-master-key - - name: MEILI_NO_ANALYTICS - value: "true" - - name: NEXTAUTH_SECRET - valueFrom: - secretKeyRef: - name: karakeep-platform-karakeep - key: nextauth-secret - - name: NEXTAUTH_URL - value: https://karakeep.jorisjonkers.dev - - name: OPENAI_API_BASE - value: https://eu.openrouter.ai/api/v1 - - name: OPENAI_API_KEY - valueFrom: - secretKeyRef: - name: karakeep-platform-karakeep - key: openrouter-api-key - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: karakeep - - name: PORT - value: "3000" - resources: - requests: - memory: 512Mi - cpu: 500m - limits: - memory: 512Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumes: - - name: karakeep-data - persistentVolumeClaim: - claimName: karakeep-data - - name: karakeep-meili - persistentVolumeClaim: - claimName: karakeep-meili - - name: meilisearch-data - persistentVolumeClaim: - claimName: meilisearch-data - - name: vpn - emptyDir: - sizeLimit: 1Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/kustomization.yaml deleted file mode 100644 index bc655f477..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/kustomization.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - aliases.yaml - - basic-memory - - docling-serve - - hindsight - - hindsight-embedding - - karakeep - - namespace.yaml - - rollout-events - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/namespace.yaml deleted file mode 100644 index 11651138a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: knowledge-platform-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/networkpolicy.yaml deleted file mode 100644 index 175059b19..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: knowledge-platform-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/rollout-events/alert.yaml deleted file mode 100644 index bb8fe4058..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-knowledge-platform - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-knowledge-platform - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-knowledge-platform - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/rollout-events/provider.yaml deleted file mode 100644 index ee2c070f8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-knowledge-platform - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/configmap.yaml deleted file mode 100644 index 002572f49..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/configmap.yaml +++ /dev/null @@ -1,35 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-c7a57a1080df - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - knowledge-platform-system-basic-memory.policy.json: | - {"path":{"secret/data/knowledge-system/vault-deploy-key":{"capabilities":["read"]},"secret/metadata/knowledge-system/vault-deploy-key":{"capabilities":["read"]}}} - knowledge-platform-system-basic-memory.role.json: | - {"bound_service_account_names":["basic-memory"],"bound_service_account_namespaces":["knowledge-platform-system"],"token_policies":["knowledge-platform-system-basic-memory"]} - knowledge-platform-system-docling-serve-backup.policy.json: | - {"path":{"secret/data/platform/backup/off-cluster":{"capabilities":["read"]},"secret/metadata/platform/backup/off-cluster":{"capabilities":["read"]}}} - knowledge-platform-system-docling-serve-backup.role.json: | - {"bound_service_account_names":["docling-serve-backup"],"bound_service_account_namespaces":["knowledge-platform-system"],"token_policies":["knowledge-platform-system-docling-serve-backup"]} - knowledge-platform-system-hindsight-api.policy.json: | - {"path":{"database/creds/knowledge-platform-owner":{"capabilities":["read"]},"secret/data/platform/hindsight":{"capabilities":["read"]},"secret/metadata/platform/hindsight":{"capabilities":["read"]}}} - knowledge-platform-system-hindsight-api.role.json: | - {"bound_service_account_names":["hindsight-api"],"bound_service_account_namespaces":["knowledge-platform-system"],"token_policies":["knowledge-platform-system-hindsight-api"]} - knowledge-platform-system-hindsight-worker.policy.json: | - {"path":{"database/creds/knowledge-platform-owner":{"capabilities":["read"]},"secret/data/platform/hindsight":{"capabilities":["read"]},"secret/metadata/platform/hindsight":{"capabilities":["read"]}}} - knowledge-platform-system-hindsight-worker.role.json: | - {"bound_service_account_names":["hindsight-worker"],"bound_service_account_namespaces":["knowledge-platform-system"],"token_policies":["knowledge-platform-system-hindsight-worker"]} - knowledge-platform-system-karakeep.policy.json: | - {"path":{"secret/data/knowledge-platform/garage/s3":{"capabilities":["read"]},"secret/data/platform/karakeep":{"capabilities":["read"]},"secret/data/platform/vpn/knowledge-platform-karakeep":{"capabilities":["read"]},"secret/metadata/knowledge-platform/garage/s3":{"capabilities":["read"]},"secret/metadata/platform/karakeep":{"capabilities":["read"]},"secret/metadata/platform/vpn/knowledge-platform-karakeep":{"capabilities":["read"]}}} - knowledge-platform-system-karakeep.role.json: | - {"bound_service_account_names":["karakeep"],"bound_service_account_namespaces":["knowledge-platform-system"],"token_policies":["knowledge-platform-system-karakeep"]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/cronjob.yaml deleted file mode 100644 index 0af0d8280..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/cronjob.yaml +++ /dev/null @@ -1,111 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-c7a57a1080df - items: - - key: knowledge-platform-system-basic-memory.policy.json - path: knowledge-platform-system-basic-memory.policy.json - - key: knowledge-platform-system-basic-memory.role.json - path: knowledge-platform-system-basic-memory.role.json - - key: knowledge-platform-system-docling-serve-backup.policy.json - path: knowledge-platform-system-docling-serve-backup.policy.json - - key: knowledge-platform-system-docling-serve-backup.role.json - path: knowledge-platform-system-docling-serve-backup.role.json - - key: knowledge-platform-system-hindsight-api.policy.json - path: knowledge-platform-system-hindsight-api.policy.json - - key: knowledge-platform-system-hindsight-api.role.json - path: knowledge-platform-system-hindsight-api.role.json - - key: knowledge-platform-system-hindsight-worker.policy.json - path: knowledge-platform-system-hindsight-worker.policy.json - - key: knowledge-platform-system-hindsight-worker.role.json - path: knowledge-platform-system-hindsight-worker.role.json - - key: knowledge-platform-system-karakeep.policy.json - path: knowledge-platform-system-karakeep.policy.json - - key: knowledge-platform-system-karakeep.role.json - path: knowledge-platform-system-karakeep.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/job.yaml deleted file mode 100644 index fcf9d08cd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/job.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-c7a57a1080df - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-c7a57a1080df - items: - - key: knowledge-platform-system-basic-memory.policy.json - path: knowledge-platform-system-basic-memory.policy.json - - key: knowledge-platform-system-basic-memory.role.json - path: knowledge-platform-system-basic-memory.role.json - - key: knowledge-platform-system-docling-serve-backup.policy.json - path: knowledge-platform-system-docling-serve-backup.policy.json - - key: knowledge-platform-system-docling-serve-backup.role.json - path: knowledge-platform-system-docling-serve-backup.role.json - - key: knowledge-platform-system-hindsight-api.policy.json - path: knowledge-platform-system-hindsight-api.policy.json - - key: knowledge-platform-system-hindsight-api.role.json - path: knowledge-platform-system-hindsight-api.role.json - - key: knowledge-platform-system-hindsight-worker.policy.json - path: knowledge-platform-system-hindsight-worker.policy.json - - key: knowledge-platform-system-hindsight-worker.role.json - path: knowledge-platform-system-hindsight-worker.role.json - - key: knowledge-platform-system-karakeep.policy.json - path: knowledge-platform-system-karakeep.policy.json - - key: knowledge-platform-system-karakeep.role.json - path: knowledge-platform-system-karakeep.role.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/networkpolicy.yaml deleted file mode 100644 index e9293f788..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-basic-memory.policy.json b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-basic-memory.policy.json deleted file mode 100644 index 8296703aa..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-basic-memory.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/knowledge-system/vault-deploy-key": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/knowledge-system/vault-deploy-key": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-basic-memory.role.json b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-basic-memory.role.json deleted file mode 100644 index e58ac7d5f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-basic-memory.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "basic-memory" - ], - "bound_service_account_namespaces": [ - "knowledge-platform-system" - ], - "token_policies": [ - "knowledge-platform-system-basic-memory" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-docling-serve-backup.policy.json b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-docling-serve-backup.policy.json deleted file mode 100644 index b1b329675..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-docling-serve-backup.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/platform/backup/off-cluster": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/backup/off-cluster": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-docling-serve-backup.role.json b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-docling-serve-backup.role.json deleted file mode 100644 index 242a61608..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-docling-serve-backup.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "docling-serve-backup" - ], - "bound_service_account_namespaces": [ - "knowledge-platform-system" - ], - "token_policies": [ - "knowledge-platform-system-docling-serve-backup" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-api.policy.json b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-api.policy.json deleted file mode 100644 index df7b9da21..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-api.policy.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "path": { - "secret/data/platform/hindsight": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/hindsight": { - "capabilities": [ - "read" - ] - }, - "database/creds/knowledge-platform-owner": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-api.role.json b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-api.role.json deleted file mode 100644 index 843b3e603..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-api.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "hindsight-api" - ], - "bound_service_account_namespaces": [ - "knowledge-platform-system" - ], - "token_policies": [ - "knowledge-platform-system-hindsight-api" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-worker.policy.json b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-worker.policy.json deleted file mode 100644 index df7b9da21..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-worker.policy.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "path": { - "secret/data/platform/hindsight": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/hindsight": { - "capabilities": [ - "read" - ] - }, - "database/creds/knowledge-platform-owner": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-worker.role.json b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-worker.role.json deleted file mode 100644 index ab834a641..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-worker.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "hindsight-worker" - ], - "bound_service_account_namespaces": [ - "knowledge-platform-system" - ], - "token_policies": [ - "knowledge-platform-system-hindsight-worker" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-karakeep.policy.json b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-karakeep.policy.json deleted file mode 100644 index 0925a12fd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-karakeep.policy.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "path": { - "secret/data/platform/karakeep": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/karakeep": { - "capabilities": [ - "read" - ] - }, - "secret/data/knowledge-platform/garage/s3": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/knowledge-platform/garage/s3": { - "capabilities": [ - "read" - ] - }, - "secret/data/platform/vpn/knowledge-platform-karakeep": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/vpn/knowledge-platform-karakeep": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-karakeep.role.json b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-karakeep.role.json deleted file mode 100644 index 05d24ea6e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-karakeep.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "karakeep" - ], - "bound_service_account_namespaces": [ - "knowledge-platform-system" - ], - "token_policies": [ - "knowledge-platform-system-karakeep" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/serviceaccount.yaml deleted file mode 100644 index d6d816406..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: knowledge-platform-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vaultconnection.yaml deleted file mode 100644 index ed471533a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/apps/knowledge-platform/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: knowledge-platform-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/human-grants/clusterrolebindings.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/human-grants/clusterrolebindings.yaml deleted file mode 100644 index 86311f89c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/human-grants/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: human:oidc:k8s-admin:cluster-admin - labels: - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: oidc:k8s-admin diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/human-grants/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/human-grants/kustomization.yaml deleted file mode 100644 index 029015f5d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/human-grants/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - clusterrolebindings.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/priority-classes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/priority-classes/kustomization.yaml deleted file mode 100644 index 8b06a2f03..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/priority-classes/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/priority-classes/priorityclasses.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/priority-classes/priorityclasses.yaml deleted file mode 100644 index a304512d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/priority-classes/priorityclasses.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-data - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 1000000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "A datastore: it schedules before what reads it." ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-critical-app - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 100000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "The foundation and the Applications the platform names: they keep scheduling under pressure." diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/stable-addresses/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/stable-addresses/kustomization.yaml deleted file mode 100644 index ad77fad11..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/stable-addresses/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - namespace.yaml - - services.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/stable-addresses/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/stable-addresses/namespace.yaml deleted file mode 100644 index 1a599d91f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/stable-addresses/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/stable-addresses/services.yaml b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/stable-addresses/services.yaml deleted file mode 100644 index d52bb903c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/expected/estate/stable-addresses/services.yaml +++ /dev/null @@ -1,45 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: hindsight-api - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: hindsight-api.knowledge-platform-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: hindsight-embedding-embeddings - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: hindsight-tei-embedding.knowledge-platform-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-garage-s3 - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: garage.data-system.svc.cluster.local ---- -apiVersion: v1 -kind: Service -metadata: - name: platform-postgres-postgres - namespace: estate-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: ExternalName - externalName: postgres.data-system.svc.cluster.local diff --git a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/oracles b/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/oracles deleted file mode 100644 index f4a1635b2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/knowledge-platform/oracles +++ /dev/null @@ -1,74 +0,0 @@ -apps/knowledge-platform/aliases.yaml knowledge-platform/rendered/apps/knowledge-platform/aliases.yaml -apps/knowledge-platform/basic-memory/configmap.yaml knowledge-platform/rendered/apps/knowledge-platform/basic-memory/configmap.yaml -apps/knowledge-platform/basic-memory/kustomization.yaml knowledge-platform/rendered/apps/knowledge-platform/basic-memory/kustomization.yaml -apps/knowledge-platform/basic-memory/networkpolicy.yaml knowledge-platform/rendered/apps/knowledge-platform/basic-memory/networkpolicy.yaml -apps/knowledge-platform/basic-memory/pvc.yaml knowledge-platform/rendered/apps/knowledge-platform/basic-memory/pvc.yaml -apps/knowledge-platform/basic-memory/route-mcp.yaml knowledge-platform/rendered/apps/knowledge-platform/basic-memory/route-mcp.yaml -apps/knowledge-platform/basic-memory/service.yaml knowledge-platform/rendered/apps/knowledge-platform/basic-memory/service.yaml -apps/knowledge-platform/basic-memory/serviceaccount.yaml knowledge-platform/rendered/apps/knowledge-platform/basic-memory/serviceaccount.yaml -apps/knowledge-platform/basic-memory/vso.yaml knowledge-platform/rendered/apps/knowledge-platform/basic-memory/vso.yaml -apps/knowledge-platform/basic-memory/workload.yaml knowledge-platform/rendered/apps/knowledge-platform/basic-memory/workload.yaml -apps/knowledge-platform/docling-serve/backup.yaml knowledge-platform/rendered/apps/knowledge-platform/docling-serve/backup.yaml -apps/knowledge-platform/docling-serve/kustomization.yaml knowledge-platform/rendered/apps/knowledge-platform/docling-serve/kustomization.yaml -apps/knowledge-platform/docling-serve/networkpolicy.yaml knowledge-platform/rendered/apps/knowledge-platform/docling-serve/networkpolicy.yaml -apps/knowledge-platform/docling-serve/pvc.yaml knowledge-platform/rendered/apps/knowledge-platform/docling-serve/pvc.yaml -apps/knowledge-platform/docling-serve/service.yaml knowledge-platform/rendered/apps/knowledge-platform/docling-serve/service.yaml -apps/knowledge-platform/docling-serve/serviceaccount.yaml knowledge-platform/rendered/apps/knowledge-platform/docling-serve/serviceaccount.yaml -apps/knowledge-platform/docling-serve/vso.yaml knowledge-platform/rendered/apps/knowledge-platform/docling-serve/vso.yaml -apps/knowledge-platform/docling-serve/workload.yaml knowledge-platform/rendered/apps/knowledge-platform/docling-serve/workload.yaml -apps/knowledge-platform/hindsight-embedding/kustomization.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight-embedding/kustomization.yaml -apps/knowledge-platform/hindsight-embedding/networkpolicy.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight-embedding/networkpolicy.yaml -apps/knowledge-platform/hindsight-embedding/pvc.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight-embedding/pvc.yaml -apps/knowledge-platform/hindsight-embedding/service.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight-embedding/service.yaml -apps/knowledge-platform/hindsight-embedding/serviceaccount.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight-embedding/serviceaccount.yaml -apps/knowledge-platform/hindsight-embedding/workload.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight-embedding/workload.yaml -apps/knowledge-platform/hindsight/canary.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight/canary.yaml -apps/knowledge-platform/hindsight/configmap.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight/configmap.yaml -apps/knowledge-platform/hindsight/kustomization.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight/kustomization.yaml -apps/knowledge-platform/hindsight/networkpolicy.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight/networkpolicy.yaml -apps/knowledge-platform/hindsight/route-api.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight/route-api.yaml -apps/knowledge-platform/hindsight/route-console.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight/route-console.yaml -apps/knowledge-platform/hindsight/service.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight/service.yaml -apps/knowledge-platform/hindsight/serviceaccount.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight/serviceaccount.yaml -apps/knowledge-platform/hindsight/vso.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight/vso.yaml -apps/knowledge-platform/hindsight/workload.yaml knowledge-platform/rendered/apps/knowledge-platform/hindsight/workload.yaml -apps/knowledge-platform/karakeep/backup.yaml knowledge-platform/rendered/apps/knowledge-platform/karakeep/backup.yaml -apps/knowledge-platform/karakeep/configmap.yaml knowledge-platform/rendered/apps/knowledge-platform/karakeep/configmap.yaml -apps/knowledge-platform/karakeep/kustomization.yaml knowledge-platform/rendered/apps/knowledge-platform/karakeep/kustomization.yaml -apps/knowledge-platform/karakeep/networkpolicy.yaml knowledge-platform/rendered/apps/knowledge-platform/karakeep/networkpolicy.yaml -apps/knowledge-platform/karakeep/pvc.yaml knowledge-platform/rendered/apps/knowledge-platform/karakeep/pvc.yaml -apps/knowledge-platform/karakeep/route-public.yaml knowledge-platform/rendered/apps/knowledge-platform/karakeep/route-public.yaml -apps/knowledge-platform/karakeep/service.yaml knowledge-platform/rendered/apps/knowledge-platform/karakeep/service.yaml -apps/knowledge-platform/karakeep/serviceaccount.yaml knowledge-platform/rendered/apps/knowledge-platform/karakeep/serviceaccount.yaml -apps/knowledge-platform/karakeep/vso.yaml knowledge-platform/rendered/apps/knowledge-platform/karakeep/vso.yaml -apps/knowledge-platform/karakeep/workload.yaml knowledge-platform/rendered/apps/knowledge-platform/karakeep/workload.yaml -apps/knowledge-platform/kustomization.yaml knowledge-platform/rendered/apps/knowledge-platform/kustomization.yaml -apps/knowledge-platform/namespace.yaml knowledge-platform/rendered/apps/knowledge-platform/namespace.yaml -apps/knowledge-platform/networkpolicy.yaml knowledge-platform/rendered/apps/knowledge-platform/networkpolicy.yaml -apps/knowledge-platform/rollout-events/alert.yaml knowledge-platform/rendered/apps/knowledge-platform/rollout-events/alert.yaml -apps/knowledge-platform/rollout-events/kustomization.yaml knowledge-platform/rendered/apps/knowledge-platform/rollout-events/kustomization.yaml -apps/knowledge-platform/rollout-events/provider.yaml knowledge-platform/rendered/apps/knowledge-platform/rollout-events/provider.yaml -apps/knowledge-platform/vault-policy/configmap.yaml knowledge-platform/rendered/apps/knowledge-platform/vault-policy/configmap.yaml -apps/knowledge-platform/vault-policy/cronjob.yaml knowledge-platform/rendered/apps/knowledge-platform/vault-policy/cronjob.yaml -apps/knowledge-platform/vault-policy/job.yaml knowledge-platform/rendered/apps/knowledge-platform/vault-policy/job.yaml -apps/knowledge-platform/vault-policy/kustomization.yaml knowledge-platform/rendered/apps/knowledge-platform/vault-policy/kustomization.yaml -apps/knowledge-platform/vault-policy/networkpolicy.yaml knowledge-platform/rendered/apps/knowledge-platform/vault-policy/networkpolicy.yaml -apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-basic-memory.policy.json knowledge-platform/rendered/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-basic-memory.policy.json -apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-basic-memory.role.json knowledge-platform/rendered/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-basic-memory.role.json -apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-docling-serve-backup.policy.json knowledge-platform/rendered/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-docling-serve-backup.policy.json -apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-docling-serve-backup.role.json knowledge-platform/rendered/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-docling-serve-backup.role.json -apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-api.policy.json knowledge-platform/rendered/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-api.policy.json -apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-api.role.json knowledge-platform/rendered/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-api.role.json -apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-worker.policy.json knowledge-platform/rendered/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-worker.policy.json -apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-worker.role.json knowledge-platform/rendered/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-hindsight-worker.role.json -apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-karakeep.policy.json knowledge-platform/rendered/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-karakeep.policy.json -apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-karakeep.role.json knowledge-platform/rendered/apps/knowledge-platform/vault-policy/policies/knowledge-platform-system-karakeep.role.json -apps/knowledge-platform/vault-policy/serviceaccount.yaml knowledge-platform/rendered/apps/knowledge-platform/vault-policy/serviceaccount.yaml -apps/knowledge-platform/vaultconnection.yaml knowledge-platform/rendered/apps/knowledge-platform/vaultconnection.yaml -estate/human-grants/clusterrolebindings.yaml platform/rendered/estate/human-grants/clusterrolebindings.yaml -estate/human-grants/kustomization.yaml platform/rendered/estate/human-grants/kustomization.yaml -estate/priority-classes/kustomization.yaml platform/rendered/estate/priority-classes/kustomization.yaml -estate/priority-classes/priorityclasses.yaml platform/rendered/estate/priority-classes/priorityclasses.yaml -estate/stable-addresses/kustomization.yaml knowledge-platform/rendered/estate/stable-addresses/kustomization.yaml -estate/stable-addresses/namespace.yaml knowledge-platform/rendered/estate/stable-addresses/namespace.yaml -estate/stable-addresses/services.yaml knowledge-platform/rendered/estate/stable-addresses/services.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/kustomization.yaml deleted file mode 100644 index baa07a1f8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - namespace.yaml - - rollout-events - - stalwart diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/namespace.yaml deleted file mode 100644 index bad1e8aab..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: mail-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/networkpolicy.yaml deleted file mode 100644 index 24062cbf6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: mail-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/rollout-events/alert.yaml deleted file mode 100644 index fc4e6781b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-mail - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-mail - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-mail - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/rollout-events/provider.yaml deleted file mode 100644 index 7aa26ed60..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-mail - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/configmap.yaml deleted file mode 100644 index 0e6644630..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/configmap.yaml +++ /dev/null @@ -1,33 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: stalwart-external-checks - namespace: mail-system - labels: - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - stalwart-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"mail","name":"stalwart-admin-1","url":"https://mail.jorisjonkers.dev/"},{"conditions":["[STATUS] < 500"],"group":"mail","name":"stalwart-admin-2","url":"https://mail.jorisjonkers.dev/"}]} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: stalwart-manifest-json-f1813d8cee - namespace: mail-system - labels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - manifest.json: | - { - "domains": [{ "name": "jorisjonkers.dev" }], - "accounts": [{ "name": "postmaster", "domain": "jorisjonkers.dev" }] - } diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/kustomization.yaml deleted file mode 100644 index 14279eb51..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - route-admin.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/networkpolicy.yaml deleted file mode 100644 index 18284dda8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/networkpolicy.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: stalwart - namespace: mail-system - labels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: stalwart - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/stalwart.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/stalwart.smtp: "true" - ports: - - protocol: TCP - port: 25 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/stalwart.imaps: "true" - ports: - - protocol: TCP - port: 993 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 25 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 993 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/route-admin.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/route-admin.yaml deleted file mode 100644 index d5a55f2af..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/route-admin.yaml +++ /dev/null @@ -1,60 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: stalwart-admin - namespace: mail-system - labels: - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`mail.jorisjonkers.dev`) && Path(`/`) - priority: 999 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers - namespace: edge-system - - name: stalwart-admin-1-redirect - namespace: mail-system - services: - - name: stalwart - namespace: mail-system - port: 8080 - - kind: Rule - match: Host(`mail.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 998 - middlewares: - - name: forward-auth - namespace: edge-system - - name: security-headers - namespace: edge-system - services: - - name: stalwart - namespace: mail-system - port: 8080 - tls: - certResolver: public-frankfurt ---- -apiVersion: traefik.io/v1alpha1 -kind: Middleware -metadata: - name: stalwart-admin-1-redirect - namespace: mail-system - labels: - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit -spec: - redirectRegex: - regex: ^(https?://[^/]+)(/.*)?$ - replacement: ${1}/admin/ - permanent: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/service.yaml deleted file mode 100644 index c84bdb505..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/service.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: stalwart - namespace: mail-system - labels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: stalwart - ports: - - name: http - port: 8080 - targetPort: http - - name: smtp - port: 25 - targetPort: smtp - - name: imaps - port: 993 - targetPort: imaps diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/serviceaccount.yaml deleted file mode 100644 index 46c95a780..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: stalwart - namespace: mail-system - labels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/workload.yaml deleted file mode 100644 index 18402bcdc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/expected/apps/mail/stalwart/workload.yaml +++ /dev/null @@ -1,144 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: stalwart - namespace: mail-system - labels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 300 - selector: - matchLabels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - template: - metadata: - labels: - app.kubernetes.io/name: stalwart - app.kubernetes.io/instance: stalwart - app.kubernetes.io/part-of: stalwart - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/stalwart: v0.16.0 - image.jorisjonkers.dev/stalwart-apply: 0.22.0 - spec: - serviceAccountName: stalwart - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 2000 - runAsGroup: 2000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - frankfurt-contabo-1 - containers: - - name: stalwart - image: docker.io/stalwartlabs/stalwart@sha256:5a2c4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f7e1f3c5a9b2d4f6e8a0c2e4b6d8f - ports: - - name: http - containerPort: 8080 - - name: smtp - containerPort: 25 - hostPort: 25 - - name: imaps - containerPort: 993 - hostPort: 993 - env: - - name: HOME - value: /tmp - resources: - requests: - memory: 512Mi - cpu: 100m - limits: - memory: 512Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - add: - - NET_BIND_SERVICE - drop: - - ALL - volumeMounts: - - name: stalwart-manifest-json-f1813d8cee - mountPath: /etc/stalwart-provisioner/manifest.json - subPath: manifest.json - readOnly: true - - name: writable-tmp - mountPath: /tmp - readinessProbe: - httpGet: - path: /healthz/ready - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz/live - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz/live - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 - - name: stalwart-apply - image: ghcr.io/jorisjonkers-dev/stalwart-provisioner@sha256:7d1f3b5a9c2e4f6b8d0a2c4e6f8b1d3a5c7e9f2b4d6a8c0e2f4b6d8a1c3e5f7b - env: - - name: HOME - value: /tmp - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: stalwart-manifest-json-f1813d8cee - mountPath: /etc/stalwart-provisioner/manifest.json - subPath: manifest.json - readOnly: true - - name: writable-tmp - mountPath: /tmp - volumes: - - name: stalwart-manifest-json-f1813d8cee - configMap: - name: stalwart-manifest-json-f1813d8cee - items: - - key: manifest.json - path: manifest.json - - name: writable-tmp - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/mail/oracles b/emf/bundles/cli/src/test/resources/stages/render/mail/oracles deleted file mode 100644 index ee95ca0bd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/mail/oracles +++ /dev/null @@ -1,13 +0,0 @@ -apps/mail/kustomization.yaml mail/rendered/apps/mail/kustomization.yaml -apps/mail/namespace.yaml mail/rendered/apps/mail/namespace.yaml -apps/mail/networkpolicy.yaml mail/rendered/apps/mail/networkpolicy.yaml -apps/mail/rollout-events/alert.yaml mail/rendered/apps/mail/rollout-events/alert.yaml -apps/mail/rollout-events/kustomization.yaml mail/rendered/apps/mail/rollout-events/kustomization.yaml -apps/mail/rollout-events/provider.yaml mail/rendered/apps/mail/rollout-events/provider.yaml -apps/mail/stalwart/configmap.yaml mail/rendered/apps/mail/stalwart/configmap.yaml -apps/mail/stalwart/kustomization.yaml mail/rendered/apps/mail/stalwart/kustomization.yaml -apps/mail/stalwart/networkpolicy.yaml mail/rendered/apps/mail/stalwart/networkpolicy.yaml -apps/mail/stalwart/route-admin.yaml mail/rendered/apps/mail/stalwart/route-admin.yaml -apps/mail/stalwart/service.yaml mail/rendered/apps/mail/stalwart/service.yaml -apps/mail/stalwart/serviceaccount.yaml mail/rendered/apps/mail/stalwart/serviceaccount.yaml -apps/mail/stalwart/workload.yaml mail/rendered/apps/mail/stalwart/workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/kustomization.yaml deleted file mode 100644 index ce1528686..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - libraries.yaml - - namespace.yaml - - notes - - rollout-events diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/libraries.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/libraries.yaml deleted file mode 100644 index b666a6052..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/libraries.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolume -metadata: - name: notes-system-media - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - capacity: - storage: 1Gi - volumeMode: Filesystem - accessModes: - - ReadWriteOnce - persistentVolumeReclaimPolicy: Retain - storageClassName: "" - claimRef: - namespace: notes-system - name: library-media - local: - path: /srv/media - nodeAffinity: - required: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: library-media - namespace: notes-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - storageClassName: "" - volumeName: notes-system-media - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/namespace.yaml deleted file mode 100644 index 91bd05009..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: notes-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/networkpolicy.yaml deleted file mode 100644 index 2f0471623..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: notes-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/canary.yaml deleted file mode 100644 index 8c83e7a2d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/canary.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: notes-api - namespace: notes-system - labels: - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: notes-api - progressDeadlineSeconds: 180 - service: - port: 8080 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: notes - process: notes-api - revision: sha256:2b25f8cbaf62431045cc22614d91a135ce897bc27a977a56a029ead0880c82aa - paths: / - readiness: /healthz/ready - hostnames: notes.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: notes - process: notes-api - revision: sha256:2b25f8cbaf62431045cc22614d91a135ce897bc27a977a56a029ead0880c82aa - paths: / - readiness: /healthz/ready - hostnames: notes.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: notes - process: notes-api - revision: sha256:2b25f8cbaf62431045cc22614d91a135ce897bc27a977a56a029ead0880c82aa - paths: / - readiness: /healthz/ready - hostnames: notes.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: notes - process: notes-api - revision: sha256:2b25f8cbaf62431045cc22614d91a135ce897bc27a977a56a029ead0880c82aa - paths: / - readiness: /healthz/ready - hostnames: notes.jorisjonkers.dev - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/configmap.yaml deleted file mode 100644 index c2d3cc129..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: notes-release-gate - namespace: notes-system - labels: - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"180s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"checks":["error-rate","latency"],"process":"notes-api","readiness":{"path":"/healthz/ready","port":8080}}]} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: notes-external-checks - namespace: notes-system - labels: - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - notes-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"notes","name":"notes-public-1","url":"https://notes.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/kustomization.yaml deleted file mode 100644 index fdbf82ca2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - podmonitor.yaml - - route-public.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/networkpolicy.yaml deleted file mode 100644 index a3d5d3020..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/networkpolicy.yaml +++ /dev/null @@ -1,71 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: notes-api - namespace: notes-system - labels: - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: notes-api - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: observability-system - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/notes.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/podmonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/podmonitor.yaml deleted file mode 100644 index 1f1448bef..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/podmonitor.yaml +++ /dev/null @@ -1,27 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: PodMonitor -metadata: - name: notes-api - namespace: notes-system - labels: - release: metrics-stack - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: notes-api - namespaceSelector: - matchNames: - - notes-system - podMetricsEndpoints: - - port: http - path: /metrics - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/route-public.yaml deleted file mode 100644 index ea74d8a92..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/route-public.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: notes-public - namespace: notes-system - labels: - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`notes.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers-strict - namespace: edge-system - services: - - name: notes-api - namespace: notes-system - port: 8080 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/serviceaccount.yaml deleted file mode 100644 index 80be8eb59..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: notes-api - namespace: notes-system - labels: - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/workload.yaml deleted file mode 100644 index 44927babf..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/notes/workload.yaml +++ /dev/null @@ -1,119 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: notes-api - namespace: notes-system - labels: - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 180 - selector: - matchLabels: - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - template: - metadata: - labels: - app.kubernetes.io/name: notes-api - app.kubernetes.io/instance: notes-api - app.kubernetes.io/part-of: notes - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: node - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/notes-api: 1.4.0 - spec: - serviceAccountName: notes-api - automountServiceAccountToken: false - runtimeClassName: nvidia-cdi - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - supplementalGroups: - - 3001 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - containers: - - name: notes-api - image: ghcr.io/jorisjonkers-dev/notes/notes-api@sha256:9c1e5a4b7d2f8e3a6b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a - ports: - - name: http - containerPort: 8080 - env: - - name: DEPLOYMENT_ENVIRONMENT - value: production - - name: NODE_ENV - value: production - - name: NOTES_PAGE_SIZE - value: "50" - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: http://otel-collector.observability-system.svc.cluster.local:4317 - - name: OTEL_SERVICE_NAME - value: notes-api - - name: PORT - value: "8080" - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - nvidia.com/gpu: "1" - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: library-media - mountPath: /attachments - subPath: Notes - readinessProbe: - httpGet: - path: /healthz/ready - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz/live - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz/live - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 4 - volumes: - - name: library-media - persistentVolumeClaim: - claimName: library-media diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/rollout-events/alert.yaml deleted file mode 100644 index 9a88e3438..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-notes - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-notes - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-notes - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/rollout-events/provider.yaml deleted file mode 100644 index 6c9ffcb42..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/expected/apps/notes/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-notes - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/oracles b/emf/bundles/cli/src/test/resources/stages/render/minimal-main/oracles deleted file mode 100644 index e5ab667ae..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/minimal-main/oracles +++ /dev/null @@ -1,15 +0,0 @@ -apps/notes/kustomization.yaml minimal/rendered/apps/notes/kustomization.yaml -apps/notes/libraries.yaml minimal/rendered/apps/notes/libraries.yaml -apps/notes/namespace.yaml minimal/rendered/apps/notes/namespace.yaml -apps/notes/networkpolicy.yaml minimal/rendered/apps/notes/networkpolicy.yaml -apps/notes/notes/canary.yaml minimal/rendered/apps/notes/notes/canary.yaml -apps/notes/notes/configmap.yaml minimal/rendered/apps/notes/notes/configmap.yaml -apps/notes/notes/kustomization.yaml minimal/rendered/apps/notes/notes/kustomization.yaml -apps/notes/notes/networkpolicy.yaml minimal/rendered/apps/notes/notes/networkpolicy.yaml -apps/notes/notes/podmonitor.yaml minimal/rendered/apps/notes/notes/podmonitor.yaml -apps/notes/notes/route-public.yaml minimal/rendered/apps/notes/notes/route-public.yaml -apps/notes/notes/serviceaccount.yaml minimal/rendered/apps/notes/notes/serviceaccount.yaml -apps/notes/notes/workload.yaml minimal/rendered/apps/notes/notes/workload.yaml -apps/notes/rollout-events/alert.yaml minimal/rendered/apps/notes/rollout-events/alert.yaml -apps/notes/rollout-events/kustomization.yaml minimal/rendered/apps/notes/rollout-events/kustomization.yaml -apps/notes/rollout-events/provider.yaml minimal/rendered/apps/notes/rollout-events/provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/configmap.yaml deleted file mode 100644 index fa710c897..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/configmap.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: gpu-device - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-device - app.kubernetes.io/part-of: node -data: - config.yaml: | - version: v1 - sharing: - timeSlicing: - resources: - - name: nvidia.com/gpu - replicas: 4 diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/kustomization.yaml deleted file mode 100644 index 4f85ca4f3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/kustomization.yaml +++ /dev/null @@ -1,8 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/serviceaccount.yaml deleted file mode 100644 index cfc1175b0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/serviceaccount.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: gpu-device - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-device - app.kubernetes.io/part-of: node diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/workload.yaml deleted file mode 100644 index 39c28453d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-device/workload.yaml +++ /dev/null @@ -1,84 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: gpu-device - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-device - app.kubernetes.io/part-of: node -spec: - selector: - matchLabels: - app.kubernetes.io/name: gpu-device - updateStrategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - template: - metadata: - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-device - app.kubernetes.io/part-of: node - spec: - serviceAccountName: gpu-device - automountServiceAccountToken: false - priorityClassName: system-node-critical - securityContext: - seccompProfile: - type: RuntimeDefault - hostPID: true - runtimeClassName: nvidia-cdi - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-gtx-960m-1 - containers: - - name: gpu-device - image: nvcr.io/nvidia/k8s-device-plugin@sha256:eeaf499dbb6f09bb79d95f788d3d87ca6ffa0ae36ed63210d5672e08ba266ff4 - env: - - name: CONFIG_FILE - value: /config/config.yaml - - name: DEVICE_ID_STRATEGY - value: index - - name: FAIL_ON_INIT_ERROR - value: "true" - - name: NVIDIA_VISIBLE_DEVICES - value: all - - name: PASS_DEVICE_SPECS - value: "true" - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - privileged: true - volumeMounts: - - name: device-plugins - mountPath: /var/lib/kubelet/device-plugins - - name: cdi - mountPath: /var/run/cdi - - name: config - mountPath: /config - readOnly: true - volumes: - - name: device-plugins - hostPath: - path: /var/lib/kubelet/device-plugins - - name: cdi - hostPath: - path: /var/run/cdi - - name: config - configMap: - name: gpu-device diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-metrics/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-metrics/kustomization.yaml deleted file mode 100644 index 341f80291..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-metrics/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-metrics/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-metrics/serviceaccount.yaml deleted file mode 100644 index 435e6a618..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-metrics/serviceaccount.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: gpu-metrics - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-metrics - app.kubernetes.io/part-of: node diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-metrics/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-metrics/workload.yaml deleted file mode 100644 index 41d1cfad6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/gpu-metrics/workload.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: gpu-metrics - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-metrics - app.kubernetes.io/part-of: node -spec: - selector: - matchLabels: - app.kubernetes.io/name: gpu-metrics - updateStrategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - template: - metadata: - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: gpu-metrics - app.kubernetes.io/part-of: node - spec: - serviceAccountName: gpu-metrics - automountServiceAccountToken: false - priorityClassName: system-node-critical - securityContext: - seccompProfile: - type: RuntimeDefault - runtimeClassName: nvidia-cdi - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-gtx-960m-1 - containers: - - name: gpu-metrics - image: nvcr.io/nvidia/k8s/dcgm-exporter@sha256:6faf8666aeffe3aa674aa33eb59433addf6b8d5ec267ac1a096892d1ffab6a0b - env: - - name: DCGM_EXPORTER_KUBERNETES - value: "true" - - name: DCGM_EXPORTER_LISTEN - value: :9400 - ports: - - name: metrics - containerPort: 9400 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - nvidia.com/gpu: "1" - securityContext: - runAsNonRoot: false - runAsUser: 0 - capabilities: - add: - - SYS_ADMIN - drop: - - ALL - volumeMounts: - - name: pod-resources - mountPath: /var/lib/kubelet/pod-resources - readOnly: true - volumes: - - name: pod-resources - hostPath: - path: /var/lib/kubelet/pod-resources diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/kustomization.yaml deleted file mode 100644 index 352e35872..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - gpu-device - - gpu-metrics - - l4-speaker - - namespace.yaml - - node-metrics - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/kustomization.yaml deleted file mode 100644 index ec636d7b6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pools.yaml - - rbac.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/pools.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/pools.yaml deleted file mode 100644 index 2ca6a7d8e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/pools.yaml +++ /dev/null @@ -1,103 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: metallb.io/v1beta1 -kind: IPAddressPool -metadata: - name: lan-dns - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - addresses: - - 192.168.0.98/32 - autoAssign: false ---- -apiVersion: metallb.io/v1beta1 -kind: L2Advertisement -metadata: - name: lan-dns - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - ipAddressPools: - - lan-dns - nodeSelectors: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 ---- -apiVersion: metallb.io/v1beta1 -kind: IPAddressPool -metadata: - name: lan-edge - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - addresses: - - 192.168.0.99/32 - autoAssign: false ---- -apiVersion: metallb.io/v1beta1 -kind: L2Advertisement -metadata: - name: lan-edge - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - ipAddressPools: - - lan-edge - nodeSelectors: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 ---- -apiVersion: metallb.io/v1beta1 -kind: IPAddressPool -metadata: - name: lan-mqtt - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - addresses: - - 192.168.0.97/32 - autoAssign: false ---- -apiVersion: metallb.io/v1beta1 -kind: L2Advertisement -metadata: - name: lan-mqtt - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - ipAddressPools: - - lan-mqtt - nodeSelectors: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/rbac.yaml deleted file mode 100644 index e82f896cf..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/rbac.yaml +++ /dev/null @@ -1,258 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: node:l4-speaker - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -rules: - - apiGroups: - - "" - resources: - - services - - endpoints - - nodes - - namespaces - - pods - verbs: - - get - - list - - watch - - apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - apiGroups: - - metallb.io - resources: - - ipaddresspools - - l2advertisements - - bgppeers - - bgpadvertisements - - communities - - bfdprofiles - - servicel2statuses - verbs: - - get - - list - - watch - - apiGroups: - - metallb.io - resources: - - servicel2statuses - - servicel2statuses/status - verbs: - - create - - delete - - update - - patch - - apiGroups: - - metallb.io - resources: - - configurationstates - - configurationstates/status - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: node:l4-speaker - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: node:l4-speaker -subjects: - - kind: ServiceAccount - name: l4-speaker - namespace: node-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: l4-speaker - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -rules: - - apiGroups: - - "" - resources: - - secrets - - configmaps - verbs: - - get - - list - - watch - - apiGroups: - - metallb.io - resources: - - servicebgpstatuses - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: l4-speaker - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: l4-speaker -subjects: - - kind: ServiceAccount - name: l4-speaker - namespace: node-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: node:l4-controller - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node -rules: - - apiGroups: - - "" - resources: - - services - - namespaces - - nodes - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - services/status - verbs: - - update - - apiGroups: - - "" - resources: - - events - verbs: - - create - - patch - - apiGroups: - - metallb.io - resources: - - ipaddresspools - - l2advertisements - - bgppeers - - bgpadvertisements - - communities - - bfdprofiles - verbs: - - get - - list - - watch - - apiGroups: - - metallb.io - resources: - - ipaddresspools/status - verbs: - - update - - apiGroups: - - metallb.io - resources: - - configurationstates - - configurationstates/status - verbs: - - get - - list - - watch - - create - - update - - patch - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: node:l4-controller - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: node:l4-controller -subjects: - - kind: ServiceAccount - name: l4-controller - namespace: node-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: l4-controller - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node -rules: - - apiGroups: - - "" - resources: - - secrets - - configmaps - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - name: l4-controller - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: l4-controller -subjects: - - kind: ServiceAccount - name: l4-controller - namespace: node-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/serviceaccount.yaml deleted file mode 100644 index a4924f9ca..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/serviceaccount.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: l4-speaker - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: l4-controller - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/vso.yaml deleted file mode 100644 index 818d055e9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/vso.yaml +++ /dev/null @@ -1,43 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: l4-speaker - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: node-system-l4-speaker - serviceAccount: l4-speaker ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: l4-speaker-memberlist - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -spec: - vaultAuthRef: l4-speaker - mount: secret - type: kv-v2 - path: node-system/l4-speaker - refreshAfter: 10m - hmacSecretData: true - destination: - name: l4-speaker-memberlist - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: DaemonSet - name: l4-speaker diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/workload.yaml deleted file mode 100644 index 2cc2330f4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/l4-speaker/workload.yaml +++ /dev/null @@ -1,172 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: l4-speaker - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node -spec: - selector: - matchLabels: - app.kubernetes.io/name: l4-speaker - updateStrategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - template: - metadata: - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-speaker - app.kubernetes.io/part-of: node - spec: - serviceAccountName: l4-speaker - automountServiceAccountToken: true - priorityClassName: system-node-critical - securityContext: - seccompProfile: - type: RuntimeDefault - hostNetwork: true - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - containers: - - name: l4-speaker - image: quay.io/metallb/speaker@sha256:a2de24e2d206541cb9f101b66876944ecd5a2f19d1783d674e982bfb829defbe - args: - - --port=7472 - - --namespace=node-system - - --log-level=info - env: - - name: METALLB_NODE_NAME - valueFrom: - fieldRef: - fieldPath: spec.nodeName - - name: METALLB_HOST - valueFrom: - fieldRef: - fieldPath: status.hostIP - - name: METALLB_POD_NAME - valueFrom: - fieldRef: - fieldPath: metadata.name - - name: METALLB_ML_BIND_ADDR - valueFrom: - fieldRef: - fieldPath: status.podIP - - name: METALLB_ML_LABELS - value: app.kubernetes.io/name=l4-speaker - - name: METALLB_ML_BIND_PORT - value: "7946" - - name: METALLB_ML_SECRET_KEY_PATH - value: /etc/ml_secret_key - ports: - - name: metrics - containerPort: 7472 - resources: - requests: - memory: 64Mi - cpu: 20m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - add: - - NET_RAW - drop: - - ALL - volumeMounts: - - name: memberlist - mountPath: /etc/ml_secret_key - readOnly: true - volumes: - - name: memberlist - secret: - secretName: l4-speaker-memberlist ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: l4-controller - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node -spec: - replicas: 1 - strategy: - type: Recreate - selector: - matchLabels: - app.kubernetes.io/name: l4-controller - template: - metadata: - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: l4-controller - app.kubernetes.io/part-of: node - spec: - serviceAccountName: l4-controller - automountServiceAccountToken: true - priorityClassName: system-cluster-critical - securityContext: - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - containers: - - name: l4-controller - image: quay.io/metallb/controller@sha256:8bd722cbf5d88cf8b9c82fed1ab069dc1a2f8e5ee383dcf57e49c359ee9d27a3 - args: - - --port=7472 - - --namespace=node-system - - --webhook-mode=disabled - - --log-level=info - ports: - - name: metrics - containerPort: 7472 - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/namespace.yaml deleted file mode 100644 index 765a84e8c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/node-metrics/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/node-metrics/kustomization.yaml deleted file mode 100644 index 341f80291..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/node-metrics/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/node-metrics/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/node-metrics/serviceaccount.yaml deleted file mode 100644 index 0619d464b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/node-metrics/serviceaccount.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: node-metrics - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: node-metrics - app.kubernetes.io/part-of: node diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/node-metrics/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/node-metrics/workload.yaml deleted file mode 100644 index 0450606ab..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/node-metrics/workload.yaml +++ /dev/null @@ -1,94 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: DaemonSet -metadata: - name: node-metrics - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: node-metrics - app.kubernetes.io/part-of: node -spec: - selector: - matchLabels: - app.kubernetes.io/name: node-metrics - updateStrategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - template: - metadata: - labels: - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: node-metrics - app.kubernetes.io/part-of: node - spec: - serviceAccountName: node-metrics - automountServiceAccountToken: false - priorityClassName: system-node-critical - securityContext: - seccompProfile: - type: RuntimeDefault - hostNetwork: true - hostPID: true - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: node-metrics - image: quay.io/prometheus/node-exporter@sha256:2303824a4e3dc61fe3195d1a6e978029d4774876cc9aba9d2c60ef85eb96a845 - args: - - --path.procfs=/host/proc - - --path.sysfs=/host/sys - - --path.rootfs=/host/root - - --web.listen-address=:9100 - ports: - - name: metrics - containerPort: 9100 - resources: - requests: - memory: 64Mi - cpu: 20m - limits: - memory: 64Mi - securityContext: - runAsNonRoot: true - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: proc - mountPath: /host/proc - readOnly: true - - name: sys - mountPath: /host/sys - readOnly: true - - name: root - mountPath: /host/root - readOnly: true - mountPropagation: HostToContainer - volumes: - - name: proc - hostPath: - path: /proc - - name: sys - hostPath: - path: /sys - - name: root - hostPath: - path: / diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/configmap.yaml deleted file mode 100644 index fdfc2d0f0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/configmap.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-7aef94bb1eca - namespace: node-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - node-system-l4-speaker.policy.json: | - {"path":{"secret/data/node-system/l4-speaker":{"capabilities":["read"]},"secret/metadata/node-system/l4-speaker":{"capabilities":["read"]}}} - node-system-l4-speaker.role.json: | - {"bound_service_account_names":["l4-speaker"],"bound_service_account_namespaces":["node-system"],"token_policies":["node-system-l4-speaker"]} - node-system.generated.json: | - {"keys":[{"bytes":32,"encoding":"hex","key":"secretkey","path":"secret/data/node-system/l4-speaker"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/cronjob.yaml deleted file mode 100644 index 3e22eefe4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/cronjob.yaml +++ /dev/null @@ -1,97 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: node-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-7aef94bb1eca - items: - - key: node-system-l4-speaker.policy.json - path: node-system-l4-speaker.policy.json - - key: node-system-l4-speaker.role.json - path: node-system-l4-speaker.role.json - - key: node-system.generated.json - path: node-system.generated.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/job.yaml deleted file mode 100644 index 90e609c8b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/job.yaml +++ /dev/null @@ -1,87 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-7aef94bb1eca - namespace: node-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-7aef94bb1eca - items: - - key: node-system-l4-speaker.policy.json - path: node-system-l4-speaker.policy.json - - key: node-system-l4-speaker.role.json - path: node-system-l4-speaker.role.json - - key: node-system.generated.json - path: node-system.generated.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/networkpolicy.yaml deleted file mode 100644 index 27afd3c8f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: node-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/policies/node-system-l4-speaker.policy.json b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/policies/node-system-l4-speaker.policy.json deleted file mode 100644 index 5bf7b5987..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/policies/node-system-l4-speaker.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/node-system/l4-speaker": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/node-system/l4-speaker": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/policies/node-system-l4-speaker.role.json b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/policies/node-system-l4-speaker.role.json deleted file mode 100644 index d6b3f7f11..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/policies/node-system-l4-speaker.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "l4-speaker" - ], - "bound_service_account_namespaces": [ - "node-system" - ], - "token_policies": [ - "node-system-l4-speaker" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/policies/node-system.generated.json b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/policies/node-system.generated.json deleted file mode 100644 index 962733633..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/policies/node-system.generated.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "keys": [ - { - "path": "secret/data/node-system/l4-speaker", - "key": "secretkey", - "bytes": 32, - "encoding": "hex" - } - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/serviceaccount.yaml deleted file mode 100644 index 4c5d4e8e6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: node-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vaultconnection.yaml deleted file mode 100644 index 592e2b05e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/apps/node/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: node-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/human-grants/clusterrolebindings.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/human-grants/clusterrolebindings.yaml deleted file mode 100644 index 86311f89c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/human-grants/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: human:oidc:k8s-admin:cluster-admin - labels: - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: oidc:k8s-admin diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/human-grants/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/human-grants/kustomization.yaml deleted file mode 100644 index 029015f5d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/human-grants/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - clusterrolebindings.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/priority-classes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/priority-classes/kustomization.yaml deleted file mode 100644 index 8b06a2f03..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/priority-classes/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/priority-classes/priorityclasses.yaml b/emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/priority-classes/priorityclasses.yaml deleted file mode 100644 index a304512d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/expected/estate/priority-classes/priorityclasses.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-data - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 1000000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "A datastore: it schedules before what reads it." ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-critical-app - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 100000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "The foundation and the Applications the platform names: they keep scheduling under pressure." diff --git a/emf/bundles/cli/src/test/resources/stages/render/node/oracles b/emf/bundles/cli/src/test/resources/stages/render/node/oracles deleted file mode 100644 index a96440332..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/node/oracles +++ /dev/null @@ -1,32 +0,0 @@ -apps/node/gpu-device/configmap.yaml node/rendered/apps/node/gpu-device/configmap.yaml -apps/node/gpu-device/kustomization.yaml node/rendered/apps/node/gpu-device/kustomization.yaml -apps/node/gpu-device/serviceaccount.yaml node/rendered/apps/node/gpu-device/serviceaccount.yaml -apps/node/gpu-device/workload.yaml node/rendered/apps/node/gpu-device/workload.yaml -apps/node/gpu-metrics/kustomization.yaml node/rendered/apps/node/gpu-metrics/kustomization.yaml -apps/node/gpu-metrics/serviceaccount.yaml node/rendered/apps/node/gpu-metrics/serviceaccount.yaml -apps/node/gpu-metrics/workload.yaml node/rendered/apps/node/gpu-metrics/workload.yaml -apps/node/kustomization.yaml node/rendered/apps/node/kustomization.yaml -apps/node/l4-speaker/kustomization.yaml node/rendered/apps/node/l4-speaker/kustomization.yaml -apps/node/l4-speaker/pools.yaml node/rendered/apps/node/l4-speaker/pools.yaml -apps/node/l4-speaker/rbac.yaml node/rendered/apps/node/l4-speaker/rbac.yaml -apps/node/l4-speaker/serviceaccount.yaml node/rendered/apps/node/l4-speaker/serviceaccount.yaml -apps/node/l4-speaker/vso.yaml node/rendered/apps/node/l4-speaker/vso.yaml -apps/node/l4-speaker/workload.yaml node/rendered/apps/node/l4-speaker/workload.yaml -apps/node/namespace.yaml node/rendered/apps/node/namespace.yaml -apps/node/node-metrics/kustomization.yaml node/rendered/apps/node/node-metrics/kustomization.yaml -apps/node/node-metrics/serviceaccount.yaml node/rendered/apps/node/node-metrics/serviceaccount.yaml -apps/node/node-metrics/workload.yaml node/rendered/apps/node/node-metrics/workload.yaml -apps/node/vault-policy/configmap.yaml node/rendered/apps/node/vault-policy/configmap.yaml -apps/node/vault-policy/cronjob.yaml node/rendered/apps/node/vault-policy/cronjob.yaml -apps/node/vault-policy/job.yaml node/rendered/apps/node/vault-policy/job.yaml -apps/node/vault-policy/kustomization.yaml node/rendered/apps/node/vault-policy/kustomization.yaml -apps/node/vault-policy/networkpolicy.yaml node/rendered/apps/node/vault-policy/networkpolicy.yaml -apps/node/vault-policy/policies/node-system-l4-speaker.policy.json node/rendered/apps/node/vault-policy/policies/node-system-l4-speaker.policy.json -apps/node/vault-policy/policies/node-system-l4-speaker.role.json node/rendered/apps/node/vault-policy/policies/node-system-l4-speaker.role.json -apps/node/vault-policy/policies/node-system.generated.json node/rendered/apps/node/vault-policy/policies/node-system.generated.json -apps/node/vault-policy/serviceaccount.yaml node/rendered/apps/node/vault-policy/serviceaccount.yaml -apps/node/vaultconnection.yaml node/rendered/apps/node/vaultconnection.yaml -estate/human-grants/clusterrolebindings.yaml platform/rendered/estate/human-grants/clusterrolebindings.yaml -estate/human-grants/kustomization.yaml platform/rendered/estate/human-grants/kustomization.yaml -estate/priority-classes/kustomization.yaml platform/rendered/estate/priority-classes/kustomization.yaml -estate/priority-classes/priorityclasses.yaml platform/rendered/estate/priority-classes/priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/alertmanagerconfig.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/alertmanagerconfig.yaml deleted file mode 100644 index ade3319a2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/alertmanagerconfig.yaml +++ /dev/null @@ -1,38 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1alpha1 -kind: AlertmanagerConfig -metadata: - name: estate-alerts - namespace: observability-system - labels: - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit -spec: - route: - receiver: "null" - groupBy: - - alertname - - namespace - groupWait: 1m - groupInterval: 5m - repeatInterval: 12h - routes: - - matchers: - - name: severity - value: critical - receiver: discord - repeatInterval: 4h - - matchers: - - name: severity - value: warning - receiver: discord - repeatInterval: 12h - receivers: - - name: "null" - - name: discord - discordConfigs: - - apiURL: - name: alertmanager-platform-alertmanager-discord - key: webhook-url - sendResolved: true diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/kustomization.yaml deleted file mode 100644 index 4223c5585..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alertmanagerconfig.yaml - - service.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/networkpolicy.yaml deleted file mode 100644 index 825f5496d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/networkpolicy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: alertmanager - namespace: observability-system - labels: - app.kubernetes.io/name: alertmanager - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: alertmanager - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/alertmanager.http: "true" - ports: - - protocol: TCP - port: 9093 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/service.yaml deleted file mode 100644 index 349be1ae9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: alertmanager - namespace: observability-system - labels: - app.kubernetes.io/name: alertmanager - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: alertmanager - ports: - - name: http - port: 9093 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/serviceaccount.yaml deleted file mode 100644 index ac12eae56..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: alertmanager - namespace: observability-system - labels: - app.kubernetes.io/name: alertmanager - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/vso.yaml deleted file mode 100644 index 09c3fde20..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/vso.yaml +++ /dev/null @@ -1,44 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: alertmanager - namespace: observability-system - labels: - app.kubernetes.io/name: alertmanager - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: observability-system-alertmanager - serviceAccount: alertmanager ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: alertmanager-platform-alertmanager-discord - namespace: observability-system - labels: - app.kubernetes.io/name: alertmanager - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - vaultAuthRef: alertmanager - mount: secret - type: kv-v2 - path: platform/alertmanager-discord - refreshAfter: 10m - hmacSecretData: true - destination: - name: alertmanager-platform-alertmanager-discord - create: true - annotations: - flagger.app/config-tracking: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/workload.yaml deleted file mode 100644 index 77fa163d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alertmanager/workload.yaml +++ /dev/null @@ -1,96 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: Alertmanager -metadata: - name: alertmanager - namespace: observability-system - labels: - app.kubernetes.io/name: alertmanager - app.kubernetes.io/instance: alertmanager - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - image: quay.io/prometheus/alertmanager@sha256:4e6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f7e1f3c5a9b2d4f6e8a0c2e4b6d8f5a2c - version: v0.28.1 - replicas: 1 - serviceAccountName: alertmanager - automountServiceAccountToken: false - podMetadata: - labels: - app.kubernetes.io/part-of: alertmanager - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/alertmanager: v0.28.1 - portName: http - securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - resources: - requests: - memory: 128Mi - cpu: 50m - limits: - memory: 128Mi - containers: - - name: alertmanager - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-alertmanager - mountPath: /alertmanager - readinessProbe: - httpGet: - path: /-/ready - port: 9093 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /-/healthy - port: 9093 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /-/healthy - port: 9093 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: writable-alertmanager - emptyDir: - sizeLimit: 64Mi - alertmanagerConfigSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - alertmanagerConfigMatcherStrategy: - type: None diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/canary.yaml deleted file mode 100644 index 9ce5ed044..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/canary.yaml +++ /dev/null @@ -1,69 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: alloy - namespace: observability-system - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: alloy - progressDeadlineSeconds: 210 - service: - port: 12345 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: alloy - process: alloy - revision: sha256:85d70bd1e948612d073b7f7cf90001f9bcecdc701d30c544ab7453d485384115 - readiness: /-/ready - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: alloy - process: alloy - revision: sha256:85d70bd1e948612d073b7f7cf90001f9bcecdc701d30c544ab7453d485384115 - readiness: /-/ready - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: alloy - process: alloy - revision: sha256:85d70bd1e948612d073b7f7cf90001f9bcecdc701d30c544ab7453d485384115 - readiness: /-/ready - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: alloy - process: alloy - revision: sha256:85d70bd1e948612d073b7f7cf90001f9bcecdc701d30c544ab7453d485384115 - readiness: /-/ready - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/configmap.yaml deleted file mode 100644 index 876e71832..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/configmap.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: alloy-release-gate - namespace: observability-system - labels: - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"210s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"alloy","readiness":{"path":"/-/ready","port":12345}}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/kustomization.yaml deleted file mode 100644 index f7b15e947..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - rbac.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/networkpolicy.yaml deleted file mode 100644 index 8c9d7d222..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/networkpolicy.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: alloy - namespace: observability-system - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: alloy - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/alloy.http: "true" - ports: - - protocol: TCP - port: 12345 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 12345 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/rbac.yaml deleted file mode 100644 index 62a735885..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/rbac.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-alloy - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - pods - - pods/log - - namespaces - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-alloy - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-alloy -subjects: - - kind: ServiceAccount - name: alloy - namespace: observability-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/serviceaccount.yaml deleted file mode 100644 index ee68ebfbc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: alloy - namespace: observability-system - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/workload.yaml deleted file mode 100644 index 08b2153c9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/alloy/workload.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: alloy - namespace: observability-system - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - template: - metadata: - labels: - app.kubernetes.io/name: alloy - app.kubernetes.io/instance: alloy - app.kubernetes.io/part-of: alloy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/alloy: 1.7.1 - spec: - serviceAccountName: alloy - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 473 - runAsGroup: 473 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: alloy - image: docker.io/grafana/alloy@sha256:65d9d6c5c7c2d5c29e38b777edf8da1dbd764f67deeeaa230724967cafe4e684 - ports: - - name: http - containerPort: 12345 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /-/ready - port: 12345 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /-/ready - port: 12345 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /-/ready - port: 12345 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/networkpolicy.yaml deleted file mode 100644 index f04393ce4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/networkpolicy.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: gatus - namespace: observability-system - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: gatus - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/gatus.http: "true" - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/rbac.yaml deleted file mode 100644 index b54aa0e0a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/rbac.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-gatus - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-gatus - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-gatus -subjects: - - kind: ServiceAccount - name: gatus - namespace: observability-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/service.yaml deleted file mode 100644 index fa623df78..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: gatus - namespace: observability-system - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: gatus - ports: - - name: http - port: 8080 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/serviceaccount.yaml deleted file mode 100644 index e9f00d112..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: gatus - namespace: observability-system - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/workload.yaml deleted file mode 100644 index 33e8a5923..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/gatus/workload.yaml +++ /dev/null @@ -1,113 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: gatus - namespace: observability-system - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - template: - metadata: - labels: - app.kubernetes.io/name: gatus - app.kubernetes.io/instance: gatus - app.kubernetes.io/part-of: gatus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/checks: 1.0.0 - image.jorisjonkers.dev/gatus: 5.17.0 - spec: - serviceAccountName: gatus - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: gatus - image: ghcr.io/twin/gatus@sha256:421c15f697f7992eb00e61643a4284e8d2f57bcc2eabea3639459fa1040add33 - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 64Mi - cpu: 20m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /health - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /health - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /health - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - - name: checks - image: ghcr.io/jorisjonkers-dev/platform/gatus-checks@sha256:a542f60b6e21372a737b4f4dd62c5fd41d76939818b57b0ebb46b650f29dcd5a - resources: - requests: - memory: 32Mi - cpu: 10m - limits: - memory: 32Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/networkpolicy.yaml deleted file mode 100644 index 5cad1efcc..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/networkpolicy.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: grafana-operator - namespace: observability-system - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: grafana-operator - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/grafana-operator.metrics: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/grafana-operator.health: "true" - ports: - - protocol: TCP - port: 8081 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/rbac.yaml deleted file mode 100644 index e552a630c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/rbac.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-grafana-operator - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - grafana.integreatly.org - resources: - - grafanas - - grafanas/status - - grafanadashboards - - grafanadashboards/status - verbs: - - get - - list - - watch - - update - - patch - - apiGroups: - - "" - resources: - - configmaps - - secrets - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-grafana-operator - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-grafana-operator -subjects: - - kind: ServiceAccount - name: grafana-operator - namespace: observability-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/service.yaml deleted file mode 100644 index 90c56dc8a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/service.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: grafana-operator - namespace: observability-system - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: grafana-operator - ports: - - name: metrics - port: 8080 - targetPort: metrics - - name: health - port: 8081 - targetPort: health diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/serviceaccount.yaml deleted file mode 100644 index 699ca11dd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: grafana-operator - namespace: observability-system - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/workload.yaml deleted file mode 100644 index 548fa4071..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana-operator/workload.yaml +++ /dev/null @@ -1,100 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: grafana-operator - namespace: observability-system - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - template: - metadata: - labels: - app.kubernetes.io/name: grafana-operator - app.kubernetes.io/instance: grafana-operator - app.kubernetes.io/part-of: grafana-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/grafana-operator: 5.17.0 - spec: - serviceAccountName: grafana-operator - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: grafana-operator - image: ghcr.io/grafana/grafana-operator@sha256:5689f1966f7e00acd0cdcff38ae0fc49d66469b384af9139412d645439937c2d - ports: - - name: metrics - containerPort: 8080 - - name: health - containerPort: 8081 - resources: - requests: - memory: 64Mi - cpu: 20m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /healthz - port: 8081 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 8081 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 8081 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/canary.yaml deleted file mode 100644 index 70d184684..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/canary.yaml +++ /dev/null @@ -1,77 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: grafana - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: grafana - progressDeadlineSeconds: 210 - service: - port: 3000 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: grafana - process: grafana - revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - paths: / - readiness: /api/health - hostnames: grafana.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: grafana - process: grafana - revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - paths: / - readiness: /api/health - hostnames: grafana.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: grafana - process: grafana - revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - paths: / - readiness: /api/health - hostnames: grafana.jorisjonkers.dev - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: grafana - process: grafana - revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - paths: / - readiness: /api/health - hostnames: grafana.jorisjonkers.dev - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/client.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/client.yaml deleted file mode 100644 index a5d856f6b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/client.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: identity.jorisjonkers.dev/v1 -kind: Client -metadata: - name: grafana - labels: - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit -spec: - signIn: native - host: grafana.jorisjonkers.dev - launchUrl: https://grafana.jorisjonkers.dev/ - iconUrl: https://grafana.jorisjonkers.dev/public/img/grafana_icon.svg - redirectUris: - - https://grafana.jorisjonkers.dev/login/generic_oauth - credential: secret - secretPath: secret/data/observability-system/grafana/client - roles: - - user - - viewer - - editor - - admin - label: Grafana - description: Metrics and dashboards diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/configmap.yaml deleted file mode 100644 index 5957d2a66..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: grafana-release-gate - namespace: observability-system - labels: - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"210s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"grafana","readiness":{"path":"/api/health","port":3000}}],"protectedBy":"grafana","protectedPath":"/api/user"} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: grafana-external-checks - namespace: observability-system - labels: - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - grafana-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"observability","name":"grafana-public-1","url":"https://grafana.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/grafana.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/grafana.yaml deleted file mode 100644 index 430e042a2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/grafana.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: grafana.integreatly.org/v1beta1 -kind: Grafana -metadata: - name: grafana - namespace: observability-system - labels: - dashboards: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit -spec: - external: - url: http://grafana.observability-system:3000 - adminUser: - name: grafana-observability-system-grafana-admin - key: user - adminPassword: - name: grafana-observability-system-grafana-admin - key: password diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/kustomization.yaml deleted file mode 100644 index 1781af062..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/kustomization.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - client.yaml - - configmap.yaml - - grafana.yaml - - route-public.yaml - - serviceaccount.yaml - - vso.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/networkpolicy.yaml deleted file mode 100644 index e2e976985..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/networkpolicy.yaml +++ /dev/null @@ -1,73 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: grafana - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: grafana - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-public - ports: - - protocol: TCP - port: 3000 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/grafana.http: "true" - ports: - - protocol: TCP - port: 3000 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 3000 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: UDP - port: 8200 - - protocol: TCP - port: 8200 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/route-public.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/route-public.yaml deleted file mode 100644 index 4899f0bd6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/route-public.yaml +++ /dev/null @@ -1,30 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: grafana-public - namespace: observability-system - labels: - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-public - external-dns.alpha.kubernetes.io/target: ingress.jorisjonkers.dev - external-dns.alpha.kubernetes.io/cloudflare-proxied: "true" -spec: - entryPoints: - - websecure - routes: - - kind: Rule - match: Host(`grafana.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: grafana - namespace: observability-system - port: 3000 - tls: - certResolver: public-frankfurt diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/serviceaccount.yaml deleted file mode 100644 index cb88e0bec..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: grafana - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/vso.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/vso.yaml deleted file mode 100644 index 6e22d6778..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/vso.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultAuth -metadata: - name: grafana - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - estate.jorisjonkers.dev/revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: observability-system-grafana - serviceAccount: grafana ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: grafana-observability-system-grafana-client - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - estate.jorisjonkers.dev/revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - vaultAuthRef: grafana - mount: secret - type: kv-v2 - path: observability-system/grafana/client - refreshAfter: 10m - hmacSecretData: true - destination: - name: grafana-observability-system-grafana-client - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: grafana-primary ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultStaticSecret -metadata: - name: grafana-observability-system-grafana-admin - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - estate.jorisjonkers.dev/revision: sha256:bb7204ad30e9f8f597b47042633308a8039ee4b9fe6816eab1b409655b088037 - kustomize.toolkit.fluxcd.io/prune: disabled -spec: - vaultAuthRef: grafana - mount: secret - type: kv-v2 - path: observability-system/grafana-admin - refreshAfter: 10m - hmacSecretData: true - destination: - name: grafana-observability-system-grafana-admin - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: Deployment - name: grafana-primary diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/workload.yaml deleted file mode 100644 index 71f98580e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/grafana/workload.yaml +++ /dev/null @@ -1,126 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: grafana - namespace: observability-system - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - template: - metadata: - labels: - app.kubernetes.io/name: grafana - app.kubernetes.io/instance: grafana - app.kubernetes.io/part-of: grafana - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/grafana: 12.2.0 - spec: - serviceAccountName: grafana - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 472 - runAsGroup: 472 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: grafana - image: docker.io/grafana/grafana@sha256:2c4e6a8b0d2f4c6e8a0b2d4f6c8e0a2b4d6f8c0e2a4b6d8f0c2e4a6b8d0f2c4e - ports: - - name: http - containerPort: 3000 - env: - - name: GF_AUTH_DISABLE_LOGIN_FORM - value: "true" - - name: GF_AUTH_GENERIC_OAUTH_API_URL - value: https://id.jorisjonkers.dev/userinfo - - name: GF_AUTH_GENERIC_OAUTH_AUTH_URL - value: https://id.jorisjonkers.dev/oauth2/authorize - - name: GF_AUTH_GENERIC_OAUTH_CLIENT_ID - value: grafana - - name: GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: grafana-observability-system-grafana-client - key: secret - - name: GF_AUTH_GENERIC_OAUTH_ENABLED - value: "true" - - name: GF_AUTH_GENERIC_OAUTH_NAME - value: jorisjonkers.dev - - name: GF_AUTH_GENERIC_OAUTH_SCOPES - value: openid,profile,email - - name: GF_AUTH_GENERIC_OAUTH_TOKEN_URL - value: https://id.jorisjonkers.dev/oauth2/token - - name: GF_SECURITY_ADMIN_PASSWORD - valueFrom: - secretKeyRef: - name: grafana-observability-system-grafana-admin - key: password - - name: GF_SECURITY_ADMIN_USER - valueFrom: - secretKeyRef: - name: grafana-observability-system-grafana-admin - key: user - - name: GF_SERVER_ROOT_URL - value: https://grafana.jorisjonkers.dev - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-var-lib-grafana - mountPath: /var/lib/grafana - readinessProbe: - httpGet: - path: /api/health - port: 3000 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - volumes: - - name: writable-var-lib-grafana - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/canary.yaml deleted file mode 100644 index 883a33420..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/canary.yaml +++ /dev/null @@ -1,69 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: kube-state-metrics - namespace: observability-system - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: kube-state-metrics - progressDeadlineSeconds: 210 - service: - port: 8080 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: kube-state-metrics - process: kube-state-metrics - revision: sha256:2193c1c60acedf71736b49fb4c5a7d1cab725c5a383d968c13bc29fa1c28c22a - readiness: /livez - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: kube-state-metrics - process: kube-state-metrics - revision: sha256:2193c1c60acedf71736b49fb4c5a7d1cab725c5a383d968c13bc29fa1c28c22a - readiness: /livez - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: kube-state-metrics - process: kube-state-metrics - revision: sha256:2193c1c60acedf71736b49fb4c5a7d1cab725c5a383d968c13bc29fa1c28c22a - readiness: /livez - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: kube-state-metrics - process: kube-state-metrics - revision: sha256:2193c1c60acedf71736b49fb4c5a7d1cab725c5a383d968c13bc29fa1c28c22a - readiness: /livez - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/configmap.yaml deleted file mode 100644 index e1a596bd6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/configmap.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: kube-state-metrics-release-gate - namespace: observability-system - labels: - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"210s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"kube-state-metrics","readiness":{"path":"/livez","port":8080}}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/kustomization.yaml deleted file mode 100644 index f7b15e947..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - rbac.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/networkpolicy.yaml deleted file mode 100644 index c4f64ce16..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/networkpolicy.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: kube-state-metrics - namespace: observability-system - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: kube-state-metrics - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/kube-state-metrics.http: "true" - ports: - - protocol: TCP - port: 8080 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/kube-state-metrics.telemetry: "true" - ports: - - protocol: TCP - port: 8081 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/rbac.yaml deleted file mode 100644 index 3dae2a0b3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/rbac.yaml +++ /dev/null @@ -1,62 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-kube-state-metrics - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - pods - - nodes - - namespaces - - services - - persistentvolumeclaims - - persistentvolumes - verbs: - - list - - watch - - apiGroups: - - apps - resources: - - deployments - - statefulsets - - daemonsets - - replicasets - verbs: - - list - - watch - - apiGroups: - - batch - resources: - - jobs - - cronjobs - verbs: - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-kube-state-metrics - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-kube-state-metrics -subjects: - - kind: ServiceAccount - name: kube-state-metrics - namespace: observability-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/serviceaccount.yaml deleted file mode 100644 index 71ced0f35..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: kube-state-metrics - namespace: observability-system - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/workload.yaml deleted file mode 100644 index 6585074c2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kube-state-metrics/workload.yaml +++ /dev/null @@ -1,103 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: kube-state-metrics - namespace: observability-system - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - template: - metadata: - labels: - app.kubernetes.io/name: kube-state-metrics - app.kubernetes.io/instance: kube-state-metrics - app.kubernetes.io/part-of: kube-state-metrics - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/kube-state-metrics: 2.15.0 - spec: - serviceAccountName: kube-state-metrics - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: kube-state-metrics - image: registry.k8s.io/kube-state-metrics/kube-state-metrics@sha256:6e9bea4d3f394ba14fe405f6027d4d2187f751814702d595a0f68a9cc679171c - ports: - - name: http - containerPort: 8080 - - name: telemetry - containerPort: 8081 - resources: - requests: - memory: 128Mi - cpu: 20m - limits: - memory: 128Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /livez - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /livez - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /livez - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kustomization.yaml deleted file mode 100644 index a4190489c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/kustomization.yaml +++ /dev/null @@ -1,21 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alertmanager - - alloy - - gatus - - grafana - - grafana-operator - - kube-state-metrics - - loki - - namespace.yaml - - otel-collector - - prometheus - - prometheus-operator - - pyroscope - - rollout-events - - tempo - - vault-policy - - vaultconnection.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/kustomization.yaml deleted file mode 100644 index 71ff1ac70..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/networkpolicy.yaml deleted file mode 100644 index 99ad9a385..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/networkpolicy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: loki - namespace: observability-system - labels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - app.kubernetes.io/part-of: loki - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: loki - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/loki.http: "true" - ports: - - protocol: TCP - port: 3100 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/pvc.yaml deleted file mode 100644 index 4f237993e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/pvc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: loki - namespace: observability-system - labels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - app.kubernetes.io/part-of: loki - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/service.yaml deleted file mode 100644 index ae39e9764..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: loki - namespace: observability-system - labels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - app.kubernetes.io/part-of: loki - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: loki - ports: - - name: http - port: 3100 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/serviceaccount.yaml deleted file mode 100644 index ae5fb1af7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: loki - namespace: observability-system - labels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - app.kubernetes.io/part-of: loki - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/workload.yaml deleted file mode 100644 index 9b421e986..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/loki/workload.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: loki - namespace: observability-system - labels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - app.kubernetes.io/part-of: loki - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - template: - metadata: - labels: - app.kubernetes.io/name: loki - app.kubernetes.io/instance: loki - app.kubernetes.io/part-of: loki - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/loki: 3.4.2 - spec: - serviceAccountName: loki - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 10001 - runAsGroup: 10001 - fsGroup: 10001 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: loki - image: docker.io/grafana/loki@sha256:982945308d3682d16636fd628c314e293499e99c00120acd9b693f5ab16e1648 - ports: - - name: http - containerPort: 3100 - resources: - requests: - memory: 512Mi - cpu: 100m - limits: - memory: 512Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: loki - mountPath: /loki - readinessProbe: - httpGet: - path: /ready - port: 3100 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /ready - port: 3100 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /ready - port: 3100 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: loki - persistentVolumeClaim: - claimName: loki diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/namespace.yaml deleted file mode 100644 index 443be6782..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: observability-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/networkpolicy.yaml deleted file mode 100644 index 2848c1891..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: observability-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/canary.yaml deleted file mode 100644 index fba37a553..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/canary.yaml +++ /dev/null @@ -1,69 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: otel-collector - namespace: observability-system - labels: - app.kubernetes.io/name: otel-collector - app.kubernetes.io/instance: otel-collector - app.kubernetes.io/part-of: otel-collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: otel-collector - progressDeadlineSeconds: 180 - service: - port: 4317 - targetPort: otlp - portName: otlp - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: otel-collector - process: otel-collector - revision: sha256:4bcdab7f158cf8d299aa2970116d870a1dd481e1a861082d99409a4d43d4fe29 - readiness: / - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: otel-collector - process: otel-collector - revision: sha256:4bcdab7f158cf8d299aa2970116d870a1dd481e1a861082d99409a4d43d4fe29 - readiness: / - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: otel-collector - process: otel-collector - revision: sha256:4bcdab7f158cf8d299aa2970116d870a1dd481e1a861082d99409a4d43d4fe29 - readiness: / - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: otel-collector - process: otel-collector - revision: sha256:4bcdab7f158cf8d299aa2970116d870a1dd481e1a861082d99409a4d43d4fe29 - readiness: / - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/configmap.yaml deleted file mode 100644 index fc5ef55b2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/configmap.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: otel-collector-release-gate - namespace: observability-system - labels: - app.kubernetes.io/part-of: otel-collector - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"180s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"otel-collector","readiness":{"path":"/","port":13133}}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/kustomization.yaml deleted file mode 100644 index 058323d97..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/networkpolicy.yaml deleted file mode 100644 index a71195006..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/networkpolicy.yaml +++ /dev/null @@ -1,61 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: otel-collector - namespace: observability-system - labels: - app.kubernetes.io/name: otel-collector - app.kubernetes.io/instance: otel-collector - app.kubernetes.io/part-of: otel-collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: otel-collector - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/otel-collector.otlp: "true" - ports: - - protocol: TCP - port: 4317 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/otel-collector.health: "true" - ports: - - protocol: TCP - port: 13133 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 4317 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/serviceaccount.yaml deleted file mode 100644 index 0ece166ed..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: otel-collector - namespace: observability-system - labels: - app.kubernetes.io/name: otel-collector - app.kubernetes.io/instance: otel-collector - app.kubernetes.io/part-of: otel-collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/workload.yaml deleted file mode 100644 index b5db56ccd..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/otel-collector/workload.yaml +++ /dev/null @@ -1,103 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: otel-collector - namespace: observability-system - labels: - app.kubernetes.io/name: otel-collector - app.kubernetes.io/instance: otel-collector - app.kubernetes.io/part-of: otel-collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 180 - selector: - matchLabels: - app.kubernetes.io/name: otel-collector - app.kubernetes.io/instance: otel-collector - template: - metadata: - labels: - app.kubernetes.io/name: otel-collector - app.kubernetes.io/instance: otel-collector - app.kubernetes.io/part-of: otel-collector - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/otel-collector: 0.120.0 - spec: - serviceAccountName: otel-collector - priorityClassName: platform-critical-app - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 10001 - runAsGroup: 10001 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: otel-collector - image: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-contrib@sha256:8e2c4a6f0b1d3e5a7c9f2b4d6e8a0c1f3b5d7e9a2c4f6b8d0e1a3c5f7b9d2e4a - ports: - - name: otlp - containerPort: 4317 - - name: health - containerPort: 13133 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: / - port: 13133 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: / - port: 13133 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: / - port: 13133 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 4 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/kustomization.yaml deleted file mode 100644 index cfe9cd666..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/networkpolicy.yaml deleted file mode 100644 index 8043b819d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/networkpolicy.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: prometheus-operator - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus-operator - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/prometheus-operator.http: "true" - ports: - - protocol: TCP - port: 8080 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/rbac.yaml deleted file mode 100644 index 68ed9dc1a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/rbac.yaml +++ /dev/null @@ -1,79 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-prometheus-operator - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - monitoring.coreos.com - resources: - - prometheuses - - prometheuses/status - - alertmanagers - - alertmanagers/status - - servicemonitors - - podmonitors - - prometheusrules - - alertmanagerconfigs - verbs: - - get - - list - - watch - - create - - update - - patch - - delete - - apiGroups: - - "" - resources: - - services - - endpoints - - pods - - nodes - - namespaces - - configmaps - - secrets - verbs: - - get - - list - - watch - - create - - update - - delete - - apiGroups: - - apps - resources: - - statefulsets - verbs: - - get - - list - - watch - - create - - update - - delete ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-prometheus-operator - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-prometheus-operator -subjects: - - kind: ServiceAccount - name: prometheus-operator - namespace: observability-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/service.yaml deleted file mode 100644 index ff0be2b1d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: prometheus-operator - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: prometheus-operator - ports: - - name: http - port: 8080 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/serviceaccount.yaml deleted file mode 100644 index eb2f601cf..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: prometheus-operator - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/workload.yaml deleted file mode 100644 index ad76cecae..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus-operator/workload.yaml +++ /dev/null @@ -1,98 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: prometheus-operator - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - template: - metadata: - labels: - app.kubernetes.io/name: prometheus-operator - app.kubernetes.io/instance: prometheus-operator - app.kubernetes.io/part-of: prometheus-operator - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/prometheus-operator: 0.81.0 - spec: - serviceAccountName: prometheus-operator - priorityClassName: platform-critical-app - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: prometheus-operator - image: quay.io/prometheus-operator/prometheus-operator@sha256:b32bec04dd57ec4c604c3f72b7103224b6006922536099eb5e92c017524819c6 - ports: - - name: http - containerPort: 8080 - resources: - requests: - memory: 128Mi - cpu: 50m - limits: - memory: 128Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /healthz - port: 8080 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/alertrules.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/alertrules.yaml deleted file mode 100644 index 489eadd1c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/alertrules.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: PrometheusRule -metadata: - name: prometheus-platform - namespace: observability-system - labels: - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - groups: - - name: platform - rules: - - alert: JobFailed - expr: kube_job_status_failed > 0 - for: 5m - labels: - severity: warning - annotations: - summary: Job {{ $labels.namespace }}/{{ $labels.job_name }} failed - - alert: TargetDown - expr: up == 0 - for: 10m - labels: - severity: critical - annotations: - summary: "{{ $labels.job }} on {{ $labels.instance }} is down" diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/flux-podmonitor.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/flux-podmonitor.yaml deleted file mode 100644 index 81c18ed94..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/flux-podmonitor.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: PodMonitor -metadata: - name: flux-controllers - namespace: observability-system - labels: - release: metrics-stack - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - jobLabel: app - selector: - matchLabels: - app.kubernetes.io/part-of: flux - namespaceSelector: - matchNames: - - flux-system - podMetricsEndpoints: - - portNumber: 8080 - path: /metrics - interval: 30s - scrapeTimeout: 10s diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/k3s-monitors.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/k3s-monitors.yaml deleted file mode 100644 index 54b65a71d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/k3s-monitors.yaml +++ /dev/null @@ -1,261 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Secret -metadata: - name: prometheus-token - namespace: observability-system - labels: - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/service-account.name: prometheus -type: kubernetes.io/service-account-token ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-prometheus-k3s - labels: - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -rules: - - apiGroups: - - "" - resources: - - nodes - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - nodes/metrics - verbs: - - get - - nonResourceURLs: - - /metrics - verbs: - - get ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-prometheus-k3s - labels: - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-prometheus-k3s -subjects: - - kind: ServiceAccount - name: prometheus - namespace: observability-system ---- -apiVersion: monitoring.coreos.com/v1alpha1 -kind: ScrapeConfig -metadata: - name: kubelet - namespace: observability-system - labels: - release: metrics-stack - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - jobName: kubelet - kubernetesSDConfigs: - - role: Node - scheme: HTTPS - metricsPath: /metrics - scrapeInterval: 30s - scrapeTimeout: 10s - honorLabels: true - honorTimestamps: true - authorization: - type: Bearer - credentials: - name: prometheus-token - key: token - tlsConfig: - insecureSkipVerify: true - relabelings: - - sourceLabels: - - __address__ - regex: (.+):\d+ - replacement: $1:10250 - targetLabel: __address__ - - sourceLabels: - - __meta_kubernetes_node_name - targetLabel: node - - sourceLabels: - - __metrics_path__ - targetLabel: metrics_path ---- -apiVersion: monitoring.coreos.com/v1alpha1 -kind: ScrapeConfig -metadata: - name: kubelet-cadvisor - namespace: observability-system - labels: - release: metrics-stack - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - jobName: kubelet - kubernetesSDConfigs: - - role: Node - scheme: HTTPS - metricsPath: /metrics/cadvisor - scrapeInterval: 30s - scrapeTimeout: 10s - honorLabels: true - honorTimestamps: true - authorization: - type: Bearer - credentials: - name: prometheus-token - key: token - tlsConfig: - insecureSkipVerify: true - relabelings: - - sourceLabels: - - __address__ - regex: (.+):\d+ - replacement: $1:10250 - targetLabel: __address__ - - sourceLabels: - - __meta_kubernetes_node_name - targetLabel: node - - sourceLabels: - - __metrics_path__ - targetLabel: metrics_path - metricRelabelings: - - action: drop - sourceLabels: - - __name__ - regex: container_cpu_(cfs_throttled_seconds_total|load_average_10s|system_seconds_total|user_seconds_total) - - action: drop - sourceLabels: - - __name__ - regex: container_fs_(io_current|io_time_seconds_total|io_time_weighted_seconds_total|reads_merged_total|sector_reads_total|sector_writes_total|writes_merged_total) - - action: drop - sourceLabels: - - __name__ - regex: container_memory_(mapped_file|swap) - - action: drop - sourceLabels: - - __name__ - regex: container_(file_descriptors|tasks_state|threads_max) - - action: drop - sourceLabels: - - __name__ - regex: container_spec.* ---- -apiVersion: monitoring.coreos.com/v1alpha1 -kind: ScrapeConfig -metadata: - name: kubelet-probes - namespace: observability-system - labels: - release: metrics-stack - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - jobName: kubelet - kubernetesSDConfigs: - - role: Node - scheme: HTTPS - metricsPath: /metrics/probes - scrapeInterval: 30s - scrapeTimeout: 10s - honorLabels: true - honorTimestamps: true - authorization: - type: Bearer - credentials: - name: prometheus-token - key: token - tlsConfig: - insecureSkipVerify: true - relabelings: - - sourceLabels: - - __address__ - regex: (.+):\d+ - replacement: $1:10250 - targetLabel: __address__ - - sourceLabels: - - __meta_kubernetes_node_name - targetLabel: node - - sourceLabels: - - __metrics_path__ - targetLabel: metrics_path ---- -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: apiserver - namespace: observability-system - labels: - release: metrics-stack - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - jobLabel: component - selector: - matchLabels: - component: apiserver - provider: kubernetes - namespaceSelector: - matchNames: - - default - endpoints: - - port: https - scheme: https - interval: 30s - scrapeTimeout: 10s - authorization: - type: Bearer - credentials: - name: prometheus-token - key: token - tlsConfig: - ca: - configMap: - name: kube-root-ca.crt - key: ca.crt - serverName: kubernetes - metricRelabelings: - - action: drop - sourceLabels: - - __name__ - - le - regex: (etcd_request|apiserver_request_slo|apiserver_request_sli|apiserver_request)_duration_seconds_bucket;(0\.15|0\.2|0\.3|0\.35|0\.4|0\.45|0\.6|0\.7|0\.8|0\.9|1\.25|1\.5|1\.75|2|3|3\.5|4|4\.5|6|7|8|9|15|20|40|45|50)(\.0)? ---- -apiVersion: monitoring.coreos.com/v1 -kind: PodMonitor -metadata: - name: coredns - namespace: observability-system - labels: - release: metrics-stack - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit -spec: - jobLabel: k8s-app - selector: - matchLabels: - k8s-app: kube-dns - namespaceSelector: - matchNames: - - kube-system - podMetricsEndpoints: - - portNumber: 9153 - path: /metrics - interval: 30s - scrapeTimeout: 10s - relabelings: - - targetLabel: job - replacement: coredns diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/kustomization.yaml deleted file mode 100644 index e89f5ac02..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/kustomization.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alertrules.yaml - - flux-podmonitor.yaml - - k3s-monitors.yaml - - rbac.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/networkpolicy.yaml deleted file mode 100644 index 5f341be3c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/networkpolicy.yaml +++ /dev/null @@ -1,107 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: prometheus - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus - app.kubernetes.io/instance: prometheus - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: prometheus - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/prometheus.http: "true" - ports: - - protocol: TCP - port: 9090 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: postgres - ports: - - protocol: UDP - port: 9187 - - protocol: TCP - port: 9187 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: data-system - podSelector: - matchLabels: - app.kubernetes.io/instance: rabbitmq - ports: - - protocol: UDP - port: 15692 - - protocol: TCP - port: 15692 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: UDP - port: 8080 - - protocol: TCP - port: 8080 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: notes-system - podSelector: - matchLabels: - app.kubernetes.io/instance: notes-api - ports: - - protocol: UDP - port: 8080 - - protocol: TCP - port: 8080 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: flux-system - podSelector: - matchLabels: - app.kubernetes.io/part-of: flux - ports: - - protocol: UDP - port: 8080 - - protocol: TCP - port: 8080 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/rbac.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/rbac.yaml deleted file mode 100644 index ce695861b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/rbac.yaml +++ /dev/null @@ -1,50 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: observability-system-prometheus - labels: - app.kubernetes.io/name: prometheus - app.kubernetes.io/instance: prometheus - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -rules: - - apiGroups: - - "" - resources: - - services - - endpoints - - pods - verbs: - - get - - list - - watch - - apiGroups: - - discovery.k8s.io - resources: - - endpointslices - verbs: - - get - - list - - watch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: observability-system-prometheus - labels: - app.kubernetes.io/name: prometheus - app.kubernetes.io/instance: prometheus - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: observability-system-prometheus -subjects: - - kind: ServiceAccount - name: prometheus - namespace: observability-system diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/service.yaml deleted file mode 100644 index 664b3e9e9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: prometheus - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus - app.kubernetes.io/instance: prometheus - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: prometheus - ports: - - name: http - port: 9090 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/serviceaccount.yaml deleted file mode 100644 index 02907a2e8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: prometheus - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus - app.kubernetes.io/instance: prometheus - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/workload.yaml deleted file mode 100644 index 2ed5ccc14..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/prometheus/workload.yaml +++ /dev/null @@ -1,117 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: monitoring.coreos.com/v1 -kind: Prometheus -metadata: - name: prometheus - namespace: observability-system - labels: - app.kubernetes.io/name: prometheus - app.kubernetes.io/instance: prometheus - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - image: quay.io/prometheus/prometheus@sha256:4c6e8a0b2d4f6a8c0e2b4d6f8a0c2e4b6d8f0a2c4e6b8d0f2a4c6e8b0d2f4a6c - version: v3.2.1 - replicas: 1 - serviceAccountName: prometheus - automountServiceAccountToken: true - priorityClassName: platform-critical-app - podMetadata: - labels: - app.kubernetes.io/part-of: prometheus - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/prometheus: v3.2.1 - portName: http - securityContext: - runAsNonRoot: true - runAsUser: 65534 - runAsGroup: 65534 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - resources: - requests: - memory: 512Mi - cpu: 100m - limits: - memory: 512Mi - containers: - - name: prometheus - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-prometheus - mountPath: /prometheus - readinessProbe: - httpGet: - path: /-/ready - port: 9090 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /-/healthy - port: 9090 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /-/healthy - port: 9090 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 12 - volumes: - - name: writable-prometheus - emptyDir: - sizeLimit: 64Mi - scrapeInterval: 30s - scrapeTimeout: 10s - evaluationInterval: 30s - serviceMonitorSelector: - matchLabels: - release: metrics-stack - serviceMonitorNamespaceSelector: {} - podMonitorSelector: - matchLabels: - release: metrics-stack - podMonitorNamespaceSelector: {} - scrapeConfigSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - scrapeConfigNamespaceSelector: {} - ruleSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - ruleNamespaceSelector: {} - alerting: - alertmanagers: - - namespace: observability-system - name: alertmanager - port: http - apiVersion: v2 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/kustomization.yaml deleted file mode 100644 index 71ff1ac70..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/networkpolicy.yaml deleted file mode 100644 index 533e9fb90..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/networkpolicy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: pyroscope - namespace: observability-system - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - app.kubernetes.io/part-of: pyroscope - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: pyroscope - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/pyroscope.http: "true" - ports: - - protocol: TCP - port: 4040 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/pvc.yaml deleted file mode 100644 index ad4ae728f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/pvc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: pyroscope - namespace: observability-system - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - app.kubernetes.io/part-of: pyroscope - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/service.yaml deleted file mode 100644 index ed5318969..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: pyroscope - namespace: observability-system - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - app.kubernetes.io/part-of: pyroscope - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: pyroscope - ports: - - name: http - port: 4040 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/serviceaccount.yaml deleted file mode 100644 index 8ef5955a6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: pyroscope - namespace: observability-system - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - app.kubernetes.io/part-of: pyroscope - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/workload.yaml deleted file mode 100644 index 78b3d69d8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/pyroscope/workload.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: pyroscope - namespace: observability-system - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - app.kubernetes.io/part-of: pyroscope - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - template: - metadata: - labels: - app.kubernetes.io/name: pyroscope - app.kubernetes.io/instance: pyroscope - app.kubernetes.io/part-of: pyroscope - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/pyroscope: 1.12.0 - spec: - serviceAccountName: pyroscope - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 10001 - runAsGroup: 10001 - fsGroup: 10001 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: pyroscope - image: docker.io/grafana/pyroscope@sha256:af2bcaf32f82481f3d0138ebd1f99ba2ca96ac6104acac0a10ee9b193e5df2af - ports: - - name: http - containerPort: 4040 - resources: - requests: - memory: 512Mi - cpu: 100m - limits: - memory: 512Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: pyroscope - mountPath: /data - readinessProbe: - httpGet: - path: /ready - port: 4040 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /ready - port: 4040 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /ready - port: 4040 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: pyroscope - persistentVolumeClaim: - claimName: pyroscope diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/rollout-events/alert.yaml deleted file mode 100644 index 9446756a6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-observability - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-observability - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-observability - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/rollout-events/provider.yaml deleted file mode 100644 index 7ee2e7582..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-observability - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/kustomization.yaml deleted file mode 100644 index 71ff1ac70..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - pvc.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/networkpolicy.yaml deleted file mode 100644 index 46d0b765d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/networkpolicy.yaml +++ /dev/null @@ -1,41 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: tempo - namespace: observability-system - labels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - app.kubernetes.io/part-of: tempo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: tempo - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/tempo.http: "true" - ports: - - protocol: TCP - port: 3200 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/pvc.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/pvc.yaml deleted file mode 100644 index 9f0838def..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/pvc.yaml +++ /dev/null @@ -1,19 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: tempo - namespace: observability-system - labels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - app.kubernetes.io/part-of: tempo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 10Gi diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/service.yaml deleted file mode 100644 index f351b8ad3..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/service.yaml +++ /dev/null @@ -1,20 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: tempo - namespace: observability-system - labels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - app.kubernetes.io/part-of: tempo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - selector: - app.kubernetes.io/instance: tempo - ports: - - name: http - port: 3200 - targetPort: http diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/serviceaccount.yaml deleted file mode 100644 index 603601cc9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: tempo - namespace: observability-system - labels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - app.kubernetes.io/part-of: tempo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/workload.yaml deleted file mode 100644 index ee18b6ac6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/tempo/workload.yaml +++ /dev/null @@ -1,105 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: tempo - namespace: observability-system - labels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - app.kubernetes.io/part-of: tempo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - replicas: 1 - strategy: - type: Recreate - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - template: - metadata: - labels: - app.kubernetes.io/name: tempo - app.kubernetes.io/instance: tempo - app.kubernetes.io/part-of: tempo - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/tempo: 2.7.1 - spec: - serviceAccountName: tempo - automountServiceAccountToken: false - securityContext: - runAsNonRoot: true - runAsUser: 10001 - runAsGroup: 10001 - fsGroup: 10001 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: tempo - image: docker.io/grafana/tempo@sha256:8d6546721a1d106cf8d27f7326ebae7e83c1592aeb7479b8f7ec9d8d700d464f - ports: - - name: http - containerPort: 3200 - resources: - requests: - memory: 512Mi - cpu: 100m - limits: - memory: 512Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: tempo - mountPath: /var/tempo - readinessProbe: - httpGet: - path: /ready - port: 3200 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /ready - port: 3200 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /ready - port: 3200 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: tempo - persistentVolumeClaim: - claimName: tempo diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/configmap.yaml deleted file mode 100644 index dbb63d095..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/configmap.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: vault-policy-b2e608d67c17 - namespace: observability-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - observability-system-alertmanager.policy.json: | - {"path":{"secret/data/platform/alertmanager-discord":{"capabilities":["read"]},"secret/metadata/platform/alertmanager-discord":{"capabilities":["read"]}}} - observability-system-alertmanager.role.json: | - {"bound_service_account_names":["alertmanager"],"bound_service_account_namespaces":["observability-system"],"token_policies":["observability-system-alertmanager"]} - observability-system-grafana.policy.json: | - {"path":{"secret/data/observability-system/grafana-admin":{"capabilities":["read"]},"secret/data/observability-system/grafana/client":{"capabilities":["read"]},"secret/metadata/observability-system/grafana-admin":{"capabilities":["read"]},"secret/metadata/observability-system/grafana/client":{"capabilities":["read"]}}} - observability-system-grafana.role.json: | - {"bound_service_account_names":["grafana"],"bound_service_account_namespaces":["observability-system"],"token_policies":["observability-system-grafana"]} - observability-system.generated.json: | - {"keys":[{"bytes":32,"encoding":"hex","key":"password","path":"secret/data/observability-system/grafana-admin"},{"bytes":32,"encoding":"hex","key":"user","path":"secret/data/observability-system/grafana-admin"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/cronjob.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/cronjob.yaml deleted file mode 100644 index f69abddcf..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/cronjob.yaml +++ /dev/null @@ -1,101 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: CronJob -metadata: - name: vault-policy - namespace: observability-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-b2e608d67c17 - items: - - key: observability-system-alertmanager.policy.json - path: observability-system-alertmanager.policy.json - - key: observability-system-alertmanager.role.json - path: observability-system-alertmanager.role.json - - key: observability-system-grafana.policy.json - path: observability-system-grafana.policy.json - - key: observability-system-grafana.role.json - path: observability-system-grafana.role.json - - key: observability-system.generated.json - path: observability-system.generated.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/job.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/job.yaml deleted file mode 100644 index 66757a228..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/job.yaml +++ /dev/null @@ -1,91 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: batch/v1 -kind: Job -metadata: - name: vault-policy-b2e608d67c17 - namespace: observability-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled -spec: - backoffLimit: 2147483647 - template: - metadata: - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - image.jorisjonkers.dev/vault-policy: 1.0.0 - spec: - serviceAccountName: vault-policy - automountServiceAccountToken: true - restartPolicy: OnFailure - activeDeadlineSeconds: 120 - securityContext: - runAsNonRoot: true - runAsUser: 65532 - runAsGroup: 65532 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - frankfurt-contabo-1 - containers: - - name: vault-policy - image: ghcr.io/jorisjonkers-dev/delivery/vault-policy@sha256:c5e7a9b1d3f5c7e9a1b3d5f7c9e1a3b5d7f9c1e3a5b7d9f1c3e5a7b9d1f3c5e7 - env: - - name: VAULT_ADDR - value: http://vault.secrets-system.svc.cluster.local:8200 - - name: VAULT_ROLE - value: policy-admin - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: 64Mi - cpu: 10m - limits: - memory: 64Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: vault-policy-b2e608d67c17 - items: - - key: observability-system-alertmanager.policy.json - path: observability-system-alertmanager.policy.json - - key: observability-system-alertmanager.role.json - path: observability-system-alertmanager.role.json - - key: observability-system-grafana.policy.json - path: observability-system-grafana.policy.json - - key: observability-system-grafana.role.json - path: observability-system-grafana.role.json - - key: observability-system.generated.json - path: observability-system.generated.json diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/kustomization.yaml deleted file mode 100644 index e76d06118..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - configmap.yaml - - cronjob.yaml - - job.yaml - - serviceaccount.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/networkpolicy.yaml deleted file mode 100644 index 00bbfd21f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/networkpolicy.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: vault-policy - namespace: observability-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: vault-policy - policyTypes: - - Ingress - - Egress - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: secrets-system - podSelector: - matchLabels: - app.kubernetes.io/instance: vault - ports: - - protocol: TCP - port: 8200 - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.policy.json b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.policy.json deleted file mode 100644 index 56db5c5f8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "path": { - "secret/data/platform/alertmanager-discord": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/platform/alertmanager-discord": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.role.json b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.role.json deleted file mode 100644 index b63e93039..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-alertmanager.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "alertmanager" - ], - "bound_service_account_namespaces": [ - "observability-system" - ], - "token_policies": [ - "observability-system-alertmanager" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-grafana.policy.json b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-grafana.policy.json deleted file mode 100644 index 30a55dec1..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-grafana.policy.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "path": { - "secret/data/observability-system/grafana/client": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/observability-system/grafana/client": { - "capabilities": [ - "read" - ] - }, - "secret/data/observability-system/grafana-admin": { - "capabilities": [ - "read" - ] - }, - "secret/metadata/observability-system/grafana-admin": { - "capabilities": [ - "read" - ] - } - } -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-grafana.role.json b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-grafana.role.json deleted file mode 100644 index 5a3890685..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system-grafana.role.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "bound_service_account_names": [ - "grafana" - ], - "bound_service_account_namespaces": [ - "observability-system" - ], - "token_policies": [ - "observability-system-grafana" - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system.generated.json b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system.generated.json deleted file mode 100644 index ca961387e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/policies/observability-system.generated.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "keys": [ - { - "path": "secret/data/observability-system/grafana-admin", - "key": "password", - "bytes": 32, - "encoding": "hex" - }, - { - "path": "secret/data/observability-system/grafana-admin", - "key": "user", - "bytes": 32, - "encoding": "hex" - } - ] -} diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/serviceaccount.yaml deleted file mode 100644 index c09926c15..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vault-policy/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: vault-policy - namespace: observability-system - labels: - app.kubernetes.io/name: vault-policy - app.kubernetes.io/instance: vault-policy - app.kubernetes.io/part-of: vault-policy - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vaultconnection.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vaultconnection.yaml deleted file mode 100644 index 39db9c968..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/apps/observability/vaultconnection.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: secrets.hashicorp.com/v1beta1 -kind: VaultConnection -metadata: - name: secret-store - namespace: observability-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - address: http://vault.secrets-system.svc.cluster.local:8200 - skipTLSVerify: false diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/human-grants/clusterrolebindings.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/human-grants/clusterrolebindings.yaml deleted file mode 100644 index 86311f89c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/human-grants/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: human:oidc:k8s-admin:cluster-admin - labels: - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: oidc:k8s-admin diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/human-grants/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/human-grants/kustomization.yaml deleted file mode 100644 index 029015f5d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/human-grants/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - clusterrolebindings.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/priority-classes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/priority-classes/kustomization.yaml deleted file mode 100644 index 8b06a2f03..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/priority-classes/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/priority-classes/priorityclasses.yaml b/emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/priority-classes/priorityclasses.yaml deleted file mode 100644 index a304512d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/expected/estate/priority-classes/priorityclasses.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-data - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 1000000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "A datastore: it schedules before what reads it." ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-critical-app - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 100000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "The foundation and the Applications the platform names: they keep scheduling under pressure." diff --git a/emf/bundles/cli/src/test/resources/stages/render/observability/oracles b/emf/bundles/cli/src/test/resources/stages/render/observability/oracles deleted file mode 100644 index 12c601c71..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/observability/oracles +++ /dev/null @@ -1,104 +0,0 @@ -apps/observability/alertmanager/alertmanagerconfig.yaml observability/rendered/apps/observability/alertmanager/alertmanagerconfig.yaml -apps/observability/alertmanager/kustomization.yaml observability/rendered/apps/observability/alertmanager/kustomization.yaml -apps/observability/alertmanager/networkpolicy.yaml observability/rendered/apps/observability/alertmanager/networkpolicy.yaml -apps/observability/alertmanager/service.yaml observability/rendered/apps/observability/alertmanager/service.yaml -apps/observability/alertmanager/serviceaccount.yaml observability/rendered/apps/observability/alertmanager/serviceaccount.yaml -apps/observability/alertmanager/vso.yaml observability/rendered/apps/observability/alertmanager/vso.yaml -apps/observability/alertmanager/workload.yaml observability/rendered/apps/observability/alertmanager/workload.yaml -apps/observability/alloy/canary.yaml observability/rendered/apps/observability/alloy/canary.yaml -apps/observability/alloy/configmap.yaml observability/rendered/apps/observability/alloy/configmap.yaml -apps/observability/alloy/kustomization.yaml observability/rendered/apps/observability/alloy/kustomization.yaml -apps/observability/alloy/networkpolicy.yaml observability/rendered/apps/observability/alloy/networkpolicy.yaml -apps/observability/alloy/rbac.yaml observability/rendered/apps/observability/alloy/rbac.yaml -apps/observability/alloy/serviceaccount.yaml observability/rendered/apps/observability/alloy/serviceaccount.yaml -apps/observability/alloy/workload.yaml observability/rendered/apps/observability/alloy/workload.yaml -apps/observability/gatus/kustomization.yaml observability/rendered/apps/observability/gatus/kustomization.yaml -apps/observability/gatus/networkpolicy.yaml observability/rendered/apps/observability/gatus/networkpolicy.yaml -apps/observability/gatus/rbac.yaml observability/rendered/apps/observability/gatus/rbac.yaml -apps/observability/gatus/service.yaml observability/rendered/apps/observability/gatus/service.yaml -apps/observability/gatus/serviceaccount.yaml observability/rendered/apps/observability/gatus/serviceaccount.yaml -apps/observability/gatus/workload.yaml observability/rendered/apps/observability/gatus/workload.yaml -apps/observability/grafana-operator/kustomization.yaml observability/rendered/apps/observability/grafana-operator/kustomization.yaml -apps/observability/grafana-operator/networkpolicy.yaml observability/rendered/apps/observability/grafana-operator/networkpolicy.yaml -apps/observability/grafana-operator/rbac.yaml observability/rendered/apps/observability/grafana-operator/rbac.yaml -apps/observability/grafana-operator/service.yaml observability/rendered/apps/observability/grafana-operator/service.yaml -apps/observability/grafana-operator/serviceaccount.yaml observability/rendered/apps/observability/grafana-operator/serviceaccount.yaml -apps/observability/grafana-operator/workload.yaml observability/rendered/apps/observability/grafana-operator/workload.yaml -apps/observability/grafana/canary.yaml observability/rendered/apps/observability/grafana/canary.yaml -apps/observability/grafana/client.yaml observability/rendered/apps/observability/grafana/client.yaml -apps/observability/grafana/configmap.yaml observability/rendered/apps/observability/grafana/configmap.yaml -apps/observability/grafana/grafana.yaml observability/rendered/apps/observability/grafana/grafana.yaml -apps/observability/grafana/kustomization.yaml observability/rendered/apps/observability/grafana/kustomization.yaml -apps/observability/grafana/networkpolicy.yaml observability/rendered/apps/observability/grafana/networkpolicy.yaml -apps/observability/grafana/route-public.yaml observability/rendered/apps/observability/grafana/route-public.yaml -apps/observability/grafana/serviceaccount.yaml observability/rendered/apps/observability/grafana/serviceaccount.yaml -apps/observability/grafana/vso.yaml observability/rendered/apps/observability/grafana/vso.yaml -apps/observability/grafana/workload.yaml observability/rendered/apps/observability/grafana/workload.yaml -apps/observability/kube-state-metrics/canary.yaml observability/rendered/apps/observability/kube-state-metrics/canary.yaml -apps/observability/kube-state-metrics/configmap.yaml observability/rendered/apps/observability/kube-state-metrics/configmap.yaml -apps/observability/kube-state-metrics/kustomization.yaml observability/rendered/apps/observability/kube-state-metrics/kustomization.yaml -apps/observability/kube-state-metrics/networkpolicy.yaml observability/rendered/apps/observability/kube-state-metrics/networkpolicy.yaml -apps/observability/kube-state-metrics/rbac.yaml observability/rendered/apps/observability/kube-state-metrics/rbac.yaml -apps/observability/kube-state-metrics/serviceaccount.yaml observability/rendered/apps/observability/kube-state-metrics/serviceaccount.yaml -apps/observability/kube-state-metrics/workload.yaml observability/rendered/apps/observability/kube-state-metrics/workload.yaml -apps/observability/kustomization.yaml observability/rendered/apps/observability/kustomization.yaml -apps/observability/loki/kustomization.yaml observability/rendered/apps/observability/loki/kustomization.yaml -apps/observability/loki/networkpolicy.yaml observability/rendered/apps/observability/loki/networkpolicy.yaml -apps/observability/loki/pvc.yaml observability/rendered/apps/observability/loki/pvc.yaml -apps/observability/loki/service.yaml observability/rendered/apps/observability/loki/service.yaml -apps/observability/loki/serviceaccount.yaml observability/rendered/apps/observability/loki/serviceaccount.yaml -apps/observability/loki/workload.yaml observability/rendered/apps/observability/loki/workload.yaml -apps/observability/namespace.yaml observability/rendered/apps/observability/namespace.yaml -apps/observability/networkpolicy.yaml observability/rendered/apps/observability/networkpolicy.yaml -apps/observability/otel-collector/canary.yaml observability/rendered/apps/observability/otel-collector/canary.yaml -apps/observability/otel-collector/configmap.yaml observability/rendered/apps/observability/otel-collector/configmap.yaml -apps/observability/otel-collector/kustomization.yaml observability/rendered/apps/observability/otel-collector/kustomization.yaml -apps/observability/otel-collector/networkpolicy.yaml observability/rendered/apps/observability/otel-collector/networkpolicy.yaml -apps/observability/otel-collector/serviceaccount.yaml observability/rendered/apps/observability/otel-collector/serviceaccount.yaml -apps/observability/otel-collector/workload.yaml observability/rendered/apps/observability/otel-collector/workload.yaml -apps/observability/prometheus-operator/kustomization.yaml observability/rendered/apps/observability/prometheus-operator/kustomization.yaml -apps/observability/prometheus-operator/networkpolicy.yaml observability/rendered/apps/observability/prometheus-operator/networkpolicy.yaml -apps/observability/prometheus-operator/rbac.yaml observability/rendered/apps/observability/prometheus-operator/rbac.yaml -apps/observability/prometheus-operator/service.yaml observability/rendered/apps/observability/prometheus-operator/service.yaml -apps/observability/prometheus-operator/serviceaccount.yaml observability/rendered/apps/observability/prometheus-operator/serviceaccount.yaml -apps/observability/prometheus-operator/workload.yaml observability/rendered/apps/observability/prometheus-operator/workload.yaml -apps/observability/prometheus/alertrules.yaml observability/rendered/apps/observability/prometheus/alertrules.yaml -apps/observability/prometheus/flux-podmonitor.yaml observability/rendered/apps/observability/prometheus/flux-podmonitor.yaml -apps/observability/prometheus/k3s-monitors.yaml observability/rendered/apps/observability/prometheus/k3s-monitors.yaml -apps/observability/prometheus/kustomization.yaml observability/rendered/apps/observability/prometheus/kustomization.yaml -apps/observability/prometheus/networkpolicy.yaml observability/rendered/apps/observability/prometheus/networkpolicy.yaml -apps/observability/prometheus/rbac.yaml observability/rendered/apps/observability/prometheus/rbac.yaml -apps/observability/prometheus/service.yaml observability/rendered/apps/observability/prometheus/service.yaml -apps/observability/prometheus/serviceaccount.yaml observability/rendered/apps/observability/prometheus/serviceaccount.yaml -apps/observability/prometheus/workload.yaml observability/rendered/apps/observability/prometheus/workload.yaml -apps/observability/pyroscope/kustomization.yaml observability/rendered/apps/observability/pyroscope/kustomization.yaml -apps/observability/pyroscope/networkpolicy.yaml observability/rendered/apps/observability/pyroscope/networkpolicy.yaml -apps/observability/pyroscope/pvc.yaml observability/rendered/apps/observability/pyroscope/pvc.yaml -apps/observability/pyroscope/service.yaml observability/rendered/apps/observability/pyroscope/service.yaml -apps/observability/pyroscope/serviceaccount.yaml observability/rendered/apps/observability/pyroscope/serviceaccount.yaml -apps/observability/pyroscope/workload.yaml observability/rendered/apps/observability/pyroscope/workload.yaml -apps/observability/rollout-events/alert.yaml observability/rendered/apps/observability/rollout-events/alert.yaml -apps/observability/rollout-events/kustomization.yaml observability/rendered/apps/observability/rollout-events/kustomization.yaml -apps/observability/rollout-events/provider.yaml observability/rendered/apps/observability/rollout-events/provider.yaml -apps/observability/tempo/kustomization.yaml observability/rendered/apps/observability/tempo/kustomization.yaml -apps/observability/tempo/networkpolicy.yaml observability/rendered/apps/observability/tempo/networkpolicy.yaml -apps/observability/tempo/pvc.yaml observability/rendered/apps/observability/tempo/pvc.yaml -apps/observability/tempo/service.yaml observability/rendered/apps/observability/tempo/service.yaml -apps/observability/tempo/serviceaccount.yaml observability/rendered/apps/observability/tempo/serviceaccount.yaml -apps/observability/tempo/workload.yaml observability/rendered/apps/observability/tempo/workload.yaml -apps/observability/vault-policy/configmap.yaml observability/rendered/apps/observability/vault-policy/configmap.yaml -apps/observability/vault-policy/cronjob.yaml observability/rendered/apps/observability/vault-policy/cronjob.yaml -apps/observability/vault-policy/job.yaml observability/rendered/apps/observability/vault-policy/job.yaml -apps/observability/vault-policy/kustomization.yaml observability/rendered/apps/observability/vault-policy/kustomization.yaml -apps/observability/vault-policy/networkpolicy.yaml observability/rendered/apps/observability/vault-policy/networkpolicy.yaml -apps/observability/vault-policy/policies/observability-system-alertmanager.policy.json observability/rendered/apps/observability/vault-policy/policies/observability-system-alertmanager.policy.json -apps/observability/vault-policy/policies/observability-system-alertmanager.role.json observability/rendered/apps/observability/vault-policy/policies/observability-system-alertmanager.role.json -apps/observability/vault-policy/policies/observability-system-grafana.policy.json observability/rendered/apps/observability/vault-policy/policies/observability-system-grafana.policy.json -apps/observability/vault-policy/policies/observability-system-grafana.role.json observability/rendered/apps/observability/vault-policy/policies/observability-system-grafana.role.json -apps/observability/vault-policy/policies/observability-system.generated.json observability/rendered/apps/observability/vault-policy/policies/observability-system.generated.json -apps/observability/vault-policy/serviceaccount.yaml observability/rendered/apps/observability/vault-policy/serviceaccount.yaml -apps/observability/vaultconnection.yaml observability/rendered/apps/observability/vaultconnection.yaml -estate/human-grants/clusterrolebindings.yaml platform/rendered/estate/human-grants/clusterrolebindings.yaml -estate/human-grants/kustomization.yaml platform/rendered/estate/human-grants/kustomization.yaml -estate/priority-classes/kustomization.yaml platform/rendered/estate/priority-classes/kustomization.yaml -estate/priority-classes/priorityclasses.yaml platform/rendered/estate/priority-classes/priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/_estate/source.yaml b/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/_estate/source.yaml deleted file mode 100644 index f1c81304a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/_estate/source.yaml +++ /dev/null @@ -1,59 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: OCIRepository -metadata: - name: estate - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - interval: 10m - url: oci://ghcr.io/jorisjonkers-dev/render-estate - ref: - digest: sha256:0000000000000000000000000000000000000000000000000000000000000000 - verify: - provider: cosign - matchOIDCIdentity: - - issuer: ^https://token\.actions\.githubusercontent\.com$ - subject: ^https://github\.com/JorisJonkers-dev/estate/\.github/workflows/compose\.yml@refs/heads/main$ ---- -apiVersion: kustomize.toolkit.fluxcd.io/v1 -kind: Kustomization -metadata: - name: estate-human-grants - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - interval: 10m - prune: true - wait: true - healthCheckExprs: - - apiVersion: v1 - kind: PersistentVolumeClaim - current: status.phase == 'Bound' || status.phase == 'Pending' && !(has(metadata.annotations) && 'volume.kubernetes.io/selected-node' in metadata.annotations) - sourceRef: - kind: OCIRepository - name: estate - path: ./estate/human-grants ---- -apiVersion: kustomize.toolkit.fluxcd.io/v1 -kind: Kustomization -metadata: - name: estate-stable-addresses - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - interval: 10m - prune: true - wait: true - healthCheckExprs: - - apiVersion: v1 - kind: PersistentVolumeClaim - current: status.phase == 'Bound' || status.phase == 'Pending' && !(has(metadata.annotations) && 'volume.kubernetes.io/selected-node' in metadata.annotations) - sourceRef: - kind: OCIRepository - name: estate - path: ./estate/stable-addresses diff --git a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/data/source.yaml b/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/data/source.yaml deleted file mode 100644 index af502e66a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/data/source.yaml +++ /dev/null @@ -1,58 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: OCIRepository -metadata: - name: project-data - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - interval: 10m - url: oci://ghcr.io/jorisjonkers-dev/render/data - ref: - digest: sha256:0000000000000000000000000000000000000000000000000000000000000000 - verify: - provider: cosign - matchOIDCIdentity: - - issuer: ^https://token\.actions\.githubusercontent\.com$ - subject: ^https://github\.com/JorisJonkers-dev/estate/\.github/workflows/compose\.yml@refs/heads/main$ ---- -apiVersion: kustomize.toolkit.fluxcd.io/v1 -kind: Kustomization -metadata: - name: apps-data - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - event.toolkit.fluxcd.io/repository: JorisJonkers-dev/data - event.toolkit.fluxcd.io/sha: 184d01a04f11edbc96f56e9a7811ece7cd3bcd39 - event.toolkit.fluxcd.io/environment: production - event.toolkit.fluxcd.io/version: 1.0.0 - event.toolkit.fluxcd.io/url: https://rabbitmq.jorisjonkers.dev -spec: - interval: 10m - prune: true - wait: true - healthCheckExprs: - - apiVersion: v1 - kind: PersistentVolumeClaim - current: status.phase == 'Bound' || status.phase == 'Pending' && !(has(metadata.annotations) && 'volume.kubernetes.io/selected-node' in metadata.annotations) - sourceRef: - kind: OCIRepository - name: project-data - path: ./apps/data - dependsOn: - - name: apps-edge - - name: apps-secrets - patches: - - patch: | - apiVersion: apps/v1 - kind: Deployment - metadata: - name: any - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled - target: - kind: Deployment diff --git a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/delivery/source.yaml b/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/delivery/source.yaml deleted file mode 100644 index df10e398f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/delivery/source.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: OCIRepository -metadata: - name: project-delivery - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - interval: 10m - url: oci://ghcr.io/jorisjonkers-dev/render/delivery - ref: - digest: sha256:0000000000000000000000000000000000000000000000000000000000000000 - verify: - provider: cosign - matchOIDCIdentity: - - issuer: ^https://token\.actions\.githubusercontent\.com$ - subject: ^https://github\.com/JorisJonkers-dev/estate/\.github/workflows/compose\.yml@refs/heads/main$ ---- -apiVersion: kustomize.toolkit.fluxcd.io/v1 -kind: Kustomization -metadata: - name: apps-delivery - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - event.toolkit.fluxcd.io/repository: JorisJonkers-dev/delivery - event.toolkit.fluxcd.io/sha: f735bfe482448637bc6c64d584717817fa63879f - event.toolkit.fluxcd.io/environment: production - event.toolkit.fluxcd.io/version: 1.0.0 -spec: - interval: 10m - prune: true - wait: true - healthCheckExprs: - - apiVersion: v1 - kind: PersistentVolumeClaim - current: status.phase == 'Bound' || status.phase == 'Pending' && !(has(metadata.annotations) && 'volume.kubernetes.io/selected-node' in metadata.annotations) - sourceRef: - kind: OCIRepository - name: project-delivery - path: ./apps/delivery - patches: - - patch: | - apiVersion: apps/v1 - kind: Deployment - metadata: - name: any - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled - target: - kind: Deployment diff --git a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/edge/source.yaml b/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/edge/source.yaml deleted file mode 100644 index 062cff5d5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/edge/source.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: OCIRepository -metadata: - name: project-edge - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - interval: 10m - url: oci://ghcr.io/jorisjonkers-dev/render/edge - ref: - digest: sha256:0000000000000000000000000000000000000000000000000000000000000000 - verify: - provider: cosign - matchOIDCIdentity: - - issuer: ^https://token\.actions\.githubusercontent\.com$ - subject: ^https://github\.com/JorisJonkers-dev/estate/\.github/workflows/compose\.yml@refs/heads/main$ ---- -apiVersion: kustomize.toolkit.fluxcd.io/v1 -kind: Kustomization -metadata: - name: apps-edge - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - event.toolkit.fluxcd.io/repository: JorisJonkers-dev/edge - event.toolkit.fluxcd.io/sha: f55b42d170365dbdd946c0a2ca5688b09ee6c011 - event.toolkit.fluxcd.io/environment: production - event.toolkit.fluxcd.io/version: 1.0.0 -spec: - interval: 10m - prune: true - wait: true - healthCheckExprs: - - apiVersion: v1 - kind: PersistentVolumeClaim - current: status.phase == 'Bound' || status.phase == 'Pending' && !(has(metadata.annotations) && 'volume.kubernetes.io/selected-node' in metadata.annotations) - sourceRef: - kind: OCIRepository - name: project-edge - path: ./apps/edge - patches: - - patch: | - apiVersion: apps/v1 - kind: Deployment - metadata: - name: any - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled - target: - kind: Deployment diff --git a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/node/source.yaml b/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/node/source.yaml deleted file mode 100644 index d50ffe746..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/node/source.yaml +++ /dev/null @@ -1,49 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: OCIRepository -metadata: - name: project-node - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - interval: 10m - url: oci://ghcr.io/jorisjonkers-dev/render/node - ref: - digest: sha256:0000000000000000000000000000000000000000000000000000000000000000 - verify: - provider: cosign - matchOIDCIdentity: - - issuer: ^https://token\.actions\.githubusercontent\.com$ - subject: ^https://github\.com/JorisJonkers-dev/estate/\.github/workflows/compose\.yml@refs/heads/main$ ---- -apiVersion: kustomize.toolkit.fluxcd.io/v1 -kind: Kustomization -metadata: - name: apps-node - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - interval: 10m - prune: true - wait: true - healthCheckExprs: - - apiVersion: v1 - kind: PersistentVolumeClaim - current: status.phase == 'Bound' || status.phase == 'Pending' && !(has(metadata.annotations) && 'volume.kubernetes.io/selected-node' in metadata.annotations) - sourceRef: - kind: OCIRepository - name: project-node - path: ./apps/node - patches: - - patch: | - apiVersion: apps/v1 - kind: Deployment - metadata: - name: any - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled - target: - kind: Deployment diff --git a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/notes/source.yaml b/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/notes/source.yaml deleted file mode 100644 index 04d09c98b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/notes/source.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: OCIRepository -metadata: - name: project-notes - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - interval: 10m - url: oci://ghcr.io/jorisjonkers-dev/render/notes - ref: - digest: sha256:0000000000000000000000000000000000000000000000000000000000000000 - verify: - provider: cosign - matchOIDCIdentity: - - issuer: ^https://token\.actions\.githubusercontent\.com$ - subject: ^https://github\.com/JorisJonkers-dev/estate/\.github/workflows/compose\.yml@refs/heads/main$ ---- -apiVersion: kustomize.toolkit.fluxcd.io/v1 -kind: Kustomization -metadata: - name: apps-notes - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - event.toolkit.fluxcd.io/repository: JorisJonkers-dev/notes - event.toolkit.fluxcd.io/sha: bda7ae704e0fa239fc4dba8286cc498c1fa9c144 - event.toolkit.fluxcd.io/environment: production - event.toolkit.fluxcd.io/version: 1.0.0 - event.toolkit.fluxcd.io/url: https://notes.jorisjonkers.dev -spec: - interval: 10m - prune: true - wait: true - healthCheckExprs: - - apiVersion: v1 - kind: PersistentVolumeClaim - current: status.phase == 'Bound' || status.phase == 'Pending' && !(has(metadata.annotations) && 'volume.kubernetes.io/selected-node' in metadata.annotations) - sourceRef: - kind: OCIRepository - name: project-notes - path: ./apps/notes - dependsOn: - - name: apps-edge - patches: - - patch: | - apiVersion: apps/v1 - kind: Deployment - metadata: - name: any - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled - target: - kind: Deployment diff --git a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/observability/source.yaml b/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/observability/source.yaml deleted file mode 100644 index c6b4e1d08..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/observability/source.yaml +++ /dev/null @@ -1,57 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: OCIRepository -metadata: - name: project-observability - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - interval: 10m - url: oci://ghcr.io/jorisjonkers-dev/render/observability - ref: - digest: sha256:0000000000000000000000000000000000000000000000000000000000000000 - verify: - provider: cosign - matchOIDCIdentity: - - issuer: ^https://token\.actions\.githubusercontent\.com$ - subject: ^https://github\.com/JorisJonkers-dev/estate/\.github/workflows/compose\.yml@refs/heads/main$ ---- -apiVersion: kustomize.toolkit.fluxcd.io/v1 -kind: Kustomization -metadata: - name: apps-observability - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - event.toolkit.fluxcd.io/repository: JorisJonkers-dev/observability - event.toolkit.fluxcd.io/sha: 138df822137d4bef66e2456320647060ea59819f - event.toolkit.fluxcd.io/environment: production - event.toolkit.fluxcd.io/version: 1.0.0 - event.toolkit.fluxcd.io/url: https://grafana.jorisjonkers.dev -spec: - interval: 10m - prune: true - wait: true - healthCheckExprs: - - apiVersion: v1 - kind: PersistentVolumeClaim - current: status.phase == 'Bound' || status.phase == 'Pending' && !(has(metadata.annotations) && 'volume.kubernetes.io/selected-node' in metadata.annotations) - sourceRef: - kind: OCIRepository - name: project-observability - path: ./apps/observability - dependsOn: - - name: apps-edge - patches: - - patch: | - apiVersion: apps/v1 - kind: Deployment - metadata: - name: any - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled - target: - kind: Deployment diff --git a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/secrets/source.yaml b/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/secrets/source.yaml deleted file mode 100644 index e2966adb9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/pins/expected/projects/secrets/source.yaml +++ /dev/null @@ -1,54 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: source.toolkit.fluxcd.io/v1 -kind: OCIRepository -metadata: - name: project-secrets - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - interval: 10m - url: oci://ghcr.io/jorisjonkers-dev/render/secrets - ref: - digest: sha256:0000000000000000000000000000000000000000000000000000000000000000 - verify: - provider: cosign - matchOIDCIdentity: - - issuer: ^https://token\.actions\.githubusercontent\.com$ - subject: ^https://github\.com/JorisJonkers-dev/estate/\.github/workflows/compose\.yml@refs/heads/main$ ---- -apiVersion: kustomize.toolkit.fluxcd.io/v1 -kind: Kustomization -metadata: - name: apps-secrets - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - event.toolkit.fluxcd.io/repository: JorisJonkers-dev/secrets - event.toolkit.fluxcd.io/sha: 7b205dcdab030cdbef923acd7535f9a76f4a0d3b - event.toolkit.fluxcd.io/environment: production - event.toolkit.fluxcd.io/version: 1.0.0 -spec: - interval: 10m - prune: true - wait: true - healthCheckExprs: - - apiVersion: v1 - kind: PersistentVolumeClaim - current: status.phase == 'Bound' || status.phase == 'Pending' && !(has(metadata.annotations) && 'volume.kubernetes.io/selected-node' in metadata.annotations) - sourceRef: - kind: OCIRepository - name: project-secrets - path: ./apps/secrets - patches: - - patch: | - apiVersion: apps/v1 - kind: Deployment - metadata: - name: any - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled - target: - kind: Deployment diff --git a/emf/bundles/cli/src/test/resources/stages/render/pins/oracles b/emf/bundles/cli/src/test/resources/stages/render/pins/oracles deleted file mode 100644 index 4d4401c4d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/pins/oracles +++ /dev/null @@ -1,8 +0,0 @@ -projects/_estate/source.yaml pins/rendered/projects/_estate/source.yaml -projects/data/source.yaml pins/rendered/projects/data/source.yaml -projects/delivery/source.yaml pins/rendered/projects/delivery/source.yaml -projects/edge/source.yaml pins/rendered/projects/edge/source.yaml -projects/node/source.yaml pins/rendered/projects/node/source.yaml -projects/notes/source.yaml pins/rendered/projects/notes/source.yaml -projects/observability/source.yaml pins/rendered/projects/observability/source.yaml -projects/secrets/source.yaml pins/rendered/projects/secrets/source.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/human-grants/clusterrolebindings.yaml b/emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/human-grants/clusterrolebindings.yaml deleted file mode 100644 index 86311f89c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/human-grants/clusterrolebindings.yaml +++ /dev/null @@ -1,16 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: human:oidc:k8s-admin:cluster-admin - labels: - app.kubernetes.io/managed-by: deploy-kit -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cluster-admin -subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: oidc:k8s-admin diff --git a/emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/human-grants/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/human-grants/kustomization.yaml deleted file mode 100644 index 029015f5d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/human-grants/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - clusterrolebindings.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/priority-classes/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/priority-classes/kustomization.yaml deleted file mode 100644 index 8b06a2f03..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/priority-classes/kustomization.yaml +++ /dev/null @@ -1,6 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/priority-classes/priorityclasses.yaml b/emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/priority-classes/priorityclasses.yaml deleted file mode 100644 index a304512d4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/platform/expected/estate/priority-classes/priorityclasses.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-data - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 1000000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "A datastore: it schedules before what reads it." ---- -apiVersion: scheduling.k8s.io/v1 -kind: PriorityClass -metadata: - name: platform-critical-app - labels: - app.kubernetes.io/managed-by: deploy-kit -value: 100000 -globalDefault: false -preemptionPolicy: PreemptLowerPriority -description: "The foundation and the Applications the platform names: they keep scheduling under pressure." diff --git a/emf/bundles/cli/src/test/resources/stages/render/platform/oracles b/emf/bundles/cli/src/test/resources/stages/render/platform/oracles deleted file mode 100644 index c1d13a2d0..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/platform/oracles +++ /dev/null @@ -1,4 +0,0 @@ -estate/human-grants/clusterrolebindings.yaml platform/rendered/estate/human-grants/clusterrolebindings.yaml -estate/human-grants/kustomization.yaml platform/rendered/estate/human-grants/kustomization.yaml -estate/priority-classes/kustomization.yaml platform/rendered/estate/priority-classes/kustomization.yaml -estate/priority-classes/priorityclasses.yaml platform/rendered/estate/priority-classes/priorityclasses.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/canary.yaml deleted file mode 100644 index b4d0d9ad2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/canary.yaml +++ /dev/null @@ -1,92 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: adguard - namespace: utility-system - labels: - app.kubernetes.io/name: adguard - app.kubernetes.io/instance: adguard - app.kubernetes.io/part-of: adguard - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: adguard - autoscalerRef: - apiVersion: autoscaling/v2 - kind: HorizontalPodAutoscaler - name: adguard - progressDeadlineSeconds: 210 - service: - port: 3000 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: adguard - process: adguard - revision: sha256:9f34923070e19389d1e83a5f4945cdc100cac60e541ac4650a550ce6d5670d55 - readiness: /login.html - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: adguard - process: adguard - revision: sha256:9f34923070e19389d1e83a5f4945cdc100cac60e541ac4650a550ce6d5670d55 - readiness: /login.html - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: adguard - process: adguard - revision: sha256:9f34923070e19389d1e83a5f4945cdc100cac60e541ac4650a550ce6d5670d55 - readiness: /login.html - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: adguard - process: adguard - revision: sha256:9f34923070e19389d1e83a5f4945cdc100cac60e541ac4650a550ce6d5670d55 - readiness: /login.html - errorRate: 1% - latency: 500ms ---- -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: adguard - namespace: utility-system - labels: - app.kubernetes.io/name: adguard - app.kubernetes.io/instance: adguard - app.kubernetes.io/part-of: adguard - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: adguard - minReplicas: 2 - maxReplicas: 2 diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/configmap.yaml deleted file mode 100644 index 8df4c4907..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/configmap.yaml +++ /dev/null @@ -1,42 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: adguard-release-gate - namespace: utility-system - labels: - app.kubernetes.io/part-of: adguard - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"210s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"adguard","readiness":{"path":"/login.html","port":3000}}]} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: adguard-adguardhome-yaml-85a1bf27a7 - namespace: utility-system - labels: - app.kubernetes.io/name: adguard - app.kubernetes.io/instance: adguard - app.kubernetes.io/part-of: adguard - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -immutable: true -data: - AdGuardHome.yaml: | - # A stand-in for AdGuard Home's configuration, written for this example: the - # live file is fleet-infra's, and this repository does not copy it. AdGuard - # rewrites the file on every start and stops if it cannot, so the file is - # seeded onto a writable path rather than mounted - # (spec/v1/10-project-intent.md#seeded-assets). - http: - address: 0.0.0.0:3000 - dns: - bind_hosts: [0.0.0.0] - port: 5353 - upstream_dns: - - https://dns.quad9.net/dns-query - bootstrap_dns: [9.9.9.10, 149.112.112.10] - schema_version: 29 diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/kustomization.yaml deleted file mode 100644 index 51711182c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/kustomization.yaml +++ /dev/null @@ -1,11 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - pdb.yaml - - service.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/networkpolicy.yaml deleted file mode 100644 index 7debab4b1..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/networkpolicy.yaml +++ /dev/null @@ -1,84 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: adguard - namespace: utility-system - labels: - app.kubernetes.io/name: adguard - app.kubernetes.io/instance: adguard - app.kubernetes.io/part-of: adguard - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: adguard - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/adguard.http: "true" - ports: - - protocol: TCP - port: 3000 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/adguard.dns: "true" - ports: - - protocol: TCP - port: 5353 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 3000 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: TCP - port: 5353 - - from: - - ipBlock: - cidr: 0.0.0.0/0 - ports: - - protocol: UDP - port: 5353 - egress: - - to: - - ipBlock: - cidr: 9.9.9.10/32 - - ipBlock: - cidr: 149.112.112.10/32 - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 - - 100.64.0.0/10 - - 169.254.0.0/16 - - 127.0.0.0/8 diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/pdb.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/pdb.yaml deleted file mode 100644 index 6593a06c8..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/pdb.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: policy/v1 -kind: PodDisruptionBudget -metadata: - name: adguard - namespace: utility-system - labels: - app.kubernetes.io/name: adguard - app.kubernetes.io/instance: adguard - app.kubernetes.io/part-of: adguard - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - maxUnavailable: 1 - selector: - matchLabels: - app.kubernetes.io/name: adguard-primary diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/service.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/service.yaml deleted file mode 100644 index bead585ff..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/service.yaml +++ /dev/null @@ -1,29 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Service -metadata: - name: adguard-lan-dns - namespace: utility-system - labels: - app.kubernetes.io/name: adguard - app.kubernetes.io/instance: adguard - app.kubernetes.io/part-of: adguard - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - annotations: - metallb.io/address-pool: lan-dns -spec: - type: LoadBalancer - externalTrafficPolicy: Local - selector: - app.kubernetes.io/instance: adguard - ports: - - name: tcp-53 - port: 53 - protocol: TCP - targetPort: 5353 - - name: udp-53 - port: 53 - protocol: UDP - targetPort: 5353 diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/serviceaccount.yaml deleted file mode 100644 index b9b3d142a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: adguard - namespace: utility-system - labels: - app.kubernetes.io/name: adguard - app.kubernetes.io/instance: adguard - app.kubernetes.io/part-of: adguard - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/workload.yaml deleted file mode 100644 index a929277f7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/adguard/workload.yaml +++ /dev/null @@ -1,165 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: adguard - namespace: utility-system - labels: - app.kubernetes.io/name: adguard - app.kubernetes.io/instance: adguard - app.kubernetes.io/part-of: adguard - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: adguard - app.kubernetes.io/instance: adguard - template: - metadata: - labels: - app.kubernetes.io/name: adguard - app.kubernetes.io/instance: adguard - app.kubernetes.io/part-of: adguard - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/adguard: v0.107.79 - image.jorisjonkers.dev/seed: 1.37.0 - spec: - serviceAccountName: adguard - automountServiceAccountToken: false - dnsPolicy: None - dnsConfig: - nameservers: - - 9.9.9.10 - - 149.112.112.10 - securityContext: - runAsNonRoot: true - runAsUser: 1000 - runAsGroup: 1000 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: - app.kubernetes.io/instance: adguard - matchLabelKeys: - - pod-template-hash - topologyKey: kubernetes.io/hostname - initContainers: - - name: seed - image: docker.io/library/busybox@sha256:a7dbc319b1438115a207e11930dc4bb3e643dcb3ec0bdd694bb36cd8fad289ec - command: - - /bin/sh - - -c - - |- - set -eu - umask 077 - mkdir -p '/opt/adguardhome/conf' - if [ -e '/opt/adguardhome/conf/AdGuardHome.yaml' ]; then cp -p '/opt/adguardhome/conf/AdGuardHome.yaml' '/opt/adguardhome/conf/AdGuardHome.yaml.superseded'; fi - cp '/seed/adguard-adguardhome-yaml-85a1bf27a7/AdGuardHome.yaml' '/opt/adguardhome/conf/AdGuardHome.yaml.seeding' - chmod 0600 '/opt/adguardhome/conf/AdGuardHome.yaml.seeding' - mv '/opt/adguardhome/conf/AdGuardHome.yaml.seeding' '/opt/adguardhome/conf/AdGuardHome.yaml' - resources: - requests: - memory: 16Mi - cpu: 10m - limits: - memory: 16Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: adguard-adguardhome-yaml-85a1bf27a7 - mountPath: /seed/adguard-adguardhome-yaml-85a1bf27a7 - readOnly: true - - name: writable-opt-adguardhome-conf - mountPath: /opt/adguardhome/conf - containers: - - name: adguard - image: docker.io/adguard/adguardhome@sha256:6b8d0f2a4c6e8b0d2f4a6c8e0b2d4f7e1f3c5a9b2d4f6e8a0c2e4b6d8f5a2c4e - ports: - - name: http - containerPort: 3000 - - name: dns - containerPort: 5353 - resources: - requests: - memory: 256Mi - cpu: 50m - limits: - memory: 256Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: writable-opt-adguardhome-work - mountPath: /opt/adguardhome/work - - name: writable-opt-adguardhome-conf - mountPath: /opt/adguardhome/conf - readinessProbe: - httpGet: - path: /login.html - port: 3000 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: /login.html - port: 3000 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: /login.html - port: 3000 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 - volumes: - - name: adguard-adguardhome-yaml-85a1bf27a7 - configMap: - name: adguard-adguardhome-yaml-85a1bf27a7 - items: - - key: AdGuardHome.yaml - path: AdGuardHome.yaml - - name: writable-opt-adguardhome-work - emptyDir: - medium: Memory - sizeLimit: 128Mi - - name: writable-opt-adguardhome-conf - emptyDir: - sizeLimit: 64Mi diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/canary.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/canary.yaml deleted file mode 100644 index a7cbdec40..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/canary.yaml +++ /dev/null @@ -1,73 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: flagger.app/v1beta1 -kind: Canary -metadata: - name: headlamp - namespace: utility-system - labels: - app.kubernetes.io/name: headlamp - app.kubernetes.io/instance: headlamp - app.kubernetes.io/part-of: headlamp - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: headlamp - progressDeadlineSeconds: 210 - service: - port: 4466 - targetPort: http - portName: http - analysis: - interval: 30s - iterations: 4 - threshold: 3 - webhooks: - - name: may-start - type: confirm-rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-start - metadata: - application: headlamp - process: headlamp - revision: sha256:00e9e8ce5e4c29f9b673031edc8e35bc40b8a6e31c53bc12984c3740ed856312 - paths: / - readiness: / - errorRate: 1% - latency: 500ms - - name: checks - type: rollout - url: http://release-gate.delivery-system.svc.cluster.local:8080/checks - metadata: - application: headlamp - process: headlamp - revision: sha256:00e9e8ce5e4c29f9b673031edc8e35bc40b8a6e31c53bc12984c3740ed856312 - paths: / - readiness: / - errorRate: 1% - latency: 500ms - - name: may-promote - type: confirm-promotion - url: http://release-gate.delivery-system.svc.cluster.local:8080/may-promote - metadata: - application: headlamp - process: headlamp - revision: sha256:00e9e8ce5e4c29f9b673031edc8e35bc40b8a6e31c53bc12984c3740ed856312 - paths: / - readiness: / - errorRate: 1% - latency: 500ms - - name: rollback - type: rollback - url: http://release-gate.delivery-system.svc.cluster.local:8080/rollback - metadata: - application: headlamp - process: headlamp - revision: sha256:00e9e8ce5e4c29f9b673031edc8e35bc40b8a6e31c53bc12984c3740ed856312 - paths: / - readiness: / - errorRate: 1% - latency: 500ms diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/configmap.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/configmap.yaml deleted file mode 100644 index 8f9ba9f58..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/configmap.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: headlamp-release-gate - namespace: utility-system - labels: - app.kubernetes.io/part-of: headlamp - app.kubernetes.io/managed-by: deploy-kit -data: - releaseGate.json: | - {"analysis":{"errorRate":"1%","interval":"30s","iterations":4,"latency":"500ms","threshold":3},"deadline":"210s","endpoint":"http://release-gate.delivery-system.svc.cluster.local:8080","members":[{"process":"headlamp","readiness":{"path":"/","port":4466}}]} ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: headlamp-external-checks - namespace: utility-system - labels: - app.kubernetes.io/part-of: headlamp - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" -data: - headlamp-external-checks.yaml: | - {"endpoints":[{"conditions":["[STATUS] < 500"],"group":"utility","name":"headlamp-lan-1","url":"http://dashboard.lan.jorisjonkers.dev/"}]} diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/kustomization.yaml deleted file mode 100644 index 63e69d13b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/kustomization.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - canary.yaml - - configmap.yaml - - route-lan.yaml - - serviceaccount.yaml - - workload.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/networkpolicy.yaml deleted file mode 100644 index 0a837220d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/networkpolicy.yaml +++ /dev/null @@ -1,67 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: headlamp - namespace: utility-system - labels: - app.kubernetes.io/name: headlamp - app.kubernetes.io/instance: headlamp - app.kubernetes.io/part-of: headlamp - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: headlamp - policyTypes: - - Ingress - - Egress - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: edge-system - podSelector: - matchLabels: - app.kubernetes.io/instance: traefik-lan - ports: - - protocol: TCP - port: 4466 - - from: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - consumes.deploy-kit.jorisjonkers.dev/headlamp.http: "true" - ports: - - protocol: TCP - port: 4466 - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: delivery-system - podSelector: - matchLabels: - app.kubernetes.io/instance: release-gate - ports: - - protocol: TCP - port: 4466 - egress: - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: kube-system - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - - to: - - ipBlock: - cidr: 10.43.0.1/32 - ports: - - protocol: TCP - port: 443 diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/route-lan.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/route-lan.yaml deleted file mode 100644 index d99dc1ac9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/route-lan.yaml +++ /dev/null @@ -1,26 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: traefik.io/v1alpha1 -kind: IngressRoute -metadata: - name: headlamp-lan - namespace: utility-system - labels: - app.kubernetes.io/part-of: headlamp - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: traefik-lan -spec: - entryPoints: - - web - routes: - - kind: Rule - match: Host(`dashboard.lan.jorisjonkers.dev`) && PathPrefix(`/`) - priority: 999 - middlewares: - - name: security-headers - namespace: edge-system - services: - - name: headlamp - namespace: utility-system - port: 4466 diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/serviceaccount.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/serviceaccount.yaml deleted file mode 100644 index 56a08a1ef..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: headlamp - namespace: utility-system - labels: - app.kubernetes.io/name: headlamp - app.kubernetes.io/instance: headlamp - app.kubernetes.io/part-of: headlamp - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/workload.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/workload.yaml deleted file mode 100644 index 23eedbb2b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/headlamp/workload.yaml +++ /dev/null @@ -1,100 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: headlamp - namespace: utility-system - labels: - app.kubernetes.io/name: headlamp - app.kubernetes.io/instance: headlamp - app.kubernetes.io/part-of: headlamp - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none -spec: - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - progressDeadlineSeconds: 210 - selector: - matchLabels: - app.kubernetes.io/name: headlamp - app.kubernetes.io/instance: headlamp - template: - metadata: - labels: - app.kubernetes.io/name: headlamp - app.kubernetes.io/instance: headlamp - app.kubernetes.io/part-of: headlamp - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: none - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - annotations: - image.jorisjonkers.dev/headlamp: v0.35.0 - spec: - serviceAccountName: headlamp - automountServiceAccountToken: true - securityContext: - runAsNonRoot: true - runAsUser: 100 - runAsGroup: 101 - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - enschede-t1000-1 - - enschede-rx7900xtx-1 - - enschede-gtx-960m-1 - - enschede-pi-1 - - enschede-pi-2 - - enschede-pi-3 - - frankfurt-contabo-1 - containers: - - name: headlamp - image: ghcr.io/headlamp-k8s/headlamp@sha256:9c3e5a7b1d4f6a8c0e2b4d6f8a1c3e5b7d9f2a4c6e8b0d2f4a6c8e1b3d5f7a9c - ports: - - name: http - containerPort: 4466 - resources: - requests: - memory: 128Mi - cpu: 50m - limits: - memory: 128Mi - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - readinessProbe: - httpGet: - path: / - port: 4466 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - livenessProbe: - httpGet: - path: / - port: 4466 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 3 - initialDelaySeconds: 0 - startupProbe: - httpGet: - path: / - port: 4466 - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 6 diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/kustomization.yaml deleted file mode 100644 index 776a0aa4c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/kustomization.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - adguard - - headlamp - - namespace.yaml - - rollout-events diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/namespace.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/namespace.yaml deleted file mode 100644 index 6deae0b3c..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/namespace.yaml +++ /dev/null @@ -1,10 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: v1 -kind: Namespace -metadata: - name: utility-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/networkpolicy.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/networkpolicy.yaml deleted file mode 100644 index 26b591082..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/networkpolicy.yaml +++ /dev/null @@ -1,15 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: networking.k8s.io/v1 -kind: NetworkPolicy -metadata: - name: default-deny - namespace: utility-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/rollout-events/alert.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/rollout-events/alert.yaml deleted file mode 100644 index a35dceffa..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/rollout-events/alert.yaml +++ /dev/null @@ -1,18 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Alert -metadata: - name: rollouts-utility - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - providerRef: - name: reporter-utility - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-utility - matchLabels: - app.kubernetes.io/managed-by: deploy-kit diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/rollout-events/kustomization.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/rollout-events/kustomization.yaml deleted file mode 100644 index 5460e018a..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/rollout-events/kustomization.yaml +++ /dev/null @@ -1,7 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: kustomize.config.k8s.io/v1beta1 -kind: Kustomization -resources: - - alert.yaml - - provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/rollout-events/provider.yaml b/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/rollout-events/provider.yaml deleted file mode 100644 index cc2a456f5..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/expected/apps/utility/rollout-events/provider.yaml +++ /dev/null @@ -1,12 +0,0 @@ -# GENERATED. Never hand-edit. ---- -apiVersion: notification.toolkit.fluxcd.io/v1beta3 -kind: Provider -metadata: - name: reporter-utility - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit -spec: - type: generic - address: http://reporter.delivery-system.svc.cluster.local:8080/flux diff --git a/emf/bundles/cli/src/test/resources/stages/render/utility/oracles b/emf/bundles/cli/src/test/resources/stages/render/utility/oracles deleted file mode 100644 index 3827747a7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/render/utility/oracles +++ /dev/null @@ -1,21 +0,0 @@ -apps/utility/adguard/canary.yaml utility/rendered/apps/utility/adguard/canary.yaml -apps/utility/adguard/configmap.yaml utility/rendered/apps/utility/adguard/configmap.yaml -apps/utility/adguard/kustomization.yaml utility/rendered/apps/utility/adguard/kustomization.yaml -apps/utility/adguard/networkpolicy.yaml utility/rendered/apps/utility/adguard/networkpolicy.yaml -apps/utility/adguard/pdb.yaml utility/rendered/apps/utility/adguard/pdb.yaml -apps/utility/adguard/service.yaml utility/rendered/apps/utility/adguard/service.yaml -apps/utility/adguard/serviceaccount.yaml utility/rendered/apps/utility/adguard/serviceaccount.yaml -apps/utility/adguard/workload.yaml utility/rendered/apps/utility/adguard/workload.yaml -apps/utility/headlamp/canary.yaml utility/rendered/apps/utility/headlamp/canary.yaml -apps/utility/headlamp/configmap.yaml utility/rendered/apps/utility/headlamp/configmap.yaml -apps/utility/headlamp/kustomization.yaml utility/rendered/apps/utility/headlamp/kustomization.yaml -apps/utility/headlamp/networkpolicy.yaml utility/rendered/apps/utility/headlamp/networkpolicy.yaml -apps/utility/headlamp/route-lan.yaml utility/rendered/apps/utility/headlamp/route-lan.yaml -apps/utility/headlamp/serviceaccount.yaml utility/rendered/apps/utility/headlamp/serviceaccount.yaml -apps/utility/headlamp/workload.yaml utility/rendered/apps/utility/headlamp/workload.yaml -apps/utility/kustomization.yaml utility/rendered/apps/utility/kustomization.yaml -apps/utility/namespace.yaml utility/rendered/apps/utility/namespace.yaml -apps/utility/networkpolicy.yaml utility/rendered/apps/utility/networkpolicy.yaml -apps/utility/rollout-events/alert.yaml utility/rendered/apps/utility/rollout-events/alert.yaml -apps/utility/rollout-events/kustomization.yaml utility/rendered/apps/utility/rollout-events/kustomization.yaml -apps/utility/rollout-events/provider.yaml utility/rendered/apps/utility/rollout-events/provider.yaml diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/agents/expected/agents.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/agents/expected/agents.resolveddeployment deleted file mode 100644 index 085129f07..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/agents/expected/agents.resolveddeployment +++ /dev/null @@ -1,482 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - https://hermes.jorisjonkers.dev/auth/callback - user - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - - - - - - memory-api-key - overleaf-session - github-pat - hindsight-api-token - openrouter-api-key - anthropic-api-key - openai-api-key - hermes - - - - - - kubernetes-mcp-server.mcp - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gateway - run - - /bin/sh - -c - set -eu -umask 077 -mkdir -p '/opt/data' -if [ -e '/opt/data/config.yaml' ]; then cp -p '/opt/data/config.yaml' '/opt/data/config.yaml.superseded'; fi -cp '/seed/hermes-config-yaml-118d92ae7c/config.yaml' '/opt/data/config.yaml.seeding' -chmod 0600 '/opt/data/config.yaml.seeding' -mv '/opt/data/config.yaml.seeding' '/opt/data/config.yaml' - - - - - - - - - - - - - - - - pods - pods/log - events - services - endpoints - nodes - namespaces - get - list - watch - - - deployments - statefulsets - daemonsets - replicasets - get - list - watch - - - jobs - cronjobs - get - list - watch - - - ingresses - networkpolicies - get - list - watch - - - ingressroutes - middlewares - get - list - watch - - - kustomizations - get - list - watch - - - helmreleases - get - list - watch - - - gitrepositories - helmrepositories - ocirepositories - get - list - watch - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - --port=8080 - --read-only - - - - - - - configmaps - get - list - watch - - - pods - get - list - watch - create - delete - - - pods/log - get - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - NET_BIND_SERVICE - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - agents-api - agents-ui - hermes - kubernetes-mcp-server - namespace.yaml - rollout-events - vault-policy - vaultconnection.yaml - - - - - backup.yaml - client.yaml - configmap.yaml - pvc.yaml - route-lan.yaml - route-public.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - - canary.yaml - configmap.yaml - rbac.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - configmap.yaml - route-public.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - read - - - read - - - - - - - - - namespace.yaml - services.yaml - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/agents/projects b/emf/bundles/cli/src/test/resources/stages/resolve/agents/projects deleted file mode 100644 index 4a33ff62f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/agents/projects +++ /dev/null @@ -1 +0,0 @@ -agents diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/auth/expected/auth.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/auth/expected/auth.resolveddeployment deleted file mode 100644 index c8f337f69..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/auth/expected/auth.resolveddeployment +++ /dev/null @@ -1,358 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - error-rate - latency - - - - - - - - - platform-postgres.postgres - - - read - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - frankfurt-contabo-1 - - - user - password - - - mail.password - valkey.password - rabbitmq.user - rabbitmq.password - - - - update - - - update - - - read - - - - - read - - - - - - - - - - - - - - - platform-postgres.postgres - platform-valkey.redis - platform-rabbitmq.amqp - stalwart.smtp - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - NET_BIND_SERVICE - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - platform-postgres.postgres - - - - - read - - - read - - - create - read - update - - - create - read - update - - - - - - aliases.yaml - auth - namespace.yaml - rollout-events - vault-policy - vaultconnection.yaml - - - - - - - - - - - canary.yaml - configmap.yaml - migration.yaml - pdb.yaml - podmonitor.yaml - route-public.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - read - - - read - - - read - - - read - - - update - - - update - - - read - - - read - - - - - - read - - - - - - - - - - - - namespace.yaml - services.yaml - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/auth/projects b/emf/bundles/cli/src/test/resources/stages/resolve/auth/projects deleted file mode 100644 index 5fa1d8144..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/auth/projects +++ /dev/null @@ -1 +0,0 @@ -auth diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/data-full/expected/data.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/data-full/expected/data.resolveddeployment deleted file mode 100644 index 039911d4b..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/data-full/expected/data.resolveddeployment +++ /dev/null @@ -1,359 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - - - - - - - - datasource - postgres - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - asset-sync - namespace.yaml - platform-garage - platform-mongo - platform-postgres - platform-rabbitmq - platform-valkey - rollout-events - vault-policy - vaultconnection.yaml - - - - - backup.yaml - configmap.yaml - pvc.yaml - service.yaml - serviceaccount.yaml - servicemonitor.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - - backup.yaml - configmap.yaml - dashboards.yaml - pvc.yaml - route-lan.yaml - route-management.yaml - service.yaml - serviceaccount.yaml - servicemonitor.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - pvc.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - read - - - read - - - - - - read - - - read - - - read - - - read - - - - - - read - - - read - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/data-full/projects b/emf/bundles/cli/src/test/resources/stages/resolve/data-full/projects deleted file mode 100644 index 1269488f7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/data-full/projects +++ /dev/null @@ -1 +0,0 @@ -data diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/data-main/expected/data.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/data-main/expected/data.resolveddeployment deleted file mode 100644 index 66e6af9a6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/data-main/expected/data.resolveddeployment +++ /dev/null @@ -1,577 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - - - - - - - - datasource - postgres - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DS_PROMETHEUS - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - mongo.data-system.svc.cluster.local - - - - - - - frankfurt-contabo-1 - - - credentials - - - - - - - - - - - - - - - - - - frankfurt-contabo-1 - - - - - - - - - - - - - - rpc-secret - admin-token - garage - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - asset-sync - namespace.yaml - platform-garage - platform-mongo - platform-postgres - platform-rabbitmq - platform-valkey - rollout-events - vault-policy - vaultconnection.yaml - - - - - backup.yaml - configmap.yaml - pvc.yaml - service.yaml - serviceaccount.yaml - servicemonitor.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - - backup.yaml - configmap.yaml - dashboards.yaml - pvc.yaml - route-lan.yaml - route-management.yaml - service.yaml - serviceaccount.yaml - servicemonitor.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - pvc.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - backup.yaml - pvc.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - backup.yaml - configmap.yaml - pvc.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - read - - - read - - - - - - read - - - read - - - read - - - read - - - - - - read - - - read - - - - - - read - - - read - - - read - - - read - - - - - - read - - - read - - - - - - read - - - read - - - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/data-main/projects b/emf/bundles/cli/src/test/resources/stages/resolve/data-main/projects deleted file mode 100644 index 1269488f7..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/data-main/projects +++ /dev/null @@ -1 +0,0 @@ -data diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/delivery/expected/delivery.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/delivery/expected/delivery.resolveddeployment deleted file mode 100644 index e6bbc8be9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/delivery/expected/delivery.resolveddeployment +++ /dev/null @@ -1,349 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - canaries - canaries/status - get - list - watch - update - patch - - - deployments - get - list - watch - create - update - patch - delete - - - horizontalpodautoscalers - get - list - watch - create - update - patch - delete - - - services - configmaps - get - list - watch - create - update - patch - delete - - - secrets - get - - - events - create - update - patch - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - release-gate.http - - - - - - - - - - - configmaps - get - list - - - configmaps - create - update - - - pods - list - - - deployments - get - - - jobs - list - patch - - - canaries - get - - - vaultauths - vaultstaticsecrets - vaultdynamicsecrets - list - delete - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - persistentvolumes - persistentvolumeclaims - pods - get - list - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - kustomizations - get - list - watch - - - canaries - get - list - watch - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - collector - flagger - namespace.yaml - release-gate - reporter - rollout-events - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - servicemonitor.yaml - workload.yaml - - - - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - namespace.yaml - services.yaml - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/delivery/projects b/emf/bundles/cli/src/test/resources/stages/resolve/delivery/projects deleted file mode 100644 index 37ef2cfb2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/delivery/projects +++ /dev/null @@ -1 +0,0 @@ -delivery diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/edge/expected/edge.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/edge/expected/edge.resolveddeployment deleted file mode 100644 index fec139f88..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/edge/expected/edge.resolveddeployment +++ /dev/null @@ -1,364 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - services - secrets - nodes - configmaps - namespaces - get - list - watch - - - pods - get - - - endpointslices - get - list - watch - - - ingressroutes - ingressroutetcps - ingressrouteudps - middlewares - middlewaretcps - serverstransports - serverstransporttcps - tlsoptions - tlsstores - traefikservices - get - list - watch - - - - - - - - - - - - - - - - - - frankfurt-contabo-1 - - - - CF_DNS_API_TOKEN - traefik-public - - - - - - --entryPoints.web.address=:8000/tcp - --entryPoints.websecure.address=:8443/tcp - --entryPoints.websecure.http.tls=true - --entryPoints.traefik.address=:8080/tcp - --ping=true - --ping.entryPoint=traefik - --metrics.prometheus=true - --metrics.prometheus.entryPoint=traefik - --providers.kubernetescrd=true - --providers.kubernetescrd.ingressClass=traefik-public - --providers.kubernetescrd.allowCrossNamespace=true - --providers.kubernetescrd.allowEmptyServices=true - --certificatesresolvers.public-frankfurt.acme.email=hostmaster@jorisjonkers.dev - --certificatesresolvers.public-frankfurt.acme.storage=/acme/public-frankfurt.json - --certificatesresolvers.public-frankfurt.acme.dnschallenge.provider=cloudflare - --log.format=json - --accesslog=true - --accesslog.format=json - - - - - - - services - secrets - nodes - configmaps - namespaces - get - list - watch - - - pods - get - - - endpointslices - get - list - watch - - - ingressroutes - ingressroutetcps - ingressrouteudps - middlewares - middlewaretcps - serverstransports - serverstransporttcps - tlsoptions - tlsstores - traefikservices - get - list - watch - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - - - --entryPoints.web.address=:8000/tcp - --entryPoints.traefik.address=:8080/tcp - --ping=true - --ping.entryPoint=traefik - --metrics.prometheus=true - --metrics.prometheus.entryPoint=traefik - --providers.kubernetescrd=true - --providers.kubernetescrd.ingressClass=traefik-lan - --providers.kubernetescrd.allowCrossNamespace=true - --providers.kubernetescrd.allowEmptyServices=true - --log.format=json - --accesslog=true - --accesslog.format=json - - - - - - - - - - services - endpoints - pods - nodes - get - list - watch - - - ingressroutes - get - list - watch - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - external-dns - namespace.yaml - rollout-events - traefik-lan - traefik-public - vault-policy - vaultconnection.yaml - - - - - pvc.yaml - rbac.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - middlewares.yaml - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - read - - - read - - - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/edge/projects b/emf/bundles/cli/src/test/resources/stages/resolve/edge/projects deleted file mode 100644 index 54aeb5dc2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/edge/projects +++ /dev/null @@ -1 +0,0 @@ -edge diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/auth.dependencies.json b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/auth.dependencies.json deleted file mode 100644 index 4461c5748..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/auth.dependencies.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"edges":[{"address":"platform-postgres:5432","application":"platform-postgres","consumer":"auth-api","peers":[{"namespace":"data-system","port":5432,"process":"postgres"}],"surface":"postgres","target":"platform-postgres-postgres.estate-system.svc.cluster.local"},{"address":"platform-valkey:6379","application":"platform-valkey","consumer":"auth-api","peers":[{"namespace":"data-system","port":6379,"process":"valkey"}],"surface":"redis","target":"platform-valkey-redis.estate-system.svc.cluster.local"},{"address":"platform-rabbitmq:5672","application":"platform-rabbitmq","consumer":"auth-api","peers":[{"namespace":"data-system","port":5672,"process":"rabbitmq"}],"surface":"amqp","target":"platform-rabbitmq-amqp.estate-system.svc.cluster.local"},{"address":"stalwart:25","application":"stalwart","consumer":"auth-api","peers":[{"namespace":"mail-system","port":25,"process":"stalwart"}],"surface":"smtp","target":"stalwart-smtp.estate-system.svc.cluster.local"}],"id":"auth"}]} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/auth.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/auth.resolveddeployment deleted file mode 100644 index 5e45fc31e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/auth.resolveddeployment +++ /dev/null @@ -1,414 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - error-rate - latency - - - - - - - - - platform-postgres.postgres - - - read - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - frankfurt-contabo-1 - - - user - password - - - mail.password - valkey.password - rabbitmq.user - rabbitmq.password - - - - update - - - update - - - read - - - - - read - - - - - - - - - - - - - - - platform-postgres.postgres - platform-valkey.redis - platform-rabbitmq.amqp - stalwart.smtp - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - NET_BIND_SERVICE - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - platform-postgres.postgres - - - - - read - - - read - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - knowledge-platform-assets - - - platform-garage.admin - - - - - read - - - read - - - create - read - update - - - - - - aliases.yaml - auth - namespace.yaml - rollout-events - vault-policy - vaultconnection.yaml - - - - - - - - - - - canary.yaml - configmap.yaml - migration.yaml - pdb.yaml - podmonitor.yaml - route-public.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - read - - - read - - - read - - - read - - - update - - - update - - - read - - - read - - - - - - read - - - - - - - - - - - - namespace.yaml - services.yaml - - - - - - - priorityclasses.yaml - - - - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/data.dependencies.json b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/data.dependencies.json deleted file mode 100644 index a34c99f60..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/data.dependencies.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"edges":[],"id":"platform-postgres"},{"edges":[],"id":"platform-rabbitmq"},{"edges":[],"id":"platform-valkey"},{"edges":[],"id":"platform-mongo"},{"edges":[],"id":"asset-sync"},{"edges":[],"id":"platform-garage"}]} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/data.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/data.resolveddeployment deleted file mode 100644 index 74fbbbfa2..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/data.resolveddeployment +++ /dev/null @@ -1,713 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - - - - - - - - datasource - postgres - - - - datasource - postgres - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DS_PROMETHEUS - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - mongo.data-system.svc.cluster.local - - - - - - - frankfurt-contabo-1 - - - credentials - - - - - - - - - - - - - - - - - - frankfurt-contabo-1 - - - - - - - - - - - - - - rpc-secret - admin-token - garage - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - platform-postgres.postgres - - - - - read - - - read - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - knowledge-platform-assets - - - platform-garage.admin - - - - - read - - - read - - - create - read - update - - - - - - asset-sync - namespace.yaml - platform-garage - platform-mongo - platform-postgres - platform-rabbitmq - platform-valkey - rollout-events - vault-policy - vaultconnection.yaml - - - - - backup.yaml - configmap.yaml - postgres-catalog.yaml - pvc.yaml - service.yaml - serviceaccount.yaml - servicemonitor.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - - backup.yaml - configmap.yaml - dashboards.yaml - pvc.yaml - route-lan.yaml - route-management.yaml - service.yaml - serviceaccount.yaml - servicemonitor.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - pvc.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - backup.yaml - pvc.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - backup.yaml - configmap.yaml - garage-catalog.yaml - pvc.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - read - - - read - - - read - - - read - - - - - - read - - - read - - - read - - - read - - - - - - read - - - read - - - - - - read - - - read - - - read - - - read - - - - - - read - - - read - - - - - - read - - - read - - - - - - - - - - - - priorityclasses.yaml - - - - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/delivery.dependencies.json b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/delivery.dependencies.json deleted file mode 100644 index c53cb560e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/delivery.dependencies.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"edges":[{"address":"release-gate:8080","application":"release-gate","consumer":"flagger","peers":[{"namespace":"delivery-system","port":8080,"process":"release-gate"}],"surface":"http"}],"id":"flagger"},{"edges":[],"id":"release-gate"},{"edges":[],"id":"collector"},{"edges":[],"id":"reporter"}]} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/delivery.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/delivery.resolveddeployment deleted file mode 100644 index 5c8cee8de..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/delivery.resolveddeployment +++ /dev/null @@ -1,436 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - canaries - canaries/status - get - list - watch - update - patch - - - deployments - get - list - watch - create - update - patch - delete - - - horizontalpodautoscalers - get - list - watch - create - update - patch - delete - - - services - configmaps - get - list - watch - create - update - patch - delete - - - secrets - get - - - events - create - update - patch - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - release-gate.http - - - - - - - - - - - configmaps - get - list - - - configmaps - create - update - - - pods - list - - - deployments - get - - - jobs - list - patch - - - canaries - get - - - vaultauths - vaultstaticsecrets - vaultdynamicsecrets - list - delete - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - persistentvolumes - persistentvolumeclaims - pods - get - list - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - kustomizations - get - list - watch - - - canaries - get - list - watch - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - platform-postgres.postgres - - - - - read - - - read - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - knowledge-platform-assets - - - platform-garage.admin - - - - - read - - - read - - - create - read - update - - - - - - collector - flagger - namespace.yaml - release-gate - reporter - rollout-events - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - servicemonitor.yaml - workload.yaml - - - - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - namespace.yaml - services.yaml - - - - - - - priorityclasses.yaml - - - - - - - - - clusterrolebindings.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/edge.dependencies.json b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/edge.dependencies.json deleted file mode 100644 index 6290d4e48..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/edge.dependencies.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"edges":[],"id":"traefik-public"},{"edges":[],"id":"traefik-lan"},{"edges":[],"id":"external-dns"}]} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/edge.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/edge.resolveddeployment deleted file mode 100644 index b30f54bfe..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/edge.resolveddeployment +++ /dev/null @@ -1,486 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - services - secrets - nodes - configmaps - namespaces - get - list - watch - - - pods - get - - - endpointslices - get - list - watch - - - ingressroutes - ingressroutetcps - ingressrouteudps - middlewares - middlewaretcps - serverstransports - serverstransporttcps - tlsoptions - tlsstores - traefikservices - get - list - watch - - - - - - - - - - - - - - - - - - frankfurt-contabo-1 - - - - CF_DNS_API_TOKEN - traefik-public - - - - - - --entryPoints.web.address=:8000/tcp - --entryPoints.websecure.address=:8443/tcp - --entryPoints.websecure.http.tls=true - --entryPoints.traefik.address=:8080/tcp - --ping=true - --ping.entryPoint=traefik - --metrics.prometheus=true - --metrics.prometheus.entryPoint=traefik - --providers.kubernetescrd=true - --providers.kubernetescrd.ingressClass=traefik-public - --providers.kubernetescrd.allowCrossNamespace=true - --providers.kubernetescrd.allowEmptyServices=true - --certificatesresolvers.public-frankfurt.acme.email=hostmaster@jorisjonkers.dev - --certificatesresolvers.public-frankfurt.acme.storage=/acme/public-frankfurt.json - --certificatesresolvers.public-frankfurt.acme.dnschallenge.provider=cloudflare - --log.format=json - --accesslog=true - --accesslog.format=json - - - - - - - services - secrets - nodes - configmaps - namespaces - get - list - watch - - - pods - get - - - endpointslices - get - list - watch - - - ingressroutes - ingressroutetcps - ingressrouteudps - middlewares - middlewaretcps - serverstransports - serverstransporttcps - tlsoptions - tlsstores - traefikservices - get - list - watch - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - - - tls.crt - tls.key - - - --entryPoints.web.address=:8000/tcp - --entryPoints.websecure.address=:8443/tcp - --entryPoints.websecure.http.tls=true - --entryPoints.traefik.address=:8080/tcp - --ping=true - --ping.entryPoint=traefik - --metrics.prometheus=true - --metrics.prometheus.entryPoint=traefik - --providers.kubernetescrd=true - --providers.kubernetescrd.ingressClass=traefik-lan - --providers.kubernetescrd.allowCrossNamespace=true - --providers.kubernetescrd.allowEmptyServices=true - --log.format=json - --accesslog=true - --accesslog.format=json - - - - - - - - - - - services - endpoints - pods - nodes - get - list - watch - - - ingressroutes - get - list - watch - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - platform-postgres.postgres - - - - - read - - - read - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - knowledge-platform-assets - - - platform-garage.admin - - - - - read - - - read - - - create - read - update - - - - - - external-dns - namespace.yaml - rollout-events - traefik-lan - traefik-public - vault-policy - vaultconnection.yaml - - - - - pvc.yaml - rbac.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - middlewares.yaml - rbac.yaml - service.yaml - serviceaccount.yaml - tlsstore.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - read - - - read - - - - - - read - - - read - - - - - - - - - priorityclasses.yaml - - - - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/identity.dependencies.json b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/identity.dependencies.json deleted file mode 100644 index 13cc96844..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/identity.dependencies.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"edges":[],"id":"identity"},{"edges":[],"id":"portal"},{"edges":[],"id":"whoami"}]} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/identity.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/identity.resolveddeployment deleted file mode 100644 index 8b2e4287e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/identity.resolveddeployment +++ /dev/null @@ -1,365 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - create - read - update - - - - - - - - - - - - - - - - - - - https://home.jorisjonkers.dev/callback - https://home.jorisjonkers.dev/silent-renew - user - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - - - - - - - - - user - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - platform-postgres.postgres - - - - - read - - - read - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - knowledge-platform-assets - - - platform-garage.admin - - - - - read - - - read - - - create - read - update - - - - - - identity - namespace.yaml - portal - rollout-events - vault-policy - vaultconnection.yaml - whoami - - - - - canary.yaml - configmap.yaml - route-public.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - canary.yaml - client.yaml - configmap.yaml - route-public.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - canary.yaml - client.yaml - configmap.yaml - pdb.yaml - route-public.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - create - read - update - - - - - - - - - priorityclasses.yaml - - - - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/mail.dependencies.json b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/mail.dependencies.json deleted file mode 100644 index 6a4667909..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/mail.dependencies.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"edges":[],"id":"stalwart"}]} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/mail.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/mail.resolveddeployment deleted file mode 100644 index 0ed0ed567..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/mail.resolveddeployment +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - frankfurt-contabo-1 - - - - - - - - NET_BIND_SERVICE - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - platform-postgres.postgres - - - - - read - - - read - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - knowledge-platform-assets - - - platform-garage.admin - - - - - read - - - read - - - create - read - update - - - - - - namespace.yaml - rollout-events - stalwart - - - - configmap.yaml - route-admin.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - priorityclasses.yaml - - - - - - - - - clusterrolebindings.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/node.dependencies.json b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/node.dependencies.json deleted file mode 100644 index 6639ee8cf..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/node.dependencies.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[]} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/node.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/node.resolveddeployment deleted file mode 100644 index 6d7a6cb44..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/node.resolveddeployment +++ /dev/null @@ -1,345 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - enschede-t1000-1 - enschede-gtx-960m-1 - - - - - - - - - - - enschede-t1000-1 - enschede-gtx-960m-1 - - - - SYS_ADMIN - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - --port=7472 - --namespace=node-system - --log-level=info - - - - - - - - - NET_RAW - - services - endpoints - nodes - namespaces - pods - get - list - watch - - - endpointslices - get - list - watch - - - events - create - patch - - - ipaddresspools - l2advertisements - bgppeers - bgpadvertisements - communities - bfdprofiles - servicel2statuses - get - list - watch - - - servicel2statuses - servicel2statuses/status - create - delete - update - patch - - - configurationstates - configurationstates/status - get - list - watch - create - update - patch - delete - - - secrets - configmaps - get - list - watch - - - servicebgpstatuses - get - list - watch - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - --port=7472 - --namespace=node-system - --webhook-mode=disabled - --log-level=info - - - services - namespaces - nodes - get - list - watch - - - services/status - update - - - events - create - patch - - - ipaddresspools - l2advertisements - bgppeers - bgpadvertisements - communities - bfdprofiles - get - list - watch - - - ipaddresspools/status - update - - - configurationstates - configurationstates/status - get - list - watch - create - update - patch - delete - - - secrets - configmaps - get - list - watch - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - --path.procfs=/host/proc - --path.sysfs=/host/sys - --path.rootfs=/host/root - --web.listen-address=:9100 - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - - gpu-device - gpu-metrics - l4-speaker - namespace.yaml - node-metrics - vault-policy - vaultconnection.yaml - - - - - - configmap.yaml - serviceaccount.yaml - workload.yaml - - - - - serviceaccount.yaml - workload.yaml - - - - - - - - pools.yaml - rbac.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - serviceaccount.yaml - workload.yaml - - - - - read - - - read - - - - - - - - - - - - priorityclasses.yaml - - - - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/notes.dependencies.json b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/notes.dependencies.json deleted file mode 100644 index 3a9a3da2f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/notes.dependencies.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"edges":[],"id":"notes"}]} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/notes.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/notes.resolveddeployment deleted file mode 100644 index 4804bb1ae..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/notes.resolveddeployment +++ /dev/null @@ -1,209 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - error-rate - latency - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - platform-postgres.postgres - - - - - read - - - read - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - knowledge-platform-assets - - - platform-garage.admin - - - - - read - - - read - - - create - read - update - - - - - - libraries.yaml - namespace.yaml - notes - rollout-events - - - - - canary.yaml - configmap.yaml - podmonitor.yaml - route-public.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - priorityclasses.yaml - - - - - - - - - clusterrolebindings.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/observability.dependencies.json b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/observability.dependencies.json deleted file mode 100644 index 1697260ef..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/observability.dependencies.json +++ /dev/null @@ -1 +0,0 @@ -{"applications":[{"edges":[],"id":"otel-collector"},{"edges":[],"id":"prometheus"},{"edges":[],"id":"prometheus-operator"},{"edges":[],"id":"kube-state-metrics"},{"edges":[],"id":"grafana-operator"},{"edges":[],"id":"grafana"},{"edges":[],"id":"loki"},{"edges":[],"id":"tempo"},{"edges":[],"id":"pyroscope"},{"edges":[],"id":"gatus"},{"edges":[],"id":"alloy"},{"edges":[],"id":"alertmanager"}]} \ No newline at end of file diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/observability.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/observability.resolveddeployment deleted file mode 100644 index 185de9488..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/expected/observability.resolveddeployment +++ /dev/null @@ -1,1067 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - services - endpoints - pods - get - list - watch - - - endpointslices - get - list - watch - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - --storage.tsdb.retention.time=15d - --storage.tsdb.retention.size=10GB - --enable-feature=exemplar-storage - --enable-feature=native-histograms - --web.enable-remote-write-receiver - --log.level=info - --query.max-concurrency - - - - - - exemplar-storage - native-histograms - - - - - - - - prometheuses - prometheuses/status - alertmanagers - alertmanagers/status - servicemonitors - podmonitors - prometheusrules - alertmanagerconfigs - get - list - watch - create - update - patch - delete - - - services - endpoints - pods - nodes - namespaces - configmaps - secrets - get - list - watch - create - update - delete - - - statefulsets - get - list - watch - create - update - delete - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - pods - nodes - namespaces - services - persistentvolumeclaims - persistentvolumes - list - watch - - - deployments - statefulsets - daemonsets - replicasets - list - watch - - - jobs - cronjobs - list - watch - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - grafanas - grafanas/status - grafanadashboards - grafanadashboards/status - get - list - watch - update - patch - - - configmaps - secrets - get - list - watch - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - https://grafana.jorisjonkers.dev/login/generic_oauth - user - viewer - editor - admin - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - id - secret - grafana - - - user - password - grafana - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - configmaps - get - list - watch - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - pods - pods/log - namespaces - get - list - watch - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - webhook-url - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - platform-postgres.postgres - - - - - read - - - read - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - create - read - update - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - knowledge-platform-assets - - - platform-garage.admin - - - - - read - - - read - - - create - read - update - - - - - - alertmanager - alloy - gatus - grafana - grafana-operator - kube-state-metrics - loki - namespace.yaml - otel-collector - prometheus - prometheus-operator - pyroscope - rollout-events - tempo - vault-policy - vaultconnection.yaml - - - - - canary.yaml - configmap.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - alertrules.yaml - flux-podmonitor.yaml - k3s-monitors.yaml - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - canary.yaml - configmap.yaml - rbac.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - canary.yaml - client.yaml - configmap.yaml - grafana.yaml - route-public.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - pvc.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - pvc.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - pvc.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - canary.yaml - configmap.yaml - rbac.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - alertmanagerconfig.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - read - - - read - - - read - - - read - - - - - - read - - - read - - - - - - - - - - - - - priorityclasses.yaml - - - - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/estate/projects b/emf/bundles/cli/src/test/resources/stages/resolve/estate/projects deleted file mode 100644 index 43c563a3f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/estate/projects +++ /dev/null @@ -1,9 +0,0 @@ -notes -data -auth -delivery -mail -identity -edge -node -observability diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/gaps.txt b/emf/bundles/cli/src/test/resources/stages/resolve/gaps.txt deleted file mode 100644 index e1f1b6380..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/gaps.txt +++ /dev/null @@ -1,73 +0,0 @@ -ContentPolicy.admin is never used in a resolve case's input -ContentPolicy.workflow is never used in a resolve case's input -ControllerKind.statefulSet is never used by a resolve case -DatabaseEngine.database is never used in a resolve case's input -DatabaseGrant is never instantiated in a resolve case's input -DatabaseGrant.delivery is never set in a resolve case's input -DatabaseGrant.engine is never set in a resolve case's input -DatabaseGrant.fileMode is never set in a resolve case's input -DatabaseGrant.mountAt is never set in a resolve case's input -DatabaseGrant.role is never set in a resolve case's input -DatabaseGrant.rotation is never set in a resolve case's input -Datastore.etcd is never used in a resolve case's input -Engine.valkey is never used in a resolve case's input -FluxUnit is never instantiated by a resolve case -FluxUnit.annotations is never set by a resolve case -FluxUnit.dependsOn is never set by a resolve case -FluxUnit.forcesDeployments is never set by a resolve case -FluxUnit.name is never set by a resolve case -FluxUnit.path is never set by a resolve case -GateMember.waitsFor is never set by a resolve case -GateProvider is never instantiated by a resolve case -GateProvider.application is never set by a resolve case -GateProvider.process is never set by a resolve case -IndexFile.namespace is never set by a resolve case -PolicyController.cni is never used in a resolve case's input -PolicyController.none is never used in a resolve case's input -PolicyPeer.protocol is never set by a resolve case -RenderSource is never instantiated by a resolve case -RenderSource.digest is never set by a resolve case -RenderSource.issuer is never set by a resolve case -RenderSource.name is never set by a resolve case -RenderSource.subject is never set by a resolve case -RenderSource.url is never set by a resolve case -ResolvedApplication.alertClass is never set by a resolve case -ResolvedAsset.seedAt is never set by a resolve case -ResolvedClient.backChannelLogoutUri is never set by a resolve case -ResolvedPlacement.boundTo is never set by a resolve case -ResolvedPlacement.from is never set by a resolve case -ResolvedProcess.command is never set by a resolve case -ResolvedProcess.nameservers is never set by a resolve case -ResolvedProcess.seeder is never set by a resolve case -ResolvedProcess.spawns is never set by a resolve case -ResolvedProcess.vpn is never set by a resolve case -ResolvedSeeder is never instantiated by a resolve case -ResolvedSeeder.command is never set by a resolve case -ResolvedSeeder.cpu is never set by a resolve case -ResolvedSeeder.image is never set by a resolve case -ResolvedSeeder.imageVersion is never set by a resolve case -ResolvedSeeder.memory is never set by a resolve case -ResolvedSeeder.mounts is never set by a resolve case -ResolvedSidecar.arguments is never set by a resolve case -ResolvedSidecar.command is never set by a resolve case -ResolvedSpawn is never instantiated by a resolve case -ResolvedSpawn.dependencies is never set by a resolve case -ResolvedSpawn.egress is never set by a resolve case -ResolvedSpawn.internetEgress is never set by a resolve case -ResolvedSpawn.name is never set by a resolve case -ResolvedSpawn.surfaces is never set by a resolve case -ResolvedVpn is never instantiated by a resolve case -ResolvedVpn.cpu is never set by a resolve case -ResolvedVpn.credential is never set by a resolve case -ResolvedVpn.environment is never set by a resolve case -ResolvedVpn.forwardedPort is never set by a resolve case -ResolvedVpn.image is never set by a resolve case -ResolvedVpn.imageVersion is never set by a resolve case -ResolvedVpn.memory is never set by a resolve case -SignInMode.token is never used in a resolve case's input -SourceFile is never instantiated by a resolve case -SourceFile.adapter is never set by a resolve case -SourceFile.path is never set by a resolve case -SourceFile.source is never set by a resolve case -SourceFile.units is never set by a resolve case -WorkloadFile.disruptionBudget is never set by a resolve case diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/identity/expected/identity.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/identity/expected/identity.resolveddeployment deleted file mode 100644 index d7a6f434f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/identity/expected/identity.resolveddeployment +++ /dev/null @@ -1,278 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - create - read - update - - - - - - - - - - - - - - - - - - - https://home.jorisjonkers.dev/callback - https://home.jorisjonkers.dev/silent-renew - user - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - - - - - - - - - user - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - identity - namespace.yaml - portal - rollout-events - vault-policy - vaultconnection.yaml - whoami - - - - - canary.yaml - configmap.yaml - route-public.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - canary.yaml - client.yaml - configmap.yaml - route-public.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - canary.yaml - client.yaml - configmap.yaml - pdb.yaml - route-public.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - create - read - update - - - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/identity/projects b/emf/bundles/cli/src/test/resources/stages/resolve/identity/projects deleted file mode 100644 index 29d727736..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/identity/projects +++ /dev/null @@ -1 +0,0 @@ -identity diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/knowledge-platform/expected/knowledge-platform.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/knowledge-platform/expected/knowledge-platform.resolveddeployment deleted file mode 100644 index 7f30ffe64..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/knowledge-platform/expected/knowledge-platform.resolveddeployment +++ /dev/null @@ -1,782 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - - - - - error-rate - latency - - - - - error-rate - latency - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - llm-api-key - hindsight-api - - - - read - - hindsight-api - - - - - - - - platform-postgres.postgres - hindsight-embedding.embeddings - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - llm-api-key - hindsight-worker - - - - read - - hindsight-worker - - - - - - - - platform-postgres.postgres - hindsight-embedding.embeddings - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - - - hindsight.api - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - frankfurt-contabo-1 - - - - - private_key - basic-memory - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - frankfurt-contabo-1 - - - - - - - - - - nextauth-secret - meili-master-key - openrouter-api-key - karakeep - - - access-key-id - secret-access-key - - - - - - - - - platform-garage.s3 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - platform-postgres.postgres - - - - - read - - - read - - - create - read - update - - - create - read - update - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - knowledge-platform-assets - - - platform-garage.admin - - - - - read - - - read - - - create - read - update - - - - - - aliases.yaml - basic-memory - docling-serve - hindsight - hindsight-embedding - karakeep - namespace.yaml - rollout-events - vault-policy - vaultconnection.yaml - - - - - - - - - backup.yaml - pvc.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - canary.yaml - configmap.yaml - route-api.yaml - route-console.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - pvc.yaml - route-mcp.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - backup.yaml - configmap.yaml - pvc.yaml - route-public.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - pvc.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - read - - - read - - - - - - read - - - read - - - read - - - - - - read - - - read - - - read - - - - - - read - - - read - - - - - - read - - - read - - - read - - - read - - - read - - - read - - - - - - - - - - - - namespace.yaml - services.yaml - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/knowledge-platform/projects b/emf/bundles/cli/src/test/resources/stages/resolve/knowledge-platform/projects deleted file mode 100644 index 5ff8b0d47..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/knowledge-platform/projects +++ /dev/null @@ -1 +0,0 @@ -knowledge-platform diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/mail/expected/mail.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/mail/expected/mail.resolveddeployment deleted file mode 100644 index 614f68200..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/mail/expected/mail.resolveddeployment +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - frankfurt-contabo-1 - - - - - - - NET_BIND_SERVICE - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - namespace.yaml - rollout-events - stalwart - - - - configmap.yaml - route-admin.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/mail/projects b/emf/bundles/cli/src/test/resources/stages/resolve/mail/projects deleted file mode 100644 index fa7963cc9..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/mail/projects +++ /dev/null @@ -1 +0,0 @@ -mail diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/minimal-main/expected/notes.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/minimal-main/expected/notes.resolveddeployment deleted file mode 100644 index 56dcc6f12..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/minimal-main/expected/notes.resolveddeployment +++ /dev/null @@ -1,123 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - error-rate - latency - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - libraries.yaml - namespace.yaml - notes - rollout-events - - - - - canary.yaml - configmap.yaml - podmonitor.yaml - route-public.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/minimal-main/projects b/emf/bundles/cli/src/test/resources/stages/resolve/minimal-main/projects deleted file mode 100644 index bfa655111..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/minimal-main/projects +++ /dev/null @@ -1 +0,0 @@ -notes diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/node/expected/node.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/node/expected/node.resolveddeployment deleted file mode 100644 index 0d8be73d6..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/node/expected/node.resolveddeployment +++ /dev/null @@ -1,337 +0,0 @@ - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - enschede-t1000-1 - enschede-gtx-960m-1 - - - - - - - - - - - enschede-t1000-1 - enschede-gtx-960m-1 - - - - SYS_ADMIN - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - --port=7472 - --namespace=node-system - --log-level=info - - - - - - - - - NET_RAW - - services - endpoints - nodes - namespaces - pods - get - list - watch - - - endpointslices - get - list - watch - - - events - create - patch - - - ipaddresspools - l2advertisements - bgppeers - bgpadvertisements - communities - bfdprofiles - servicel2statuses - get - list - watch - - - servicel2statuses - servicel2statuses/status - create - delete - update - patch - - - configurationstates - configurationstates/status - get - list - watch - create - update - patch - delete - - - secrets - configmaps - get - list - watch - - - servicebgpstatuses - get - list - watch - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - --port=7472 - --namespace=node-system - --webhook-mode=disabled - --log-level=info - - - services - namespaces - nodes - get - list - watch - - - services/status - update - - - events - create - patch - - - ipaddresspools - l2advertisements - bgppeers - bgpadvertisements - communities - bfdprofiles - get - list - watch - - - ipaddresspools/status - update - - - configurationstates - configurationstates/status - get - list - watch - create - update - patch - delete - - - secrets - configmaps - get - list - watch - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - --path.procfs=/host/proc - --path.sysfs=/host/sys - --path.rootfs=/host/root - --web.listen-address=:9100 - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - - gpu-device - gpu-metrics - l4-speaker - namespace.yaml - node-metrics - vault-policy - vaultconnection.yaml - - - - - - configmap.yaml - serviceaccount.yaml - workload.yaml - - - - - serviceaccount.yaml - workload.yaml - - - - - - - - pools.yaml - rbac.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - serviceaccount.yaml - workload.yaml - - - - - read - - - read - - - - - - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/node/projects b/emf/bundles/cli/src/test/resources/stages/resolve/node/projects deleted file mode 100644 index 64f5a0a68..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/node/projects +++ /dev/null @@ -1 +0,0 @@ -node diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/observability/expected/observability.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/observability/expected/observability.resolveddeployment deleted file mode 100644 index 26f466a2e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/observability/expected/observability.resolveddeployment +++ /dev/null @@ -1,929 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - services - endpoints - pods - get - list - watch - - - endpointslices - get - list - watch - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - prometheuses - prometheuses/status - alertmanagers - alertmanagers/status - servicemonitors - podmonitors - prometheusrules - alertmanagerconfigs - get - list - watch - create - update - patch - delete - - - services - endpoints - pods - nodes - namespaces - configmaps - secrets - get - list - watch - create - update - delete - - - statefulsets - get - list - watch - create - update - delete - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - pods - nodes - namespaces - services - persistentvolumeclaims - persistentvolumes - list - watch - - - deployments - statefulsets - daemonsets - replicasets - list - watch - - - jobs - cronjobs - list - watch - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - grafanas - grafanas/status - grafanadashboards - grafanadashboards/status - get - list - watch - update - patch - - - configmaps - secrets - get - list - watch - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - https://grafana.jorisjonkers.dev/login/generic_oauth - user - viewer - editor - admin - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - id - secret - grafana - - - user - password - grafana - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - configmaps - get - list - watch - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - pods - pods/log - namespaces - get - list - watch - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - webhook-url - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - alertmanager - alloy - gatus - grafana - grafana-operator - kube-state-metrics - loki - namespace.yaml - otel-collector - prometheus - prometheus-operator - pyroscope - rollout-events - tempo - vault-policy - vaultconnection.yaml - - - - - canary.yaml - configmap.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - alertrules.yaml - flux-podmonitor.yaml - k3s-monitors.yaml - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - canary.yaml - configmap.yaml - rbac.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - canary.yaml - client.yaml - configmap.yaml - grafana.yaml - route-public.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - pvc.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - pvc.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - pvc.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - canary.yaml - configmap.yaml - rbac.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - alertmanagerconfig.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - read - - - read - - - read - - - read - - - - - - read - - - read - - - - - - - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/observability/projects b/emf/bundles/cli/src/test/resources/stages/resolve/observability/projects deleted file mode 100644 index d57392940..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/observability/projects +++ /dev/null @@ -1 +0,0 @@ -observability diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/pins/expected/pins.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/pins/expected/pins.resolveddeployment deleted file mode 100644 index c960166ce..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/pins/expected/pins.resolveddeployment +++ /dev/null @@ -1,84 +0,0 @@ - - - - - - - - - enschede-t1000-1 - - - - - - - - - - - - - apps-edge - apps-secrets - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - apps-edge - - - - - - - - - - - apps-edge - - - - - - - - - - - - - - - - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/pins/projects b/emf/bundles/cli/src/test/resources/stages/resolve/pins/projects deleted file mode 100644 index 0e7f5503e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/pins/projects +++ /dev/null @@ -1 +0,0 @@ -pins diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/platform/expected/platform.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/platform/expected/platform.resolveddeployment deleted file mode 100644 index 021e75c0d..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/platform/expected/platform.resolveddeployment +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - enschede-t1000-1 - - - - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/platform/projects b/emf/bundles/cli/src/test/resources/stages/resolve/platform/projects deleted file mode 100644 index f99e8394e..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/platform/projects +++ /dev/null @@ -1 +0,0 @@ -platform diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/utility/expected/utility.resolveddeployment b/emf/bundles/cli/src/test/resources/stages/resolve/utility/expected/utility.resolveddeployment deleted file mode 100644 index fd67ec85f..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/utility/expected/utility.resolveddeployment +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - - - - - 9.9.9.10 - 149.112.112.10 - - /bin/sh - -c - set -eu -umask 077 -mkdir -p '/opt/adguardhome/conf' -if [ -e '/opt/adguardhome/conf/AdGuardHome.yaml' ]; then cp -p '/opt/adguardhome/conf/AdGuardHome.yaml' '/opt/adguardhome/conf/AdGuardHome.yaml.superseded'; fi -cp '/seed/adguard-adguardhome-yaml-85a1bf27a7/AdGuardHome.yaml' '/opt/adguardhome/conf/AdGuardHome.yaml.seeding' -chmod 0600 '/opt/adguardhome/conf/AdGuardHome.yaml.seeding' -mv '/opt/adguardhome/conf/AdGuardHome.yaml.seeding' '/opt/adguardhome/conf/AdGuardHome.yaml' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - adguard - headlamp - namespace.yaml - rollout-events - - - - canary.yaml - configmap.yaml - pdb.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - canary.yaml - configmap.yaml - route-lan.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/bundles/cli/src/test/resources/stages/resolve/utility/projects b/emf/bundles/cli/src/test/resources/stages/resolve/utility/projects deleted file mode 100644 index ee6a762e4..000000000 --- a/emf/bundles/cli/src/test/resources/stages/resolve/utility/projects +++ /dev/null @@ -1 +0,0 @@ -utility diff --git a/emf/bundles/metamodel/META-INF/MANIFEST.MF b/emf/bundles/metamodel/META-INF/MANIFEST.MF deleted file mode 100644 index 7477f427a..000000000 --- a/emf/bundles/metamodel/META-INF/MANIFEST.MF +++ /dev/null @@ -1,27 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: deploy-kit model-driven metamodel -Bundle-SymbolicName: dev.jorisjonkers.deploykit.emf.metamodel;singleton:=true -Bundle-Version: 0.1.0.qualifier -Bundle-RequiredExecutionEnvironment: JavaSE-21 -Automatic-Module-Name: dev.jorisjonkers.deploykit.emf.metamodel -Export-Package: dev.jorisjonkers.deploykit.emf.metamodel.descriptor, - dev.jorisjonkers.deploykit.emf.metamodel.json, - dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs, - dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.impl, - dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.util, - dev.jorisjonkers.deploykit.emf.metamodel.projectintent, - dev.jorisjonkers.deploykit.emf.metamodel.projectintent.impl, - dev.jorisjonkers.deploykit.emf.metamodel.projectintent.util, - dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment, - dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.impl, - dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.util, - dev.jorisjonkers.deploykit.emf.metamodel.revision -Require-Bundle: org.eclipse.emf.ecore;visibility:=reexport, - org.eclipse.emf.ecore.xmi, - org.eclipse.ocl.pivot, - org.eclipse.ocl.xtext.completeocl, - org.eclipse.emf.mwe2.launch, - org.eclipse.emf.mwe.utils, - org.eclipse.emf.mwe2.lib, - org.eclipse.emf.codegen.ecore diff --git a/emf/bundles/metamodel/build.properties b/emf/bundles/metamodel/build.properties deleted file mode 100644 index ccdc6bdbc..000000000 --- a/emf/bundles/metamodel/build.properties +++ /dev/null @@ -1,7 +0,0 @@ -source.. = src/main/java/,\ - model/,\ - target/generated-sources/emf/ -bin.includes = META-INF/,\ - .,\ - plugin.xml,\ - model/ diff --git a/emf/bundles/metamodel/model/cache-continuous.xmi b/emf/bundles/metamodel/model/cache-continuous.xmi deleted file mode 100644 index 56ff67d28..000000000 --- a/emf/bundles/metamodel/model/cache-continuous.xmi +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/emf/bundles/metamodel/model/cache.xmi b/emf/bundles/metamodel/model/cache.xmi deleted file mode 100644 index 544aca0b5..000000000 --- a/emf/bundles/metamodel/model/cache.xmi +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/emf/bundles/metamodel/model/pinned-inputs.ecore b/emf/bundles/metamodel/model/pinned-inputs.ecore deleted file mode 100644 index a0cf4da99..000000000 --- a/emf/bundles/metamodel/model/pinned-inputs.ecore +++ /dev/null @@ -1,168 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/emf/bundles/metamodel/model/pinned-inputs.genmodel b/emf/bundles/metamodel/model/pinned-inputs.genmodel deleted file mode 100644 index 8f08c4cc1..000000000 --- a/emf/bundles/metamodel/model/pinned-inputs.genmodel +++ /dev/null @@ -1,9 +0,0 @@ - - - pinned-inputs.ecore - - diff --git a/emf/bundles/metamodel/model/project-intent.ecore b/emf/bundles/metamodel/model/project-intent.ecore deleted file mode 100644 index 6d1b501dd..000000000 --- a/emf/bundles/metamodel/model/project-intent.ecore +++ /dev/null @@ -1,996 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - -
- - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/emf/bundles/metamodel/model/project-intent.genmodel b/emf/bundles/metamodel/model/project-intent.genmodel deleted file mode 100644 index 011a67b6f..000000000 --- a/emf/bundles/metamodel/model/project-intent.genmodel +++ /dev/null @@ -1,9 +0,0 @@ - - - project-intent.ecore - - diff --git a/emf/bundles/metamodel/model/project-intent.ocl b/emf/bundles/metamodel/model/project-intent.ocl deleted file mode 100644 index d25f958c5..000000000 --- a/emf/bundles/metamodel/model/project-intent.ocl +++ /dev/null @@ -1,1207 +0,0 @@ --- Document-level constraints of Project Intent (docs/adr/emf/0110). Each --- invariant is named after the diagnostic code it reports. - --- The metamodel is imported as the file beside this one, not by its nsURI: in --- Eclipse, OCL > Load Document resolves an nsURI import as a URL to download, and --- the file is the one the examiner's editor already holds (emf/README.md, step 3). -import 'project-intent.ecore' - -package projectintent - -context Application - -- The Release Unit switches as one, so its members answer the cutover - -- question alike: an interrupted member's gap inside a unit that promised - -- to keep serving makes neither answer true of the unit. Jobs switch - -- nothing, and a member no level answers is E_CUTOVER_MISSING's. - inv E_RELEASE_UNIT_MIXED_CUTOVER: - processes->select(lifecycle = Lifecycle::application - and effectiveCutover <> Cutover::absent) - ->collect(effectiveCutover)->asSet()->size() <= 1 - - -- A continuous Application switches blue/green, and the gate analyses the - -- switch at the platform's cadence, so the platform must offer one. - inv E_NO_DELIVERY_POLICY: - processes->exists(lifecycle = Lifecycle::application - and effectiveCutover = Cutover::continuous) - implies Platform.allInstances()->forAll(delivery <> null) - -context Process - -- A volume cannot attach to the second copy a continuous cutover starts - -- beside the old one, and a silent downgrade is what makes an owner believe - -- in continuity they do not have. The effective answer: an RWO volume under - -- an Application declaring `continuous` is the same defect written one - -- level up. - inv E_CUTOVER_UNHONOURABLE: - (runsToCompletion = false and effectiveCutover = Cutover::continuous) - implies (volumes->isEmpty() - -- A host port holds one copy as a volume does, unless the delivery - -- machinery cuts the Process over rolling, never a pod more. - and (not onNode or Platform.allInstances()->exists(p | p.delivery <> null - and p.delivery.machinery->includes(oclContainer().oclAsType(Application))))) - - -- The engine keys the backup method and, where it owns databases, the catalog - -- its consumers derive, so it names something nothing asks for only when no - -- volume derives a backup and it owns no database. `Engine::absent` is the - -- literal a document cannot write: EMF reads an unset enumeration as its first - -- literal, so the model gives absence one of its own. - inv E_ENGINE_WITHOUT_DURABILITY: - engine <> Engine::absent implies - (volumes->exists(durability = DurabilityClass::recoverable or durability = DurabilityClass::irreplaceable) - or engine = Engine::postgres) - -context Volume - -- The backup method comes from the Process's engine, and a guessed backup is - -- the kind nobody finds out about until a restore. - inv E_DURABILITY_WITHOUT_ENGINE: - (durability = DurabilityClass::recoverable or durability = DurabilityClass::irreplaceable) implies - oclContainer().oclAsType(Process).engine <> Engine::absent - -context Volume - -- The claims a volume reserves in its project's namespace: its own, and the - -- backup claim a durability that derives a backup adds beside it. - def: reserved : Sequence(String) = - if durability = DurabilityClass::reconstructible - then Sequence{claim} - else Sequence{claim, claim.concat('-backup')} - endif - - -- A project's Processes share one namespace, and a claim is named as - -- written: a volume reserving a claim an earlier volume of the project - -- already holds would mount the same PersistentVolumeClaim, and one under the - -- claim an acme tier derives on its proxy's Process, `-acme`, would - -- mount the proxy's ACME state (spec/v1/14-platform-intent.md#tiers). - inv E_DUPLICATE_CLAIM: - let project : Project = oclContainer().oclContainer().oclContainer().oclAsType(Project) in - let volumes : Sequence(Volume) = project.applications.processes.volumes in - volumes->select(v | volumes->indexOf(v) < volumes->indexOf(self)) - ->collect(v | v.reserved)->excludesAll(reserved) - and not project.applications.processes->exists(q | - claim = q.name + '-acme' - and Tier.allInstances()->exists(t | t.certificates = CertificateSource::acme and q.answers(t))) - -context Rotation - -- An environment variable is read once, when the process starts. - inv E_ENV_CANNOT_RELOAD: - tolerates = Tolerance::reload implies - (if oclContainer().oclIsKindOf(Credentials) - then oclContainer().oclAsType(Credentials).delivery <> Delivery::env - else oclContainer().oclAsType(Grant).delivery <> Delivery::env endif) - -context KvGrant - -- A grant delivers to a file only one key, with the file and the mode it lands at. - inv schema: - delivery = Delivery::file implies (mountAt <> null and fileMode <> null and keys->size() = 1) - - -- Custody creates and deletes paths at runtime, and a renewal tier holds no - -- capability on its path: neither has anything to project. - inv E_ILLEGAL_DELIVERY_FOR_ACCESS: - not ((access = AccessTier::custody and (delivery = Delivery::env or delivery = Delivery::file)) - or (access = AccessTier::selfRenew and delivery = Delivery::env)) - -context TransitGrant - -- A transit key is used, never read: there is no value to write anywhere. - inv E_NON_KV_DELIVERY: delivery = Delivery::selfDelivery - -context DatabaseGrant - -- A database credential is minted per lease and re-read at runtime. - inv E_NON_KV_DELIVERY: delivery = Delivery::selfDelivery - -context Route - -- Precedence is derived, and two routes sharing a path and a match cannot be - -- ordered by it. - inv E_DUPLICATE_ROUTE_MATCH: - oclContainer().oclAsType(Exposure).routes - ->select(r | r.path = self.path and r.match = self.match)->first() = self - -context Tier - -- An authenticated route reaches the proxy with nothing to ask whether the - -- visitor is allowed in unless the tier names the endpoint that decides. - inv E_NO_FORWARD_AUTH_ENDPOINT: - audiences->includes(Audience::authenticated) implies forwardAuth <> null - --- Across documents (spec/v1/14-platform-intent.md#the-model). An invariant sits --- on the object the author must change, which is why most are on a project's --- classes. A tier's proxy that names no declared Application is --- E_UNKNOWN_TIER_PROXY, and is a link that does not resolve rather than an --- invariant: the reference is an Ecore reference, and the linker finds it has --- no target. - -context Exposure - -- A route's audience is the only way it reaches a tier. - inv E_NO_TIER_FOR_AUDIENCE: - Tier.allInstances()->notEmpty() implies Tier.allInstances()->exists(audiences->includes(self.audience)) - -context Route - -- A route that writes its own audience reaches the tier carrying that one. - -- `Audience::absent` is what an unset audience reads as. - inv E_NO_TIER_FOR_AUDIENCE: - (audience <> Audience::absent and Tier.allInstances()->notEmpty()) - implies Tier.allInstances()->exists(audiences->includes(self.audience)) - -context Process - -- The backup method is the image the platform names for the engine. - inv E_NO_ENGINE_POLICY: - EnginePolicies.allInstances()->forAll(policies | - (engine = Engine::postgres implies policies.postgres <> null) - and (engine = Engine::rabbitmq implies policies.rabbitmq <> null) - and (engine = Engine::valkey implies policies.valkey <> null) - and (engine = Engine::mongo implies policies.mongo <> null) - and (engine = Engine::files implies policies.files <> null) - and (engine = Engine::s3 implies policies.s3 <> null)) - - -- Where the engine's method dumps over the network, the Process is what it - -- connects to, so the surface the platform names for the engine is one the - -- Process provides. A method that reads the volume alone names none. - inv E_BACKUP_SURFACE_NOT_PROVIDED: - EnginePolicies.allInstances()->forAll(policies | - let named : EnginePolicy = - if engine = Engine::postgres then policies.postgres - else if engine = Engine::rabbitmq then policies.rabbitmq - else if engine = Engine::valkey then policies.valkey - else if engine = Engine::mongo then policies.mongo - else if engine = Engine::files then policies.files - else if engine = Engine::s3 then policies.s3 - else null endif endif endif endif endif endif in - (named <> null and named.surface <> null) - implies provides->includes(named.surface)) - -context Process - -- A consumer's pods carry the Application's id and a surface, joined by a dot, - -- as the name of a label the provider's policy admits, so the pair is a label's - -- name: at most 63 characters, starting and ending with a letter or digit. - inv E_SURFACE_LABEL_INVALID: - let app : String = oclContainer().oclAsType(Application).id in - provides->keys()->forAll(surface | (app + '.' + surface).matches('[A-Za-z0-9]([-_.A-Za-z0-9]{0,61}[A-Za-z0-9])?')) - -context ApiAccess - -- Kubernetes API access is the platform's to admit: a Process that declares - -- it in an Application the Platform document does not name would hold a - -- grant nobody with authority over the cluster gave. The platform admits by - -- id, so an id two Applications carry admits neither: a second project - -- naming its own Application `flagger` is not the one the platform meant. - -- Read with no Platform document, there is nobody to admit it and nothing - -- to refuse. - -- An Application the platform admits to its own namespace alone holds access - -- there too. - inv E_PROCESS_RBAC_GRANT: - Platform.allInstances()->notEmpty() implies - ApiAccessPolicy.allInstances()->exists(policy | - admittedBy(policy.holders) or admittedBy(policy.namespaceHolders)) - - def: admittedBy(names : OrderedSet(Application)) : Boolean = - names->exists(holder | - holder.processes->exists(process | process.api = self) - and Application.allInstances()->select(other | other.id = holder.id)->size() = 1) - -context ApiRule - -- Admitted to its namespace alone, a rule that reaches the cluster is one the - -- platform did not give. - inv E_PROCESS_RBAC_GRANT: - let access : ApiAccess = oclContainer().oclAsType(ApiAccess) in - ApiAccessPolicy.allInstances()->forAll(policy | - (access.admittedBy(policy.namespaceHolders) and not access.admittedBy(policy.holders)) - implies scope = ApiScope::_'namespace') - -context Process - -- A spawn template derives API access to create its pods, so the platform - -- admits it as it admits an `api` block, at either scope. - inv E_PROCESS_RBAC_GRANT__spawns: - (Platform.allInstances()->notEmpty() and api = null and spawns->notEmpty()) implies - ApiAccessPolicy.allInstances()->exists(policy | - policy.holders->union(policy.namespaceHolders)->exists(holder | - holder.processes->includes(self) - and Application.allInstances()->select(other | other.id = holder.id)->size() = 1)) - -context Volume - -- A Durability Class names a guarantee only a platform policy keeps. - inv E_NO_DURABILITY_POLICY: - DurabilityPolicies.allInstances()->forAll(policies | - (durability = DurabilityClass::reconstructible implies policies.reconstructible <> null) - and (durability = DurabilityClass::recoverable implies policies.recoverable <> null) - and (durability = DurabilityClass::irreplaceable implies policies.irreplaceable <> null)) - -context LibraryMount - -- A library is the platform's to declare: a mount names one the Platform - -- document declares. Read with no Platform document, nothing is declared and - -- nothing is refused. - inv E_UNKNOWN_LIBRARY: - Platform.allInstances()->forAll(platform | platform.libraries->includes(library)) - - -- And the platform's to grant: to the Process's project, for what it mounts it for. - inv E_LIBRARY_NOT_GRANTED: - let project : String = oclContainer().oclAsType(Process).projectName in - Platform.allInstances()->forAll(platform | - platform.libraries->includes(library) implies - let grants : Map(String, LibraryAccess) = platform.libraries->at(library).grants in - grants->includes(project) - and (access = LibraryAccess::write implies grants->at(project) = LibraryAccess::write)) - - -- A directory inside the library: relative, with no `.` or `..` segment. - inv schema: - subPath = null or subPath.matches('(?![.][.]?(/|$))[^/]+(/(?![.][.]?(/|$))[^/]+)*') - -context VpnAttachment - -- An attachment names the VPN the platform runs. Read with no Platform - -- document, no VPN is declared and nothing is refused. - inv E_NO_VPN_POLICY: - Platform.allInstances()->forAll(platform | platform.vpn <> null) - -context VpnPolicy - -- Each setting is a variable name, and none is one the render derives from the attached Process. - inv schema: - settings->keys()->forAll(k | k.matches('[A-Z_][A-Z0-9_]*') - and not Set{'FIREWALL_INPUT_PORTS', 'VPN_PORT_FORWARDING', 'VPN_PORT_FORWARDING_UP_COMMAND'}->includes(k)) - -context LibraryDeclaration - -- An absolute directory with no `.` or `..` segment, never `/`, owned by a group above 0. - inv schema: - gid > 0 and path.matches('(/(?![.][.]?(/|$))[^/]+)+') - -context Grant - -- A file lands below a directory other than `/`, which the render mounts whole. - inv schema__mountAt: - mountAt = null or mountAt.matches('(/(?![.][.]?(/|$))[^/\\s]+){2,}') - - -- A secret written into the cluster is readable on disk unless the platform - -- encrypts secrets at rest. - inv E_SECRETS_AT_REST_REQUIRED: - delivery <> Delivery::selfDelivery implies Substrate.allInstances()->forAll(secretsEncryption) - --- Shared Intent (spec/v1/10-project-intent.md#shared-intent). Every invariant --- below sits on the lower declaration, and on the object that has one where the --- family has an object at all: a grant, an edge, an asset. - -context SharedIntent - -- The chain is two hops, Project > Application > Process, so this enumerates - -- rather than closes over it. - def: levelsAbove : OrderedSet(SharedIntent) = - if self.oclIsKindOf(Process) and oclContainer().oclIsKindOf(Application) - then OrderedSet{oclContainer().oclAsType(SharedIntent), - oclContainer().oclContainer().oclAsType(SharedIntent)} - else - if self.oclIsKindOf(Application) - then OrderedSet{oclContainer().oclAsType(SharedIntent)} - else OrderedSet{} - endif - endif - - -- `absent` when no level answered. - def: effectiveCutover : Cutover = - if cutover <> Cutover::absent then cutover - else - let answered : OrderedSet(SharedIntent) = - levelsAbove->select(l | l.cutover <> Cutover::absent) in - if answered->isEmpty() then Cutover::absent else answered->first().cutover endif - endif - -context Placement - -- Eligibility sums every container's quantity, so a shared one means - -- something different for each Process that holds it. - inv E_SHARED_QUANTITY: - (memory <> null or cpu <> null) implies oclContainer().oclIsKindOf(Process) - -context SharedIntent - -- The families with no object of their own share one invariant, because they - -- share the one context an invariant can point at. Each `placement` key - -- counts separately: `site` above and `arch` below is two declarations of - -- two things. - inv E_SHARED_DECLARATION_DUPLICATED: - levelsAbove->forAll(above | - (startupBudget <> null implies startupBudget <> above.startupBudget) - and (cutover <> Cutover::absent implies cutover <> above.cutover) - and writablePaths->forAll(w | above.writablePaths->forAll(o | not w.sameAs(o))) - and ((placement <> null and above.placement <> null) implies - (placement.arch->notEmpty() implies placement.arch <> above.placement.arch) - and (placement.site <> null implies placement.site <> above.placement.site) - and (placement.capabilities->notEmpty() implies - placement.capabilities <> above.placement.capabilities) - and (placement.disk <> null implies - above.placement.disk = null - or placement.disk.media <> above.placement.disk.media) - and (placement.gpu <> null implies - above.placement.gpu = null - or placement.gpu.memory <> above.placement.gpu.memory - or placement.gpu._'class' <> above.placement.gpu._'class' - or placement.gpu.vendor <> above.placement.gpu.vendor - or placement.gpu.model <> above.placement.gpu.model))) - -context EnvVariable - -- A variable is one declaration within one Cluster Target, and the value is - -- a term: a scope below setting it differently is that level's version of it. - inv E_SHARED_DECLARATION_DUPLICATED: - let mine : EnvFile = oclContainer().oclAsType(EnvFile) in - mine.oclContainer().oclAsType(SharedIntent).levelsAbove->forAll(above | - above.env->forAll(other | - other.entries->forAll(entry | - not (entry.name = name and sameValue(entry.value, value))))) - -context EnvVariable - -- A literal equals a literal with the same text, and a placeholder equals a - -- placeholder naming the same source. - def: sameValue(one : EnvValue, other : EnvValue) : Boolean = - (one.oclIsKindOf(EnvLiteral) and other.oclIsKindOf(EnvLiteral) - and one.oclAsType(EnvLiteral).text = other.oclAsType(EnvLiteral).text) - or (one.oclIsKindOf(Placeholder) and other.oclIsKindOf(Placeholder) - and one.oclAsType(Placeholder).kind = other.oclAsType(Placeholder).kind - and one.oclAsType(Placeholder).source = other.oclAsType(Placeholder).source) - -context DependencyEdge - -- `required` is included: an edge differing in it is a replacement. - inv E_SHARED_DECLARATION_DUPLICATED: - oclContainer().oclAsType(SharedIntent).levelsAbove->forAll(above | - above.dependsOn->forAll(other | - not (application = other.application and surface = other.surface - and required = other.required))) - -context AssetDeclaration - -- Where an Asset lands, mounted or seeded, is the identity: two files cannot - -- arrive at one path. - def: landsAt : String = - if self.oclIsKindOf(Asset) then self.oclAsType(Asset).mountAt - else self.oclAsType(SeededAsset).seedAt endif - - inv E_SHARED_DECLARATION_DUPLICATED: - oclContainer().oclAsType(SharedIntent).levelsAbove->forAll(above | - above.assets->forAll(other | not (landsAt = other.landsAt and from = other.from))) - -context WritablePathDeclaration - -- The same path held the same way: on disk, or in memory at one size. - def: sameAs(other : WritablePathDeclaration) : Boolean = - path = other.path and oclType() = other.oclType() - and (self.oclIsKindOf(MemoryPath) implies - self.oclAsType(MemoryPath).memory = other.oclAsType(MemoryPath).memory) - -context KvKey - -- A key as a duplicate compares it: its name, and how it is generated if it is. - def: term : String = - if self.oclIsKindOf(GeneratedKey) then - let g : Generate = self.oclAsType(GeneratedKey).generate in - name + ' generate ' + (if g.bytes = null then '' else g.bytes.toString() endif) - + ' ' + g.encoding.toString() - else name endif - -context Grant - -- A grant states its rotation or states none, and either way the restatement - -- has to match for the second declaration to be a duplicate. - def: sameRotationAs(other : Grant) : Boolean = - if rotation = null or other.rotation = null then rotation = other.rotation - else rotation.tolerates = other.rotation.tolerates - and rotation.maxAge = other.rotation.maxAge - endif - -context KvGrant - -- The derived read path is the identity; equal terms make it a duplicate - -- rather than a replacement. - inv E_SHARED_DECLARATION_DUPLICATED: - oclContainer().oclAsType(SharedIntent).levelsAbove->forAll(above | - above.secrets->selectByKind(KvGrant)->forAll(other | - not (path = other.path and access = other.access and keys.term = other.keys.term - and delivery = other.delivery and mountAt = other.mountAt - and fileMode = other.fileMode and sameRotationAs(other)))) - -context DatabaseGrant - -- The derived read path is `database/creds/`, so the role is the identity. - inv E_SHARED_DECLARATION_DUPLICATED: - oclContainer().oclAsType(SharedIntent).levelsAbove->forAll(above | - above.secrets->selectByKind(DatabaseGrant)->forAll(other | - not (role = other.role and delivery = other.delivery - and mountAt = other.mountAt and fileMode = other.fileMode - and sameRotationAs(other)))) - -context TransitGrant - -- One derived read path per operation, so key and operations are the identity. - inv E_SHARED_DECLARATION_DUPLICATED: - oclContainer().oclAsType(SharedIntent).levelsAbove->forAll(above | - above.secrets->selectByKind(TransitGrant)->forAll(other | - not (key = other.key and operations = other.operations - and delivery = other.delivery and mountAt = other.mountAt - and fileMode = other.fileMode and sameRotationAs(other)))) - -context Process - -- A quantity is never shared, so nothing above the Process supplies one. - inv E_PLACEMENT_INCOMPLETE: - placement <> null and placement.memory <> null and placement.cpu <> null - - -- Required on every Process, and answerable above one, so what is refused is - -- a Process no level answers for. - inv E_CUTOVER_MISSING: - runsToCompletion or effectiveCutover <> Cutover::absent - - -- A prepare Process runs to completion before the new version starts: it - -- listens on nothing, has no readiness, runs once and cuts over nothing. - inv E_PREPARE_PROCESS_SERVES: - lifecycle = Lifecycle::prepare implies - (provides->isEmpty() and probes = null and replicas = null and cutover = Cutover::absent) - - -- A scheduled Process runs to completion on its schedule, so it serves - -- nothing either. - inv E_SCHEDULED_PROCESS_SERVES: - lifecycle = Lifecycle::scheduled implies - (provides->isEmpty() and probes = null and replicas = null and cutover = Cutover::absent) - - -- A scheduled Process runs on the schedule it states, and only one does. - inv E_SCHEDULE_MISSING: - lifecycle = Lifecycle::scheduled implies schedule <> null - - inv E_SCHEDULE_UNSCHEDULED__schedule: - schedule <> null implies lifecycle = Lifecycle::scheduled - - -- Five cron fields (spec/v1/10-project-intent.md#scheduled-processes). - inv schema__schedule: - schedule = null or schedule.matches('[0-9A-Za-z*/,?-]+( [0-9A-Za-z*/,?-]+){4}') - - -- A Process that runs to completion cuts over nothing. - def: runsToCompletion : Boolean = - lifecycle = Lifecycle::prepare or lifecycle = Lifecycle::scheduled - --- Migration (spec/v1/10-project-intent.md#migration). A project's database has --- one owner role, which only its migration holds, and one Application of the --- project moves its schema. - -context SharedIntent - -- The project a declaration belongs to, from any of the three levels. - def: projectName : String = projectDocument.project - -context SharedIntent - -- The Project document a declaration belongs to, from any of the three levels. - def: projectDocument : Project = - if self.oclIsKindOf(Project) then self.oclAsType(Project) - else - if self.oclIsKindOf(Application) then oclContainer().oclAsType(Project) - else oclContainer().oclContainer().oclAsType(Project) - endif - endif - -context SharedIntent - -- Where a level's grants come in the document: the project's first, then each - -- Application's before its Processes'. - def: grantRank : Integer = - if self.oclIsKindOf(Project) then 0 - else - if self.oclIsKindOf(Application) then projectDocument.applications->indexOf(self.oclAsType(Application)) * 1000 - else projectDocument.applications->indexOf(oclContainer().oclAsType(Application)) * 1000 - + oclContainer().oclAsType(Application).processes->indexOf(self.oclAsType(Process)) - endif - endif - --- Generated keys (spec/v1/10-project-intent.md#generated-keys): the Vault policy --- job writes each, once, under its own Project's prefix, and nothing else --- writes its path. - -context GeneratedKey - def: grant : KvGrant = oclContainer().oclAsType(KvGrant) - - def: owner : SharedIntent = grant.oclContainer().oclAsType(SharedIntent) - - -- Where the key comes in its document, so the first of two is the one declared first. - def: rank : Integer = - (owner.grantRank * 1000 + owner.secrets->indexOf(grant)) * 1000 + grant.keys->indexOf(self) - - -- A `.`, `..` or empty segment below the prefix could climb out of it. - inv E_GENERATED_KEY_OUTSIDE_PROJECT: - let prefix : String = 'secret/data/' + owner.projectName + '-system/' in - grant.path.startsWith(prefix) and grant.path.size() > prefix.size() and - let below : String = '/' + grant.path.substring(prefix.size() + 1, grant.path.size()) + '/' in - below.indexOf('//') = 0 and below.indexOf('/./') = 0 and below.indexOf('/../') = 0 - - -- The first grant to generate a key owns it; a later one lists it plainly. A - -- grant below one it replaces restates `generate` to keep the key generated. - inv E_GENERATED_KEY_TWICE: - not GeneratedKey.allInstances()->exists(k | k.owner.projectDocument = owner.projectDocument - and k.grant.path = grant.path and k.name = name and k.rank < rank - and not (owner.levelsAbove->includes(k.owner) or k.owner.levelsAbove->includes(owner))) - - -- A `self-roll` grant on the path, or a `custody` grant on it or above it, - -- writes it too. - inv E_GENERATED_KEY_WRITTEN_ELSEWHERE: - not KvGrant.allInstances()->exists(g | - (g.access = AccessTier::selfRoll and g.path = grant.path) - or (g.access = AccessTier::custody - and (g.path = grant.path or grant.path.startsWith(g.path + '/')))) - -context Generate - -- The schema bounds a generated key's length, and spells an adopted location - -- as one kv path, no segment empty or opening with a dot, and one key. - inv schema: - (bytes = null or (bytes >= 16 and bytes <= 512)) - and (adopt = null or adopt.matches('secret/data(/[A-Za-z0-9_-][A-Za-z0-9._-]*)+#[A-Za-z0-9._-]+')) - - -- A key adopts only a value a grant of its own project file already reads. - inv E_GENERATED_KEY_ADOPTS_UNGRANTED: - adopt = null or - let key : GeneratedKey = oclContainer().oclAsType(GeneratedKey) in - let path : String = adopt.substring(1, adopt.indexOf('#') - 1) in - KvGrant.allInstances()->exists(g | - g.oclContainer().oclAsType(SharedIntent).projectDocument = key.owner.projectDocument - and g.path = path) - -context DatabaseGrant - -- The owner role changes the schema, and is derived for the migration alone. - inv E_OWNER_ROLE_GRANTED: - role <> oclContainer().oclAsType(SharedIntent).projectName.concat('-owner') - -context Migration - -- A second Application of one project declaring how the schema moves. - inv E_MIGRATION_OWNER_DUPLICATED: - let application : Application = oclContainer().oclAsType(Application) in - self.oclIsKindOf(NoMigration) - or application.oclContainer().oclAsType(Project).applications - ->select(a | a.migration <> null and not a.migration.oclIsKindOf(NoMigration)) - ->first() = application - -context Application - -- Every provider an Application's Processes reach, from every level. - def: edgeTargets : Set(String) = - oclContainer().oclAsType(Project).dependsOn.application->asSet() - ->union(dependsOn.application->asSet()) - ->union(processes.dependsOn.application->asSet()) - - -- The Applications whose engine owns databases, among the documents read. - -- Whether this Application's engine owns databases, whose consumers derive one. - def: ownsDatabases : Boolean = processes->exists(engine = Engine::postgres) - - def: databaseIds : Set(String) = - Application.allInstances()->select(a | a.ownsDatabases).id->asSet() - - def: derivesDatabase : Boolean = edgeTargets->exists(t | databaseIds->includes(t)) - - -- Across documents: an Application whose edge reaches a database answers how - -- its schema moves. - inv E_MIGRATION_UNDECLARED: - (Platform.allInstances()->notEmpty() and derivesDatabase) implies migration <> null - -context Migration - -- Decided only where every provider the Application reaches was read with it. - inv E_MIGRATION_WITHOUT_DATABASE: - let application : Application = oclContainer().oclAsType(Application) in - (Platform.allInstances()->notEmpty() - and application.edgeTargets->forAll(t | Application.allInstances().id->includes(t))) - implies application.derivesDatabase - - -- A changelog builds on the platform's runner. - inv E_NO_MIGRATION_POLICY: - self.oclIsKindOf(ManagedMigration) implies Platform.allInstances()->forAll(migration <> null) - - -- The Release Gate starts a migration, and it holds only an Application a - -- Process of which switches blue/green: one that is continuous, on an - -- Application the platform does not list as delivery machinery. - inv E_MIGRATION_UNGATED: - let application : Application = oclContainer().oclAsType(Application) in - (Platform.allInstances()->notEmpty() and self.oclIsKindOf(ManagedMigration)) implies - (application.processes->exists(lifecycle = Lifecycle::application - and effectiveCutover = Cutover::continuous) - and Platform.allInstances()->forAll(p | p.delivery = null - or p.delivery.machinery->excludes(application))) - -context Credentials - -- An edge delivers its credential to a file only with the directory and the mode its - -- username and password files land at. - inv schema: - delivery = Delivery::file implies (mountAt <> null and fileMode <> null) - - -- A directory other than `/`, which a mount would cover entirely. - inv schema__mountAt: - mountAt = null or mountAt.matches('(/(?![.][.]?(/|$))[^/\\s]+)+') - - -- Only an edge to a database derives a credential to rotate. - inv E_CREDENTIALS_WITHOUT_DATABASE: - let edge : DependencyEdge = oclContainer().oclAsType(DependencyEdge) in - (Platform.allInstances()->notEmpty() and Application.allInstances().id->includes(edge.application)) - implies Application.allInstances()->exists(a | a.id = edge.application and a.ownsDatabases) - --- Every refusal resolution used to stop at (deploy-kit#204), each answered here --- over the authored model with its env files attached, at the Process or the --- Application the production implementation names. - -context Process - -- What every level of the Process holds: its own declarations and each - -- level's above it. - def: envFiles : Sequence(EnvFile) = - env->asSequence()->union(levelsAbove->asSequence()->collect(l | l.env)->asSequence()) - - def: placeholdersOf(k : PlaceholderKind) : Sequence(Placeholder) = - envFiles->collect(entries)->collect(value) - ->select(v | v.oclIsKindOf(Placeholder))->collect(v | v.oclAsType(Placeholder)) - ->select(p | p.kind = k) - - def: envGrants : Sequence(KvGrant) = - secrets->asSequence()->union(levelsAbove->asSequence()->collect(l | l.secrets)->asSequence()) - ->select(g | g.oclIsKindOf(KvGrant))->collect(g | g.oclAsType(KvGrant)) - ->select(g | g.delivery = Delivery::env) - - def: heldEdges : Sequence(DependencyEdge) = - dependsOn->asSequence()->union(levelsAbove->asSequence()->collect(l | l.dependsOn)->asSequence()) - - -- An edge to a surface of a Process whose engine owns databases derives a credential. - def: reachesDatabase : Boolean = - heldEdges->exists(e | Application.allInstances()->exists(a | a.id = e.application - and a.processes->exists(q | q.engine = Engine::postgres - and q.provides->keys()->includes(e.surface)))) - - -- A placeholder reads one key of a path an env grant of the Process lists. - inv E_UNAUTHORISED_SECRET_REFERENCE: - placeholdersOf(PlaceholderKind::secret)->forAll(p | - envGrants->exists(g | g.keys->exists(k | p.source = g.path + '#' + k.name))) - - -- An env grant nothing reads is a dead grant; a Process no env file reaches - -- is undecided, its files perhaps not among those read. - inv E_UNBOUND_SECRET_GRANT: - envFiles->notEmpty() implies envGrants->forAll(g | - placeholdersOf(PlaceholderKind::secret)->exists(p | p.source.startsWith(g.path + '#'))) - - -- A dependency placeholder names the Application of one edge the Process - -- holds and a coordinate it hands out; an exposure placeholder, an exposure - -- an Application of the set declares and a field of it. An Application the - -- set does not declare is not this invariant's to say. - inv E_UNRESOLVED_PLACEHOLDER: - placeholdersOf(PlaceholderKind::dependency)->forAll(p | - Sequence{'host', 'port'}->exists(c | - heldEdges->select(e | e.application + '.' + c = p.source)->size() = 1 - and heldEdges->select(e | p.source.startsWith(e.application + '.'))->size() = 1) - -- The login an edge delivers to the environment, as a whole value. - or (p.suffix = null and Sequence{'username', 'password'}->exists(c | - heldEdges->select(e | e.application + '.' + c = p.source - and e.credentials <> null and e.credentials.delivery = Delivery::env)->size() = 1 - and heldEdges->select(e | p.source.startsWith(e.application + '.'))->size() = 1)) - -- An edge naming buckets hands the object store's endpoint, and its key whole. - or (heldEdges->select(e | e.application + '.endpoint' = p.source and e.buckets->notEmpty())->size() = 1 - and heldEdges->select(e | p.source.startsWith(e.application + '.'))->size() = 1) - or (p.suffix = null and Sequence{'accessKeyId', 'secretAccessKey'}->exists(c | - heldEdges->select(e | e.application + '.' + c = p.source and e.buckets->notEmpty())->size() = 1 - and heldEdges->select(e | p.source.startsWith(e.application + '.'))->size() = 1))) - -- A client placeholder reads the issuer, the id or the whole secret of its - -- own Application's Client. - and placeholdersOf(PlaceholderKind::client)->forAll(p | - oclContainer().oclAsType(Application).client <> null - and Sequence{'issuer', 'id', 'secret'}->includes(p.source)) - and placeholdersOf(PlaceholderKind::exposure)->forAll(p | - Application.allInstances()->forAll(a | not p.source.startsWith(a.id + '.') - or a.exposure->exists(x | Sequence{'url', 'host', 'scheme'}->exists(f | - p.source = a.id + '.' + x.name + '#' + f)))) - - -- The Runtime Profile injects these, so an env file writing one is a second - -- answer to a question the model already answers. - inv E_PROFILE_KEY_AUTHORED: - (Platform.allInstances()->notEmpty() - and (runtime = Runtime::jvm or runtime = Runtime::node or runtime = Runtime::python)) - implies envFiles->collect(entries)->forAll(e | - e.name <> 'DEPLOYMENT_ENVIRONMENT' and e.name <> 'OTEL_SERVICE_NAME' - and (provides->size() = 1 implies e.name <> 'PORT') - and (Platform.allInstances()->exists(t | t.telemetry <> null) - implies e.name <> 'OTEL_EXPORTER_OTLP_ENDPOINT')) - -context Application - -- The gate waits for readiness, so an Application that switches blue/green - -- publishes it on at least one member. - inv E_RELEASE_UNIT_NO_READINESS: - (Platform.allInstances()->notEmpty() - and Platform.allInstances()->forAll(p | p.delivery = null or p.delivery.machinery->excludes(self))) - implies - let gated : OrderedSet(Process) = processes->select(lifecycle = Lifecycle::application - and effectiveCutover = Cutover::continuous) in - gated->notEmpty() implies gated->exists(g | - g.probes <> null and g.probes.oclIsKindOf(Probes) - and g.probes.oclAsType(Probes).readiness <> null) - - -- A grant, an off-cluster backup, a backup that dumps over the network and a - -- managed migration each read a credential from the Secret Store, so a - -- platform naming none offers none. - inv E_NO_SECRET_STORE: - Platform.allInstances()->forAll(p | p.secretStore <> null - or not ((migration <> null and migration.oclIsKindOf(ManagedMigration)) - or processes->exists(pr | pr.envGrants->notEmpty() - or pr.secrets->notEmpty() - or pr.reachesDatabase - or pr.levelsAbove->exists(l | l.secrets->notEmpty()) - or pr.volumes->exists(v | - (v.durability = DurabilityClass::recoverable and p.durability.recoverable <> null - and p.durability.recoverable.offCluster <> null) - or (v.durability = DurabilityClass::irreplaceable and p.durability.irreplaceable <> null - and p.durability.irreplaceable.offCluster <> null)) - or (pr.volumes->exists(v | v.durability <> DurabilityClass::reconstructible) - and (let named : EnginePolicy = - if pr.engine = Engine::postgres then p.engines.postgres - else if pr.engine = Engine::rabbitmq then p.engines.rabbitmq - else if pr.engine = Engine::valkey then p.engines.valkey - else if pr.engine = Engine::files then p.engines.files - else null endif endif endif endif in - named <> null and named.surface <> null))))) - -context DurabilityPolicy - -- A class that derives a backup says when it runs and how many copies it keeps. - inv E_DURABILITY_POLICY_INCOMPLETE: - let policies : DurabilityPolicies = oclContainer().oclAsType(DurabilityPolicies) in - (policies.recoverable = self or policies.irreplaceable = self) - implies (schedule <> null and retain <> null) - --- The identity and reference invariants over the composed union --- (spec/v1/40-composition.md#the-estate-wide-invariants): every document read --- together is one extent, so `allInstances` is the union. Every collision is --- refused at each of its sides, so the set reads the same in any order. - -context Project - inv E_DUPLICATE_PROJECT: - Project.allInstances()->select(p | p.project = self.project)->size() = 1 - -context Application - inv E_DUPLICATE_APPLICATION_ID: - Application.allInstances()->select(a | a.id = self.id)->size() = 1 - -context Process - -- The name is the Process's identity in the project's namespace. - inv E_DUPLICATE_PROCESS_NAME: - oclContainer().oclContainer().oclAsType(Project).applications.processes - ->select(p | p.name = self.name)->size() = 1 - - -- The Processes every required edge the Process holds reaches. - def: requiredPeers : Set(Process) = - heldEdges->select(e | e.required <> false)->collect(e | e.providing)->asSet() - -context Exposure - inv E_DUPLICATE_EXPOSURE_NAME: - oclContainer().oclAsType(Application).exposure->select(x | x.name = self.name)->size() = 1 - - -- A host is unique on a tier: inside one proxy two rules for one host have no - -- defined winner, while two tiers are two proxies, the split-horizon shape a - -- host served both on the LAN and in public takes. An audience no tier - -- carries claims its host on none. - def: tierName : String = - let tiers : Sequence(Tier) = - Tier.allInstances()->select(t | t.audiences->includes(audience))->asSequence() in - if tiers->isEmpty() then null else tiers->first().name endif - - inv E_DUPLICATE_HOST: - tierName = null - or Exposure.allInstances()->select(x | x.host = host and x.tierName = tierName)->size() = 1 - -context DependencyEdge - -- Every Process below the level the edge is written at holds it. - def: holders : Set(Process) = - let owner : OclAny = oclContainer() in - if owner.oclIsKindOf(Process) then Set{owner.oclAsType(Process)} - else - if owner.oclIsKindOf(Application) then owner.oclAsType(Application).processes->asSet() - else owner.oclAsType(Project).applications.processes->asSet() - endif - endif - - -- The Processes of the union that provide the surface under the Application id. - def: providing : Set(Process) = - Application.allInstances()->select(a | a.id = application).processes - ->select(p | p.provides->includes(surface))->asSet() - - def: declared : Boolean = Application.allInstances()->exists(a | a.id = application) - - def: provider : Boolean = - Platform.allInstances()->exists(p | p.providers->exists(v | v.name = application)) - - -- A reference resolves against the union or the Platform document's providers. - inv E_UNRESOLVED_APPLICATION: - Platform.allInstances()->notEmpty() implies (declared or provider) - - inv E_UNKNOWN_SURFACE: - (Platform.allInstances()->notEmpty() and (declared or provider)) implies - (providing->notEmpty() - or Platform.allInstances()->exists(p | p.providers->exists(v | - v.name = application and v.surfaces->includes(surface)))) - - -- The project whose namespace the edge's alias lives in. - def: home : Project = - if oclContainer().oclIsKindOf(Process) then oclContainer().oclContainer().oclContainer().oclAsType(Project) - else if oclContainer().oclIsKindOf(Application) then oclContainer().oclContainer().oclAsType(Project) - else oclContainer().oclAsType(Project) endif endif - - -- Where the provider serves: its Process's Service, in its project's - -- namespace, or the address a provider records. - def: served : String = - if providing->notEmpty() then - let p : Process = providing->any(true) in - p.name + '.' + p.oclContainer().oclContainer().oclAsType(Project).project + '-system.svc.cluster.local' - else - let addresses : Bag(String) = Platform.allInstances().providers - ->select(v | v.name = application and v.surfaces->includes(surface))->collect(v | v.address) in - if addresses->isEmpty() then null else addresses->asSequence()->first() endif - endif - - -- An edge derives an alias where its provider serves outside the project's - -- namespace at a name, not an IP (spec/v1/16-dependencies.md#the-alias). - def: aliased : Boolean = - served <> null and not served.endsWith('.' + home.project + '-system.svc.cluster.local') - and not served.matches('[0-9.]+|.*:.*') - - -- The alias's name: the Application Id, or the Id and the surface where the - -- project's edges name several surfaces of it. - def: aliasName : String = - if DependencyEdge.allInstances()->select(d | d.home = home and d.application = application) - ->collect(d | d.surface)->asSet()->size() > 1 - then application + '-' + surface else application endif - - -- An alias takes no name a Service of its project holds, nor one another - -- Application's alias takes there. - inv E_ALIAS_COLLISION: - (Platform.allInstances()->notEmpty() and aliased) implies - (not home.applications.processes->select(p | p.provides->notEmpty()) - ->exists(p | aliasName = p.name or aliasName = p.name + '-primary' or aliasName = p.name + '-canary') - and not DependencyEdge.allInstances()->exists(d | d.home = home and d.aliased - and d.aliasName = aliasName and d.application <> application)) - - -- A required edge closes a cycle where a Process it reaches reaches back to - -- a Process that holds it; an optional one starts without its peer. - inv E_DEPENDENCY_CYCLE: - (Platform.allInstances()->notEmpty() and required <> false) implies - not holders->exists(h | providing->exists(p | - p = h or p.requiredPeers->closure(q | q.requiredPeers)->includes(h))) - --- The order the Reconcile Units follow (spec/v1/20-resolved-deployment.md#the-reconcile-unit), --- read off the authored union as resolution derives it, Project by Project. - -context Application - -- Whether a Process of the Application holds a credential the Secret Store issues, whose role - -- is written first: a grant at any level, a VPN, an edge into a database, a Client secret it - -- reads or, on the sign-in provider, writes, a managed migration, or a catalog its datastore - -- applies. - def: holdsGrant : Boolean = - (migration <> null and migration.oclIsKindOf(ManagedMigration)) - or processes->exists(pr | pr.secrets->notEmpty() or pr.levelsAbove->exists(l | l.secrets->notEmpty()) - or pr.vpn <> null or pr.reachesDatabase - or pr.placeholdersOf(PlaceholderKind::client)->exists(p | p.source = 'secret')) - or (Platform.allInstances()->exists(p | p.signIn <> null and p.signIn.provider = self) - and Application.allInstances()->exists(a | a.client <> null and a.client.credential = ClientCredential::secret)) - or Platform.allInstances()->exists(p | p.policyJob <> null and processes->exists(pr | - let named : EnginePolicy = - if pr.engine = Engine::postgres then p.engines.postgres - else if pr.engine = Engine::s3 then p.engines.s3 else null endif endif in - named <> null and named.catalog <> null)) - - -- The Projects whose units this Application's share of its Project's unit follows: each a - -- required edge reaches, the Secret Store's where it holds a grant, and the one that declares - -- each proxy its exposures' tiers name. The Secret Store's own Project follows nothing, since - -- every unit holding a grant follows it. - def: follows : Set(Project) = - let own : Project = oclContainer().oclAsType(Project) in - let stores : Set(Project) = Platform.allInstances()->select(p | p.secretStore <> null) - ->collect(p | p.secretStore.oclContainer())->select(c | c <> null and c.oclIsKindOf(Project)) - ->collect(c | c.oclAsType(Project))->asSet() in - if stores->includes(own) then Set{} else - (processes->collect(pr | pr.heldEdges)->select(e | e.required <> false) - ->collect(e | Application.allInstances()->select(a | a.id = e.application)) - ->collect(a | a.oclContainer().oclAsType(Project))->asSet() - ->union(if holdsGrant then stores else Set{} endif) - ->union(exposure->select(x | x.tier <> null)->collect(x | x.tier.traefik.oclContainer()) - ->select(c | c <> null and c.oclIsKindOf(Project))->collect(c | c.oclAsType(Project))->asSet())) - ->excluding(own) - endif - - -- A unit that follows itself through any others is a deadlock Flux never leaves, so its - -- Project is refused at the first Application that follows a unit on the cycle. - inv E_RECONCILE_CYCLE: - let own : Project = oclContainer().oclAsType(Project) in - Platform.allInstances()->isEmpty() or not own.reach->includes(own) - or (let cycle : Set(Project) = own.reach->select(q | q <> own and q.reach->includes(own)) in - own.applications->select(a | a.follows->exists(q | cycle->includes(q)))->first() <> self) - -context Project - -- Every Project whose unit this one's follows, itself only through a cycle. - def: reach : Set(Project) = - applications->collect(a | a.follows)->asSet()->closure(q | q.applications->collect(a | a.follows)->asSet()) - --- The rules main's catch-up added (spec/v1/14-platform-intent.md, spec/v1/17-sign-in.md). - -context Exposure - -- The tier this exposure's audience reaches, where the Platform document has one. - def: tier : Tier = - let tiers : Sequence(Tier) = - Tier.allInstances()->select(t | t.audiences->includes(audience))->asSequence() in - if tiers->isEmpty() then null else tiers->first() endif - - -- A route the tier's proxy admits carries the tier's ingress class, so an - -- exposure on a tier that names none would be admitted by no proxy. - inv E_TIER_WITHOUT_INGRESS_CLASS: - tier = null or tier.ingressClass <> null - - -- Not proxied, a host is published straight at the tier's own address, which - -- the tier's DNS must name. - inv E_NO_DIRECT_TARGET__proxied: - (proxied = false and tier <> null and tier.dns <> null) implies tier.dns.direct <> null - -context Route - -- A redirect its own route matches again sends the client back to it. - inv E_REDIRECT_LOOP: - redirectTo = null - or (if match = Match::exact then redirectTo <> path else not redirectTo.startsWith(path) endif) - -context Process - -- A tier issuing certificates through acme cannot have its proxy run twice: - -- a second copy would issue the same names. - inv E_ACME_PROXY_REPLICATED__replicas: - Tier.allInstances()->exists(t | t.certificates = CertificateSource::acme - and t.traefik.processes->includes(self)) - implies replicas = null - - -- The Prometheus operator runs a monitoring role's one Process: so it is `interrupted`, since the - -- operator replaces its one pod in place, and serves on one port - -- (spec/v1/14-platform-intent.md#the-operators-objects). Its arguments are asked in Java, at - -- the entry each is. - def: operated : Boolean = - let application : Application = oclContainer().oclAsType(Application) in - application.operatedRole and application.processes->size() = 1 - - inv E_OPERATED_PROCESS__cutover: - operated implies cutover = Cutover::interrupted - - inv E_OPERATED_PROCESS__provides: - operated implies provides->size() = 1 - - -- The Process of an Application a tier names as its proxy that provides every surface the - -- tier's listener derives, the first that does: the one that answers the tier. - def: answersTier : Boolean = Tier.allInstances()->exists(t | answers(t)) - - -- Whether this Process answers tier `t`: the first of its proxy's Processes that provides every - -- surface the tier's listener derives. - def: answers(t : Tier) : Boolean = - t.traefik <> null and - let answering : OrderedSet(Process) = t.traefik.processes->select(q | - q.provides->keys()->includes('web') - and (t.listener = Listener::tls implies q.provides->keys()->includes('websecure'))) in - answering->notEmpty() and answering->first() = self - - -- A tier's proxy reads its routes through the Kubernetes API, and the platform says where - -- the API answers only in its `apiAccess` (spec/v1/14-platform-intent.md#tiers). - inv E_NO_API_ACCESS_POLICY: - answersTier implies Platform.allInstances()->forAll(p | p.apiAccess <> null) - - -- A Process exposed on a node's own address holds a host port, so one copy. - def: onNode : Boolean = - let application : Application = oclContainer().oclAsType(Application) in - application.l4Exposure->exists(e | e.process = self - and Platform.allInstances()->exists(p | p.l4Addresses->keys()->includes(e.address) - and p.l4Addresses->at(e.address).oclIsKindOf(NodeAddress))) - - inv E_NODE_ADDRESS_REPLICATED__replicas: - onNode implies replicas = null - - -- The catalog applied over a surface the Process does not provide reaches nothing. - inv E_CATALOG_SURFACE_NOT_PROVIDED: - EnginePolicies.allInstances()->forAll(policies | - let named : EnginePolicy = - if engine = Engine::postgres then policies.postgres - else if engine = Engine::mongo then policies.mongo - else if engine = Engine::s3 then policies.s3 - else null endif endif endif in - (named <> null and named.catalogSurface <> null) - implies provides->keys()->includes(named.catalogSurface)) - -context Application - -- Alert rules belong to the monitoring stack, which evaluates them. - inv E_ALERT_RULES_OUTSIDE_MONITORING__alertRules: - (Platform.allInstances()->notEmpty() and alertRules->notEmpty()) implies - Monitoring.allInstances()->exists(m | m.grafana = self or m.prometheus = self or m.alertmanager = self) - - -- A Client signs its users in through the platform's provider. - inv E_NO_SIGN_IN_PROVIDER__client: - (client <> null and Platform.allInstances()->notEmpty()) implies - Platform.allInstances()->forAll(p | p.signIn <> null) - - -- A Client is an object of the identity CRD, which bootstrap installs. - inv E_CLIENT_CRD_NOT_BOOTSTRAPPED__client: - (client <> null and Platform.allInstances()->forAll(p | p.signIn <> null)) implies - Bootstrap.allInstances()->forAll(b | b.crds->includes('identity.jorisjonkers.dev/v1')) - -context L4Exposure - -- A client dials one port and protocol on an address once. - inv E_DUPLICATE_L4_PORT: - let entries : OrderedSet(L4Exposure) = oclContainer().oclAsType(Application).l4Exposure in - entries->select(e | entries->indexOf(e) < entries->indexOf(self))->forAll(e | - not (e.process = process and e.address = address and e.protocol = protocol and e.port = port)) - - -- The address is one the Platform document names. - inv E_UNKNOWN_L4_ADDRESS: - Platform.allInstances()->forAll(p | p.l4Addresses->keys()->includes(address)) - - -- A Process that serves DNS resolves through the platform's upstream - -- nameservers, so it must not depend on the cluster's own DNS. - inv E_NO_UPSTREAM_NAMESERVERS: - let entries : OrderedSet(L4Exposure) = oclContainer().oclAsType(Application).l4Exposure in - (port = 53 and entries->select(e | e.port = 53 and e.process = process)->first() = self) implies - Substrate.allInstances()->forAll(s | s.upstreamNameservers->notEmpty()) - -context Tier - -- A certificate read from the Secret Store is what a tls tier that issues none serves: on a - -- plain tier nothing would serve it, and on an acme tier the resolver issues what its routes - -- serve (spec/v1/14-platform-intent.md#tiers). - inv E_CERTIFICATE_FROM_UNSERVED__certificateFrom: - certificateFrom <> null implies (listener = Listener::tls and certificates = CertificateSource::none) - - -- And it is read from the Secret Store, which the platform must name. - inv E_NO_SECRET_STORE__certificateFrom: - certificateFrom <> null implies oclContainer().oclAsType(Platform).secretStore <> null - - -- Every proxy serves the one default TLS store, so a second tier naming a certificate would - -- name the one every proxy already serves. - inv E_CERTIFICATE_FROM_REPEATED__certificateFrom: - let tiers : OrderedSet(Tier) = oclContainer().oclAsType(Platform).tiers in - certificateFrom = null or tiers->select(t | tiers->indexOf(t) < tiers->indexOf(self)) - ->forAll(t | t.certificateFrom = null) - - -- Certificates issued through acme need the platform's ACME account. - inv E_NO_ACME_POLICY: - certificates = CertificateSource::acme implies Platform.allInstances()->forAll(p | p.acme <> null) - - -- One proxy admits one ingress class, so a second tier on it naming another - -- is admitted by none. - inv E_TIER_CLASS_UNFILTERED__ingressClass: - let tiers : OrderedSet(Tier) = oclContainer().oclAsType(Platform).tiers in - ingressClass = null or tiers->select(t | tiers->indexOf(t) < tiers->indexOf(self) - and t.traefik = traefik and t.ingressClass <> null)->forAll(t | t.ingressClass = ingressClass) - -context Application - -- Whether the monitoring stack names this Application as its Prometheus or its Alertmanager. - def: operatedRole : Boolean = - Monitoring.allInstances()->exists(m | m.prometheus = self or m.alertmanager = self) - - -- The operator runs one Process as each role. - inv E_OPERATED_PROCESS__processes: - operatedRole implies processes->size() <= 1 - -context HumanGrant - -- One group holds one cluster role once. - inv E_DUPLICATE_HUMAN_GRANT: - let grants : OrderedSet(HumanGrant) = oclContainer().oclAsType(Platform).humanGrants in - grants->select(g | grants->indexOf(g) < grants->indexOf(self)) - ->forAll(g | not (g.group = group and g.clusterRole = clusterRole)) - -context SeverityRoute - -- A route sends to a receiver the monitoring block declares. - inv E_UNKNOWN_RECEIVER__receiver: - oclContainer().oclAsType(Monitoring).receivers->exists(r | r.name = receiver) - -context DependencyEdge - -- A bucket is derived only on an object store: a Process whose engine is s3, - -- on the surface the edge names. - inv E_BUCKETS_WITHOUT_OBJECT_STORE__buckets: - (buckets->notEmpty() and Application.allInstances()->exists(a | a.id = application)) implies - Application.allInstances()->exists(a | a.id = application - and a.processes->exists(p | p.engine = Engine::s3 and p.provides->keys()->includes(surface))) - -context Process - -- `self` is for a Process that talks to Vault itself, which it shows by wiring - -- its own Vault client with the role the platform derived for it - -- (spec/v1/10-project-intent.md#which-tier-may-use-which-delivery). - inv E_SELF_WITHOUT_VAULT_CLIENT: - secrets->exists(g | g.delivery = Delivery::selfDelivery) - implies placeholdersOf(PlaceholderKind::identity)->exists(p | p.source = 'vaultRole') - - -- Only a native Client declaring `credential: secret` holds a secret to read - -- (spec/v1/17-sign-in.md#what-is-checked). - inv E_CLIENT_PLACEHOLDER_WITHOUT_SECRET: - let client : Client = oclContainer().oclAsType(Application).client in - (client <> null and (client.signIn <> SignInMode::native or client.credential = ClientCredential::pkce)) - implies placeholdersOf(PlaceholderKind::client)->forAll(p | p.source <> 'secret') - -context Client - -- The exposure the Client signs people in on: the one it names, or the - -- Application's only one. - def: signsInOn : Exposure = - let exposures : OrderedSet(Exposure) = oclContainer().oclAsType(Application).exposure in - if exposure <> null then exposures->select(x | x.name = exposure)->first() - else if exposures->size() = 1 then exposures->first() else null endif endif - - -- A native Client's protected path reaches a gate member, which the Release - -- Gate asks for it: the Process the longest Route reaching it takes it to, the - -- first declared on a tie, publishing readiness (spec/v1/17-sign-in.md#what-is-checked). - inv E_CLIENT_PATH_UNROUTED__protectedPath: - (protectedPath <> null and signsInOn <> null) implies - let reaching : OrderedSet(Route) = signsInOn.routes->select(r | r.redirectTo = null - and (if r.match = Match::exact then protectedPath = r.path - else protectedPath.startsWith(r.path) endif)) in - reaching->notEmpty() - and reaching->select(r | reaching->forAll(o | o.path.size() <= r.path.size()))->first().process - ->forAll(p | p.probes <> null and p.probes.oclIsKindOf(Probes) - and p.probes.oclAsType(Probes).readiness <> null) - --- A Client's fields by Sign-in Mode (spec/v1/17-sign-in.md#what-is-checked): a --- native Client takes every field, a gated one a tile's, and a token one none, --- and each mode requires what it needs to be signed in to. A field a mode does --- not take is refused at the field; one it requires and lacks, at the Client. - -context Client - inv E_CLIENT_FIELD_FOR_MODE__label: label <> null implies signIn <> SignInMode::token - inv E_CLIENT_FIELD_FOR_MODE__description: description <> null implies signIn <> SignInMode::token - inv E_CLIENT_FIELD_FOR_MODE__iconPath: iconPath <> null implies signIn <> SignInMode::token - inv E_CLIENT_FIELD_FOR_MODE__launchPath: launchPath <> null implies signIn <> SignInMode::token - inv E_CLIENT_FIELD_FOR_MODE__redirectPaths: redirectPaths->notEmpty() implies signIn = SignInMode::native - inv E_CLIENT_FIELD_FOR_MODE__protectedPath: protectedPath <> null implies signIn = SignInMode::native - inv E_CLIENT_FIELD_FOR_MODE__backChannelLogoutPath: - backChannelLogoutPath <> null implies signIn = SignInMode::native - inv E_CLIENT_FIELD_FOR_MODE__credential: - credential <> ClientCredential::absent implies signIn = SignInMode::native - - inv E_CLIENT_FIELD_FOR_MODE: - (signIn = SignInMode::native implies - (label <> null and redirectPaths->notEmpty() and protectedPath <> null - and credential <> ClientCredential::absent)) - and (signIn = SignInMode::gated implies label <> null) - --- A Process holds the Assets it declares and those a level above shares down to it, --- a lower level holding the path two levels name (spec/v1/10-project-intent.md#sharing-merges-and-a-duplicate-is-refused). - -context Process - def: heldAssets : Sequence(AssetDeclaration) = - let application : Application = oclContainer().oclAsType(Application) in - let project : Project = application.oclContainer().oclAsType(Project) in - let own : Sequence(AssetDeclaration) = assets->asSequence() in - let shared : Sequence(AssetDeclaration) = own->union(application.assets->asSequence() - ->select(a | own->forAll(b | b.landsAt <> a.landsAt))) in - shared->union(project.assets->asSequence() - ->select(a | shared->forAll(b | b.landsAt <> a.landsAt) and own->forAll(b | b.landsAt <> a.landsAt))) - - -- The Assets that are seeded, in the order the levels hold them, lowest first. - def: seededAssets : Sequence(SeededAsset) = heldAssets->selectByKind(SeededAsset) - - -- Where a seeded file may land: below a volume, or a writable path of any level. - def: landingDirectories : Sequence(String) = - let application : Application = oclContainer().oclAsType(Application) in - let project : Project = application.oclContainer().oclAsType(Project) in - volumes->collect(mountAt)->asSequence() - ->union(writablePaths->collect(path)->asSequence()) - ->union(application.writablePaths->collect(path)->asSequence()) - ->union(project.writablePaths->collect(path)->asSequence()) - - -- A file is below a directory when it names one more or more segments under it, none of - -- them empty, `.` or `..`. - def: below(file : String, directory : String) : Boolean = - let root : String = directory.replaceAll('/+$', '') in - file.startsWith(root.concat('/')) - and (if file.size() > root.size() + 1 - then let rest : String = file.substring(root.size() + 2, file.size()) in - rest.matches('([^/]+/)*[^/]+') and not rest.matches('(.*/)?[.][.]?(/.*)?') - else false endif) - -context SidecarAsset - -- A sidecar mounts the Process's own Assets, and no other. - inv E_UNKNOWN_SIDECAR_ASSET: - oclContainer().oclContainer().oclAsType(Process).heldAssets->exists(a | a.from = self.from) - -context SeededAsset - -- The Processes the level that declares the Asset shares it with. - def: carriers : Set(Process) = - let level : SharedIntent = oclContainer().oclAsType(SharedIntent) in - if level.oclIsKindOf(Process) then Set{level.oclAsType(Process)} - else - if level.oclIsKindOf(Application) then level.oclAsType(Application).processes->asSet() - else level.oclAsType(Project).applications.processes->asSet() endif - endif - - -- Seeding runs the platform's seeder, which the Platform document names; the Asset a - -- Process seeds first is where the refusal is written, once for the Process. - inv E_NO_SEEDER__seedAt: - Platform.allInstances()->forAll(seeder <> null) - or carriers->forAll(p | p.seededAssets->isEmpty() or p.seededAssets->first() <> self) - - -- A seeded file lands below one of the Process's own volumes or writable paths. - inv E_SEED_OUTSIDE_VOLUME__seedAt: - Platform.allInstances()->isEmpty() - or carriers->forAll(p | not p.seededAssets->includes(self) - or p.landingDirectories->exists(directory | p.below(seedAt, directory))) - -endpackage diff --git a/emf/bundles/metamodel/model/resolved-deployment.ecore b/emf/bundles/metamodel/model/resolved-deployment.ecore deleted file mode 100644 index 499d60268..000000000 --- a/emf/bundles/metamodel/model/resolved-deployment.ecore +++ /dev/null @@ -1,1398 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/emf/bundles/metamodel/model/resolved-deployment.genmodel b/emf/bundles/metamodel/model/resolved-deployment.genmodel deleted file mode 100644 index c6d4e8014..000000000 --- a/emf/bundles/metamodel/model/resolved-deployment.genmodel +++ /dev/null @@ -1,9 +0,0 @@ - - - resolved-deployment.ecore - - diff --git a/emf/bundles/metamodel/model/resolved-deployment.ocl b/emf/bundles/metamodel/model/resolved-deployment.ocl deleted file mode 100644 index 326bf3173..000000000 --- a/emf/bundles/metamodel/model/resolved-deployment.ocl +++ /dev/null @@ -1,25 +0,0 @@ --- Document-level constraints of the Resolved Deployment, asked of a resolution --- before anything is rendered from it (docs/adr/emf/0143). Each invariant is --- named after the diagnostic code it reports, and its feature is the position --- the refusal is written at in the project file the Process comes from. - -import 'https://jorisjonkers.dev/deploy-kit/resolved-deployment/1' - -package resolveddeployment - -context ResolvedProcess - -- Every dimension a Process declared is matched against the node contract, so - -- no eligible node is a Process nothing can hold: its replicas, a writable path - -- held in memory, the seeder beside it and the pool its L4 Addresses hold it to - -- all count (spec/v1/20-resolved-deployment.md#layer-2-does-not-assign-a-node). - inv E_PLACEMENT_UNSATISFIABLE__placement: - placement.eligibleNodes->notEmpty() - - -- Replicas spread across nodes need a node each, and a rollout's old and new - -- pod may still share one, so fewer eligible nodes than the count leaves a - -- replica that never schedules. None eligible is the placement's own refusal. - inv E_PLACEMENT_UNSATISFIABLE__replicas: - (spread and placement.eligibleNodes->notEmpty()) - implies placement.eligibleNodes->size() >= replicas - -endpackage diff --git a/emf/bundles/metamodel/plugin.properties b/emf/bundles/metamodel/plugin.properties deleted file mode 100644 index 111e9b11a..000000000 --- a/emf/bundles/metamodel/plugin.properties +++ /dev/null @@ -1,4 +0,0 @@ -# - -pluginName = deploy-kit model-driven metamodel -providerName = www.example.org diff --git a/emf/bundles/metamodel/plugin.xml b/emf/bundles/metamodel/plugin.xml deleted file mode 100644 index 2cc02160b..000000000 --- a/emf/bundles/metamodel/plugin.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/emf/bundles/metamodel/pom.xml b/emf/bundles/metamodel/pom.xml deleted file mode 100644 index f55948355..000000000 --- a/emf/bundles/metamodel/pom.xml +++ /dev/null @@ -1,135 +0,0 @@ - - - 4.0.0 - - - dev.jorisjonkers.deploykit.emf - emf-parent - 0.1.0-SNAPSHOT - ../../pom.xml - - - dev.jorisjonkers.deploykit.emf.metamodel - eclipse-plugin - deploy-kit model-driven metamodel - - - - - - org.codehaus.mojo - exec-maven-plugin - - - generate-metamodel - generate-sources - java - - - /${project.basedir}/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GenerateProjectIntent.mwe2 - -p - rootPath=/${project.basedir}/.. - - - - - - generate-target-metamodel - generate-sources - java - - - /${project.basedir}/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GenerateResolvedDeployment.mwe2 - -p - rootPath=/${project.basedir}/.. - - - - - - generate-pinned-inputs - generate-sources - java - - - /${project.basedir}/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GeneratePinnedInputs.mwe2 - -p - rootPath=/${project.basedir}/.. - - - - - - org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher - compile - false - - ${project.basedir}/src/main/java - - - - - - org.jacoco - jacoco-maven-plugin - - - prepare-agent - - - dev.jorisjonkers.deploykit.emf.metamodel.projectintent.* - dev.jorisjonkers.deploykit.emf.metamodel.projectintent.impl.* - dev.jorisjonkers.deploykit.emf.metamodel.projectintent.util.* - dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.* - dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.impl.* - dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.util.* - dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.* - dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.impl.* - dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.util.* - - - - - report - - - dev/jorisjonkers/deploykit/emf/metamodel/projectintent/** - dev/jorisjonkers/deploykit/emf/metamodel/resolveddeployment/** - dev/jorisjonkers/deploykit/emf/metamodel/pinnedinputs/** - - - - - coverage-floor - - - dev/jorisjonkers/deploykit/emf/metamodel/projectintent/** - dev/jorisjonkers/deploykit/emf/metamodel/resolveddeployment/** - dev/jorisjonkers/deploykit/emf/metamodel/pinnedinputs/** - - - - - - - org.pitest - pitest-maven - - - dev.jorisjonkers.deploykit.emf.metamodel.projectintent.* - dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.* - dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.* - - false - - - - - diff --git a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GeneratePinnedInputs.mwe2 b/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GeneratePinnedInputs.mwe2 deleted file mode 100644 index 7fb072430..000000000 --- a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GeneratePinnedInputs.mwe2 +++ /dev/null @@ -1,21 +0,0 @@ -module dev.jorisjonkers.deploykit.emf.metamodel.GeneratePinnedInputs - -import org.eclipse.emf.mwe.utils.* -import org.eclipse.emf.mwe2.ecore.* - -var rootPath = ".." -var project = "dev.jorisjonkers.deploykit.emf.metamodel" - -// The genmodel's Java, written under target/ and never committed -// (emf/docs/architecture.md#metamodels). -Workflow { - bean = StandaloneSetup { - scanClassPath = true - projectMapping = { projectName = project path = "${rootPath}/metamodel" } - } - component = EcoreGenerator { - genModel = "platform:/resource/${project}/model/pinned-inputs.genmodel" - srcPath = "platform:/resource/${project}/target/generated-sources/emf" - lineDelimiter = "\n" - } -} diff --git a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GenerateProjectIntent.mwe2 b/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GenerateProjectIntent.mwe2 deleted file mode 100644 index bfa13472e..000000000 --- a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GenerateProjectIntent.mwe2 +++ /dev/null @@ -1,21 +0,0 @@ -module dev.jorisjonkers.deploykit.emf.metamodel.GenerateProjectIntent - -import org.eclipse.emf.mwe.utils.* -import org.eclipse.emf.mwe2.ecore.* - -var rootPath = ".." -var project = "dev.jorisjonkers.deploykit.emf.metamodel" - -// The genmodel's Java, written under target/ and never committed -// (emf/docs/architecture.md#metamodels). -Workflow { - bean = StandaloneSetup { - scanClassPath = true - projectMapping = { projectName = project path = "${rootPath}/metamodel" } - } - component = EcoreGenerator { - genModel = "platform:/resource/${project}/model/project-intent.genmodel" - srcPath = "platform:/resource/${project}/target/generated-sources/emf" - lineDelimiter = "\n" - } -} diff --git a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GenerateResolvedDeployment.mwe2 b/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GenerateResolvedDeployment.mwe2 deleted file mode 100644 index 9387443a9..000000000 --- a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/GenerateResolvedDeployment.mwe2 +++ /dev/null @@ -1,21 +0,0 @@ -module dev.jorisjonkers.deploykit.emf.metamodel.GenerateResolvedDeployment - -import org.eclipse.emf.mwe.utils.* -import org.eclipse.emf.mwe2.ecore.* - -var rootPath = ".." -var project = "dev.jorisjonkers.deploykit.emf.metamodel" - -// The genmodel's Java, written under target/ and never committed -// (emf/docs/architecture.md#metamodels). -Workflow { - bean = StandaloneSetup { - scanClassPath = true - projectMapping = { projectName = project path = "${rootPath}/metamodel" } - } - component = EcoreGenerator { - genModel = "platform:/resource/${project}/model/resolved-deployment.genmodel" - srcPath = "platform:/resource/${project}/target/generated-sources/emf" - lineDelimiter = "\n" - } -} diff --git a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DependencyEdges.java b/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DependencyEdges.java deleted file mode 100644 index 141135bd0..000000000 --- a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DependencyEdges.java +++ /dev/null @@ -1,83 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.metamodel.descriptor; - -import dev.jorisjonkers.deploykit.emf.metamodel.json.CanonicalJson; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedApplication; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedEdge; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedProcess; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -/** - * The resolved dependency edges of a Resolved Deployment model, in the shape the parity contract - * fixes: one entry per Application, each an {@code id} and its {@code edges}, and an Application - * with no dependency carrying an empty list - * (docs/architecture.md#the-parity-contract). - * - *

This is the half of resolution both implementations must agree on before either renders, so it - * is compared as canonical JSON against {@code spec/v1/examples//expected/dependencies.json}. - * The Resolved Deployment itself is not compared: the two implementations shape layer 2 differently - * on purpose (emf/docs/architecture.md#metamodels). - */ -public final class DependencyEdges { - - /** The name a run writes, the oracle's own. */ - public static final String NAME = "dependencies.json"; - - private DependencyEdges() {} - - /** The edges of {@code deployment}, as the nested maps and lists the canonical writer takes. */ - public static Map of(ResolvedDeployment deployment) { - List applications = new ArrayList<>(); - for (ResolvedApplication application : deployment.getApplications()) { - applications.add(entry(application)); - } - return Map.of("applications", applications); - } - - /** Writes {@code deployment}'s edges under {@code directory}, and returns the file. */ - public static Path write(Path directory, ResolvedDeployment deployment) throws IOException { - Files.createDirectories(directory); - return Files.writeString(directory.resolve(NAME), CanonicalJson.write(of(deployment)), StandardCharsets.UTF_8); - } - - private static Map entry(ResolvedApplication application) { - List edges = new ArrayList<>(); - for (ResolvedProcess process : application.getProcesses()) { - for (ResolvedEdge edge : process.getDependencies()) { - edges.add(edge(process, edge)); - } - } - Map entry = new LinkedHashMap<>(); - entry.put("id", application.getId()); - entry.put("edges", edges); - return entry; - } - - private static Map edge(ResolvedProcess consumer, ResolvedEdge edge) { - Map written = new LinkedHashMap<>(); - written.put("consumer", consumer.getName()); - written.put("application", edge.getApplication()); - written.put("surface", edge.getSurface()); - written.put("address", edge.getAddress()); - if (edge.getTarget() != null) { - written.put("target", edge.getTarget()); - } - List peers = new ArrayList<>(); - edge.getPeers() - .forEach(peer -> peers.add(Map.of( - "namespace", peer.getNamespace(), - "process", peer.getProcess(), - "port", (long) peer.getPort()))); - if (!peers.isEmpty()) { - written.put("peers", peers); - } - return written; - } -} diff --git a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/Descriptor.java b/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/Descriptor.java deleted file mode 100644 index a72ce8896..000000000 --- a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/Descriptor.java +++ /dev/null @@ -1,174 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.metamodel.descriptor; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import org.eclipse.emf.ecore.EAnnotation; -import org.eclipse.emf.ecore.EAttribute; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EClassifier; -import org.eclipse.emf.ecore.EEnum; -import org.eclipse.emf.ecore.EEnumLiteral; -import org.eclipse.emf.ecore.EModelElement; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EStructuralFeature; - -/** - * The structure of a metamodel, in the shape the parity contract fixes: every class with its - * features, each feature's types and multiplicity, and every closed vocabulary with its literals - * (docs/architecture.md#the-parity-contract). - * - *

The shape is neither Ecore's nor the wire schema's. An abstract class is the union of what can - * stand in its place, so it is not listed and a feature that points at one names its concrete - * classes. A map entry is not a class either: the feature that holds the entries is a map. A class - * the language writes as the value of one of its features is that feature's type, so a plain key - * is a {@code string}. And a class nobody authors is not listed: the lowered Project and Application are what a transformation - * writes (docs/adr/model/0125). - */ -public final class Descriptor { - - private static final String JSON = "https://jorisjonkers.dev/deploy-kit/json"; - private static final Map PRIMITIVES = - Map.of("java.lang.String", "string", "java.lang.Integer", "int", "java.lang.Boolean", "boolean"); - - private Descriptor() {} - - /** The descriptor of {@code metamodel}, as a JSON value. */ - public static Map of(EPackage metamodel) { - List classes = new ArrayList<>(); - List vocabularies = new ArrayList<>(); - for (EClassifier classifier : sorted(metamodel.getEClassifiers())) { - switch (classifier) { - case EEnum vocabulary -> vocabularies.add(vocabulary(vocabulary)); - case EClass owner -> { - if (isListed(owner)) { - classes.add(owner(owner)); - } - } - default -> - throw new IllegalArgumentException( - classifier.getName() + " is neither a class nor a closed vocabulary"); - } - } - return Map.of("classes", classes, "vocabularies", vocabularies); - } - - private static List sorted(List classifiers) { - return classifiers.stream() - .sorted(Comparator.comparing(EClassifier::getName)) - .toList(); - } - - /** Whether a class is one the descriptor lists: an abstract class is a union, a map entry a map. */ - private static boolean isListed(EClass owner) { - return !owner.isAbstract() - && !isMapEntry(owner) - && !"no".equals(detail(owner, "authored")) - && detail(owner, "value") == null; - } - - /** The descriptor spells a class as its document spells it, and `env` is a directory beside one. */ - private static boolean isInTheDocument(EStructuralFeature feature) { - return !"no".equals(detail(feature, "document")); - } - - /** The key a document writes a feature under: its name, unless the name is no Java identifier. */ - public static String keyOf(EStructuralFeature feature) { - String key = detail(feature, "key"); - return key == null ? feature.getName() : key; - } - - /** What this element's JSON annotation says under {@code key}, or nothing where it carries none. */ - private static String detail(EModelElement element, String key) { - EAnnotation json = element.getEAnnotation(JSON); - return json == null ? null : json.getDetails().get(key); - } - - private static boolean isMapEntry(EClassifier classifier) { - return Map.Entry.class.getName().equals(classifier.getInstanceClassName()); - } - - private static Map vocabulary(EEnum vocabulary) { - Map json = new LinkedHashMap<>(); - json.put("name", vocabulary.getName()); - // A literal with no spelling is the model's way of saying "unset", which is - // not a value the language can write and not part of the vocabulary. - json.put( - "literals", - vocabulary.getELiterals().stream() - .map(EEnumLiteral::getLiteral) - .filter(literal -> !literal.isEmpty()) - .toList()); - return json; - } - - private static Map owner(EClass owner) { - Map json = new LinkedHashMap<>(); - json.put("name", owner.getName()); - json.put( - "features", - owner.getEAllStructuralFeatures().stream() - .filter(Descriptor::isInTheDocument) - .sorted(Comparator.comparing(Descriptor::keyOf)) - .map(Descriptor::feature) - .toList()); - String scalar = detail(owner, "scalar"); - if (scalar != null) { - json.put("scalar", scalar); - } - return json; - } - - private static Map feature(EStructuralFeature feature) { - boolean map = feature instanceof EReference containment - && containment.isContainment() - && isMapEntry(containment.getEReferenceType()); - boolean linked = feature instanceof EReference reference && !reference.isContainment(); - Map json = new LinkedHashMap<>(); - json.put("name", keyOf(feature)); - json.put("types", linked ? List.of(feature.getEType().getName()) : types(feature, map)); - json.put("required", feature.isRequired()); - json.put("many", feature.isMany() && !map); - json.put("map", map); - json.put("reference", linked); - if (map) { - String entry = detail(feature.getEType(), "entry"); - json.put("entry", entry == null ? feature.getEType().getName() : entry); - } - return json; - } - - /** The types a feature admits: a vocabulary, a primitive, a class, or the classes a union stands for. */ - private static List types(EStructuralFeature feature, boolean map) { - if (map) { - EClass entry = ((EReference) feature).getEReferenceType(); - return types(entry.getEStructuralFeature("value"), false); - } - EClassifier type = feature.getEType(); - if (feature instanceof EAttribute) { - return List.of(type instanceof EEnum ? type.getName() : PRIMITIVES.get(type.getInstanceClassName())); - } - EClass referenced = (EClass) type; - if (!referenced.isAbstract()) { - return List.of(nameOf(referenced)); - } - return referenced.getEPackage().getEClassifiers().stream() - .filter(EClass.class::isInstance) - .map(EClass.class::cast) - .filter(candidate -> !candidate.isAbstract() && referenced.isSuperTypeOf(candidate)) - .map(Descriptor::nameOf) - .sorted() - .toList(); - } - - /** A class by its name, or by the type of the one feature the language writes it as. */ - private static String nameOf(EClass candidate) { - String value = detail(candidate, "value"); - return value == null - ? candidate.getName() - : types(candidate.getEStructuralFeature(value), false).getFirst(); - } -} diff --git a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DescriptorFile.java b/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DescriptorFile.java deleted file mode 100644 index 74c7ddf58..000000000 --- a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DescriptorFile.java +++ /dev/null @@ -1,31 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.metamodel.descriptor; - -import dev.jorisjonkers.deploykit.emf.metamodel.json.CanonicalJson; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; - -/** - * The source metamodel's descriptor, written where a run of the build leaves it: the same reflective - * walk {@link Descriptor} performs, in the canonical JSON the oracle is committed in - * (docs/adr/emf/0080-parity-crosses-the-cli-file-interface.md). The file is named for its oracle, - * {@code spec/v1/examples/expected/descriptor.json}, so the two are obviously a pair. - */ -public final class DescriptorFile { - - /** The name a run writes, the oracle's own. */ - public static final String NAME = "descriptor.json"; - - private DescriptorFile() {} - - /** Writes the source metamodel's descriptor under {@code directory}, and returns the file. */ - public static Path write(Path directory) throws IOException { - Files.createDirectories(directory); - return Files.writeString( - directory.resolve(NAME), - CanonicalJson.write(Descriptor.of(ProjectIntentPackage.eINSTANCE)), - StandardCharsets.UTF_8); - } -} diff --git a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/json/CanonicalJson.java b/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/json/CanonicalJson.java deleted file mode 100644 index cacd507a3..000000000 --- a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/json/CanonicalJson.java +++ /dev/null @@ -1,160 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.metamodel.json; - -import java.math.BigDecimal; -import java.math.MathContext; -import java.math.RoundingMode; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * Writes a JSON value in the RFC 8785 canonical form the parity contract compares oracle files in: - * object keys sorted by UTF-16 code units, numbers as ECMAScript formats a double, no insignificant - * whitespace. A value is a {@link Map} with string keys, a {@link List}, a {@link String}, a {@link - * Boolean}, a {@link Double}, or an integral {@link Integer}, {@link Long}, {@link Short} or {@link - * Byte}. An absent optional field is absent, so {@code null} is refused rather than written. - */ -public final class CanonicalJson { - - private static final long MAX_SAFE_INTEGER = 9_007_199_254_740_991L; - - private CanonicalJson() {} - - /** The canonical serialisation of {@code value}. */ - public static String write(Object value) { - StringBuilder out = new StringBuilder(); - append(out, value, ""); - return out.toString(); - } - - private static void append(StringBuilder out, Object value, String pointer) { - switch (value) { - case null -> - throw new IllegalArgumentException( - "null at " + pointer + ": an absent optional field is absent, never null"); - case Map map -> appendObject(out, map, pointer); - case List list -> appendArray(out, list, pointer); - case String text -> appendString(out, text, pointer); - case Boolean bool -> out.append(bool); - case Double number -> out.append(formatDouble(number, pointer)); - case Integer number -> out.append(number); - case Short number -> out.append(number); - case Byte number -> out.append(number); - case Long number -> out.append(checkSafe(number, pointer)); - default -> - throw new IllegalArgumentException( - value.getClass().getName() + " at " + pointer + " is not a JSON value"); - } - } - - private static void appendObject(StringBuilder out, Map map, String pointer) { - List keys = new ArrayList<>(map.size()); - for (Object key : map.keySet()) { - if (!(key instanceof String text)) { - throw new IllegalArgumentException("object key at " + pointer + " is not a string"); - } - keys.add(text); - } - keys.sort(String::compareTo); - out.append('{'); - String separator = ""; - for (String key : keys) { - out.append(separator); - appendString(out, key, pointer); - out.append(':'); - append(out, map.get(key), pointer + "/" + escapePointer(key)); - separator = ","; - } - out.append('}'); - } - - private static void appendArray(StringBuilder out, List list, String pointer) { - out.append('['); - for (int i = 0; i < list.size(); i++) { - if (i > 0) { - out.append(','); - } - append(out, list.get(i), pointer + "/" + i); - } - out.append(']'); - } - - private static void appendString(StringBuilder out, String text, String pointer) { - out.append('"'); - for (int i = 0; i < text.length(); i++) { - char c = text.charAt(i); - if (Character.isHighSurrogate(c) && i + 1 < text.length() && Character.isLowSurrogate(text.charAt(i + 1))) { - out.append(c).append(text.charAt(++i)); - } else if (Character.isSurrogate(c)) { - throw new IllegalArgumentException("string at " + pointer + " holds a lone surrogate at index " + i); - } else { - appendChar(out, c); - } - } - out.append('"'); - } - - private static void appendChar(StringBuilder out, char c) { - switch (c) { - case '"' -> out.append("\\\""); - case '\\' -> out.append("\\\\"); - case '\b' -> out.append("\\b"); - case '\f' -> out.append("\\f"); - case '\n' -> out.append("\\n"); - case '\r' -> out.append("\\r"); - case '\t' -> out.append("\\t"); - default -> { - if (c < 0x20) { - out.append(String.format("\\u%04x", (int) c)); - } else { - out.append(c); - } - } - } - } - - private static long checkSafe(long number, String pointer) { - if (Math.abs(number) > MAX_SAFE_INTEGER) { - throw new IllegalArgumentException( - number + " at " + pointer + " is outside the range a JSON number carries exactly"); - } - return number; - } - - /** ECMAScript Number::toString over the shortest decimal that round-trips the double. */ - private static String formatDouble(double value, String pointer) { - if (Double.isNaN(value) || Double.isInfinite(value)) { - throw new IllegalArgumentException(value + " at " + pointer + " is not a JSON number"); - } - if (value == 0.0) { - return "0"; - } - // Double.toString yields the shortest round-tripping decimal (JDK 19 and later), except that - // it never prints fewer than two significant digits; one digit may still round-trip. - BigDecimal decimal = new BigDecimal(Double.toString(Math.abs(value))).stripTrailingZeros(); - BigDecimal oneDigit = decimal.round(new MathContext(1, RoundingMode.HALF_EVEN)); - if (oneDigit.doubleValue() == Math.abs(value)) { - decimal = oneDigit.stripTrailingZeros(); - } - String digits = decimal.unscaledValue().toString(); - int k = digits.length(); - int n = decimal.precision() - decimal.scale(); - String sign = Double.toString(value).startsWith("-") ? "-" : ""; - if (n > 21 || n <= -6) { - String exponent = Integer.toString(n - 1); - String mantissa = k == 1 ? digits : digits.charAt(0) + "." + digits.substring(1); - return sign + mantissa + "e" + (exponent.startsWith("-") ? exponent : "+" + exponent); - } - if (n <= 0) { - return sign + "0." + "0".repeat(-n) + digits; - } - if (n >= k) { - return sign + digits + "0".repeat(n - k); - } - return sign + digits.substring(0, n) + "." + digits.substring(n); - } - - private static String escapePointer(String segment) { - return segment.replace("~", "~0").replace("/", "~1"); - } -} diff --git a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/revision/ModelDigest.java b/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/revision/ModelDigest.java deleted file mode 100644 index fce7545a3..000000000 --- a/emf/bundles/metamodel/src/main/java/dev/jorisjonkers/deploykit/emf/metamodel/revision/ModelDigest.java +++ /dev/null @@ -1,90 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.metamodel.revision; - -import dev.jorisjonkers.deploykit.emf.metamodel.json.CanonicalJson; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.HexFormat; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import org.eclipse.emf.common.util.Enumerator; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.util.EcoreUtil; - -/** - * The digest of a pinned input (spec/v1/20-resolved-deployment.md#pinned-inputs): {@code - * sha256:} over the canonical JSON of the model read from it, so a change of spelling that - * reads as the same model does not move it, and any change of what it says does. The model is walked - * reflectively: a set attribute as its value, an - * enumeration as its literal, a contained object as an object, and a reference as the identifier of - * what it points at, or its path where the class carries none. A feature nobody set is absent. - */ -public final class ModelDigest { - - private ModelDigest() {} - - /** {@code sha256:} over the canonical JSON of {@code model}. */ - public static String of(EObject model) { - return "sha256:" + HexFormat.of().formatHex(digest("SHA-256", CanonicalJson.write(json(model)))); - } - - /** {@code sha256:} over the canonical JSON of {@code text}: the string, quoted and escaped. */ - public static String ofText(String text) { - return "sha256:" + HexFormat.of().formatHex(digest("SHA-256", CanonicalJson.write(text))); - } - - /** {@code sha256:} over {@code text}'s UTF-8 bytes, as written. */ - public static String ofBytes(String text) { - return "sha256:" + HexFormat.of().formatHex(digest("SHA-256", text)); - } - - /** {@code text} digested by {@code algorithm}; every Java platform implements SHA-256. */ - static byte[] digest(String algorithm, String text) { - try { - return MessageDigest.getInstance(algorithm).digest(text.getBytes(StandardCharsets.UTF_8)); - } catch (NoSuchAlgorithmException absent) { - throw new IllegalStateException(absent); - } - } - - private static Map json(EObject object) { - Map json = new LinkedHashMap<>(); - for (EStructuralFeature feature : object.eClass().getEAllStructuralFeatures()) { - if (object.eIsSet(feature)) { - json.put(feature.getName(), value(object, feature)); - } - } - return json; - } - - private static Object value(EObject owner, EStructuralFeature feature) { - Object value = owner.eGet(feature); - if (feature.isMany()) { - List items = new ArrayList<>(); - for (Object item : (List) value) { - items.add(single(feature, item)); - } - return items; - } - return single(feature, value); - } - - private static Object single(EStructuralFeature feature, Object value) { - if (feature instanceof EReference reference) { - EObject target = (EObject) value; - if (reference.isContainment()) { - return json(target); - } - String id = EcoreUtil.getID(target); - return id == null ? EcoreUtil.getURI(target).fragment() : id; - } - if (value instanceof Enumerator literal) { - return literal.getLiteral(); - } - return value; - } -} diff --git a/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/ProjectIntentOclTest.java b/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/ProjectIntentOclTest.java deleted file mode 100644 index a3a49d039..000000000 --- a/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/ProjectIntentOclTest.java +++ /dev/null @@ -1,107 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.metamodel; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.EValidator; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.emf.ecore.util.Diagnostician; -import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; -import org.eclipse.ocl.pivot.utilities.OCL; -import org.eclipse.ocl.xtext.completeocl.CompleteOCLStandaloneSetup; -import org.eclipse.ocl.xtext.completeocl.validation.CompleteOCLEObjectValidator; -import org.junit.jupiter.api.Test; - -/** - * What emf/README.md's step 3 shows an examiner, headless: Project Intent's Complete OCL document, - * loaded beside the metamodel it constrains, refuses the one Project of the two that breaks an - * invariant, and names that invariant. The models are read through the metamodel file, as the - * Sample Reflective Ecore Model Editor reads them, never through the generated package. - */ -class ProjectIntentOclTest { - - private static final Path MODEL = Path.of("model").toAbsolutePath(); - - private static URI uri(String file) { - return URI.createFileURI(MODEL.resolve(file).toString()); - } - - private static OCL ocl() { - CompleteOCLStandaloneSetup.doSetup(); - OCL ocl = OCL.newInstance(OCL.NO_PROJECTS); - ResourceSet resources = ocl.getResourceSet(); - resources.getResourceFactoryRegistry().getExtensionToFactoryMap().put("ecore", new EcoreResourceFactoryImpl()); - resources.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xmi", new XMIResourceFactoryImpl()); - return ocl; - } - - /** - * The metamodel file the document imports, answering its nsURI in this resource set alone, as an - * editor's registry does: a test elsewhere in this JVM may have registered the generated package - * globally, and the models must be read through the file. - */ - private static EPackage metamodel(ResourceSet resources) { - EPackage intent = (EPackage) resources - .getResource(uri("project-intent.ecore"), true) - .getContents() - .get(0); - resources.getPackageRegistry().put(intent.getNsURI(), intent); - return intent; - } - - /** - * The one model at {@code file}, validated in a resource set of its own with the document loaded, - * as an editor holds it: an invariant across documents ranges over its resource set, so two - * Projects read together would each refuse the other's name. - */ - private static Diagnostic validate(String file) { - OCL ocl = ocl(); - ResourceSet resources = ocl.getResourceSet(); - EPackage intent = metamodel(resources); - EValidator.Registry.INSTANCE.put(intent, new CompleteOCLEObjectValidator(intent, uri("project-intent.ocl"))); - try { - EObject project = - resources.getResource(uri(file), true).getContents().get(0); - assertThat(project.eClass().getEPackage()).isSameAs(intent); - return Diagnostician.INSTANCE.validate(project); - } finally { - EValidator.Registry.INSTANCE.remove(intent); - ocl.dispose(); - } - } - - /** Every invariant a validation reports, as Eclipse OCL names it: {@code Class::NAME}. */ - private static List violated(Diagnostic diagnostic) { - List violated = new ArrayList<>(); - String message = diagnostic.getMessage(); - if (message != null && message.contains("' constraint is violated")) { - violated.add(message.substring(message.indexOf('\'') + 1, message.indexOf("' constraint"))); - } - diagnostic.getChildren().forEach(child -> violated.addAll(violated(child))); - return violated; - } - - @Test - void theProjectValidatesClean() { - Diagnostic accepted = validate("cache.xmi"); - - assertThat(violated(accepted)).isEmpty(); - assertThat(accepted.getSeverity()).isEqualTo(Diagnostic.OK); - } - - @Test - void itsContinuousCutoverOverAVolumeBreaksExactlyOneInvariant() { - Diagnostic refused = validate("cache-continuous.xmi"); - - assertThat(violated(refused)).containsExactly("Process::E_CUTOVER_UNHONOURABLE"); - // Eclipse OCL reports a failed invariant as a warning unless the constraint says otherwise. - assertThat(refused.getSeverity()).isEqualTo(Diagnostic.WARNING); - } -} diff --git a/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/ResolvedDeploymentTest.java b/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/ResolvedDeploymentTest.java deleted file mode 100644 index b37768f20..000000000 --- a/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/ResolvedDeploymentTest.java +++ /dev/null @@ -1,403 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.metamodel; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.descriptor.DependencyEdges; -import dev.jorisjonkers.deploykit.emf.metamodel.json.CanonicalJson; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.Cutover; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.Deliverable; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.PolicyPeer; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedApplication; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedEdge; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedProcess; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.Switchover; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; -import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EClass; -import org.eclipse.emf.ecore.EClassifier; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import org.eclipse.emf.ecore.util.Diagnostician; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** - * The Resolved Deployment target metamodel (#87), and the hand-written `minimal` model that is the - * target half of both tracers before either exists. - */ -class ResolvedDeploymentTest { - - /** `emf/models/`, from the module's own directory. */ - private static final Path MODELS = - Path.of("..", "..", "models").toAbsolutePath().normalize(); - - /** The repository root, from the module's own directory. */ - private static final Path REPOSITORY = - Path.of("..", "..", "..").toAbsolutePath().normalize(); - - /** - * The committed source descriptor, as text. A field rather than a local because CodeQL analyses - * this file without the generated sources under `target/`, which `.github/codeql/codeql-config.yml` - * excludes: a local whose only read sits inside an expression over a generated type reads as - * never read. - */ - private static final String DESCRIPTOR = descriptor(); - - private static String descriptor() { - try { - return Files.readString( - REPOSITORY.resolve("spec/v1/examples/expected/descriptor.json"), StandardCharsets.UTF_8); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private static ResolvedDeployment minimal() { - ResourceSet resources = new ResourceSetImpl(); - resources - .getResourceFactoryRegistry() - .getExtensionToFactoryMap() - .put(Resource.Factory.Registry.DEFAULT_EXTENSION, new XMIResourceFactoryImpl()); - resources.getPackageRegistry().put(ResolvedDeploymentPackage.eNS_URI, ResolvedDeploymentPackage.eINSTANCE); - URI uri = URI.createFileURI(MODELS.resolve("minimal.resolveddeployment").toString()); - return (ResolvedDeployment) - resources.getResource(uri, true).getContents().get(0); - } - - @Test - void theHandWrittenMinimalModelValidatesAgainstTheMetamodel() { - Diagnostic diagnostic = Diagnostician.INSTANCE.validate(minimal()); - - assertThat(diagnostic.getChildren()).isEmpty(); - assertThat(diagnostic.getSeverity()).isEqualTo(Diagnostic.OK); - } - - @Test - void aPrepareProcessCarriesNoCutoverAndStillValidates() { - // spec/v1/10-project-intent.md#prepare-processes: a prepare Process runs - // once and cuts over nothing, so layer 2 leaves both unset. - ResolvedDeployment deployment = minimal(); - ResolvedProcess process = - deployment.getApplications().get(0).getProcesses().get(0); - process.unsetCutover(); - process.unsetSwitchover(); - - assertThat(process.isSetCutover()).isFalse(); - assertThat(Diagnostician.INSTANCE.validate(deployment).getSeverity()).isEqualTo(Diagnostic.OK); - } - - @Test - void everyProcessSwitchesAsItsCutoverAllowsAndOnlyABlueGreenApplicationIsGated() { - // spec/v1/55-delivery.md#switchover: `continuous` derives blue-green, or - // rolling on delivery machinery; `interrupted` derives stop-start; and an - // Application carries release-gate inputs exactly when a Process of it - // switches blue-green. - for (ResolvedApplication application : minimal().getApplications()) { - boolean gated = application.getProcesses().stream() - .anyMatch(process -> process.getSwitchover() == Switchover.BLUE_GREEN); - assertThat(application.getReleaseGate() != null).isEqualTo(gated); - for (ResolvedProcess process : application.getProcesses()) { - assertThat(process.getSwitchover()) - .isIn( - process.getCutover() == Cutover.CONTINUOUS - ? List.of(Switchover.BLUE_GREEN, Switchover.ROLLING) - : List.of(Switchover.STOP_START)); - } - } - } - - @Test - void itsExportedDependencyEdgesEqualTheCommittedOracle() throws IOException { - // notes holds no dependency edge, so the export is the empty list the - // committed oracle carries. The shape is what both implementations match. - Path oracle = REPOSITORY.resolve("spec/v1/examples/minimal/expected/dependencies.json"); - - String exported = CanonicalJson.write(DependencyEdges.of(minimal())); - - assertThat(exported).isEqualTo(Files.readString(oracle, StandardCharsets.UTF_8)); - } - - @Test - void aRunLeavesTheEdgesWhereTheContractLooksForThem(@TempDir Path directory) throws IOException { - Path written = DependencyEdges.write(directory, minimal()); - - assertThat(written).hasFileName(DependencyEdges.NAME); - assertThat(Files.readString(written, StandardCharsets.UTF_8)) - .isEqualTo(CanonicalJson.write(DependencyEdges.of(minimal()))); - } - - /** - * The spellings the production implementation's own check refuses - * (test/model/resolved-deployment.test.ts, after - * docs/adr/model/0011-authored-values-name-model-concepts.md). - */ - private static final Set KUBERNETES_AND_TRAEFIK_FIELDS = Set.of( - "objectKind", - "strategy", - "maxSurge", - "maxUnavailable", - "securityContext", - "runAsNonRoot", - "runAsUser", - "runAsGroup", - "allowPrivilegeEscalation", - "readOnlyRootFilesystem", - "seccompProfile", - "fsGroup", - "capabilities", - "nodeSelector", - "affinity", - "resources", - "requests", - "limits", - "emptyDir", - "sizeLimit", - "periodSeconds", - "timeoutSeconds", - "failureThreshold", - "initialDelaySeconds", - "progressDeadlineSeconds", - "automountServiceAccountToken", - "serviceAccount", - "serviceAccountName", - "secretObjects", - "middlewares", - "entryPoints"); - - /** Every class of the target metamodel. */ - private static List targetClasses() { - return ResolvedDeploymentPackage.eINSTANCE.getEClassifiers().stream() - .filter(EClass.class::isInstance) - .map(EClass.class::cast) - .toList(); - } - - @Test - void theResolvedModelNamesNoKubernetesOrTraefikField() { - // The production implementation's refused spellings, over every class of the resolved - // model. The Deliverable plan is left out: it spells the target formats on purpose, - // and the production model has no such plan to check. - Set plan = targetClasses().stream() - .filter(ResolvedDeploymentPackage.eINSTANCE.getDeliverable()::isSuperTypeOf) - .collect(Collectors.toCollection(java.util.HashSet::new)); - // A class only the plan contains is the plan's too; one the resolved model also contains is not. - boolean grew = true; - while (grew) { - grew = false; - for (EClass type : targetClasses()) { - List containers = targetClasses().stream() - .filter(owner -> owner.getEReferences().stream() - .anyMatch(reference -> - reference.isContainment() && reference.getEReferenceType() == type)) - .toList(); - if (!plan.contains(type) && !containers.isEmpty() && plan.containsAll(containers)) { - grew = plan.add(type); - } - } - } - - assertThat(plan.stream().map(EClassifier::getName)) - .contains("ProcessPolicy", "SecretHolder") - .doesNotContain("PolicyPeer"); - assertThat(targetClasses().stream() - .filter(type -> !plan.contains(type)) - .flatMap(type -> type.getEStructuralFeatures().stream()) - .map(feature -> feature.getName())) - .isNotEmpty() - .doesNotContainAnyElementsOf(KUBERNETES_AND_TRAEFIK_FIELDS); - } - - @Test - void everyResourceFamilyOfTheProposalHasATypedClassTheTemplatesWalk() { - // The project proposal's generated-resources table, one row per family: - // a namespace and indexes, workload resources with their identity, - // network policy, edge routing, monitoring, and secret resources; and - // what the rendered trees hold beyond it: Services, claims, Asset - // ConfigMaps, backups, the Secret Store connection, Vault's own - // documents, the RBAC of a Process that holds API access, the budget - // of a count above one, a migration's identity and Jobs, the route - // Flux's events take to the Reporter, the volume and claim of a - // library a project mounts, the default TLS store a tier's certificate - // derives, Grafana's instance, and the scrapes of k3s itself. - assertThat(ResolvedDeploymentPackage.eINSTANCE.getEClassifiers().stream() - .filter(EClass.class::isInstance) - .map(EClass.class::cast) - .filter(type -> !type.isAbstract()) - .filter(type -> ResolvedDeploymentPackage.eINSTANCE - .getDeliverable() - .isSuperTypeOf(type)) - .map(EClassifier::getName) - .collect(Collectors.toSet())) - .containsExactlyInAnyOrder( - "NamespaceFile", - "IndexFile", - "WorkloadFile", - "SwitchoverFile", - "IdentityFile", - "NetworkPolicyFile", - "IngressRouteFile", - "MonitorFile", - "SecretFile", - "ServiceFile", - "RbacFile", - "PolicyJobFile", - "CatalogJobFile", - "EventsFile", - "BudgetFile", - "MigrationFile", - "ClaimFile", - "AliasFile", - "LibraryFile", - "ConfigMapFile", - "BackupFile", - "ConnectionFile", - "VaultPolicyFile", - "VaultRoleFile", - "GeneratedKeysFile", - "PriorityClassFile", - "HumanGrantFile", - "NodeAgentFile", - "AddressPoolFile", - "ClientFile", - "AlertRulesFile", - "AlertingFile", - "FluxMonitorFile", - "DashboardFile", - "SharedMiddlewareFile", - "StableAddressFile", - "SourceFile", - "TlsStoreFile", - "GrafanaFile", - "K3sMonitorsFile"); - } - - @Test - void theMinimalModelAssignsAPathToEveryFileTheRenderedTreeHolds() { - // The paths under spec/v1/examples/minimal/rendered/, which is what the Acceleo templates - // must write (#94), and the platform's estate-scoped share every render holds. - List paths = - minimal().getDeliverables().stream().map(Deliverable::getPath).toList(); - - assertThat(paths) - .containsExactlyInAnyOrder( - "apps/notes/namespace.yaml", - "apps/notes/kustomization.yaml", - "apps/notes/networkpolicy.yaml", - "apps/notes/libraries.yaml", - "apps/notes/notes/kustomization.yaml", - "apps/notes/notes/workload.yaml", - "apps/notes/notes/canary.yaml", - "apps/notes/notes/serviceaccount.yaml", - "apps/notes/notes/configmap.yaml", - "apps/notes/notes/podmonitor.yaml", - "apps/notes/notes/networkpolicy.yaml", - "apps/notes/rollout-events/alert.yaml", - "apps/notes/rollout-events/provider.yaml", - "estate/priority-classes/priorityclasses.yaml", - "estate/priority-classes/kustomization.yaml", - "estate/human-grants/clusterrolebindings.yaml", - "estate/human-grants/kustomization.yaml", - "apps/notes/rollout-events/kustomization.yaml", - "apps/notes/notes/route-public.yaml"); - } - - @Test - void thePathsItAssignsAreThePathsTheRenderedTreeActuallyHolds() throws IOException { - // The project's share is minimal's own tree, its route among it, and its estate-scoped - // share is the platform's alone. - Set assigned = - minimal().getDeliverables().stream().map(Deliverable::getPath).collect(Collectors.toSet()); - Set committed = - new java.util.HashSet<>(yamlUnder(REPOSITORY.resolve("spec/v1/examples/minimal/rendered"))); - committed.addAll(yamlUnder(REPOSITORY.resolve("spec/v1/examples/platform/rendered"))); - - assertThat(assigned).isEqualTo(committed); - } - - private static Set yamlUnder(Path rendered) throws IOException { - try (var files = Files.walk(rendered)) { - return files.filter(Files::isRegularFile) - .map(file -> rendered.relativize(file).toString()) - .filter(name -> name.endsWith(".yaml")) - .collect(Collectors.toSet()); - } - } - - /** - * `minimal` holds no dependency edge, which is the point of it, so the export's own shape is - * proved on a model built here: one edge whose connection the policy names a peer for, and one - * that resolves to an address with no peer of its own. - */ - @Test - void anEdgeExportsItsConsumer_itsProviderAndThePeersThePolicyAllows() { - ResolvedDeploymentFactory make = ResolvedDeploymentFactory.eINSTANCE; - ResolvedDeployment deployment = make.createResolvedDeployment(); - ResolvedApplication application = make.createResolvedApplication(); - application.setId("knowledge"); - ResolvedProcess process = make.createResolvedProcess(); - process.setName("knowledge-api"); - ResolvedEdge withPeer = make.createResolvedEdge(); - withPeer.setApplication("platform-postgres"); - withPeer.setSurface("postgres"); - withPeer.setAddress("platform-postgres:5432"); - withPeer.setTarget("platform-postgres.data-system.svc.cluster.local"); - PolicyPeer peer = make.createPolicyPeer(); - peer.setNamespace("data-system"); - peer.setProcess("platform-postgres"); - peer.setPort(5432); - withPeer.getPeers().add(peer); - ResolvedEdge withoutPeer = make.createResolvedEdge(); - withoutPeer.setApplication("stalwart"); - withoutPeer.setSurface("smtp"); - withoutPeer.setAddress("10.0.0.12:25"); - process.getDependencies().add(withPeer); - process.getDependencies().add(withoutPeer); - application.getProcesses().add(process); - deployment.getApplications().add(application); - - String exported = CanonicalJson.write(DependencyEdges.of(deployment)); - - assertThat(exported) - .isEqualTo("{\"applications\":[{\"edges\":[" - + "{\"address\":\"platform-postgres:5432\"," - + "\"application\":\"platform-postgres\",\"consumer\":\"knowledge-api\"," - + "\"peers\":[{\"namespace\":\"data-system\",\"port\":5432," - + "\"process\":\"platform-postgres\"}],\"surface\":\"postgres\"," - + "\"target\":\"platform-postgres.data-system.svc.cluster.local\"}," - + "{\"address\":\"10.0.0.12:25\",\"application\":\"stalwart\"," - + "\"consumer\":\"knowledge-api\",\"surface\":\"smtp\"}]," - + "\"id\":\"knowledge\"}]}"); - } - - /** - * The descriptor covers the source metamodel only: target structures are compared through what - * they generate, not structurally (docs/architecture.md#the-parity-contract). A target class - * reaching the descriptor would put this implementation's shape into an oracle the other one - * has to match, and the two shape layer 2 differently on purpose. - */ - @Test - void noClassOfTheTargetPackageReachesTheDescriptor() { - // Cutover, Match and DurabilityClass are the source metamodel's own - // vocabularies, carried here by the same names on purpose. Nothing else - // shares a name: layer 1 has EnvVariable where layer 2 has EnvEntry, - // because an author sets a variable and a render writes an entry. - assertThat(ResolvedDeploymentPackage.eINSTANCE.getEClassifiers().stream() - .map(EClassifier::getName) - .filter(name -> DESCRIPTOR.contains("\"name\":\"" + name + "\"")) - .collect(Collectors.toSet())) - .containsExactlyInAnyOrder("Cutover", "Match", "DurabilityClass"); - } -} diff --git a/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DescriptorFileTest.java b/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DescriptorFileTest.java deleted file mode 100644 index 8ad6fa10e..000000000 --- a/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DescriptorFileTest.java +++ /dev/null @@ -1,35 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.metamodel.descriptor; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.json.CanonicalJson; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** The descriptor a run of this module's build leaves behind, beside the oracle it is paired with. */ -class DescriptorFileTest { - - /** Where a run of this module leaves what the parity contract compares, under its build output. */ - private static final Path OUTPUT = Path.of("target", "parity"); - - @Test - void aRunLeavesTheDescriptorUnderTheModulesBuildOutput() throws IOException { - Path file = DescriptorFile.write(OUTPUT); - - assertThat(file).isEqualTo(OUTPUT.resolve("descriptor.json")); - assertThat(Files.readString(file, StandardCharsets.UTF_8)) - .isEqualTo(CanonicalJson.write(Descriptor.of(ProjectIntentPackage.eINSTANCE))); - } - - @Test - void aDirectoryNoRunHasWrittenYetIsCreated(@TempDir Path directory) throws IOException { - Path file = DescriptorFile.write(directory.resolve("target").resolve("parity")); - - assertThat(file).exists(); - } -} diff --git a/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DescriptorTest.java b/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DescriptorTest.java deleted file mode 100644 index fd86ad364..000000000 --- a/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/descriptor/DescriptorTest.java +++ /dev/null @@ -1,192 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.metamodel.descriptor; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import java.util.List; -import java.util.Map; -import org.eclipse.emf.ecore.EDataType; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.EcoreFactory; -import org.junit.jupiter.api.Test; - -/** What the descriptor says about the Project Intent metamodel. */ -class DescriptorTest { - - @SuppressWarnings("unchecked") - private static List> entries(String kind) { - return (List>) - Descriptor.of(ProjectIntentPackage.eINSTANCE).get(kind); - } - - private static Map named(String kind, String name) { - return entries(kind).stream() - .filter(entry -> name.equals(entry.get("name"))) - .findFirst() - .orElseThrow(); - } - - @SuppressWarnings("unchecked") - private static Map feature(String owner, String name) { - return ((List>) named("classes", owner).get("features")) - .stream() - .filter(feature -> name.equals(feature.get("name"))) - .findFirst() - .orElseThrow(); - } - - @Test - void everyClassAndVocabularyIsListedOnceAndSorted() { - List classes = entries("classes").stream() - .map(entry -> (String) entry.get("name")) - .toList(); - List vocabularies = entries("vocabularies").stream() - .map(entry -> (String) entry.get("name")) - .toList(); - - assertThat(classes).isSorted().doesNotHaveDuplicates().contains("Project", "Process", "KvGrant"); - assertThat(vocabularies).isSorted().doesNotHaveDuplicates().contains("Lifecycle", "TransitOp"); - } - - @Test - void aClassNobodyAuthorsIsNoPartOfTheAuthoredShape() { - List classes = entries("classes").stream() - .map(entry -> (String) entry.get("name")) - .toList(); - - assertThat(classes).doesNotContain("EffectiveProject", "EffectiveApplication"); - // A class carrying the same annotation for another reason stays listed. - assertThat(named("classes", "NoProbes").get("scalar")).isEqualTo("none"); - assertThat(classes).contains("NoProbes", "Application"); - } - - @Test - void aFeatureNoDocumentSpellsIsNoPartOfTheDocumentsShape() { - // `env` is a directory beside the document, so it is on the class and - // not in the descriptor, while every other shared family is in both. - assertThat(ProjectIntentPackage.eINSTANCE.getProcess().getEAllStructuralFeatures()) - .extracting(EStructuralFeature::getName) - .contains("env", "secrets"); - assertThat(named("classes", "Process").get("features").toString()) - .doesNotContain("\"env\"") - .contains("secrets"); - } - - @Test - void anAbstractClassIsAUnionRatherThanAClassOfItsOwn() { - assertThat(entries("classes").stream().map(entry -> entry.get("name"))) - .doesNotContain("Grant", "Probe", "ProbePolicy"); - assertThat(feature("Process", "secrets").get("types")) - .isEqualTo(List.of("DatabaseGrant", "KvGrant", "TransitGrant")); - assertThat(feature("Process", "probes").get("types")).isEqualTo(List.of("NoProbes", "Probes")); - } - - @Test - void aMapEntryIsAMapRatherThanAClassOfItsOwn() { - assertThat(entries("classes").stream().map(entry -> entry.get("name"))).doesNotContain("Surface"); - assertThat(feature("Process", "provides")) - .isEqualTo(Map.of( - "name", - "provides", - "types", - List.of("int"), - "required", - false, - "many", - false, - "map", - true, - "reference", - false, - "entry", - "Surface")); - } - - @Test - void aFeatureCarriesItsTypeAndItsMultiplicity() { - assertThat(feature("Project", "applications")) - .isEqualTo(Map.of( - "name", - "applications", - "types", - List.of("Application"), - "required", - true, - "many", - true, - "map", - false, - "reference", - false)); - assertThat(feature("Process", "startupBudget").get("types")).isEqualTo(List.of("string")); - assertThat(feature("Process", "cutover").get("types")).isEqualTo(List.of("Cutover")); - assertThat(feature("DependencyEdge", "required").get("types")).isEqualTo(List.of("boolean")); - assertThat(feature("HttpProbe", "port").get("types")).isEqualTo(List.of("int")); - assertThat(feature("Exposure", "contentPolicy").get("required")).isEqualTo(false); - } - - @Test - void aNameTheModelLinksIsAReferenceToItsTarget() { - assertThat(feature("Route", "process")) - .isEqualTo(Map.of( - "name", - "process", - "types", - List.of("Process"), - "required", - true, - "many", - false, - "map", - false, - "reference", - true)); - assertThat(feature("Scrape", "surface").get("types")).isEqualTo(List.of("Surface")); - assertThat(feature("Scrape", "surface").get("reference")).isEqualTo(true); - assertThat(feature("DependencyEdge", "surface").get("reference")).isEqualTo(false); - } - - @Test - void aClassWrittenAsOneWordCarriesThatWord() { - assertThat(named("classes", "NoProbes")) - .isEqualTo(Map.of("name", "NoProbes", "features", List.of(), "scalar", "none")); - assertThat(named("classes", "Probes")).doesNotContainKey("scalar"); - } - - @Test - void aClassifierThatIsNeitherAClassNorAVocabularyIsRefused() { - EPackage metamodel = EcoreFactory.eINSTANCE.createEPackage(); - EDataType stray = EcoreFactory.eINSTANCE.createEDataType(); - stray.setName("Quantity"); - metamodel.getEClassifiers().add(stray); - - assertThatThrownBy(() -> Descriptor.of(metamodel)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("Quantity is neither a class nor a closed vocabulary"); - } - - @Test - void aVocabularyCarriesItsLiteralsInOrder() { - assertThat(named("vocabularies", "Lifecycle")) - .isEqualTo( - Map.of("name", "Lifecycle", "literals", List.of("application", "job", "prepare", "scheduled"))); - } - - @Test - void aFeatureWhoseKeyIsNoJavaIdentifierIsWrittenUnderItsKeyAndSortedByIt() { - assertThat(((List) named("classes", "NodeAgents").get("features")) - .stream() - .map(feature -> ((Map) feature).get("name")) - .toList()) - .isEqualTo(List.of("gpu-device", "gpu-metrics", "l4-speaker", "node-metrics")); - } - - @Test - void aMapEntryTheProductionImplementationLeavesUnnamedCarriesTheNameItWrites() { - assertThat(feature("MonitorCadence", "labels").get("entry")).isEqualTo("undefined"); - assertThat(feature("Platform", "l4Addresses").get("entry")).isEqualTo("L4Address"); - assertThat(feature("Platform", "l4Addresses").get("types")).isEqualTo(List.of("NodeAddress", "PoolAddress")); - } -} diff --git a/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/json/CanonicalJsonTest.java b/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/json/CanonicalJsonTest.java deleted file mode 100644 index 32d63c6cd..000000000 --- a/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/json/CanonicalJsonTest.java +++ /dev/null @@ -1,164 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.metamodel.json; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.CsvSource; - -/** - * The RFC 8785 serialisation the parity contract compares oracle files with. Cases marked RFC come - * from the specification's own examples. - */ -class CanonicalJsonTest { - - @Test - void sortsObjectKeysByUtf16CodeUnitsAtEveryDepth() { - // RFC 8785 section 3.2.3: the property sorting example. - Map inner = new LinkedHashMap<>(); - inner.put("\u20ac", "Euro Sign"); - inner.put("\r", "Carriage Return"); - inner.put("\ufb33", "Hebrew Letter Dalet With Dagesh"); - inner.put("1", "One"); - inner.put("\ud83d\ude00", "Emoji: Grinning Face"); - inner.put("\u0080", "Control"); - inner.put("\u00f6", "Latin Small Letter O With Diaeresis"); - - assertThat(CanonicalJson.write(inner)) - .isEqualTo("{\"\\r\":\"Carriage Return\",\"1\":\"One\",\"\u0080\":\"Control\"," - + "\"\u00f6\":\"Latin Small Letter O With Diaeresis\",\"\u20ac\":\"Euro Sign\"," - + "\"\ud83d\ude00\":\"Emoji: Grinning Face\",\"\ufb33\":\"Hebrew Letter Dalet With Dagesh\"}"); - } - - @Test - void writesNestedStructuresWithoutInsignificantWhitespace() { - Map document = new LinkedHashMap<>(); - document.put("processes", List.of(Map.of("name", "api"), Map.of())); - document.put("applications", new ArrayList<>()); - document.put("enabled", true); - document.put("disabled", false); - - assertThat(CanonicalJson.write(document)) - .isEqualTo("{\"applications\":[],\"disabled\":false,\"enabled\":true," - + "\"processes\":[{\"name\":\"api\"},{}]}"); - } - - @Test - void escapesOnlyWhatTheSpecificationEscapes() { - String text = "quote\" backslash\\ controls\b\f\n\r\t\u000f\u001f slash/ del\u007f line\u2028 euro\u20ac"; - - assertThat(CanonicalJson.write(text)) - .isEqualTo("\"quote\\\" backslash\\\\ controls\\b\\f\\n\\r\\t\\u000f\\u001f" - + " slash/ del\u007f line\u2028 euro\u20ac\""); - } - - @ParameterizedTest(name = "{0} -> {1}") - @CsvSource({ - // RFC 8785 appendix B and ECMAScript Number::toString boundaries. - "0.0, 0", - "-0.0, 0", - "1.0, 1", - "-1.5, -1.5", - "4.50, 4.5", - "0.002, 0.002", - "0.5, 0.5", - "-0.000001, -0.000001", - "10.0, 10", - "1.0E-6, 0.000001", - "0.000001, 0.000001", - "0.0000001, 1e-7", - "1.0E-27, 1e-27", - "123456789012345680000, 123456789012345680000", - "1.0E21, 1e+21", - "1.0E30, 1e+30", - "1.2345E25, 1.2345e+25", - "333333333.33333329, 333333333.3333333", - "9007199254740991.0, 9007199254740991", - "-9007199254740991.0, -9007199254740991", - "1.7976931348623157E308, 1.7976931348623157e+308", - "4.9E-324, 5e-324", - "295147905179352830000, 295147905179352830000", - }) - void formatsDoublesAsEcmaScriptDoes(double value, String expected) { - assertThat(CanonicalJson.write(value)).isEqualTo(expected); - } - - @Test - void writesIntegralNumbersExactlyWithinTheSafeRange() { - assertThat(CanonicalJson.write( - List.of(0, -7, 42L, (short) 3, (byte) -2, 9007199254740991L, -9007199254740991L))) - .isEqualTo("[0,-7,42,3,-2,9007199254740991,-9007199254740991]"); - } - - @Test - void refusesAnAbsentValueWrittenAsNullAndSaysWhere() { - Map document = new LinkedHashMap<>(); - document.put("applications", Arrays.asList(Map.of("id", "auth"), null)); - - assertThatThrownBy(() -> CanonicalJson.write(document)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("null at /applications/1: an absent optional field is absent, never null"); - } - - @Test - void escapesPointerSegmentsInMessages() { - Map inner = new LinkedHashMap<>(); - inner.put("a/b~c", null); - - assertThatThrownBy(() -> CanonicalJson.write(Map.of("x", inner))).hasMessageStartingWith("null at /x/a~1b~0c:"); - } - - @Test - void refusesANullRootAndNullKeys() { - Map nullKey = new LinkedHashMap<>(); - nullKey.put(null, 1); - - assertThatThrownBy(() -> CanonicalJson.write(null)).hasMessageStartingWith("null at :"); - assertThatThrownBy(() -> CanonicalJson.write(nullKey)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("object key at is not a string"); - } - - @Test - void refusesNonStringKeys() { - assertThatThrownBy(() -> CanonicalJson.write(Map.of(1, "one"))) - .isInstanceOf(IllegalArgumentException.class) - .hasMessage("object key at is not a string"); - } - - @Test - void refusesNumbersJsonCannotCarryExactly() { - assertThatThrownBy(() -> CanonicalJson.write(Double.NaN)).hasMessage("NaN at is not a JSON number"); - assertThatThrownBy(() -> CanonicalJson.write(Double.POSITIVE_INFINITY)) - .hasMessage("Infinity at is not a JSON number"); - assertThatThrownBy(() -> CanonicalJson.write(9007199254740992L)) - .hasMessage("9007199254740992 at is outside the range a JSON number carries exactly"); - assertThatThrownBy(() -> CanonicalJson.write(-9007199254740992L)) - .hasMessage("-9007199254740992 at is outside the range a JSON number carries exactly"); - } - - @Test - void refusesTypesThatAreNotJson() { - assertThatThrownBy(() -> CanonicalJson.write(1.5f)).hasMessage("java.lang.Float at is not a JSON value"); - assertThatThrownBy(() -> CanonicalJson.write(new Object())) - .hasMessage("java.lang.Object at is not a JSON value"); - } - - @Test - void refusesStringsThatAreNotWellFormedUnicode() { - assertThatThrownBy(() -> CanonicalJson.write("lone \ud800 high")) - .hasMessage("string at holds a lone surrogate at index 5"); - assertThatThrownBy(() -> CanonicalJson.write("lone \udc00 low")) - .hasMessage("string at holds a lone surrogate at index 5"); - assertThatThrownBy(() -> CanonicalJson.write("ends \ud800")) - .hasMessage("string at holds a lone surrogate at index 5"); - assertThatThrownBy(() -> CanonicalJson.write(Map.of("bad \ud800", 1))) - .hasMessage("string at holds a lone surrogate at index 4"); - } -} diff --git a/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/revision/ModelDigestTest.java b/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/revision/ModelDigestTest.java deleted file mode 100644 index a639921b7..000000000 --- a/emf/bundles/metamodel/src/test/java/dev/jorisjonkers/deploykit/emf/metamodel/revision/ModelDigestTest.java +++ /dev/null @@ -1,116 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.metamodel.revision; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Lifecycle; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.PlainPath; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Process; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Scrape; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.junit.jupiter.api.Test; - -/** A pinned input's digest: the canonical form of its model, so it moves when what it says does. */ -class ModelDigestTest { - - private static final ProjectIntentFactory MODEL = ProjectIntentFactory.eINSTANCE; - - private static Project project() { - Process process = MODEL.createProcess(); - process.setName("notes-api"); - process.setLifecycle(Lifecycle.APPLICATION); - process.getWritablePaths().add(path("/tmp")); - Application application = MODEL.createApplication(); - application.setId("notes"); - application.getProcesses().add(process); - application.setObservability(MODEL.createObservability()); - Scrape scrape = MODEL.createScrape(); - scrape.setProcess(process); - scrape.setPath("/metrics"); - application.getObservability().setScrape(scrape); - Project project = MODEL.createProject(); - project.setProject("notes"); - project.getApplications().add(application); - return project; - } - - @Test - void theSameModelHasTheSameDigestAndAnythingItSaysMovesIt() { - String recorded = ModelDigest.of(project()); - - assertThat(recorded).matches("sha256:[0-9a-f]{64}"); - assertThat(ModelDigest.of(EcoreUtil.copy(project()))).isEqualTo(recorded); - - // An attribute, a list entry and an enumeration literal each move it. - Project renamed = project(); - renamed.setOwner("someone-else"); - assertThat(ModelDigest.of(renamed)).isNotEqualTo(recorded); - Project listed = project(); - listed.getApplications().get(0).getProcesses().get(0).getWritablePaths().add(path("/var/cache")); - assertThat(ModelDigest.of(listed)).isNotEqualTo(recorded); - Project job = project(); - job.getApplications().get(0).getProcesses().get(0).setLifecycle(Lifecycle.JOB); - assertThat(ModelDigest.of(job)).isNotEqualTo(recorded); - } - - @Test - void aReferenceIsTheIdOfWhatItNamesOrItsPathWhereItCarriesNone() { - // A Process carries no ID, so the scrape names it by its path; renaming it moves only the - // Process's own entry, and moving the scrape to another Process moves the digest. - Project one = project(); - Process second = MODEL.createProcess(); - second.setName("notes-api"); - second.setLifecycle(Lifecycle.APPLICATION); - second.getWritablePaths().add(path("/tmp")); - one.getApplications().get(0).getProcesses().add(second); - String first = ModelDigest.of(one); - one.getApplications().get(0).getObservability().getScrape().setProcess(second); - - assertThat(ModelDigest.of(one)).isNotEqualTo(first); - - // An Application carries one, so a Platform document names it by it. - Platform platform = MODEL.createPlatform(); - platform.setSecretStore(one.getApplications().get(0)); - String named = ModelDigest.of(platform); - one.getApplications().get(0).setId("vault"); - assertThat(ModelDigest.of(platform)).isNotEqualTo(named); - } - - @Test - void aTextIsDigestedAsTheJsonStringItIsWrittenAs() { - // sha256 over `"a\nb"`, the canonical JSON of the two-line text: the digest the production - // implementation gives an Asset's content, so an Asset's name is the same in both. - assertThat(ModelDigest.ofText("a\nb")) - .isEqualTo(ModelDigest.ofText("a\nb")) - .isNotEqualTo(ModelDigest.ofText("a\nc")) - .isEqualTo("sha256:" + sha256("\"a\\nb\"")); - } - - @Test - void aCanonicalTextIsDigestedAsWrittenAndAnUnknownAlgorithmIsADefect() { - // The revision's text is already canonical JSON, so its bytes are what is hashed. - assertThat(ModelDigest.ofBytes("{\"id\":\"notes\"}")).isEqualTo("sha256:" + sha256("{\"id\":\"notes\"}")); - assertThatThrownBy(() -> ModelDigest.digest("no-such-algorithm", "text")) - .isInstanceOf(IllegalStateException.class); - } - - private static String sha256(String text) { - try { - return java.util.HexFormat.of() - .formatHex(java.security.MessageDigest.getInstance("SHA-256") - .digest(text.getBytes(java.nio.charset.StandardCharsets.UTF_8))); - } catch (java.security.NoSuchAlgorithmException absent) { - throw new IllegalStateException(absent); - } - } - - private static PlainPath path(String written) { - PlainPath path = MODEL.createPlainPath(); - path.setPath(written); - return path; - } -} diff --git a/emf/bundles/render/META-INF/MANIFEST.MF b/emf/bundles/render/META-INF/MANIFEST.MF deleted file mode 100644 index dd48c9ad4..000000000 --- a/emf/bundles/render/META-INF/MANIFEST.MF +++ /dev/null @@ -1,13 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: deploy-kit model-driven render -Bundle-SymbolicName: dev.jorisjonkers.deploykit.emf.render;singleton:=true -Bundle-Version: 0.1.0.qualifier -Bundle-RequiredExecutionEnvironment: JavaSE-21 -Automatic-Module-Name: dev.jorisjonkers.deploykit.emf.render -Export-Package: dev.jorisjonkers.deploykit.emf.render -Require-Bundle: org.eclipse.emf.ecore, - org.eclipse.emf.ecore.xmi, - org.eclipse.acceleo.aql, - org.eclipse.acceleo.query, - dev.jorisjonkers.deploykit.emf.metamodel diff --git a/emf/bundles/render/build.properties b/emf/bundles/render/build.properties deleted file mode 100644 index 4cc22cbb5..000000000 --- a/emf/bundles/render/build.properties +++ /dev/null @@ -1,5 +0,0 @@ -source.. = src/main/java/,\ - model/ -bin.includes = META-INF/,\ - .,\ - model/ diff --git a/emf/bundles/render/model/render.mtl b/emf/bundles/render/model/render.mtl deleted file mode 100644 index de08265b7..000000000 --- a/emf/bundles/render/model/render.mtl +++ /dev/null @@ -1,3607 +0,0 @@ -[module render('https://jorisjonkers.dev/deploy-kit/resolved-deployment/1')/] - -[comment The Deliverable Set (spec/v1/30-deliverables.md): one file per Deliverable a Resolved - Deployment carries, at the path the path plan assigned it. The templates spell the target - formats and decide nothing: every value is read from the model. A block's body carries two - spaces of margin that are not written, and a call written at a column repeats that column's - text before every line it writes, so a shared fragment is spelled once, unindented. /] - -[comment @main /] -[template public render(deployment : resolveddeployment::ResolvedDeployment)] - [for (d : resolveddeployment::Deliverable | deployment.deliverables)] - [file (d.path, overwrite, 'UTF-8')] - [d.document()/] - [/file] - [/for] -[/template] - -[comment A YAML document opens on the one header line, and each object on its own separator. A - Vault document is JSON, which carries no comment and so no header. /] -[template private document(d : resolveddeployment::Deliverable)] - [if (d.oclIsKindOf(resolveddeployment::VaultPolicyFile))] - [d.oclAsType(resolveddeployment::VaultPolicyFile).json()/] - [elseif (d.oclIsKindOf(resolveddeployment::VaultRoleFile))] - [d.oclAsType(resolveddeployment::VaultRoleFile).json()/] - [elseif (d.oclIsKindOf(resolveddeployment::GeneratedKeysFile))] - [d.oclAsType(resolveddeployment::GeneratedKeysFile).json()/] - [elseif (d.oclIsKindOf(resolveddeployment::CatalogJobFile) and d.oclAsType(resolveddeployment::CatalogJobFile).part = 'policy')] - [d.oclAsType(resolveddeployment::CatalogJobFile).json()/] - [else] - # GENERATED. Never hand-edit. - [d.yaml()/] - [/if] -[/template] - -[comment Each kind's objects, by the template for its own type: a kind with none fails the rendering - rather than writing a file that holds only the header. /] -[template private yaml(d : resolveddeployment::Deliverable)] - [d.objects()/] -[/template] - -[comment ======================================================= project files /] - -[comment A namespace is never pruned, so no prune deletes it and the claims in it - (spec/v1/30-deliverables.md#flagger-ready-objects). /] -[template private objects(d : resolveddeployment::NamespaceFile)] - --- - apiVersion: v1 - kind: Namespace - metadata: - name: [d.namespace/] - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled -[/template] - -[comment An index lists what its directory holds, in order. /] -[template private objects(d : resolveddeployment::IndexFile)] - --- - apiVersion: kustomize.config.k8s.io/v1beta1 - kind: Kustomization - resources: - [for (r : String | d.resources->sortedBy(r | r))] - - [r/] - [/for] -[/template] - -[comment A project-level file holds no policy: it is the project's default-deny, which selects - every pod and belongs to no Process. /] -[template private objects(d : resolveddeployment::NetworkPolicyFile)] - [if (d.policies->isEmpty())] - --- - apiVersion: networking.k8s.io/v1 - kind: NetworkPolicy - metadata: - name: default-deny - namespace: [d.projectNamespace()/] - labels: - app.kubernetes.io/managed-by: deploy-kit - spec: - podSelector: - matchLabels: {} - policyTypes: - - Ingress - - Egress - [else] - [for (p : resolveddeployment::ProcessPolicy | d.policies)] - [p.policy()/] - [for (s : resolveddeployment::ResolvedSpawn | p.process.spawns)] - [s.spawnPolicy(p.process)/] - [/for] - [if (p.process.backups()->notEmpty())] - [p.process.backupPolicy()/] - [/if] - [/for] - [if (d.migration <> null)] - [d.migration.migrationPolicy()/] - [/if] - [/if] -[/template] - -[comment The migration identity's own policy: what its plan admits, and nothing in. Its Jobs' pods - carry the identity as their instance. /] -[template private migrationPolicy(m : resolveddeployment::ResolvedMigration)] - --- - apiVersion: networking.k8s.io/v1 - kind: NetworkPolicy - metadata: - name: [m.identity/] - namespace: [m.application().namespace/] - labels: - [m.identity.labelSet('none', m.application().id)/] - spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: [m.identity/] - policyTypes: - - Ingress - - Egress - egress: - [for (peer : resolveddeployment::PolicyPeer | m.egress)] - - to: - [peer.peer()/] - ports: - [if (peer.rule = 'cluster-dns')] - - protocol: UDP - port: [peer.port/] - [/if] - - protocol: TCP - port: [peer.port/] - [/for] -[/template] - -[comment A spawned pod's own policy: the Process that made it reaches it on what it serves, and it - reaches its edges, its baseline and, where its template declares it, the public internet. /] -[template private spawnPolicy(s : resolveddeployment::ResolvedSpawn, p : resolveddeployment::ResolvedProcess)] - --- - apiVersion: networking.k8s.io/v1 - kind: NetworkPolicy - metadata: - name: [s.name/] - namespace: [p.application().namespace/] - labels: - [p.labels()/] - spec: - podSelector: - matchLabels: - deploy-kit.jorisjonkers.dev/spawned-from: [s.name/] - policyTypes: - - Ingress - - Egress - [if (s.surfaces->notEmpty())] - ingress: - - from: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: [p.application().namespace/] - podSelector: - matchLabels: - app.kubernetes.io/instance: [p.name/] - ports: - [for (x : resolveddeployment::ResolvedSurface | s.surfaces)] - - protocol: TCP - port: [x.port/] - [/for] - [/if] - egress: - [for (peer : resolveddeployment::PolicyPeer | s.dependencies.peers)] - - to: - [peer.peer()/] - ports: - - protocol: TCP - port: [peer.port/] - [/for] - [for (peer : resolveddeployment::PolicyPeer | s.egress)] - - to: - [peer.peer()/] - ports: - [if (peer.rule = 'cluster-dns')] - - protocol: UDP - port: [peer.port/] - [/if] - - protocol: TCP - port: [peer.port/] - [/for] - [if (s.internetEgress <> null)] - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 - - 100.64.0.0/10 - - 169.254.0.0/16 - - 127.0.0.0/8 - [/if] -[/template] - -[comment A backup identity's own policy. Every backup of a Process runs as the one identity, so - the policy admits what all of them need: the Process they dump and the cluster's DNS, which - every plan of the Process shares, and each range any of them copies off-cluster to, once. - Nothing reaches the identity's pods. /] -[template private backupPolicy(p : resolveddeployment::ResolvedProcess)] - --- - apiVersion: networking.k8s.io/v1 - kind: NetworkPolicy - metadata: - name: [p.backups()->first().backup.identity/] - namespace: [p.application().namespace/] - labels: - [p.backups()->first().backup.identity.labelSet('none', p.application().id)/] - spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: [p.backups()->first().backup.identity/] - policyTypes: - - Ingress - - Egress - egress: - [for (peer : resolveddeployment::PolicyPeer | p.backups()->first().backup.egress)] - - to: - [peer.peer()/] - ports: - [if (peer.rule = 'cluster-dns')] - - protocol: UDP - port: [peer.port/] - [/if] - - protocol: TCP - port: [peer.port/] - [/for] - [for (range : resolveddeployment::AdmittedRange | p.backupRanges())] - - to: - - ipBlock: - cidr: [range.cidr/] - ports: - - protocol: TCP - port: [range.port/] - [/for] -[/template] - -[template private policy(p : resolveddeployment::ProcessPolicy)] - --- - apiVersion: networking.k8s.io/v1 - kind: NetworkPolicy - metadata: - [p.process.metadata()/] - spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: [p.process.name/] - policyTypes: - - Ingress - - Egress - [if (p.ingress->notEmpty())] - ingress: - [for (peer : resolveddeployment::PolicyPeer | p.ingress)] - - from: - [peer.peer()/] - ports: - - protocol: [if (peer.protocol <> null)][peer.protocol/][else]TCP[/if] - port: [peer.port/] - [/for] - [/if] - egress: - [comment Every peer of every edge, in one loop: a loop within a loop indents its lines by - where the policy's other blocks left off, which a policy with no ingress shows. /] - [for (peer : resolveddeployment::PolicyPeer | p.process.dependencies.peers)] - - to: - [peer.peer()/] - ports: - - protocol: TCP - port: [peer.port/] - [/for] - [comment The pods it makes from its templates, on the surfaces they serve it. /] - [for (s : resolveddeployment::ResolvedSpawn | p.process.spawns->select(s | s.surfaces->notEmpty()))] - - to: - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: [p.process.application().namespace/] - podSelector: - matchLabels: - deploy-kit.jorisjonkers.dev/spawned-from: [s.name/] - ports: - [for (x : resolveddeployment::ResolvedSurface | s.surfaces)] - - protocol: TCP - port: [x.port/] - [/for] - [/for] - [comment The cluster's DNS answers on UDP, and on TCP for a truncated response. The gate's own - requests reach every member's pods, on whichever port the member's own policy admits them. /] - [for (peer : resolveddeployment::PolicyPeer | p.egress)] - [if (peer.rule = 'gate-members')] - - to: - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - [else] - - to: - [peer.peer()/] - ports: - - protocol: UDP - port: [peer.port/] - - protocol: TCP - port: [peer.port/] - [/if] - [/for] - [comment The nameservers a Process that serves DNS resolves through, by address: off the - cluster, and answering on UDP and on TCP. /] - [if (p.process.nameservers->notEmpty())] - - to: - [for (n : String | p.process.nameservers)] - - ipBlock: - cidr: [n/]/32 - [/for] - ports: - - protocol: UDP - port: 53 - - protocol: TCP - port: 53 - [/if] - [comment Where the Kubernetes API answers, for a Process that holds access to it: an address, - because the API server is no pod a selector reaches. /] - [if (p.process.api <> null)] - [for (range : resolveddeployment::AdmittedRange | p.process.api.server)] - - to: - - ipBlock: - cidr: [range.cidr/] - ports: - - protocol: TCP - port: [range.port/] - [/for] - [/if] - [comment The public internet, for a Process that declares it: every IPv4 address but the ranges - no public host answers on, so the cluster, the LAN and the node stay out of reach. /] - [if (p.process.internetEgress <> null)] - - to: - - ipBlock: - cidr: 0.0.0.0/0 - except: - - 10.0.0.0/8 - - 172.16.0.0/12 - - 192.168.0.0/16 - - 100.64.0.0/10 - - 169.254.0.0/16 - - 127.0.0.0/8 - [/if] -[/template] - -[comment A consumer is every pod carrying the consumer label of the surface, in any namespace - this model manages (spec/v1/16-dependencies.md#the-consumer-label); every other peer is named. /] -[template private peer(peer : resolveddeployment::PolicyPeer)] - [if (peer.consumes <> null)] - - namespaceSelector: - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - podSelector: - matchLabels: - [peer.consumes.consumerLabel()/] - [elseif (peer.cidr <> null)] - - ipBlock: - cidr: [peer.cidr/] - [elseif (peer.rule = 'flux-metrics')] - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: [peer.namespace/] - podSelector: - matchLabels: - app.kubernetes.io/part-of: flux - [else] - - namespaceSelector: - matchLabels: - kubernetes.io/metadata.name: [peer.namespace/] - [if (peer.process <> null)] - podSelector: - matchLabels: - [if (peer.rule = 'flux-events')]app[else]app.kubernetes.io/instance[/if]: [peer.process/] - [/if] - [/if] -[/template] - -[comment The label a pod carries for one surface it consumes, which the provider's policy admits. /] -[template private consumerLabel(consumed : String)] - consumes.deploy-kit.jorisjonkers.dev/[consumed/]: "true" -[/template] - -[comment =================================================== application files /] - -[template private metadata(p : resolveddeployment::ResolvedProcess)] - name: [p.name/] - namespace: [p.application().namespace/] - labels: - [p.labels()/] -[/template] - -[template private labels(p : resolveddeployment::ResolvedProcess)] - app.kubernetes.io/name: [p.name/] - app.kubernetes.io/instance: [p.name/] - app.kubernetes.io/part-of: [p.application().id/] - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: [p.component/] -[/template] - -[comment The fixed label set: the name twice, the Application, the manager and the runtime. /] -[template private labelSet(name : String, component : String, application : String)] - app.kubernetes.io/name: [name/] - app.kubernetes.io/instance: [name/] - app.kubernetes.io/part-of: [application/] - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/component: [component/] -[/template] - -[comment The Process's own ServiceAccount, and one for the backup identity every backup of it runs as. /] -[template private objects(d : resolveddeployment::IdentityFile)] - [for (p : resolveddeployment::ResolvedProcess | d.processes)] - --- - apiVersion: v1 - kind: ServiceAccount - metadata: - [p.metadata()/] - [if (p.backups()->notEmpty())] - --- - apiVersion: v1 - kind: ServiceAccount - metadata: - [p.backups()->first().backup.backupMetadata(p)/] - [/if] - [/for] -[/template] - -[template private backupMetadata(b : resolveddeployment::BackupPlan, p : resolveddeployment::ResolvedProcess)] - name: [b.identity/] - namespace: [p.application().namespace/] - labels: - [b.identity.labelSet('none', p.application().id)/] -[/template] - -[template private objects(d : resolveddeployment::MonitorFile)] - --- - apiVersion: monitoring.coreos.com/v1 - kind: [d.kind.toString()/] - metadata: - name: [d.process.name/] - namespace: [d.process.application().namespace/] - labels: - [for (l : resolveddeployment::KeyValue | d.process.application().scrape.labels->reject(l | d.process.ownLabelKeys()->includes(l.key)))] - [l.key/]: [l.value.scalar()/] - [/for] - [d.process.labels()/] - spec: - jobLabel: app.kubernetes.io/instance - selector: - matchLabels: - app.kubernetes.io/instance: [d.process.name/] - namespaceSelector: - matchNames: - - [d.process.application().namespace/] - [if (d.kind.toString() = 'PodMonitor')]podMetricsEndpoints[else]endpoints[/if]: - - port: [d.surface/] - path: [d.scrapePath/] - interval: [d.interval/] - scrapeTimeout: [d.timeout/] - [if (d.process.application().scrape.honorLabels)] - honorLabels: true - [/if] -[/template] - -[template private objects(d : resolveddeployment::SwitchoverFile)] - [for (p : resolveddeployment::ResolvedProcess | d.processes)] - --- - apiVersion: flagger.app/v1beta1 - kind: Canary - metadata: - [p.metadata()/] - spec: - provider: kubernetes - targetRef: - apiVersion: apps/v1 - kind: Deployment - name: [p.name/] - [if (p.replicas > 1)] - autoscalerRef: - apiVersion: autoscaling/v2 - kind: HorizontalPodAutoscaler - name: [p.name/] - [/if] - progressDeadlineSeconds: [p.deadline.seconds()/] - service: - port: [p.surfaces->first().port/] - targetPort: [p.surfaces->first().name/] - portName: [p.surfaces->first().name/] - analysis: - interval: [p.application().releaseGate.analysis.interval/] - iterations: [p.application().releaseGate.analysis.iterations/] - threshold: [p.application().releaseGate.analysis.threshold/] - webhooks: - [p.webhook('may-start', 'confirm-rollout')/] - [p.webhook('checks', 'rollout')/] - [p.webhook('may-promote', 'confirm-promotion')/] - [p.webhook('rollback', 'rollback')/] - [if (p.replicas > 1)] - --- - apiVersion: autoscaling/v2 - kind: HorizontalPodAutoscaler - metadata: - [p.metadata()/] - spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: [p.name/] - minReplicas: [p.replicas/] - maxReplicas: [p.replicas/] - [/if] - [/for] -[/template] - -[comment The budget of a Process above one replica, over the pods that serve between releases. /] -[template private objects(d : resolveddeployment::BudgetFile)] - [for (p : resolveddeployment::ResolvedProcess | d.processes)] - --- - apiVersion: policy/v1 - kind: PodDisruptionBudget - metadata: - [p.metadata()/] - spec: - maxUnavailable: 1 - selector: - matchLabels: - [p.servingLabel/]: [p.serving/] - [/for] -[/template] - -[comment The migration identity and its Jobs (spec/v1/55-delivery.md#failure-and-undo): the up of - this revision and, where the release was proven against a serving one, the down to it. Both are - named by the revision's tag, suspended, and created once: the Release Gate alone writes - `suspend` afterwards. /] -[template private objects(d : resolveddeployment::MigrationFile)] - --- - apiVersion: v1 - kind: ServiceAccount - metadata: - name: [d.application.migration.identity/] - namespace: [d.application.namespace/] - labels: - [d.application.migration.identity.labelSet('none', d.application.id)/] - [d.migrationJob(d.application.migration.identity + '-' + d.upTag, 'up', d.upTag)/] - [if (d.downTag <> null)] - [d.migrationJob(d.application.migration.identity + '-down-' + d.upTag, 'down', d.downTag)/] - [/if] -[/template] - -[template private migrationJob(d : resolveddeployment::MigrationFile, name : String, command : String, tag : String)] - --- - apiVersion: batch/v1 - kind: Job - metadata: - name: [name/] - namespace: [d.application.namespace/] - labels: - [d.application.migration.identity.labelSet('none', d.application.id)/] - annotations: - kustomize.toolkit.fluxcd.io/ssa: IfNotPresent - spec: - suspend: true - backoffLimit: 0 - activeDeadlineSeconds: [d.application.migration.deadline.seconds()/] - template: - metadata: - labels: - [d.application.migration.identity.labelSet('none', d.application.id)/] - [for (c : String | d.application.migration.consumes)] - [c.consumerLabel()/] - [/for] - [if (d.application.migration.runnerVersion <> null)] - annotations: - image.jorisjonkers.dev/migration: [d.application.migration.runnerVersion.scalar()/] - [/if] - spec: - serviceAccountName: [d.application.migration.identity/] - automountServiceAccountToken: true - restartPolicy: Never - securityContext: - runAsNonRoot: true - runAsUser: [d.application.migration.uid/] - runAsGroup: [d.application.migration.gid/] - seccompProfile: - type: RuntimeDefault - containers: - - name: migration - image: [d.application.migration.runner/] - args: - - [command/] - - [tag.scalar()/] - env: - - name: DATABASE_HOST - value: [d.application.migration.database.host/] - - name: DATABASE_PORT - value: [d.application.migration.database.port.toString().scalar()/] - - name: DATABASE_NAME - value: [d.application.migration.database.name/] - - name: VAULT_ADDR - value: [d.application.secretStore/] - - name: VAULT_ROLE - value: [d.role/] - - name: VAULT_CREDENTIALS_PATH - value: [d.application.migration.credential.paths->first().path/] - [if (d.application.migration.home <> null)] - [d.application.migration.home.homeEntry()/] - [/if] - resources: - requests: - memory: [d.application.migration.memory/] - cpu: [d.application.migration.cpu/] - limits: - memory: [d.application.migration.memory/] - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: scratch - mountPath: /tmp - volumes: - - name: scratch - emptyDir: - sizeLimit: [d.application.migration.scratch/] -[/template] - -[template private webhook(p : resolveddeployment::ResolvedProcess, name : String, type : String)] - - name: [name/] - type: [type/] - url: [p.application().releaseGate.endpoint/]/[name/] - metadata: - application: [p.application().id/] - process: [p.name/] - revision: [p.application().revision/] - [if (p.paths()->notEmpty())] - paths: [p.paths()->sep(' ')/] - [/if] - [if (p.readinessPath() <> null)] - readiness: [p.readinessPath()/] - [/if] - [if (p.hostnames()->notEmpty())] - hostnames: [p.hostnames()->sep(' ')/] - [/if] - errorRate: [p.application().releaseGate.analysis.errorRate/] - latency: [p.application().releaseGate.analysis.latency/] -[/template] - -[template private objects(d : resolveddeployment::WorkloadFile)] - [for (p : resolveddeployment::ResolvedProcess | d.processes)] - [p.workload(d)/] - [/for] -[/template] - -[comment Flagger scales and promotes a blue-green Deployment, so it carries no replica count and - its new version starts beside the old one; a rolling one is the delivery machinery's, pod by - pod under its own count and never a pod more, because a proxy on a host port and a controller - with no leader election cannot run two copies; a stop-start one keeps its count and stops - before it starts again. /] -[template private workload(p : resolveddeployment::ResolvedProcess, d : resolveddeployment::WorkloadFile)] - [if (p.operated <> null)] - [p.operatedWorkload()/] - [elseif (d.controller.toString() = 'CronJob')] - [p.scheduled()/] - [else] - [p.deployment(d)/] - [/if] -[/template] - -[comment A scheduled Process's CronJob: at its own schedule, never two runs at once, and a run that - cannot start within its start deadline is skipped. A parked schedule starts no run. A failed run is - retried in its pod. /] -[template private scheduled(p : resolveddeployment::ResolvedProcess)] - --- - apiVersion: batch/v1 - kind: CronJob - metadata: - [p.metadata()/] - spec: - schedule: [p.schedule.scalar()/] - [if (p.parked)] - suspend: true - [/if] - concurrencyPolicy: Forbid - startingDeadlineSeconds: [p.startDeadline.seconds()/] - jobTemplate: - spec: - template: - [p.pod('OnFailure')/] -[/template] - -[template private deployment(p : resolveddeployment::ResolvedProcess, d : resolveddeployment::WorkloadFile)] - --- - apiVersion: apps/v1 - kind: [d.controller.toString()/] - metadata: - [p.metadata()/] - spec: - [if (p.switchover.toString() = 'blue-green')] - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 1 - maxUnavailable: 0 - [elseif (p.switchover.toString() = 'rolling')] - replicas: [p.replicas/] - strategy: - type: RollingUpdate - rollingUpdate: - maxSurge: 0 - maxUnavailable: 1 - [else] - replicas: [p.replicas/] - strategy: - type: Recreate - [/if] - progressDeadlineSeconds: [p.deadline.seconds()/] - selector: - matchLabels: - app.kubernetes.io/name: [p.name/] - app.kubernetes.io/instance: [p.name/] - template: - [p.pod('')/] -[/template] - -[comment The monitoring stack's Prometheus or Alertmanager as the Prometheus operator's own object - (spec/v1/14-platform-intent.md#the-operators-objects): the pod the render would have run, handed - to the operator whole, its own container patched by the Process's variables, posture, mounts and - probes, and what the Platform document says each selects and notifies. The operator sets the - name, instance and manager labels on every pod itself. /] -[template private operatedWorkload(p : resolveddeployment::ResolvedProcess)] - --- - apiVersion: monitoring.coreos.com/v1 - kind: [p.operated.kind/] - metadata: - [p.metadata()/] - spec: - image: [p.image/] - [if (p.imageVersion <> null)] - version: [p.imageVersion.scalar()/] - [/if] - replicas: [p.replicas/] - serviceAccountName: [p.identity/] - automountServiceAccountToken: [p.identityToken/] - [if (p.priorityClass <> null)] - priorityClassName: [p.priorityClass/] - [/if] - podMetadata: - labels: - app.kubernetes.io/part-of: [p.application().id/] - app.kubernetes.io/component: [p.component/] - [for (c : String | p.consumes)] - [c.consumerLabel()/] - [/for] - [if (p.member())] - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - [/if] - [if (p.versioned()->notEmpty())] - annotations: - [for (n : String | p.versioned())] - image.jorisjonkers.dev/[n/]: [p.versionOf(n).scalar()/] - [/for] - [/if] - portName: [p.surfaces->first().name/] - [p.podSecurity()/] - [p.podAffinity()/] - resources: - requests: - memory: [p.memory/] - cpu: [p.cpu/] - limits: - memory: [p.memory/] - containers: - - name: [p.operated.container/] - [if (p.holdsEnv())] - [p.containerEnv()/] - [/if] - [p.containerSecurity()/] - [if (p.mounts())] - [p.containerMounts()/] - [/if] - [if (p.probed())] - [p.probes()/] - [/if] - [if (p.volumes->notEmpty() or p.libraries->notEmpty() or p.assets->notEmpty() or p.writablePaths->notEmpty() or p.files()->notEmpty() or p.vpn <> null)] - [p.podVolumes()/] - [/if] - [if (p.operated.additionalArgs->notEmpty())] - additionalArgs: - [for (f : resolveddeployment::OperatedFlag | p.operated.additionalArgs)] - - name: [f.name.scalar()/] - [if (f.value <> null)] - value: [f.value.scalar()/] - [/if] - [/for] - [/if] - [if (p.operated.kind = 'Prometheus')] - [p.operated.prometheusSpec()/] - [else] - alertmanagerConfigSelector: - [p.operated.managedSelection()/] - alertmanagerConfigMatcherStrategy: - type: None - [/if] - [if (p.operated.retention <> null)] - retention: [p.operated.retention.scalar()/] - [/if] - [if (p.operated.retentionSize <> null)] - retentionSize: [p.operated.retentionSize.scalar()/] - [/if] - [if (p.operated.remoteWriteReceiver)] - enableRemoteWriteReceiver: true - [/if] - [if (p.operated.features->notEmpty())] - enableFeatures: - [for (x : String | p.operated.features)] - - [x.scalar()/] - [/for] - [/if] -[/template] - -[comment What a Prometheus scrapes, evaluates and notifies: the monitors of every namespace by the - labels the platform's monitors carry, every scrape of k3s and every rule group the render - writes, and the Alertmanager of the monitoring stack. /] -[template private prometheusSpec(o : resolveddeployment::ResolvedOperated)] - scrapeInterval: [o.interval/] - scrapeTimeout: [o.timeout/] - evaluationInterval: [o.interval/] - [if (o.monitors->isEmpty())] - serviceMonitorSelector: {} - serviceMonitorNamespaceSelector: {} - podMonitorSelector: {} - podMonitorNamespaceSelector: {} - [else] - serviceMonitorSelector: - [o.monitorLabels()/] - serviceMonitorNamespaceSelector: {} - podMonitorSelector: - [o.monitorLabels()/] - podMonitorNamespaceSelector: {} - [/if] - scrapeConfigSelector: - [o.managedSelection()/] - scrapeConfigNamespaceSelector: {} - ruleSelector: - [o.managedSelection()/] - ruleNamespaceSelector: {} - [if (o.alertmanager <> null)] - alerting: - alertmanagers: - - namespace: [o.alertmanager.namespace/] - name: [o.alertmanager.service/] - port: [o.alertmanager.port/] - apiVersion: v2 - [/if] -[/template] - -[comment The labels the platform's monitors carry, as a selection. /] -[template private monitorLabels(o : resolveddeployment::ResolvedOperated)] - matchLabels: - [for (l : resolveddeployment::KeyValue | o.monitors)] - [l.key/]: [l.value.scalar()/] - [/for] -[/template] - -[comment Every object the render writes, by the label it manages them by. /] -[template private managedSelection(o : resolveddeployment::ResolvedOperated)] - matchLabels: - app.kubernetes.io/managed-by: deploy-kit -[/template] - -[comment The pod a Process runs in, whatever controller starts it, unindented: `restart` is the - policy a run to completion restarts by, and nothing for a pod that serves. /] -[template private pod(p : resolveddeployment::ResolvedProcess, restart : String)] - metadata: - labels: - [p.labels()/] - [for (c : String | p.consumes)] - [c.consumerLabel()/] - [/for] - [if (p.member())] - gated.deploy-kit.jorisjonkers.dev/release-gate: "true" - [/if] - [if (p.versioned()->notEmpty())] - annotations: - [for (n : String | p.versioned())] - image.jorisjonkers.dev/[n/]: [p.versionOf(n).scalar()/] - [/for] - [/if] - spec: - serviceAccountName: [p.identity/] - [if (p.priorityClass <> null)] - priorityClassName: [p.priorityClass/] - [/if] - automountServiceAccountToken: [p.identityToken/] - [if (p.nameservers->notEmpty())] - dnsPolicy: None - dnsConfig: - nameservers: - [for (n : String | p.nameservers)] - - [n/] - [/for] - [/if] - [comment A replica set member checks the name it is configured by is its own, which through its - Service holds only where traffic turns back to the pod it left: the pod's own loopback. /] - [if (p.selfNames->notEmpty())] - hostAliases: - - ip: 127.0.0.1 - hostnames: - [for (n : String | p.selfNames)] - - [n/] - [/for] - [/if] - [if (restart <> '')] - restartPolicy: [restart/] - [/if] - [if (p.gpu <> null)] - runtimeClassName: [p.gpu.runtimeClass/] - [/if] - [p.podSecurity()/] - [p.podAffinity()/] - [comment The seeder first, so every later step reads the seeded files; then the VPN, which starts - and stays; then each init step. /] - [if (p.seeder <> null or p.vpn <> null or p.sidecars->exists(c | c.init))] - initContainers: - [if (p.seeder <> null)] - [p.seeder.seederContainer()/] - [/if] - [if (p.vpn <> null)] - [p.vpn.vpnContainer()/] - [/if] - [for (c : resolveddeployment::ResolvedSidecar | p.sidecars->select(c | c.init))] - [c.sidecar(p)/] - [/for] - [/if] - containers: - [p.container()/] - [for (c : resolveddeployment::ResolvedSidecar | p.sidecars->reject(c | c.init))] - [c.sidecar(p)/] - [/for] - [if (p.volumes->notEmpty() or p.libraries->notEmpty() or p.assets->notEmpty() or p.writablePaths->notEmpty() or p.files()->notEmpty() or p.vpn <> null)] - [p.podVolumes()/] - [/if] -[/template] - -[comment The step that seeds a Process's Assets, under the posture and as the Process's own user. /] -[template private seederContainer(s : resolveddeployment::ResolvedSeeder)] - - name: seed - image: [s.image/] - command: - [for (c : String | s.command)] - [c.listItem()/] - [/for] - resources: - requests: - memory: [s.memory/] - cpu: [s.cpu/] - limits: - memory: [s.memory/] - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - [for (m : resolveddeployment::ContainerMount | s.mounts)] - [m.mount()/] - [/for] -[/template] - -[template private mount(m : resolveddeployment::ContainerMount)] - - name: [m.name/] - mountPath: [m.mountAt/] - [if (m.subPath <> null)] - subPath: [m.subPath/] - [/if] - [if (m.readOnly)] - readOnly: true - [/if] -[/template] - -[comment A container beside the Process or before it, under the same posture, the same variables, - the same writable paths and the same file grants: every container of its pod is the Process. It - mounts the Process's volumes and Assets it names, each where it says. /] -[template private sidecar(c : resolveddeployment::ResolvedSidecar, p : resolveddeployment::ResolvedProcess)] - - name: [c.name/] - image: [c.image/] - [if (c.command->notEmpty())] - command: - [for (x : String | c.command)] - [x.listItem()/] - [/for] - [/if] - [if (c.arguments->notEmpty())] - args: - [for (x : String | c.arguments)] - [x.listItem()/] - [/for] - [/if] - [if (p.environment->notEmpty() or c.home <> null)] - env: - [if (p.environment->notEmpty())] - [p.env()/] - [/if] - [if (c.home <> null)] - [c.home.homeEntry()/] - [/if] - [/if] - resources: - requests: - memory: [c.memory/] - cpu: [c.cpu/] - limits: - memory: [c.memory/] - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - [if (c.mounts->notEmpty() or p.writablePaths->notEmpty() or p.files()->notEmpty())] - volumeMounts: - [for (m : resolveddeployment::ContainerMount | c.mounts)] - [m.mount()/] - [/for] - [for (w : resolveddeployment::WritablePath | p.writablePaths)] - - name: [w.path.writableOf()/] - mountPath: [w.path/] - [/for] - [for (g : resolveddeployment::ResolvedGrant | p.files())] - - name: secret-[g.destination/] - mountPath: [g.directoryOf()/] - readOnly: true - [/for] - [/if] -[/template] - -[comment The home a container with a writable /tmp is handed, last among its variables. /] -[template private homeEntry(home : String)] - - name: HOME - value: [home.scalar()/] -[/template] - -[comment A variable as written, or a secret reference as one key of the Secret its grant syncs to. /] -[template private env(p : resolveddeployment::ResolvedProcess)] - [for (e : resolveddeployment::EnvEntry | p.environment)] - [if (e.secret = null)] - - name: [e.name/] - value: [e.value.scalar()/] - [else] - - name: [e.name/] - valueFrom: - secretKeyRef: - name: [p.destinationOf(e.secret.path)/] - key: [e.secret.key/] - [if (e.secret.optional)] - optional: true - [/if] - [/if] - [/for] -[/template] - -[comment The platform's VPN beside an attached Process: a native sidecar started before it, the one - container that runs as root with the two network capabilities, reading its own Secret. /] -[template private vpnContainer(v : resolveddeployment::ResolvedVpn)] - - name: vpn - image: [v.image/] - restartPolicy: Always - env: - [for (e : resolveddeployment::EnvEntry | v.environment)] - - name: [e.name/] - value: [e.value.scalar()/] - [/for] - envFrom: - - secretRef: - name: [v.credential.destination/] - resources: - requests: - memory: [v.memory/] - cpu: [v.cpu/] - limits: - memory: [v.memory/] - securityContext: - runAsNonRoot: false - runAsUser: 0 - runAsGroup: 0 - capabilities: - add: - - NET_ADMIN - - NET_RAW - startupProbe: - exec: - command: - - /gluetun-entrypoint - - healthcheck - periodSeconds: 5 - timeoutSeconds: 5 - failureThreshold: 60 - volumeMounts: - - name: vpn - mountPath: /run/vpn -[/template] - -[template private container(p : resolveddeployment::ResolvedProcess)] - - name: [p.name/] - image: [p.image/] - [if (p.command->notEmpty())] - command: - [for (x : String | p.command)] - [x.listItem()/] - [/for] - [/if] - [if (p.arguments->notEmpty())] - args: - [for (x : String | p.arguments)] - [x.listItem()/] - [/for] - [/if] - [if (p.surfaces->notEmpty())] - ports: - [for (s : resolveddeployment::ResolvedSurface | p.surfaces)] - - name: [s.name/] - containerPort: [s.port/] - [if (s.hostPort <> null)] - hostPort: [s.hostPort/] - [/if] - [/for] - [for (x : resolveddeployment::L4Port | p.nodePorts)] - - name: [x.name/] - containerPort: [x.targetPort/] - hostPort: [x.port/] - protocol: [x.protocol/] - [/for] - [/if] - [if (p.holdsEnv())] - [p.containerEnv()/] - [/if] - resources: - requests: - memory: [p.memory/] - cpu: [p.cpu/] - limits: - memory: [p.memory/] - [comment One share of the card's resource, which the scheduler also takes as the request. /] - [if (p.gpu <> null)] - [p.gpu.resource/]: "1" - [/if] - [p.containerSecurity()/] - [if (p.mounts())] - [p.containerMounts()/] - [/if] - [if (p.probed())] - [p.probes()/] - [/if] -[/template] - -[comment The pod's own posture: as the image's user and group, under the runtime's default seccomp - profile. /] -[template private podSecurity(p : resolveddeployment::ResolvedProcess)] - securityContext: - runAsNonRoot: true - runAsUser: [p.uid/] - runAsGroup: [p.gid/] - [comment A volume is written as the image's group, and only a volume is. A library's group is - its own, and an fsGroup would re-own the whole library. /] - [if (p.volumes->notEmpty() and p.libraries->isEmpty())] - fsGroup: [p.gid/] - [/if] - [comment Traefik refuses ACME storage any group may read, and the kubelet adds group access to a - volume's files on every mount unless told not to. /] - [if (p.keepsAcmeState)] - fsGroupChangePolicy: OnRootMismatch - [/if] - [if (p.libraries->notEmpty())] - supplementalGroups: - [for (g : Integer | p.libraries.gid->asOrderedSet()->sortedBy(x | x))] - - [g/] - [/for] - [/if] - seccompProfile: - type: RuntimeDefault -[/template] - -[comment The node its volume is bound to, or every node eligible for it, each by name; and where - its replicas spread, each repelling the others of its own revision. /] -[template private podAffinity(p : resolveddeployment::ResolvedProcess)] - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - [if (p.placement.boundTo <> null)] - - [p.placement.boundTo/] - [else] - [for (n : String | p.placement.eligibleNodes)] - - [n/] - [/for] - [/if] - [if (p.spread)] - podAntiAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - - labelSelector: - matchLabels: - app.kubernetes.io/instance: [p.name/] - matchLabelKeys: - - pod-template-hash - topologyKey: kubernetes.io/hostname - [/if] -[/template] - -[comment Every volume the pod mounts: its claims, its libraries' claims, its Assets, its writable - paths, its file grants and the VPN's port file. /] -[template private podVolumes(p : resolveddeployment::ResolvedProcess)] - volumes: - [for (v : resolveddeployment::ResolvedVolume | p.volumes)] - - name: [v.claim/] - persistentVolumeClaim: - claimName: [v.claim/] - [/for] - [comment Two mounts of one library below two directories share its one claim. /] - [for (c : String | p.libraries.claim->asOrderedSet())] - - name: [c/] - persistentVolumeClaim: - claimName: [c/] - [/for] - [for (a : resolveddeployment::ResolvedAsset | p.assets)] - - name: [a.name/] - configMap: - name: [a.name/] - items: - - key: [a._from.fileOf()/] - path: [a._from.fileOf()/] - [/for] - [for (w : resolveddeployment::WritablePath | p.writablePaths)] - - name: [w.path.writableOf()/] - emptyDir: - [if (w.memory)] - medium: Memory - [/if] - sizeLimit: [w.size/] - [/for] - [for (g : resolveddeployment::ResolvedGrant | p.files())] - - name: secret-[g.destination/] - secret: - secretName: [g.destination/] - items: - [if (g.engine = 'database')] - - key: username - path: username - - key: password - path: password - [else] - - key: [g.keys->first()/] - path: [g.mountAt.fileOf()/] - [/if] - defaultMode: [g.fileMode.octal()/] - [/for] - [if (p.vpn <> null)] - - name: vpn - emptyDir: - sizeLimit: 1Mi - [/if] -[/template] - -[comment The container's variables: as written, then the home a writable /tmp gives it. /] -[template private containerEnv(p : resolveddeployment::ResolvedProcess)] - env: - [if (p.environment->notEmpty())] - [p.env()/] - [/if] - [if (p.home <> null)] - [p.home.homeEntry()/] - [/if] -[/template] - -[comment The container's posture: no escalation, no root filesystem written, and every capability - dropped but those the Process adds. /] -[template private containerSecurity(p : resolveddeployment::ResolvedProcess)] - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - [if (p.addedPrivileges->notEmpty())] - add: - [for (c : String | p.addedPrivileges)] - - [c/] - [/for] - [/if] - drop: - - ALL -[/template] - -[comment Where the container mounts each volume of its pod. /] -[template private containerMounts(p : resolveddeployment::ResolvedProcess)] - volumeMounts: - [for (v : resolveddeployment::ResolvedVolume | p.volumes)] - - name: [v.claim/] - mountPath: [v.mountAt/] - [/for] - [for (m : resolveddeployment::ResolvedLibraryMount | p.libraries)] - - name: [m.claim/] - mountPath: [m.mountAt/] - [if (m.subPath <> null)] - subPath: [m.subPath/] - [/if] - [if (m.access = 'read')] - readOnly: true - [/if] - [/for] - [for (a : resolveddeployment::ResolvedAsset | p.assets->select(a | a.seedAt = null))] - - name: [a.name/] - mountPath: [a.mountAt/] - subPath: [a._from.fileOf()/] - readOnly: true - [/for] - [for (w : resolveddeployment::WritablePath | p.writablePaths)] - - name: [w.path.writableOf()/] - mountPath: [w.path/] - [/for] - [for (g : resolveddeployment::ResolvedGrant | p.files())] - - name: secret-[g.destination/] - mountPath: [g.directoryOf()/] - readOnly: true - [/for] - [if (p.vpn <> null and p.vpn.forwardedPort)] - - name: vpn - mountPath: /run/vpn - readOnly: true - [/if] -[/template] - -[comment How the kubelet asks whether the container is ready, alive and started. /] -[template private probes(p : resolveddeployment::ResolvedProcess)] - [if (p.readiness <> null)] - readinessProbe: - [p.readiness.target.probeTarget()/] - periodSeconds: [p.readiness.period.seconds()/] - timeoutSeconds: [p.readiness.timeout.seconds()/] - failureThreshold: [p.readiness.failures/] - initialDelaySeconds: 0 - [/if] - [if (p.liveness <> null)] - livenessProbe: - [p.liveness.target.probeTarget()/] - periodSeconds: [p.liveness.period.seconds()/] - timeoutSeconds: [p.liveness.timeout.seconds()/] - failureThreshold: [p.liveness.failures/] - initialDelaySeconds: 0 - [/if] - [if (p.startup <> null)] - startupProbe: - [p.startup.target.probeTarget()/] - periodSeconds: [p.startup.period.seconds()/] - timeoutSeconds: [p.startup.timeout.seconds()/] - failureThreshold: [p.startup.failures/] - [/if] -[/template] - -[template private probeTarget(t : resolveddeployment::ProbeTarget)] - [if (t.oclIsKindOf(resolveddeployment::HttpTarget))] - httpGet: - path: [t.oclAsType(resolveddeployment::HttpTarget).path/] - port: [t.oclAsType(resolveddeployment::HttpTarget).port/] - [else] - tcpSocket: - port: [t.oclAsType(resolveddeployment::TcpTarget).tcp/] - [/if] -[/template] - -[comment What a Process that holds Kubernetes API access may ask of it: its namespace's rules as a - Role in its own namespace under its identity, and its cluster's as a ClusterRole under the name its - namespace and identity make, each bound to its one ServiceAccount. A scope with no rule renders - nothing. /] -[template private objects(d : resolveddeployment::RbacFile)] - [for (p : resolveddeployment::ResolvedProcess | d.processes)] - [if (p.api.rules->exists(r | r.scope.toString() = 'namespace'))] - --- - apiVersion: rbac.authorization.k8s.io/v1 - kind: Role - metadata: - name: [p.identity/] - namespace: [p.application().namespace/] - labels: - [p.labels()/] - rules: - [for (r : resolveddeployment::ResolvedApiRule | p.api.rules->select(r | r.scope.toString() = 'namespace'))] - [r.rule()/] - [/for] - --- - apiVersion: rbac.authorization.k8s.io/v1 - kind: RoleBinding - metadata: - name: [p.identity/] - namespace: [p.application().namespace/] - labels: - [p.labels()/] - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: [p.identity/] - subjects: - - kind: ServiceAccount - name: [p.identity/] - namespace: [p.application().namespace/] - [/if] - [if (p.api.rules->exists(r | r.scope.toString() = 'cluster'))] - --- - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRole - metadata: - name: [p.application().namespace/]-[p.identity/] - labels: - [p.labels()/] - rules: - [for (r : resolveddeployment::ResolvedApiRule | p.api.rules->select(r | r.scope.toString() = 'cluster'))] - [r.rule()/] - [/for] - --- - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRoleBinding - metadata: - name: [p.application().namespace/]-[p.identity/] - labels: - [p.labels()/] - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: [p.application().namespace/]-[p.identity/] - subjects: - - kind: ServiceAccount - name: [p.identity/] - namespace: [p.application().namespace/] - [/if] - [/for] -[/template] - -[comment The Service a Process Flagger does not switch is reached by; Flagger generates a - blue-green one's. /] -[template private objects(d : resolveddeployment::ServiceFile)] - [for (p : resolveddeployment::ResolvedProcess | d.processes)] - [comment A blue-green Process's own Services are Flagger's: only its L4 Services are here. /] - [if (p.l4Services->isEmpty() or not (p.switchover.toString() = 'blue-green'))] - --- - apiVersion: v1 - kind: Service - metadata: - [p.metadata()/] - spec: - selector: - app.kubernetes.io/instance: [p.name/] - ports: - [for (s : resolveddeployment::ResolvedSurface | p.surfaces)] - - name: [s.name/] - port: [s.port/] - targetPort: [s.name/] - [/for] - [/if] - [for (l : resolveddeployment::ResolvedL4Service | p.l4Services)] - [l.l4Service(p)/] - [/for] - [/for] -[/template] - -[comment The Service of a pool L4 Address: a load balancer whose `Local` traffic policy keeps the - client's address, and so sends a connection only to a pod on the node that announces it. /] -[template private l4Service(l : resolveddeployment::ResolvedL4Service, p : resolveddeployment::ResolvedProcess)] - --- - apiVersion: v1 - kind: Service - metadata: - name: [l.name/] - namespace: [p.application().namespace/] - labels: - [p.labels()/] - annotations: - metallb.io/address-pool: [l.pool/] - spec: - type: LoadBalancer - externalTrafficPolicy: Local - selector: - app.kubernetes.io/instance: [p.name/] - ports: - [for (x : resolveddeployment::L4Port | l.ports)] - - name: [x.name/] - port: [x.port/] - protocol: [x.protocol/] - targetPort: [x.targetPort/] - [/for] -[/template] - -[comment Per name the project's edges dial a provider outside its namespace by, the alias that - holds it there: a Service of type ExternalName, with no selector and no port. /] -[template private objects(d : resolveddeployment::AliasFile)] - [for (a : resolveddeployment::Alias | d.aliases)] - --- - apiVersion: v1 - kind: Service - metadata: - name: [a.name/] - namespace: [d.namespace/] - labels: - app.kubernetes.io/managed-by: deploy-kit - spec: - type: ExternalName - externalName: [a.target/] - [/for] -[/template] - -[comment Every Stable Address, an ExternalName Service in the estate's namespace, kept current by - Flux like every other object of the render. /] -[template private objects(d : resolveddeployment::StableAddressFile)] - [for (a : resolveddeployment::Alias | d.addresses)] - --- - apiVersion: v1 - kind: Service - metadata: - name: [a.name/] - namespace: [d.namespace/] - labels: - app.kubernetes.io/managed-by: deploy-kit - spec: - type: ExternalName - externalName: [a.target/] - [/for] -[/template] - -[comment Per library the project mounts, the local volume onto its directory, held to its node, - and the claim bound to it; neither is ever pruned. /] -[template private objects(d : resolveddeployment::LibraryFile)] - [for (m : resolveddeployment::ResolvedLibraryMount | d.libraries)] - --- - apiVersion: v1 - kind: PersistentVolume - metadata: - name: [m.volume/] - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled - spec: - capacity: - storage: [d.size/] - volumeMode: Filesystem - accessModes: - - ReadWriteOnce - persistentVolumeReclaimPolicy: Retain - storageClassName: "" - claimRef: - namespace: [d.namespace/] - name: [m.claim/] - local: - path: [m.path/] - nodeAffinity: - required: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - - [m.node/] - --- - apiVersion: v1 - kind: PersistentVolumeClaim - metadata: - name: [m.claim/] - namespace: [d.namespace/] - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled - spec: - storageClassName: "" - volumeName: [m.volume/] - accessModes: - - ReadWriteOnce - resources: - requests: - storage: [d.size/] - [/for] -[/template] - -[comment A claim for each volume, and for each backed-up one the claim its copies land on, at the same - size. A claim whose class derives a backup is never pruned, and neither is its copies'. /] -[template private objects(d : resolveddeployment::ClaimFile)] - [for (p : resolveddeployment::ResolvedProcess | d.processes)] - [for (v : resolveddeployment::ResolvedVolume | p.volumes)] - [p.claim(v.claim, v.size, v.backup <> null)/] - [if (v.backup <> null)] - [p.claim(v.backup.claim, v.size, true)/] - [/if] - [/for] - [/for] -[/template] - -[template private claim(p : resolveddeployment::ResolvedProcess, name : String, size : String, kept : Boolean)] - --- - apiVersion: v1 - kind: PersistentVolumeClaim - metadata: - name: [name/] - namespace: [p.application().namespace/] - labels: - [p.labels()/] - [if (kept)] - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled - [/if] - spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: [size/] -[/template] - -[comment The Release Gate's inputs first, in a ConfigMap named for the Application that keeps its - name across releases and so is not immutable; then an immutable ConfigMap per Asset, under the - content-named name an edit changes. /] -[template private objects(d : resolveddeployment::ConfigMapFile)] - [if (d.releaseGate <> null)] - --- - apiVersion: v1 - kind: ConfigMap - metadata: - name: [d.application.id/]-release-gate - namespace: [d.application.namespace/] - labels: - app.kubernetes.io/part-of: [d.application.id/] - app.kubernetes.io/managed-by: deploy-kit - data: - releaseGate.json: | - [d.releaseGate/] - [/if] - [if (d.externalChecks <> null)] - --- - apiVersion: v1 - kind: ConfigMap - metadata: - name: [d.application.id/]-external-checks - namespace: [d.application.namespace/] - labels: - app.kubernetes.io/part-of: [d.application.id/] - app.kubernetes.io/managed-by: deploy-kit - estate.jorisjonkers.dev/external-checks: "true" - data: - [d.application.id/]-external-checks.yaml: | - [d.externalChecks/] - [/if] - [for (p : resolveddeployment::ResolvedProcess | d.processes)] - [for (a : resolveddeployment::ResolvedAsset | p.assets)] - --- - apiVersion: v1 - kind: ConfigMap - metadata: - name: [a.name/] - namespace: [p.application().namespace/] - labels: - [p.labels()/] - immutable: true - data: - [a._from.fileOf()/]: [a.content.chomping()/] - [a.content.blockOf(' ')/] - [/for] - [/for] -[/template] - -[comment A backup per backed-up volume, at its class's schedule: the engine's method image, run as the - backup identity, reading the volume at `/data` and writing its copies to the backup claim at - `/backup`, pruned to `retain`. /] -[template private objects(d : resolveddeployment::BackupFile)] - [for (p : resolveddeployment::ResolvedProcess | d.processes)] - [for (v : resolveddeployment::ResolvedVolume | p.backups())] - [v.backup.cronJob(v, p)/] - [/for] - [/for] -[/template] - -[template private cronJob(b : resolveddeployment::BackupPlan, v : resolveddeployment::ResolvedVolume, p : resolveddeployment::ResolvedProcess)] - --- - apiVersion: batch/v1 - kind: CronJob - metadata: - name: [b.claim/] - namespace: [p.application().namespace/] - labels: - [b.identity.labelSet('none', p.application().id)/] - spec: - schedule: [b.schedule.scalar()/] - concurrencyPolicy: Forbid - jobTemplate: - spec: - template: - metadata: - labels: - [b.identity.labelSet('none', p.application().id)/] - [if (b.methodVersion <> null)] - annotations: - image.jorisjonkers.dev/backup: [b.methodVersion.scalar()/] - [/if] - spec: - serviceAccountName: [b.identity/] - automountServiceAccountToken: false - restartPolicy: OnFailure - securityContext: - runAsNonRoot: true - runAsUser: [b.uid/] - runAsGroup: [b.gid/] - fsGroup: [b.gid/] - seccompProfile: - type: RuntimeDefault - containers: - - name: backup - image: [b.method/] - env: - - name: BACKUP_RETAIN - value: [b.retain.toString().scalar()/] - [if (b.offCluster <> null)] - - name: BACKUP_OFF_CLUSTER - value: [b.offCluster.scalar()/] - [/if] - [if (b.offClusterPath <> null)] - - name: BACKUP_OFF_CLUSTER_PATH - value: [b.offClusterPath.scalar()/] - [/if] - [if (b.offClusterRecipient <> null)] - - name: BACKUP_OFF_CLUSTER_RECIPIENT - value: [b.offClusterRecipient.scalar()/] - [/if] - [if (b.peer <> null)] - - name: BACKUP_HOST - value: [b.peer.host/] - - name: BACKUP_PORT - value: [b.peer.port.toString().scalar()/] - [/if] - [if (b.credential <> null or b.peer <> null)] - envFrom: - [/if] - [if (b.credential <> null)] - - secretRef: - name: [b.credential.destination/] - [/if] - [if (b.peer <> null)] - - secretRef: - name: [b.peer.credential.destination/] - [/if] - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: data - mountPath: /data - readOnly: true - - name: backup - mountPath: /backup - volumes: - - name: data - persistentVolumeClaim: - claimName: [v.claim/] - readOnly: true - - name: backup - persistentVolumeClaim: - claimName: [b.claim/] -[/template] - -[comment ========================================================= the operator /] - -[comment The operator's connection to the Secret Store. TLS is never skipped: the schema asks, and - the answer is fixed. /] -[comment The default TLS store a tier's certificate derives, beside the tier's proxy. /] -[template private objects(d : resolveddeployment::TlsStoreFile)] - --- - apiVersion: traefik.io/v1alpha1 - kind: TLSStore - metadata: - name: default - namespace: [d.namespace/] - labels: - app.kubernetes.io/part-of: [d.application/] - app.kubernetes.io/managed-by: deploy-kit - spec: - defaultCertificate: - secretName: [d.secret/] -[/template] - -[comment The monitoring stack's Grafana as the Grafana operator reaches it: an external instance - carrying the labels every dashboard selects it by, signed in to with its admin credential. /] -[template private objects(d : resolveddeployment::GrafanaFile)] - --- - apiVersion: grafana.integreatly.org/v1beta1 - kind: Grafana - metadata: - name: [d.application.id/] - namespace: [d.application.namespace/] - labels: - [for (l : resolveddeployment::KeyValue | d.application.grafana.labels)] - [l.key/]: [l.value.scalar()/] - [/for] - app.kubernetes.io/part-of: [d.application.id/] - app.kubernetes.io/managed-by: deploy-kit - spec: - external: - url: [d.application.grafana.url/] - adminUser: - name: [d.application.grafana.secret/] - key: [d.application.grafana.user/] - adminPassword: - name: [d.application.grafana.secret/] - key: [d.application.grafana.password/] -[/template] - -[comment k3s's own components, scraped by the metrics stack from its own namespace - (spec/v1/14-platform-intent.md#k3ss-metrics): the token of the stack's ServiceAccount the scrapes - authenticate with and the read they take, a ScrapeConfig per kubelet endpoint, a ServiceMonitor - of the API server's Service and a PodMonitor of the cluster's DNS, each where the bootstrap set - records it. /] -[template private objects(d : resolveddeployment::K3sMonitorsFile)] - [d.application.k3sScrape.k3sMonitors(d.application)/] -[/template] - -[template private k3sMonitors(k : resolveddeployment::ResolvedK3sScrape, a : resolveddeployment::ResolvedApplication)] - --- - apiVersion: v1 - kind: Secret - metadata: - name: [k.identity/]-token - namespace: [a.namespace/] - labels: - [a.ownLabels()/] - annotations: - kubernetes.io/service-account.name: [k.identity/] - type: kubernetes.io/service-account-token - --- - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRole - metadata: - name: [a.namespace/]-[k.identity/]-k3s - labels: - [a.ownLabels()/] - rules: - - apiGroups: - - "" - resources: - - nodes - verbs: - - get - - list - - watch - - apiGroups: - - "" - resources: - - nodes/metrics - verbs: - - get - - nonResourceURLs: - - /metrics - verbs: - - get - --- - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRoleBinding - metadata: - name: [a.namespace/]-[k.identity/]-k3s - labels: - [a.ownLabels()/] - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: [a.namespace/]-[k.identity/]-k3s - subjects: - - kind: ServiceAccount - name: [k.identity/] - namespace: [a.namespace/] - [if (k.kubeletPort <> null)] - [k.kubeletScrape(a, 'kubelet', '/metrics')/] - [k.kubeletScrape(a, 'kubelet-cadvisor', '/metrics/cadvisor')/] - [k.kubeletScrape(a, 'kubelet-probes', '/metrics/probes')/] - [/if] - [if (k.apiServerService <> null)] - --- - apiVersion: monitoring.coreos.com/v1 - kind: ServiceMonitor - metadata: - name: apiserver - namespace: [a.namespace/] - labels: - [k.scrapeLabels(a)/] - spec: - jobLabel: component - selector: - matchLabels: - component: apiserver - provider: kubernetes - namespaceSelector: - matchNames: - - [k.apiServerNamespace/] - endpoints: - - port: [k.apiServerPort/] - scheme: https - interval: [k.interval/] - scrapeTimeout: [k.timeout/] - [k.bearer()/] - tlsConfig: - ca: - configMap: - name: kube-root-ca.crt - key: ca.crt - serverName: [k.apiServerService/] - metricRelabelings: - - action: drop - sourceLabels: - - __name__ - - le - regex: (etcd_request|apiserver_request_slo|apiserver_request_sli|apiserver_request)_duration_seconds_bucket;(0\.15|0\.2|0\.3|0\.35|0\.4|0\.45|0\.6|0\.7|0\.8|0\.9|1\.25|1\.5|1\.75|2|3|3\.5|4|4\.5|6|7|8|9|15|20|40|45|50)(\.0)? - [/if] - [if (k.coreDnsPort <> null)] - --- - apiVersion: monitoring.coreos.com/v1 - kind: PodMonitor - metadata: - name: coredns - namespace: [a.namespace/] - labels: - [k.scrapeLabels(a)/] - spec: - jobLabel: k8s-app - selector: - matchLabels: - k8s-app: kube-dns - namespaceSelector: - matchNames: - - [k.coreDnsNamespace/] - podMetricsEndpoints: - - portNumber: [k.coreDnsPort/] - path: /metrics - interval: [k.interval/] - scrapeTimeout: [k.timeout/] - relabelings: - - targetLabel: job - replacement: coredns - [/if] -[/template] - -[comment One endpoint of the kubelet, at its recorded port on each node, its serving certificate its - own, signed by no authority the pod holds. The cadvisor endpoint drops the series no rule reads. /] -[template private kubeletScrape(k : resolveddeployment::ResolvedK3sScrape, a : resolveddeployment::ResolvedApplication, name : String, path : String)] - --- - apiVersion: monitoring.coreos.com/v1alpha1 - kind: ScrapeConfig - metadata: - name: [name/] - namespace: [a.namespace/] - labels: - [k.scrapeLabels(a)/] - spec: - jobName: kubelet - kubernetesSDConfigs: - - role: Node - scheme: HTTPS - metricsPath: [path/] - scrapeInterval: [k.interval/] - scrapeTimeout: [k.timeout/] - honorLabels: true - honorTimestamps: true - [k.bearer()/] - tlsConfig: - insecureSkipVerify: true - relabelings: - - sourceLabels: - - __address__ - regex: (.+):\d+ - replacement: $1:[k.kubeletPort/] - targetLabel: __address__ - - sourceLabels: - - __meta_kubernetes_node_name - targetLabel: node - - sourceLabels: - - __metrics_path__ - targetLabel: metrics_path - [if (name = 'kubelet-cadvisor')] - metricRelabelings: - [for (x : String | Sequence{'container_cpu_(cfs_throttled_seconds_total|load_average_10s|system_seconds_total|user_seconds_total)', 'container_fs_(io_current|io_time_seconds_total|io_time_weighted_seconds_total|reads_merged_total|sector_reads_total|sector_writes_total|writes_merged_total)', 'container_memory_(mapped_file|swap)', 'container_(file_descriptors|tasks_state|threads_max)', 'container_spec.*'})] - - action: drop - sourceLabels: - - __name__ - regex: [x/] - [/for] - [/if] -[/template] - -[comment How a scrape of k3s authenticates: as the stack's ServiceAccount, by its token Secret. /] -[template private bearer(k : resolveddeployment::ResolvedK3sScrape)] - authorization: - type: Bearer - credentials: - name: [k.identity/]-token - key: token -[/template] - -[comment A scrape's labels: the platform's monitor labels beside its Application's own. /] -[template private scrapeLabels(k : resolveddeployment::ResolvedK3sScrape, a : resolveddeployment::ResolvedApplication)] - [for (l : resolveddeployment::KeyValue | k.labels)] - [l.key/]: [l.value.scalar()/] - [/for] - [a.ownLabels()/] -[/template] - -[comment What marks an object as the Application's and the render's alone. /] -[template private ownLabels(a : resolveddeployment::ResolvedApplication)] - app.kubernetes.io/part-of: [a.id/] - app.kubernetes.io/managed-by: deploy-kit -[/template] - -[template private objects(d : resolveddeployment::ConnectionFile)] - --- - apiVersion: secrets.hashicorp.com/v1beta1 - kind: VaultConnection - metadata: - name: secret-store - namespace: [d.namespace/] - labels: - app.kubernetes.io/managed-by: deploy-kit - spec: - address: [d.address/] - skipTLSVerify: false -[/template] - -[comment For each holder, how the operator authenticates as it, then one synced Secret per grant, read - every hour from the kv mount, never tracked by Flagger, and restarting what is serving. A gated - Application's sync objects outlive the release that drops them: Flux keeps them, and the Release - Gate removes an older revision's once the Application serves - (spec/v1/55-delivery.md#a-removed-grant-outlives-its-release). /] -[template private objects(d : resolveddeployment::SecretFile)] - [for (h : resolveddeployment::SecretHolder | d.holders)] - --- - apiVersion: secrets.hashicorp.com/v1beta1 - kind: VaultAuth - metadata: - [h.holderMetadata(d.application)/] - spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: [d.application.namespace/]-[h.identity/] - serviceAccount: [h.identity/] - [for (g : resolveddeployment::ResolvedGrant | h.grants)] - [if (g.engine = 'database')] - [g.dynamicSecret(h, d)/] - [else] - [g.staticSecret(h, d)/] - [/if] - [/for] - [/for] -[/template] - -[comment A kv grant's value, read every hour from the kv mount. /] -[template private staticSecret(g : resolveddeployment::ResolvedGrant, h : resolveddeployment::SecretHolder, d : resolveddeployment::SecretFile)] - --- - apiVersion: secrets.hashicorp.com/v1beta1 - kind: VaultStaticSecret - metadata: - name: [g.destination/] - namespace: [d.application.namespace/] - labels: - [h.identity.labelSet(h.component, d.application.id)/] - [if (d.application.releaseGate <> null)] - annotations: - estate.jorisjonkers.dev/revision: [d.application.revision/] - kustomize.toolkit.fluxcd.io/prune: disabled - [/if] - spec: - vaultAuthRef: [h.identity/] - mount: secret - type: kv-v2 - path: [g.path.substring(13)/] - refreshAfter: 10m - hmacSecretData: true - destination: - name: [g.destination/] - create: true - annotations: - flagger.app/config-tracking: disabled - [g.restarts(d)/] -[/template] - -[comment A database credential an edge delivers to the environment, issued and renewed by the store - (spec/v1/10-project-intent.md#migration). /] -[template private dynamicSecret(g : resolveddeployment::ResolvedGrant, h : resolveddeployment::SecretHolder, d : resolveddeployment::SecretFile)] - --- - apiVersion: secrets.hashicorp.com/v1beta1 - kind: VaultDynamicSecret - metadata: - name: [g.destination/] - namespace: [d.application.namespace/] - labels: - [h.identity.labelSet(h.component, d.application.id)/] - [if (d.application.releaseGate <> null)] - annotations: - estate.jorisjonkers.dev/revision: [d.application.revision/] - kustomize.toolkit.fluxcd.io/prune: disabled - [/if] - spec: - vaultAuthRef: [h.identity/] - mount: database - path: [g.paths->first().path.substring(10)/] - destination: - name: [g.destination/] - create: true - annotations: - flagger.app/config-tracking: disabled - [g.restarts(d)/] -[/template] - -[comment What a rotation restarts: what is serving, where the grant restarts anything. /] -[template private restarts(g : resolveddeployment::ResolvedGrant, d : resolveddeployment::SecretFile)] - [if (g.restartTargets->notEmpty())] - rolloutRestartTargets: - [for (t : String | g.restartTargets)] - [if (d.application.operatedOf(t) <> null)] - - kind: StatefulSet - name: [d.application.operatedOf(t).container/]-[t/] - [else] - - kind: Deployment - name: [d.application.servingOf(t)/] - [/if] - [/for] - [/if] -[/template] - -[template private holderMetadata(h : resolveddeployment::SecretHolder, a : resolveddeployment::ResolvedApplication)] - name: [h.identity/] - namespace: [a.namespace/] - labels: - [h.identity.labelSet(h.component, a.id)/] - [if (a.releaseGate <> null)] - annotations: - estate.jorisjonkers.dev/revision: [a.revision/] - kustomize.toolkit.fluxcd.io/prune: disabled - [/if] -[/template] - -[comment ============================================================ Vault /] - -[template private json(d : resolveddeployment::VaultPolicyFile)] - { - "path": { - [for (k : resolveddeployment::PolicyPath | d.paths) separator(',\n')] - "[k.path/]": { - "capabilities": ['['/] - [for (c : String | k.allows) separator(',\n')] - "[c/]"[/for] - ] - }[/for] - } - } -[/template] - -[template private json(d : resolveddeployment::VaultRoleFile)] - { - "bound_service_account_names": [ '[' /] - "[d.identity/]" - ], - "bound_service_account_namespaces": [ '[' /] - "[d.namespace/]" - ], - "token_policies": [ '[' /] - "[d.namespace/]-[d.identity/]" - ] - } -[/template] - -[template private json(d : resolveddeployment::GeneratedKeysFile)] - { - "keys": [ '[' /] - [d.keys->collect(k | k.entry())->sep(',\n')/] - ] - } -[/template] - -[comment The Vault policy job: the ServiceAccount it runs as, the ConfigMap that hands it every - document of this render as canonical JSON on one line, the Job that writes them into the Secret - Store, and the job's own policy. The ConfigMap and the Job share the name the documents' digest - gives them. /] -[comment The route Flux's events take to the Reporter (spec/v1/30-deliverables.md#the-rollout-events): - a generic Provider that names where they are posted, and an Alert that sends it every event of a - unit the render manages. Both live in Flux's namespace. /] -[template private objects(d : resolveddeployment::EventsFile)] - --- - apiVersion: notification.toolkit.fluxcd.io/v1beta3 - [if (d.part = 'provider')] - kind: Provider - metadata: - name: reporter-[d.project/] - namespace: [d.events.namespace/] - labels: - app.kubernetes.io/managed-by: deploy-kit - spec: - type: generic - address: [d.events.address/] - [else] - kind: Alert - metadata: - name: rollouts-[d.project/] - namespace: [d.events.namespace/] - labels: - app.kubernetes.io/managed-by: deploy-kit - spec: - providerRef: - name: reporter-[d.project/] - eventSeverity: info - eventSources: - - kind: Kustomization - name: apps-[d.project/] - matchLabels: - app.kubernetes.io/managed-by: deploy-kit - [/if] -[/template] - -[comment The run the Job and the CronJob share, unindented. /] -[template private pod(d : resolveddeployment::PolicyJobFile)] - metadata: - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - [if (d.job.imageVersion <> null)] - annotations: - image.jorisjonkers.dev/[d.job.identity/]: [d.job.imageVersion.scalar()/] - [/if] - spec: - serviceAccountName: [d.job.identity/] - automountServiceAccountToken: true - restartPolicy: OnFailure - [comment One attempt's deadline: a start too slow or a run that hangs fails the pod, and the - Job starts another. /] - activeDeadlineSeconds: [d.job.deadline.seconds()/] - securityContext: - runAsNonRoot: true - runAsUser: [d.job.uid/] - runAsGroup: [d.job.gid/] - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - [for (n : String | d.job.eligibleNodes)] - - [n/] - [/for] - containers: - - name: [d.job.identity/] - image: [d.job.image/] - env: - - name: VAULT_ADDR - value: [d.job.address/] - - name: VAULT_ROLE - value: [d.job.role/] - - name: POLICIES_DIR - value: /policies - resources: - requests: - memory: [d.job.memory/] - cpu: [d.job.cpu/] - limits: - memory: [d.job.memory/] - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: policies - mountPath: /policies - readOnly: true - volumes: - - name: policies - configMap: - name: [d.name/] - items: - [for (document : resolveddeployment::PolicyDocument | d.documents)] - - key: [document.file/] - path: [document.file/] - [/for] -[/template] - -[template private objects(d : resolveddeployment::PolicyJobFile)] - [if (d.part = 'serviceaccount')] - --- - apiVersion: v1 - kind: ServiceAccount - metadata: - name: [d.job.identity/] - namespace: [d.namespace/] - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - [elseif (d.part = 'configmap')] - --- - apiVersion: v1 - kind: ConfigMap - metadata: - name: [d.name/] - namespace: [d.namespace/] - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - immutable: true - data: - [for (document : resolveddeployment::PolicyDocument | d.documents)] - [document.file/]: | - [document.json/] - [/for] - [elseif (d.part = 'job')] - --- - apiVersion: batch/v1 - kind: Job - metadata: - name: [d.name/] - namespace: [d.namespace/] - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled - spec: - backoffLimit: 2147483647 - template: - [d.pod()/] - [elseif (d.part = 'cronjob')] - --- - apiVersion: batch/v1 - kind: CronJob - metadata: - name: [d.job.identity/] - namespace: [d.namespace/] - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - [d.pod()/] - [else] - --- - apiVersion: networking.k8s.io/v1 - kind: NetworkPolicy - metadata: - name: [d.job.identity/] - namespace: [d.namespace/] - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: [d.job.identity/] - policyTypes: - - Ingress - - Egress - egress: - [for (peer : resolveddeployment::PolicyPeer | d.job.egress)] - - to: - [peer.peer()/] - ports: - [if (peer.rule = 'cluster-dns')] - - protocol: UDP - port: [peer.port/] - [/if] - - protocol: TCP - port: [peer.port/] - [/for] - [/if] -[/template] - -[comment A datastore's catalog method (spec/v1/16-dependencies.md#applying-the-catalog): its - ServiceAccount, the ConfigMap that hands it the catalog, the Job and the hourly CronJob in one - file, or its own policy. /] -[template private catalogPod(d : resolveddeployment::CatalogJobFile)] - metadata: - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - [for (c : String | d.job.consumes)] - [c.consumerLabel()/] - [/for] - [if (d.job.imageVersion <> null)] - annotations: - image.jorisjonkers.dev/[d.job.identity/]: [d.job.imageVersion.scalar()/] - [/if] - spec: - serviceAccountName: [d.job.identity/] - automountServiceAccountToken: true - restartPolicy: OnFailure - [comment One attempt's deadline: a start too slow or a run that hangs fails the pod, and the - Job starts another. /] - activeDeadlineSeconds: [d.job.deadline.seconds()/] - securityContext: - runAsNonRoot: true - runAsUser: [d.job.uid/] - runAsGroup: [d.job.gid/] - seccompProfile: - type: RuntimeDefault - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - [for (n : String | d.job.eligibleNodes)] - - [n/] - [/for] - containers: - - name: [d.job.identity/] - image: [d.job.image/] - env: - - name: VAULT_ADDR - value: [d.job.address/] - - name: VAULT_ROLE - value: [d.job.role/] - - name: CATALOG_FILE - value: /catalog/catalog.json - resources: - requests: - memory: [d.job.memory/] - cpu: [d.job.cpu/] - limits: - memory: [d.job.memory/] - securityContext: - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - capabilities: - drop: - - ALL - volumeMounts: - - name: catalog - mountPath: /catalog - readOnly: true - volumes: - - name: catalog - configMap: - name: [d.name/] - items: - - key: catalog.json - path: catalog.json -[/template] - -[template private objects(d : resolveddeployment::CatalogJobFile)] - [if (d.part = 'objects')] - --- - apiVersion: v1 - kind: ServiceAccount - metadata: - name: [d.job.identity/] - namespace: [d.job.namespace/] - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - --- - apiVersion: v1 - kind: ConfigMap - metadata: - name: [d.name/] - namespace: [d.job.namespace/] - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - immutable: true - data: - catalog.json: | - [d.catalogJson/] - --- - apiVersion: batch/v1 - kind: Job - metadata: - name: [d.name/] - namespace: [d.job.namespace/] - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled - spec: - backoffLimit: 2147483647 - template: - [d.catalogPod()/] - --- - apiVersion: batch/v1 - kind: CronJob - metadata: - name: [d.job.identity/] - namespace: [d.job.namespace/] - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - spec: - schedule: "@hourly" - concurrencyPolicy: Forbid - jobTemplate: - metadata: - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - spec: - backoffLimit: 6 - activeDeadlineSeconds: 3000 - template: - [d.catalogPod()/] - [else] - --- - apiVersion: networking.k8s.io/v1 - kind: NetworkPolicy - metadata: - name: [d.job.identity/] - namespace: [d.job.namespace/] - labels: - [d.job.identity.labelSet('none', d.job.identity)/] - spec: - podSelector: - matchLabels: - app.kubernetes.io/instance: [d.job.identity/] - policyTypes: - - Ingress - - Egress - egress: - [for (peer : resolveddeployment::PolicyPeer | d.job.egress)] - - to: - [peer.peer()/] - ports: - [if (peer.rule = 'cluster-dns')] - - protocol: UDP - port: [peer.port/] - [/if] - - protocol: TCP - port: [peer.port/] - [/for] - [/if] -[/template] - -[template private json(d : resolveddeployment::CatalogJobFile)] - { - "path": { - [for (k : resolveddeployment::PolicyPath | d.job.policy) separator(',\n')] - "[k.path/]": { - "capabilities": ['['/] - [for (c : String | k.allows) separator(',\n')] - "[c/]"[/for] - ] - }[/for] - } - } -[/template] - -[comment ============================================================ the edge /] - -[comment A route set belongs to an Application and to none of its Processes. /] -[template private objects(d : resolveddeployment::IngressRouteFile)] - --- - apiVersion: traefik.io/v1alpha1 - kind: IngressRoute - metadata: - name: [d.exposure.application().id/]-[d.exposure.name/] - namespace: [d.exposure.application().namespace/] - labels: - app.kubernetes.io/part-of: [d.exposure.application().id/] - app.kubernetes.io/managed-by: deploy-kit - annotations: - kubernetes.io/ingress.class: [d.exposure.ingressClass/] - [if (d.exposure.dns <> null)] - external-dns.alpha.kubernetes.io/target: [d.exposure.dns.target/] - external-dns.alpha.kubernetes.io/cloudflare-proxied: "[d.exposure.dns.proxied/]" - [/if] - spec: - entryPoints: - - [d.entryPoint/] - routes: - [for (r : resolveddeployment::ResolvedRoute | d.exposure.routes)] - [r.route(d.exposure)/] - [/for] - [if (d.certificateResolver <> null)] - tls: - certResolver: [d.certificateResolver/] - [elseif (d.terminatesTls)] - tls: {} - [/if] - [for (r : resolveddeployment::ResolvedRoute | d.exposure.routes)] - [for (m : resolveddeployment::MiddlewareStep | r.middleware->select(s | s.kind.toString() = 'rate-limit' or s.kind.toString() = 'redirect'))] - [if (m.kind.toString() = 'redirect')] - [m.redirect(d.exposure)/] - [else] - [m.rateLimit(d.exposure)/] - [/if] - [/for] - [/for] -[/template] - -[comment A route's rate limit, its own Middleware beside its IngressRoute, since its values are that - route's alone. Behind Cloudflare every connection is Cloudflare's, so a client is the address it - forwards. /] -[template private rateLimit(m : resolveddeployment::MiddlewareStep, e : resolveddeployment::ResolvedExposure)] - --- - apiVersion: traefik.io/v1alpha1 - kind: Middleware - metadata: - name: [m.name/] - namespace: [m.namespace/] - labels: - app.kubernetes.io/part-of: [e.application().id/] - app.kubernetes.io/managed-by: deploy-kit - spec: - rateLimit: - average: [m.allowance/] - period: [m.per/] - burst: [m.burst/] - [if (m.clientAddress = 'cloudflare')] - sourceCriterion: - requestHeaderName: CF-Connecting-IP - [/if] -[/template] - -[comment The shared Middlewares of a tier proxy's namespace: its forward-auth, the security-headers - baseline every route carries, and the baseline with each content policy. /] -[template private objects(d : resolveddeployment::SharedMiddlewareFile)] - [if (d.forwardAuth <> null)] - --- - apiVersion: traefik.io/v1alpha1 - kind: Middleware - metadata: - [d.sharedMetadata('forward-auth')/] - spec: - forwardAuth: - address: [d.forwardAuth.address/] - trustForwardHeader: true - [/if] - --- - apiVersion: traefik.io/v1alpha1 - kind: Middleware - metadata: - [d.sharedMetadata('security-headers')/] - spec: - headers: - [d.baseline()/] - [for (c : resolveddeployment::ContentPolicyHeaders | d.policies)] - --- - apiVersion: traefik.io/v1alpha1 - kind: Middleware - metadata: - [d.sharedMetadata('security-headers-' + c.name)/] - spec: - headers: - [d.baseline()/] - contentSecurityPolicy: [c.contentSecurityPolicy.scalar()/] - [/for] -[/template] - -[template private sharedMetadata(d : resolveddeployment::SharedMiddlewareFile, name : String)] - name: [name/] - namespace: [d.namespace/] - labels: - app.kubernetes.io/part-of: [d.application/] - app.kubernetes.io/managed-by: deploy-kit -[/template] - -[comment The baseline every route carries: no sniffing, no framing, HTTPS remembered. /] -[template private baseline(d : resolveddeployment::SharedMiddlewareFile)] - contentTypeNosniff: true - frameDeny: true - referrerPolicy: strict-origin-when-cross-origin - permissionsPolicy: camera=(), microphone=(), geolocation=() - stsSeconds: 31536000 - stsIncludeSubdomains: true -[/template] - -[comment A route's redirect, its own Middleware beside its IngressRoute: the scheme and host the - request came on, and the path the route names. Not permanent, so a client caches no landing path - that may change; the route's own match decides which requests reach it. /] -[template private redirect(m : resolveddeployment::MiddlewareStep, e : resolveddeployment::ResolvedExposure)] - --- - apiVersion: traefik.io/v1alpha1 - kind: Middleware - metadata: - name: [m.name/] - namespace: [m.namespace/] - labels: - app.kubernetes.io/part-of: [e.application().id/] - app.kubernetes.io/managed-by: deploy-kit - spec: - redirectRegex: - regex: ^(https?://['['/]^/]+)(/.*)?$ - replacement: ${1}[m.redirectTo/] - permanent: false -[/template] - -[comment Traefik tries the higher priority first, and precedence 1 is matched first. /] -[template private route(r : resolveddeployment::ResolvedRoute, e : resolveddeployment::ResolvedExposure)] - - kind: Rule - match: Host(`[e.host/]`) && [if (r.match.toString() = 'exact')]Path[else]PathPrefix[/if](`[r.path/]`) - priority: [1000 - r.precedence/] - middlewares: - [for (m : resolveddeployment::MiddlewareStep | r.middleware)] - - name: [m.name/] - namespace: [m.namespace/] - [/for] - services: - [if (r.gate <> null)] - - name: [r.gate.name/] - namespace: [r.gate.namespace/] - port: [r.gate.port/] - [else] - - name: [r.process.name/] - namespace: [e.application().namespace/] - port: [r.process.surfaces->select(s | s.name = r.surface)->first().port/] - [/if] -[/template] - -[comment ====================================================== sign-in and monitoring /] - -[comment The Client an Application declares: cluster-scoped, so it names no namespace, and named by - the Application Id, which is its Client id. /] -[template private objects(d : resolveddeployment::ClientFile)] - --- - apiVersion: identity.jorisjonkers.dev/v1 - kind: Client - metadata: - name: [d.application.id/] - labels: - app.kubernetes.io/part-of: [d.application.id/] - app.kubernetes.io/managed-by: deploy-kit - spec: - signIn: [d.application.client.signIn/] - host: [d.application.client.host/] - [if (d.application.client.launchUrl <> null)] - launchUrl: [d.application.client.launchUrl/] - [/if] - [if (d.application.client.iconUrl <> null)] - iconUrl: [d.application.client.iconUrl/] - [/if] - [if (d.application.client.redirectUris->notEmpty())] - redirectUris: - [for (u : String | d.application.client.redirectUris)] - - [u/] - [/for] - [/if] - [if (d.application.client.backChannelLogoutUri <> null)] - backChannelLogoutUri: [d.application.client.backChannelLogoutUri/] - [/if] - [if (d.application.client.credential <> null)] - credential: [d.application.client.credential/] - [/if] - [if (d.application.client.secretPath <> null)] - secretPath: [d.application.client.secretPath/] - [/if] - roles: - [for (r : String | d.application.client.roles)] - - [r/] - [/for] - [if (d.application.client.label <> null)] - label: [d.application.client.label.scalar()/] - [/if] - [if (d.application.client.description <> null)] - description: [d.application.client.description.scalar()/] - [/if] -[/template] - -[comment The labels of an object that belongs to an Application and to none of its Processes. /] -[template private applicationLabels(a : resolveddeployment::ResolvedApplication)] - app.kubernetes.io/part-of: [a.id/] - app.kubernetes.io/managed-by: deploy-kit -[/template] - -[comment One PrometheusRule per rule file, its groups as the file writes them. /] -[template private objects(d : resolveddeployment::AlertRulesFile)] - [for (f : resolveddeployment::ResolvedAlertRules | d.application.alertRules)] - --- - apiVersion: monitoring.coreos.com/v1 - kind: PrometheusRule - metadata: - name: [f.name/] - namespace: [d.application.namespace/] - labels: - [d.application.applicationLabels()/] - spec: - groups: - [f.groups->collect(g | g.item(' '))->sep('\n')/] - [/for] -[/template] - -[comment The one routing of every alert: by severity to its receiver, and an alert that matches no - severity to the receiver that delivers nothing. /] -[template private objects(d : resolveddeployment::AlertingFile)] - --- - apiVersion: monitoring.coreos.com/v1alpha1 - kind: AlertmanagerConfig - metadata: - name: estate-alerts - namespace: [d.application.namespace/] - labels: - [d.application.applicationLabels()/] - spec: - route: - receiver: "null" - groupBy: - - alertname - - namespace - groupWait: 1m - groupInterval: 5m - repeatInterval: 12h - routes: - [for (r : resolveddeployment::AlertRoute | d.application.alerting.routes)] - - matchers: - - name: severity - value: [r.severity.scalar()/] - receiver: [r.receiver.scalar()/] - repeatInterval: [r.repeat/] - [/for] - receivers: - - name: "null" - [for (r : resolveddeployment::AlertReceiver | d.application.alerting.receivers)] - - name: [r.name.scalar()/] - discordConfigs: - - apiURL: - name: [r.secret/] - key: [r.key/] - sendResolved: true - [/for] -[/template] - -[comment Flux's controllers, selected by the label Flux's install gives them and reached by number. /] -[template private objects(d : resolveddeployment::FluxMonitorFile)] - --- - apiVersion: monitoring.coreos.com/v1 - kind: PodMonitor - metadata: - name: flux-controllers - namespace: [d.application.namespace/] - labels: - [for (l : resolveddeployment::KeyValue | d.application.fluxScrape.labels->reject(l | d.application.ownApplicationLabelKeys()->includes(l.key)))] - [l.key/]: [l.value.scalar()/] - [/for] - [d.application.applicationLabels()/] - spec: - jobLabel: app - selector: - matchLabels: - app.kubernetes.io/part-of: flux - namespaceSelector: - matchNames: - - [d.application.fluxScrape.namespace/] - podMetricsEndpoints: - - portNumber: [d.application.fluxScrape.port/] - path: [d.application.fluxScrape.path/] - interval: [d.application.fluxScrape.interval/] - scrapeTimeout: [d.application.fluxScrape.timeout/] -[/template] - -[comment One GrafanaDashboard per dashboard file, for the Grafana in its own Project's namespace. /] -[template private objects(d : resolveddeployment::DashboardFile)] - [for (f : resolveddeployment::ResolvedDashboard | d.application.dashboards.files)] - --- - apiVersion: grafana.integreatly.org/v1beta1 - kind: GrafanaDashboard - metadata: - name: [f.name/] - namespace: [d.application.namespace/] - labels: - [d.application.applicationLabels()/] - spec: - instanceSelector: - matchLabels: - [for (l : resolveddeployment::KeyValue | d.application.dashboards.instance)] - [l.key/]: [l.value.scalar()/] - [/for] - allowCrossNamespaceImport: true - folder: [d.application.dashboards.folder/] - json: [f.content.chomping()/] - [f.content.blockOf(' ')/] - [if (f.inputs->notEmpty())] - datasources: - [for (i : String | f.inputs)] - - inputName: [i/] - datasourceName: [d.application.dashboards.datasource/] - [/for] - [/if] - [/for] -[/template] - -[comment ======================================================== the node agents /] - -[comment One part of the Node Agents: their workloads, their ServiceAccounts, their cluster roles and - bindings, or the settings file of each that reads one. Each carries the labels a node agent - carries, which name no instance and no component. /] -[template private objects(d : resolveddeployment::NodeAgentFile)] - [for (a : resolveddeployment::ResolvedNodeAgent | d.agents)] - [if (d.part = 'workload')] - [a.agentWorkload()/] - [elseif (d.part = 'serviceaccount')] - --- - apiVersion: v1 - kind: ServiceAccount - metadata: - [a.agentMetadata()/] - [elseif (d.part = 'rbac')] - [a.agentRbac()/] - [elseif (d.part = 'vso')] - [if (a.memberlist <> null)] - [a.agentSecrets()/] - [/if] - [else] - --- - apiVersion: v1 - kind: ConfigMap - metadata: - [a.agentMetadata()/] - data: - [a.config.file/]: [a.config.content.chomping()/] - [a.config.content.blockOf(' ')/] - [/if] - [/for] -[/template] - -[template private agentMetadata(a : resolveddeployment::ResolvedNodeAgent)] - name: [a.name/] - namespace: [a.namespace/] - labels: - [a.agentLabels()/] -[/template] - -[template private agentLabels(a : resolveddeployment::ResolvedNodeAgent)] - app.kubernetes.io/managed-by: deploy-kit - app.kubernetes.io/name: [a.name/] - app.kubernetes.io/part-of: [a.application/] -[/template] - -[comment A DaemonSet agent replaces one node's pod at a time; the controller of a fixed count stops - before it starts again. /] -[template private agentWorkload(a : resolveddeployment::ResolvedNodeAgent)] - --- - apiVersion: apps/v1 - kind: [a.controller.toString()/] - metadata: - [a.agentMetadata()/] - spec: - [if (a.replicas <> null)] - replicas: [a.replicas/] - strategy: - type: Recreate - [/if] - selector: - matchLabels: - app.kubernetes.io/name: [a.name/] - [if (a.replicas = null)] - updateStrategy: - type: RollingUpdate - rollingUpdate: - maxUnavailable: 1 - [/if] - template: - metadata: - labels: - [a.agentLabels()/] - spec: - serviceAccountName: [a.name/] - automountServiceAccountToken: [a.identityToken/] - priorityClassName: [a.priorityClass/] - securityContext: - seccompProfile: - type: RuntimeDefault - [if (a.hostNetwork)] - hostNetwork: true - [/if] - [if (a.hostProcesses)] - hostPID: true - [/if] - [if (a.runtimeClass <> null)] - runtimeClassName: [a.runtimeClass/] - [/if] - affinity: - nodeAffinity: - requiredDuringSchedulingIgnoredDuringExecution: - nodeSelectorTerms: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - [for (n : String | a.eligibleNodes)] - - [n/] - [/for] - containers: - [a.agentContainer()/] - [if (a.mounts->notEmpty() or a.config <> null or a.memberlist <> null)] - volumes: - [for (m : resolveddeployment::HostMount | a.mounts)] - - name: [m.name/] - hostPath: - path: [m.hostPath/] - [/for] - [if (a.config <> null)] - - name: config - configMap: - name: [a.name/] - [/if] - [if (a.memberlist <> null)] - - name: memberlist - secret: - secretName: [a.memberlist.secret/] - [/if] - [/if] -[/template] - -[template private agentContainer(a : resolveddeployment::ResolvedNodeAgent)] - - name: [a.name/] - image: [a.image/] - [if (a.arguments->notEmpty())] - args: - [for (g : String | a.arguments)] - - [g.scalar()/] - [/for] - [/if] - [if (a.environment->notEmpty())] - env: - [for (e : resolveddeployment::EnvEntry | a.environment)] - [if (e.field <> null)] - - name: [e.name/] - valueFrom: - fieldRef: - fieldPath: [e.field/] - [else] - - name: [e.name/] - value: [e.value.scalar()/] - [/if] - [/for] - [/if] - [if (a.surfaces->notEmpty())] - ports: - [for (s : resolveddeployment::ResolvedSurface | a.surfaces)] - - name: [s.name/] - containerPort: [s.port/] - [/for] - [/if] - resources: - requests: - memory: [a.memory/] - cpu: [a.cpu/] - limits: - memory: [a.memory/] - [if (a.deviceShare <> null)] - [a.deviceShare/]: "1" - [/if] - securityContext: - [if (a.privileged)] - privileged: true - [else] - [if (a.nonRoot <> null)] - runAsNonRoot: [a.nonRoot/] - [/if] - [if (a.uid <> null)] - runAsUser: [a.uid/] - [/if] - [if (a.gid <> null)] - runAsGroup: [a.gid/] - [/if] - [if (a.confined)] - allowPrivilegeEscalation: false - readOnlyRootFilesystem: true - [/if] - capabilities: - [if (a.addedPrivileges->notEmpty())] - add: - [for (c : String | a.addedPrivileges)] - - [c/] - [/for] - [/if] - drop: - - ALL - [/if] - [if (a.mounts->notEmpty() or a.config <> null or a.memberlist <> null)] - volumeMounts: - [for (m : resolveddeployment::HostMount | a.mounts)] - - name: [m.name/] - mountPath: [m.mountAt/] - [if (m.readOnly)] - readOnly: true - [/if] - [if (m.propagated)] - mountPropagation: HostToContainer - [/if] - [/for] - [if (a.config <> null)] - - name: config - mountPath: [a.config.mountAt/] - readOnly: true - [/if] - [if (a.memberlist <> null)] - - name: memberlist - mountPath: /etc/ml_secret_key - readOnly: true - [/if] - [/if] -[/template] - -[comment An agent's cluster role and its binding, both named for the agent's Project and the agent, - then the role and binding of what it reads in its own namespace alone, named for the agent. /] -[template private agentRbac(a : resolveddeployment::ResolvedNodeAgent)] - --- - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRole - metadata: - name: [a.application/]:[a.name/] - labels: - [a.agentLabels()/] - rules: - [for (r : resolveddeployment::ResolvedApiRule | a.rules->select(r | r.scope = resolveddeployment::RuleScope::cluster))] - [r.rule()/] - [/for] - --- - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRoleBinding - metadata: - name: [a.application/]:[a.name/] - labels: - [a.agentLabels()/] - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: [a.application/]:[a.name/] - subjects: - - kind: ServiceAccount - name: [a.name/] - namespace: [a.namespace/] - [if (a.rules->exists(r | r.scope = resolveddeployment::RuleScope::namespace))] - --- - apiVersion: rbac.authorization.k8s.io/v1 - kind: Role - metadata: - [a.agentMetadata()/] - rules: - [for (r : resolveddeployment::ResolvedApiRule | a.rules->select(r | r.scope = resolveddeployment::RuleScope::namespace))] - [r.rule()/] - [/for] - --- - apiVersion: rbac.authorization.k8s.io/v1 - kind: RoleBinding - metadata: - [a.agentMetadata()/] - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: [a.name/] - subjects: - - kind: ServiceAccount - name: [a.name/] - namespace: [a.namespace/] - [/if] -[/template] - -[comment Where the speaker runs memberlist: how the operator signs in as it, and the static secret its - key lands in, whose change restarts every speaker, since each reads its key at start. /] -[template private agentSecrets(a : resolveddeployment::ResolvedNodeAgent)] - --- - apiVersion: secrets.hashicorp.com/v1beta1 - kind: VaultAuth - metadata: - [a.agentMetadata()/] - spec: - vaultConnectionRef: secret-store - method: kubernetes - mount: kubernetes - kubernetes: - role: [a.namespace/]-[a.name/] - serviceAccount: [a.name/] - --- - apiVersion: secrets.hashicorp.com/v1beta1 - kind: VaultStaticSecret - metadata: - name: [a.memberlist.secret/] - namespace: [a.namespace/] - labels: - [a.agentLabels()/] - spec: - vaultAuthRef: [a.name/] - mount: secret - type: kv-v2 - path: [a.memberlist.path.substring(13)/] - refreshAfter: 10m - hmacSecretData: true - destination: - name: [a.memberlist.secret/] - create: true - annotations: - flagger.app/config-tracking: disabled - rolloutRestartTargets: - - kind: DaemonSet - name: [a.name/] -[/template] - -[comment One rule of a role. `core` is the group Kubernetes itself spells as no name at all. /] -[template private rule(r : resolveddeployment::ResolvedApiRule)] - - apiGroups: - - [if (r.group = 'core')]""[else][r.group/][/if] - resources: - [for (o : String | r.objects)] - - [o/] - [/for] - verbs: - [for (v : String | r.verbs)] - - [v/] - [/for] -[/template] - -[comment Each pool the speaker answers for, an address no Service takes unless it names the pool, and - its advertisement from the nodes named. /] -[template private objects(d : resolveddeployment::AddressPoolFile)] - [for (p : resolveddeployment::ResolvedAddressPool | d.pools)] - --- - apiVersion: metallb.io/v1beta1 - kind: IPAddressPool - metadata: - name: [p.name/] - namespace: [d.namespace/] - labels: - app.kubernetes.io/managed-by: deploy-kit - spec: - addresses: - - [p.range/] - autoAssign: false - --- - apiVersion: metallb.io/v1beta1 - kind: L2Advertisement - metadata: - name: [p.name/] - namespace: [d.namespace/] - labels: - app.kubernetes.io/managed-by: deploy-kit - spec: - ipAddressPools: - - [p.name/] - nodeSelectors: - - matchExpressions: - - key: kubernetes.io/hostname - operator: In - values: - [for (n : String | p.nodes)] - - [n/] - [/for] - [/for] -[/template] - -[comment ========================================================== the sources /] - -[comment What Flux pulls a Project's pinned render from, verified as the composition signed it, and - each unit it applies from it: pruned, waited on, and healthy once every claim is bound or waits - for its first consumer. /] -[template private objects(d : resolveddeployment::SourceFile)] - --- - apiVersion: source.toolkit.fluxcd.io/v1 - kind: OCIRepository - metadata: - name: [d.source.name/] - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit - spec: - interval: 10m - url: [d.source.url/] - ref: - digest: [d.source.digest/] - verify: - provider: cosign - matchOIDCIdentity: - - issuer: [d.source.issuer/] - subject: [d.source.subject/] - [for (u : resolveddeployment::FluxUnit | d.units)] - [u.unit(d.source)/] - [/for] -[/template] - -[template private unit(u : resolveddeployment::FluxUnit, s : resolveddeployment::RenderSource)] - --- - apiVersion: kustomize.toolkit.fluxcd.io/v1 - kind: Kustomization - metadata: - name: [u.name/] - namespace: flux-system - labels: - app.kubernetes.io/managed-by: deploy-kit - [if (u.annotations->notEmpty())] - annotations: - [for (a : resolveddeployment::KeyValue | u.annotations)] - [a.key/]: [a.value.scalar()/] - [/for] - [/if] - spec: - interval: 10m - prune: true - wait: true - healthCheckExprs: - - apiVersion: v1 - kind: PersistentVolumeClaim - current: status.phase == 'Bound' || status.phase == 'Pending' && !(has(metadata.annotations) && 'volume.kubernetes.io/selected-node' in metadata.annotations) - sourceRef: - kind: OCIRepository - name: [s.name/] - path: [u.path/] - [if (u.dependsOn->notEmpty())] - dependsOn: - [for (n : String | u.dependsOn)] - - name: [n/] - [/for] - [/if] - [if (u.forcesDeployments)] - patches: - - patch: | - apiVersion: apps/v1 - kind: Deployment - metadata: - name: any - annotations: - kustomize.toolkit.fluxcd.io/force: Enabled - target: - kind: Deployment - [/if] -[/template] - -[comment ========================================================== the estate /] - -[comment The two priority classes, the datastore's first: neither is the default, and each may evict a - lower one. Which of the two a class is fixes its description. /] -[template private objects(d : resolveddeployment::PriorityClassFile)] - [d.data.priorityClass('A datastore: it schedules before what reads it.')/] - [d.critical.priorityClass('The foundation and the Applications the platform names: they keep scheduling under pressure.')/] -[/template] - -[template private priorityClass(p : resolveddeployment::ResolvedPriority, description : String)] - --- - apiVersion: scheduling.k8s.io/v1 - kind: PriorityClass - metadata: - name: [p.name/] - labels: - app.kubernetes.io/managed-by: deploy-kit - value: [p.value/] - globalDefault: false - preemptionPolicy: PreemptLowerPriority - description: [description.scalar()/] -[/template] - -[comment A Human Grant: the sign-in provider's group bound to a cluster role, under a name both make. /] -[template private objects(d : resolveddeployment::HumanGrantFile)] - [for (g : resolveddeployment::HumanGrantBinding | d.grants)] - --- - apiVersion: rbac.authorization.k8s.io/v1 - kind: ClusterRoleBinding - metadata: - name: human:[g.group/]:[g.clusterRole/] - labels: - app.kubernetes.io/managed-by: deploy-kit - roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: [g.clusterRole/] - subjects: - - apiGroup: rbac.authorization.k8s.io - kind: Group - name: [g.group/] - [/for] -[/template] - -[comment One item of a list of words: a scalar, or a block scalar where the word spans lines, its - lines one by one, since a template's lines take the column it is called at and an expression's - later lines do not reliably. A blank line of such a word is not kept. /] -[template private listItem(value : String)] - [if (value.contains('\n'))] - - [value.chomping()/] - [for (l : String | value.tokenize('\n'))] - [l/] - [/for] - [else] - - [value.scalar()/] - [/if] -[/template] - -[comment ============================================================= queries /] - -[comment The containers of a Process's pod whose image the lock records a version for, by name. /] -[query private versioned(p : resolveddeployment::ResolvedProcess) : Sequence(String) = - (if p.imageVersion = null then Sequence{} else Sequence{p.name} endif) - ->concat(p.sidecars->select(c | c.imageVersion <> null)->collect(c | c.name)) - ->concat(if p.vpn = null or p.vpn.imageVersion = null then Sequence{} else Sequence{'vpn'} endif) - ->concat(if p.seeder = null or p.seeder.imageVersion = null then Sequence{} else Sequence{'seed'} endif) - ->sortedBy(n | n) /] - -[query private versionOf(p : resolveddeployment::ResolvedProcess, n : String) : String = - if n = p.name then p.imageVersion - else if p.sidecars->exists(c | c.name = n) then p.sidecars->select(c | c.name = n)->first().imageVersion - else if n = 'seed' and p.seeder <> null then p.seeder.imageVersion - else p.vpn.imageVersion endif endif endif /] - -[comment Whether the Process is a member of its Application's release gate, whose pods carry the label - the Release Gate's policy admits. /] -[query private member(p : resolveddeployment::ResolvedProcess) : Boolean = - p.application().releaseGate <> null and p.application().releaseGate.members->exists(m | m.process = p) /] - -[comment The keys a monitor writes itself: the platform's selector labels never replace them, so each is written once. /] -[query private ownLabelKeys(p : resolveddeployment::ResolvedProcess) : Sequence(String) = - Sequence{'app.kubernetes.io/name', 'app.kubernetes.io/instance', 'app.kubernetes.io/part-of', 'app.kubernetes.io/managed-by', 'app.kubernetes.io/component'} /] - -[query private ownApplicationLabelKeys(a : resolveddeployment::ResolvedApplication) : Sequence(String) = - Sequence{'app.kubernetes.io/part-of', 'app.kubernetes.io/managed-by'} /] - -[query private application(p : resolveddeployment::ResolvedProcess) : resolveddeployment::ResolvedApplication = - p.eContainer().oclAsType(resolveddeployment::ResolvedApplication) /] - -[comment What the Release Gate's checks request (spec/v1/55-delivery.md#the-release-gate): every - Route's path to the Process, the path its readiness is asked on, and the host of each Route the - internet reaches. Each list holds a value once, in order. /] -[query private routed(p : resolveddeployment::ResolvedProcess) : Sequence(resolveddeployment::ResolvedRoute) = - p.application().exposure->collect(e | e.routes)->select(r | r.process = p)->asSequence() /] - -[query private paths(p : resolveddeployment::ResolvedProcess) : Sequence(String) = - p.routed()->collect(r | r.path)->asOrderedSet()->sortedBy(v | v)->asSequence() /] - -[query private hostnames(p : resolveddeployment::ResolvedProcess) : Sequence(String) = - p.application().exposure - ->select(e | e.routes->exists(r | r.process = p and (r.audience = 'anonymous' or r.audience = 'authenticated'))) - ->collect(e | e.host)->asOrderedSet()->sortedBy(v | v)->asSequence() /] - -[comment One generated key as its JSON object, the location it adopts its value from last where it - adopts one. One expression rather than a block in a line, which would break the line's - indentation; each line after the first takes the indentation of the line it starts on. /] -[query private entry(k : resolveddeployment::ResolvedGeneratedKey) : String = - '{\n "path": "' + k.path + '",\n "key": "' + k.key + '",\n "bytes": ' + k.bytes.toString() - + ',\n "encoding": "' + k.encoding + '"' - + (if k.adoptPath = null then '' - else ',\n "adopt": {\n "path": "' + k.adoptPath + '",\n "key": "' + k.adoptKey + '"\n }' endif) - + '\n}' /] - -[query private readinessPath(p : resolveddeployment::ResolvedProcess) : String = - p.application().releaseGate.members - ->select(m | m.process = p and m.readiness.oclIsKindOf(resolveddeployment::HttpTarget)) - ->collect(m | m.readiness.oclAsType(resolveddeployment::HttpTarget).path)->first() /] - -[query private application(m : resolveddeployment::ResolvedMigration) : resolveddeployment::ResolvedApplication = - m.eContainer().oclAsType(resolveddeployment::ResolvedApplication) /] - -[query private application(e : resolveddeployment::ResolvedExposure) : resolveddeployment::ResolvedApplication = - e.eContainer().oclAsType(resolveddeployment::ResolvedApplication) /] - -[query private projectNamespace(d : resolveddeployment::Deliverable) : String = - d.eContainer().oclAsType(resolveddeployment::ResolvedDeployment).applications->first().namespace /] - -[comment A duration as whole seconds: `60s` is 60, `10m` 600 and `1h` 3600. /] -[query private seconds(duration : String) : Integer = - let amount : Integer = duration.substring(1, duration.size() - 1).toInteger() in - if duration.endsWith('h') then amount * 3600 - else if duration.endsWith('m') then amount * 60 else amount endif endif /] - -[comment Every range a backup of the Process copies off-cluster to, once each in the order met: the - first of each cidr and port. /] -[query private backupRanges(p : resolveddeployment::ResolvedProcess) : Sequence(resolveddeployment::AdmittedRange) = - let all : Sequence(resolveddeployment::AdmittedRange) = p.backups().backup.destinations in - all->select(r | all->select(o | o.cidr = r.cidr and o.port = r.port)->first() = r) /] - -[comment The volumes whose class derives a backup. /] -[query private backups(p : resolveddeployment::ResolvedProcess) : Sequence(resolveddeployment::ResolvedVolume) = - p.volumes->select(v | v.backup <> null) /] - -[comment The file an Asset arrives as: the last segment of the path it is read from. /] -[query private fileOf(source : String) : String = source.tokenize('/')->last() /] - -[comment A writable path's volume, named for the path. /] -[query private writableOf(path : String) : String = 'writable' + path.replaceAll('[^a-z0-9]+', '-') /] - -[comment The Process's grants delivered as files, each synced to a Secret. /] -[query private files(p : resolveddeployment::ResolvedProcess) : OrderedSet(resolveddeployment::ResolvedGrant) = - p.secrets->select(g | g.delivery = 'file' and g.destination <> null) /] - -[comment Where a file grant's file lands is mounted whole, the directory of its mountAt, so a rotated - value reaches the file, which a mount of the one file would never see again. A credential's - mountAt is its directory already. /] -[query private directoryOf(g : resolveddeployment::ResolvedGrant) : String = - if g.engine = 'database' then g.mountAt - else g.mountAt.substring(1, g.mountAt.size() - g.mountAt.fileOf().size() - 1) endif /] - -[comment An octal file mode, such as 0400, as the number a volume's defaultMode holds. /] -[query private octal(mode : String) : Integer = - if mode.size() = 1 then mode.toInteger() - else mode.substring(1, mode.size() - 1).octal() * 8 + mode.substring(mode.size(), mode.size()).toInteger() endif /] - -[comment The Secret a kv grant on `path` syncs to, for the Process's own variables. /] -[query private destinationOf(p : resolveddeployment::ResolvedProcess, path : String) : String = - p.secrets->select(g | g.destination <> null - and (g.path = path or g.paths->exists(x | x.path = path)))->first().destination /] - -[comment The Deployment that serves for the Process of that name. /] -[comment Whether the container holds a variable, a mount, or a probe. /] -[query private holdsEnv(p : resolveddeployment::ResolvedProcess) : Boolean = - p.environment->notEmpty() or p.home <> null /] - -[query private mounts(p : resolveddeployment::ResolvedProcess) : Boolean = - p.volumes->notEmpty() or p.libraries->notEmpty() or p.assets->exists(a | a.seedAt = null) or p.writablePaths->notEmpty() or p.files()->notEmpty() or (p.vpn <> null and p.vpn.forwardedPort) /] - -[query private probed(p : resolveddeployment::ResolvedProcess) : Boolean = - p.readiness <> null or p.liveness <> null or p.startup <> null /] - -[query private servingOf(a : resolveddeployment::ResolvedApplication, name : String) : String = - a.processes->select(p | p.name = name)->first().serving /] - -[comment What the Prometheus operator runs a Process as, which it restarts from the StatefulSet it - names for its container and the Process. /] -[query private operatedOf(a : resolveddeployment::ResolvedApplication, name : String) : resolveddeployment::ResolvedOperated = - a.processes->select(p | p.name = name)->first().operated /] - -[comment How a block scalar keeps its last line break: once, not at all, or every one. /] -[query private chomping(content : String) : String = - if content.endsWith('\n\n') then '|+' else if content.endsWith('\n') then '|' else '|-' endif endif /] - -[comment A block scalar's body: every line under `indent`, a blank line left blank. The line the - call stands on ends the last line, so one line break is left for it to write, unless the body - keeps its trailing ones: a line that already ends in a break gets none more. /] -[query private blockOf(content : String, indent : String) : String = - (if content.endsWith('\n') and not content.endsWith('\n\n') then content.substring(1, content.size() - 1) else content endif) - .replaceAll('(?m)^(?=.)', indent) /] - -[comment Whether a string scalar is quoted: where a YAML 1.1 reader, which the Kubernetes API is, - would read it as null, a boolean, an integer, a float or a timestamp, or where a plain scalar - cannot hold it. /] -[query private quoted(value : String) : Boolean = - value.matches('|~|null|Null|NULL|y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF|[-+]?0b[0-1_]+|[-+]?0[0-7_]+|[-+]?[0-9][0-9_]*|[-+]?0x[0-9a-fA-F_]+|[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+|[-+]?([0-9][0-9_]*)?[.][0-9_]*([eE][-+]?[0-9]+)?|[-+]?[0-9][0-9_]*[eE][-+]?[0-9]+|[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+[.][0-9_]*|[-+]?[.](inf|Inf|INF)|[.](nan|NaN|NAN)|[0-9]{4}-[0-9]{1,2}-[0-9]{1,2}(([Tt]| +)[0-9]{1,2}:[0-9]{2}:[0-9]{2}([.][0-9]*)?( *(Z|[-+][0-9]{1,2}(:[0-9]{2})?))?)?') - or value.unplain() /] - -[comment A string scalar, double-quoted where it is quoted, and written plain otherwise. /] -[query private scalar(value : String) : String = - if value.quoted() then '"' + value + '"' else value endif /] - -[comment A string scalar of a rule-group file, as the production implementation's YAML writer writes - it: plain where it can be, single-quoted where it holds a double quote and no single one, and - double-quoted, escaped, otherwise. /] -[query private written(value : String) : String = - if not value.quoted() then value - else if value.contains('"') and not value.contains('\'') then '\'' + value + '\'' - else '"' + value.replaceAll('\\\\', '\\\\\\\\').replaceAll('"', '\\\\"') + '"' endif endif /] - -[comment A value of a rule-group file as an item of a block sequence at `indent`: the dash, and the - value after it, a collection's first line on the dash's own line. /] -[query private item(d : resolveddeployment::Datum, indent : String) : String = - indent + '- ' + (if d.oclIsKindOf(resolveddeployment::DatumScalar) - then d.oclAsType(resolveddeployment::DatumScalar).inline(indent + ' ') - else if d.hollow() then d.hollowText() - else d.lines(indent + ' ').substring(indent.size() + 3) endif endif) /] - -[comment An entry of a mapping at `indent`: its key, and its value after it, a collection's lines - under it, a sequence's indented as far as a mapping's. /] -[query private entry(e : resolveddeployment::DatumEntry, indent : String) : String = - indent + e.key.written() + ':' + (if e.value.oclIsKindOf(resolveddeployment::DatumScalar) - then ' ' + e.value.oclAsType(resolveddeployment::DatumScalar).inline(indent + ' ') - else if e.value.hollow() then ' ' + e.value.hollowText() - else '\n' + e.value.lines(indent + ' ') endif endif) /] - -[comment A mapping's or a sequence's lines at `indent`. /] -[query private lines(d : resolveddeployment::Datum, indent : String) : String = - if d.oclIsKindOf(resolveddeployment::DatumMap) - then d.oclAsType(resolveddeployment::DatumMap).entries->collect(e | e.entry(indent))->sep('\n')->toString() - else d.oclAsType(resolveddeployment::DatumList).items->collect(i | i.item(indent))->sep('\n')->toString() endif /] - -[comment Whether a mapping or a sequence holds nothing, which is written on its key's line. /] -[query private hollow(d : resolveddeployment::Datum) : Boolean = - if d.oclIsKindOf(resolveddeployment::DatumMap) then d.oclAsType(resolveddeployment::DatumMap).entries->isEmpty() - else d.oclAsType(resolveddeployment::DatumList).items->isEmpty() endif /] - -[query private hollowText(d : resolveddeployment::Datum) : String = - if d.oclIsKindOf(resolveddeployment::DatumMap) then '{}' else '[]' endif /] - -[comment A scalar after its key or its dash: a number, a boolean or a null as its text, a string of - several lines as a literal block scalar under `indent`, and any other string as written. /] -[query private inline(s : resolveddeployment::DatumScalar, indent : String) : String = - if s.kind <> resolveddeployment::DatumKind::string then s.text - else if s.text.contains('\n') and not s.text.matches('(?s).*\n[\t ]+') then - '|' + (if s.text.matches('(?s)[ \n]* .*') then '2' else '' endif) + s.text.blockChomp() + '\n' - + (if s.text.endsWith('\n') then s.text.substring(1, s.text.size() - 1) else s.text endif).replaceAll('(?m)^(?=.)', indent) - else s.text.written() endif endif /] - -[comment How a block scalar of a string keeps its trailing line breaks: none, one, or every one. /] -[query private blockChomp(value : String) : String = - if value.matches('(?s).*\n[\n\t ]*\n') then '+' else if value.endsWith('\n') then '' else '-' endif endif /] - -[comment Whether a plain scalar cannot hold the value: it opens on an indicator, holds a mapping's - separator or a comment's, ends on a colon, or opens or ends on a space. /] -[query private unplain(value : String) : Boolean = - if value.size() = 0 then false - else Sequence{',', '[', ']', '{', '}', '#', '&', '*', '!', '|', '>', '"', '%', '@', '`'}->includes(value.substring(1, 1)) - or value.startsWith('\'') or value.matches('[-?:]( .*)?') or value.matches('.*: .*') - or value.matches('.* #.*') or value.endsWith(':') or value.startsWith(' ') or value.endsWith(' ') endif /] diff --git a/emf/bundles/render/pom.xml b/emf/bundles/render/pom.xml deleted file mode 100644 index 882c73719..000000000 --- a/emf/bundles/render/pom.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - 4.0.0 - - - dev.jorisjonkers.deploykit.emf - emf-parent - 0.1.0-SNAPSHOT - ../../pom.xml - - - dev.jorisjonkers.deploykit.emf.render - eclipse-plugin - deploy-kit model-driven render - diff --git a/emf/bundles/render/render.launch b/emf/bundles/render/render.launch deleted file mode 100644 index 2cf91af9e..000000000 --- a/emf/bundles/render/render.launch +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - diff --git a/emf/bundles/render/src/main/java/dev/jorisjonkers/deploykit/emf/render/RenderModel.java b/emf/bundles/render/src/main/java/dev/jorisjonkers/deploykit/emf/render/RenderModel.java deleted file mode 100644 index 5b713c850..000000000 --- a/emf/bundles/render/src/main/java/dev/jorisjonkers/deploykit/emf/render/RenderModel.java +++ /dev/null @@ -1,34 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.render; - -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentPackage; -import java.nio.file.Path; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl; - -/** - * The rendering run on one Resolved Deployment model file, the run {@code render.launch} makes in - * Eclipse: {@code args[0]} the model, {@code args[1]} the directory its Deliverable Set is written - * under, through {@link Rendering#render}, the entry the pipeline and the tests use. - * - *

The model's package is registered by its namespace URI in the model's own resource set, so a model - * that names no schema location loads as the generated classes the templates are written against, - * whether or not a workspace or a plug-in registry knows the package. - */ -public final class RenderModel { - - private RenderModel() {} - - public static void main(String[] args) { - ResourceSet resources = new ResourceSetImpl(); - resources.getPackageRegistry().put(ResolvedDeploymentPackage.eNS_URI, ResolvedDeploymentPackage.eINSTANCE); - resources.getResourceFactoryRegistry().getExtensionToFactoryMap().put("*", new XMIResourceFactoryImpl()); - Resource model = resources.getResource( - URI.createFileURI(Path.of(args[0]).toAbsolutePath().toString()), true); - Rendering.render( - model.getContents().stream().map(ResolvedDeployment.class::cast).toList(), Path.of(args[1])); - } -} diff --git a/emf/bundles/render/src/main/java/dev/jorisjonkers/deploykit/emf/render/Rendering.java b/emf/bundles/render/src/main/java/dev/jorisjonkers/deploykit/emf/render/Rendering.java deleted file mode 100644 index 3814cd601..000000000 --- a/emf/bundles/render/src/main/java/dev/jorisjonkers/deploykit/emf/render/Rendering.java +++ /dev/null @@ -1,154 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.render; - -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentPackage; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.function.Function; -import java.util.stream.Stream; -import org.eclipse.acceleo.Module; -import org.eclipse.acceleo.aql.AcceleoUtil; -import org.eclipse.acceleo.aql.evaluation.AcceleoEvaluator; -import org.eclipse.acceleo.aql.evaluation.strategy.DefaultGenerationStrategy; -import org.eclipse.acceleo.aql.evaluation.strategy.DefaultWriterFactory; -import org.eclipse.acceleo.aql.parser.AcceleoParser; -import org.eclipse.acceleo.aql.parser.ModuleLoader; -import org.eclipse.acceleo.query.runtime.impl.namespace.ClassLoaderQualifiedNameResolver; -import org.eclipse.acceleo.query.runtime.namespace.IQualifiedNameQueryEnvironment; -import org.eclipse.emf.common.util.BasicMonitor; -import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; -import org.eclipse.emf.ecore.util.EcoreUtil; -import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; - -/** - * The rendering, {@code render.mtl}, run on Resolved Deployments: every Deliverable they carry - * written under a root, at the path the path plan assigned it (spec/v1/30-deliverables.md). The - * templates write the files as they stand; nothing formats them afterwards. - */ -public final class Rendering { - - private static final String MODULE = "render"; - private static final String SEPARATOR = "::"; - private static final String NEW_LINE = "\n"; - private static final String MODEL = "rendered.resolveddeployment"; - - /** The refusals of a rendering that refuses nothing it writes. */ - private static final Function> NOTHING = aside -> List.of(); - - private Rendering() {} - - /** - * The Deliverable Sets of {@code deployments}, written under {@code root}. The Deployments are - * copied, so the caller's models are left as they were. The files are written aside, to {@link - * #asideOf}, and moved under {@code root} only once every one is written: a template that does not - * parse or fails to evaluate fails the rendering with what Acceleo said and leaves {@code root} as - * it was, rather than a partial tree to be read as whole. - */ - public static void render(List deployments, Path root) { - render(deployments, root, MODULE, NOTHING); - } - - /** - * {@code deployments} rendered under {@code root} unless {@code refusals} finds something wrong - * with the files as written aside: then nothing is moved under {@code root}, and what it found is - * returned. - */ - public static List render( - List deployments, Path root, Function> refusals) { - return render(deployments, root, MODULE, refusals); - } - - /** {@code deployments} rendered by the named module: the seam a test drives a broken one through. */ - static void render(List deployments, Path root, String module) { - render(deployments, root, module, NOTHING); - } - - private static List render( - List deployments, Path root, String module, Function> refusals) { - Path aside = asideOf(root); - try { - delete(aside); - try { - Files.createDirectories(aside); - generate(deployments, aside, module); - List refused = refusals.apply(aside); - if (refused.isEmpty()) { - moveUnder(aside, root); - } - return refused; - } finally { - delete(aside); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private static void generate(List deployments, Path root, String module) { - ResourceSet resources = new ResourceSetImpl(); - resources.getPackageRegistry().put(ResolvedDeploymentPackage.eNS_URI, ResolvedDeploymentPackage.eINSTANCE); - Resource model = new XMIResourceImpl(URI.createURI(MODEL)); - resources.getResources().add(model); - model.getContents().addAll(EcoreUtil.copyAll(deployments)); - ClassLoaderQualifiedNameResolver resolver = new ClassLoaderQualifiedNameResolver( - Rendering.class.getClassLoader(), resources.getPackageRegistry(), SEPARATOR); - IQualifiedNameQueryEnvironment environment = - AcceleoUtil.newAcceleoQueryEnvironment(Map.of(), resolver, resources, false); - // A template's parameter type resolves only against the packages its environment knows. - environment.registerEPackage(ResolvedDeploymentPackage.eINSTANCE); - AcceleoEvaluator evaluator = new AcceleoEvaluator(environment.getLookupEngine(), NEW_LINE); - resolver.addLoader(new ModuleLoader(new AcceleoParser(), evaluator)); - // The templates call no Java service, so there is none to clean up after the run. - AcceleoUtil.generate( - evaluator, - environment, - (Module) resolver.resolve(module), - model, - new DefaultGenerationStrategy(resources.getURIConverter(), new DefaultWriterFactory()), - URI.createFileURI(root.toAbsolutePath() + "/"), - null, - new BasicMonitor()); - Diagnostic diagnostic = evaluator.getGenerationResult().getDiagnostic(); - if (diagnostic.getSeverity() != Diagnostic.OK) { - throw new IllegalStateException("the rendering did not complete: " + diagnostic); - } - } - - /** Where a rendering into {@code root} writes before it is whole: beside it, and gone after it. */ - static Path asideOf(Path root) { - Path absolute = root.toAbsolutePath(); - return absolute.resolveSibling(absolute.getFileName() + ".partial"); - } - - /** Every file under {@code from} moved to the same path under {@code root}, over what is there. */ - private static void moveUnder(Path from, Path root) throws IOException { - try (Stream files = Files.walk(from)) { - for (Path file : files.filter(Files::isRegularFile).toList()) { - Path target = root.resolve(from.relativize(file).toString()); - Files.createDirectories(target.getParent()); - Files.move(file, target, StandardCopyOption.REPLACE_EXISTING); - } - } - } - - private static void delete(Path directory) throws IOException { - if (!Files.exists(directory)) { - return; - } - try (Stream paths = Files.walk(directory)) { - for (Path path : paths.sorted(Comparator.reverseOrder()).toList()) { - Files.delete(path); - } - } - } -} diff --git a/emf/bundles/render/src/test/java/dev/jorisjonkers/deploykit/emf/render/RenderModelTest.java b/emf/bundles/render/src/test/java/dev/jorisjonkers/deploykit/emf/render/RenderModelTest.java deleted file mode 100644 index 707db2454..000000000 --- a/emf/bundles/render/src/test/java/dev/jorisjonkers/deploykit/emf/render/RenderModelTest.java +++ /dev/null @@ -1,48 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.render; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Map; -import java.util.TreeMap; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -/** The run render.launch makes: the committed minimal model rendered to minimal's committed tree. */ -class RenderModelTest { - - /** The directory holding {@code emf/pom.xml}, from wherever the test runs below it. */ - private static Path repository() { - Path dir = Path.of("").toAbsolutePath(); - while (!Files.isRegularFile(dir.resolve("emf/pom.xml"))) { - dir = dir.getParent(); - } - return dir; - } - - /** Every file below {@code root}, by its path below it. */ - private static Map tree(Path root) throws IOException { - Map files = new TreeMap<>(); - try (Stream paths = Files.walk(root)) { - for (Path file : paths.filter(Files::isRegularFile).toList()) { - files.put(root.relativize(file).toString().replace('\\', '/'), Files.readString(file)); - } - } - return files; - } - - @Test - void theCommittedMinimalModelRendersMinimalsCommittedTreeByteForByte(@TempDir Path out) throws IOException { - Path repository = repository(); - - RenderModel.main(new String[] { - repository.resolve("emf/models/minimal.resolveddeployment").toString(), out.toString() - }); - - assertThat(tree(out.resolve("apps/notes"))) - .isEqualTo(tree(repository.resolve("spec/v1/examples/minimal/rendered/apps/notes"))); - } -} diff --git a/emf/bundles/render/src/test/java/dev/jorisjonkers/deploykit/emf/render/RenderingTest.java b/emf/bundles/render/src/test/java/dev/jorisjonkers/deploykit/emf/render/RenderingTest.java deleted file mode 100644 index 347bc1292..000000000 --- a/emf/bundles/render/src/test/java/dev/jorisjonkers/deploykit/emf/render/RenderingTest.java +++ /dev/null @@ -1,204 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.render; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.AdapterName; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.GeneratedKeysFile; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.NamespaceFile; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedGeneratedKey; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.stream.Stream; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.io.TempDir; - -// The rendering seam (emf/docs/architecture.md#text-generation): a Resolved Deployment in, its files -// out, with nothing in between. Every committed tree is compared, from the transformation's output, -// through the pipeline's one entry (RenderedTreeTest in the cli bundle). -class RenderingTest { - - /** A Deployment holding one Deliverable: the namespace of a project. */ - private static ResolvedDeployment namespaceOnly() { - ResolvedDeploymentFactory model = ResolvedDeploymentFactory.eINSTANCE; - NamespaceFile namespace = model.createNamespaceFile(); - namespace.setPath("apps/notes/namespace.yaml"); - namespace.setAdapter(AdapterName.KUBERNETES); - namespace.setNamespace("notes-system"); - ResolvedDeployment deployment = model.createResolvedDeployment(); - deployment.getDeliverables().add(namespace); - return deployment; - } - - @Test - void aDeliverableIsWrittenAtItsPathUnderTheOneHeader(@TempDir Path out) throws IOException { - Rendering.render(List.of(namespaceOnly()), out); - - assertThat(Files.readString(out.resolve("apps/notes/namespace.yaml"))).isEqualTo(""" - # GENERATED. Never hand-edit. - --- - apiVersion: v1 - kind: Namespace - metadata: - name: notes-system - labels: - app.kubernetes.io/managed-by: deploy-kit - annotations: - kustomize.toolkit.fluxcd.io/prune: disabled - """); - } - - @Test - void aGeneratedKeyCarriesTheLocationItAdoptsItsValueFrom(@TempDir Path out) throws IOException { - ResolvedDeploymentFactory model = ResolvedDeploymentFactory.eINSTANCE; - GeneratedKeysFile keys = model.createGeneratedKeysFile(); - keys.setPath("apps/tribelt/vault-policy/policies/tribelt-system.generated.json"); - keys.setAdapter(AdapterName.VAULT_POLICY); - for (String name : List.of("session_key", "visitor_hmac_key")) { - ResolvedGeneratedKey key = model.createResolvedGeneratedKey(); - key.setPath("secret/data/tribelt-system/keys"); - key.setKey(name); - key.setBytes(32); - key.setEncoding("hex"); - keys.getKeys().add(key); - } - keys.getKeys().get(0).setAdoptPath("secret/data/platform/tribelt"); - keys.getKeys().get(0).setAdoptKey("session_key"); - ResolvedDeployment deployment = model.createResolvedDeployment(); - deployment.getDeliverables().add(keys); - - Rendering.render(List.of(deployment), out); - - assertThat(Files.readString(out.resolve("apps/tribelt/vault-policy/policies/tribelt-system.generated.json"))) - .isEqualTo(""" - { - "keys": [ - { - "path": "secret/data/tribelt-system/keys", - "key": "session_key", - "bytes": 32, - "encoding": "hex", - "adopt": { - "path": "secret/data/platform/tribelt", - "key": "session_key" - } - }, - { - "path": "secret/data/tribelt-system/keys", - "key": "visitor_hmac_key", - "bytes": 32, - "encoding": "hex" - } - ] - } - """); - } - - @Test - void theCallersDeploymentsAreLeftWhereTheyWere(@TempDir Path out) { - ResolvedDeployment deployment = namespaceOnly(); - - Rendering.render(List.of(deployment), out); - - assertThat(deployment.eResource()).isNull(); - assertThat(deployment.getDeliverables()).hasSize(1); - } - - @Test - void theNamedModuleSeamRendersWithTheRealModule(@TempDir Path out) { - Rendering.render(List.of(namespaceOnly()), out, "render"); - - assertThat(out.resolve("apps/notes/namespace.yaml")).exists(); - } - - @Test - void aTemplateThatDoesNotParseFailsTheRenderingWithWhatAcceleoSaid(@TempDir Path out) { - assertThatThrownBy(() -> Rendering.render(List.of(namespaceOnly()), out, "unindented")) - .isInstanceOf(IllegalStateException.class) - .hasMessageStartingWith("the rendering did not complete: ") - .hasMessageContaining("Acceleo parsing error"); - } - - @Test - void aRenderingLeavesNothingAside(@TempDir Path out) { - Rendering.render(List.of(namespaceOnly()), out); - - assertThat(Rendering.asideOf(out)).doesNotExist(); - } - - @Test - void aRenderingWritesOverWhatIsAlreadyAtAPath(@TempDir Path out) throws IOException { - Path namespace = out.resolve("apps/notes/namespace.yaml"); - Files.createDirectories(namespace.getParent()); - Files.writeString(namespace, "stale"); - - Rendering.render(List.of(namespaceOnly()), out); - - assertThat(Files.readString(namespace)).contains("name: notes-system"); - } - - @Test - void aTemplateThatFailsHalfwayLeavesTheRootAsItWasAndNothingAside(@TempDir Path directory) throws IOException { - Path out = directory.resolve("out"); - Files.createDirectories(out); - Files.writeString(out.resolve("kept.yaml"), "kept"); - - assertThatThrownBy(() -> Rendering.render(List.of(namespaceOnly()), out, "halfway")) - .isInstanceOf(IllegalStateException.class) - .hasMessageStartingWith("the rendering did not complete: "); - - try (Stream files = Files.walk(out)) { - assertThat(files.filter(Files::isRegularFile).map(out::relativize).map(Path::toString)) - .containsExactly("kept.yaml"); - } - assertThat(Rendering.asideOf(out)).doesNotExist(); - } - - @Test - void whatAFailedRenderingLeftAsideIsClearedByTheNext(@TempDir Path directory) throws IOException { - Path out = directory.resolve("out"); - Path leftover = Rendering.asideOf(out).resolve("apps/stale.yaml"); - Files.createDirectories(leftover.getParent()); - Files.writeString(leftover, "stale"); - - Rendering.render(List.of(namespaceOnly()), out); - - assertThat(out.resolve("apps/stale.yaml")).doesNotExist(); - assertThat(Rendering.asideOf(out)).doesNotExist(); - } - - @Test - void aRootThatCannotHoldTheFilesFailsTheRenderingAndLeavesNothingAside(@TempDir Path directory) throws IOException { - Path out = Files.writeString(directory.resolve("out"), "a file, not a directory"); - - assertThatThrownBy(() -> Rendering.render(List.of(namespaceOnly()), out)) - .isInstanceOf(UncheckedIOException.class); - - assertThat(Files.readString(out)).isEqualTo("a file, not a directory"); - assertThat(Rendering.asideOf(out)).doesNotExist(); - } - - @Test - void aRenderingWhoseFilesAreRefusedWritesNothingAndSaysWhy(@TempDir Path out) { - List refused = Rendering.render(List.of(namespaceOnly()), out, aside -> { - assertThat(aside.resolve("apps/notes/namespace.yaml")).exists(); - return List.of("refused"); - }); - - assertThat(refused).containsExactly("refused"); - assertThat(out).isEmptyDirectory(); - assertThat(Rendering.asideOf(out)).doesNotExist(); - } - - @Test - void aRenderingWhoseFilesAreNotRefusedIsWritten(@TempDir Path out) { - assertThat(Rendering.render(List.of(namespaceOnly()), out, aside -> List.of())) - .isEmpty(); - assertThat(out.resolve("apps/notes/namespace.yaml")).exists(); - } -} diff --git a/emf/bundles/render/src/test/resources/halfway.mtl b/emf/bundles/render/src/test/resources/halfway.mtl deleted file mode 100644 index 16b581d33..000000000 --- a/emf/bundles/render/src/test/resources/halfway.mtl +++ /dev/null @@ -1,14 +0,0 @@ -[module halfway('https://jorisjonkers.dev/deploy-kit/resolved-deployment/1')/] - -[comment Writes each Deliverable's file, then fails to evaluate: what a template that breaks on a - later file leaves behind. /] - -[comment @main /] -[template public render(deployment : resolveddeployment::ResolvedDeployment)] - [for (d : resolveddeployment::Deliverable | deployment.deliverables)] - [file (d.path, overwrite, 'UTF-8')] - [d.path/] - [/file] - [/for] - [deployment.noSuchQuery()/] -[/template] diff --git a/emf/bundles/render/src/test/resources/unindented.mtl b/emf/bundles/render/src/test/resources/unindented.mtl deleted file mode 100644 index 8c214b4d5..000000000 --- a/emf/bundles/render/src/test/resources/unindented.mtl +++ /dev/null @@ -1,10 +0,0 @@ -[module unindented('https://jorisjonkers.dev/deploy-kit/resolved-deployment/1')/] - -[comment A body written without its two spaces of margin, which Acceleo refuses to parse. /] - -[comment @main /] -[template public unindented(deployment : resolveddeployment::ResolvedDeployment)] -[file ('unindented.yaml', overwrite, 'UTF-8')] -# GENERATED. Never hand-edit. -[/file] -[/template] diff --git a/emf/bundles/resolve/META-INF/MANIFEST.MF b/emf/bundles/resolve/META-INF/MANIFEST.MF deleted file mode 100644 index 85af542a2..000000000 --- a/emf/bundles/resolve/META-INF/MANIFEST.MF +++ /dev/null @@ -1,12 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: deploy-kit model-driven resolve -Bundle-SymbolicName: dev.jorisjonkers.deploykit.emf.resolve;singleton:=true -Bundle-Version: 0.1.0.qualifier -Bundle-RequiredExecutionEnvironment: JavaSE-21 -Automatic-Module-Name: dev.jorisjonkers.deploykit.emf.resolve -Export-Package: dev.jorisjonkers.deploykit.emf.resolve -Require-Bundle: org.eclipse.emf.ecore, - org.eclipse.emf.ecore.xmi, - org.eclipse.m2m.qvt.oml, - dev.jorisjonkers.deploykit.emf.metamodel diff --git a/emf/bundles/resolve/build.properties b/emf/bundles/resolve/build.properties deleted file mode 100644 index 7ab845f9b..000000000 --- a/emf/bundles/resolve/build.properties +++ /dev/null @@ -1,6 +0,0 @@ -source.. = src/main/java/,\ - model/ -bin.includes = META-INF/,\ - plugin.xml,\ - .,\ - model/ diff --git a/emf/bundles/resolve/model/lower.qvto b/emf/bundles/resolve/model/lower.qvto deleted file mode 100644 index f0ac50848..000000000 --- a/emf/bundles/resolve/model/lower.qvto +++ /dev/null @@ -1,474 +0,0 @@ --- The lowering (spec/v1/10-project-intent.md#the-effective-intent, --- docs/adr/model/0012-shared-intent-descends-and-is-lowered.md). Source and target are the same metamodel: the shapes --- differ only in that EffectiveProject and EffectiveApplication carry no --- SharedIntent. Total, because every refusal it depends on fires before it. -modeltype PI uses 'https://jorisjonkers.dev/deploy-kit/project-intent/1'; -modeltype ECORE uses 'http://www.eclipse.org/emf/2002/Ecore'; - -transformation lower(in source : PI, out target : PI); - -main() { - source.rootObjects()[Project]->map lower(); -} - --- An unsettable feature is written only where the source states it: assigning --- what an unset one reads marks the copy set, with a null or, for an --- enumeration, its first literal, and the Effective Intent would then state what --- no author wrote. A null says so for a value; an enumeration has to be asked. -query ECORE::EObject::states(feature : String) : Boolean = - self.eIsSet(self.eClass().getEStructuralFeature(feature)); - -mapping Project::lower() : EffectiveProject { - -- Nobody authors the Effective Intent, so the document's header stays behind. - project := self.project; - owner := self.owner; - applications := self.applications->map lower(self); -} - -mapping Application::lower(in prj : Project) : EffectiveApplication { - id := self.id; - -- The Processes first: `resolveone` below can only find a copy once it exists. - processes := self.processes->map lower(self, prj); - if self.description <> null then description := self.description endif; - client := self.client.map copy(); - l4Exposure := self.l4Exposure->map copy(); - dashboards := self.dashboards->collect(d | object Dashboard { _from := d._from; }); - alertRules := self.alertRules->collect(r | object AlertRules { _from := r._from; }); - observability := self.observability.map copy(); - exposure := self.exposure->map copy(); - -- How the schema moves defines the Application, so it stays on it. - migration := self.migration.map copy(); -} - -mapping Migration::copy() : Migration - disjuncts ManagedMigration::copy, SelfMigration::copy, NoMigration::copy {} - -mapping ManagedMigration::copy() : ManagedMigration { - changelog := self.changelog; -} - -mapping SelfMigration::copy() : SelfMigration {} - -mapping NoMigration::copy() : NoMigration {} - -mapping Process::lower(in app : Application, in prj : Project) : Process { - init { - -- lowest level first, which is what decides every merge below - var levels : Sequence(Placement) := - Sequence{self.placement, app.placement, prj.placement}->select(p | p <> null); - var quantities : Sequence(Placement) := - Sequence{self.placement}->select(p | p <> null); - var withArch : Sequence(Placement) := levels->select(p | p.arch->notEmpty()); - var withSite : Sequence(Placement) := levels->select(p | p.site <> null); - var withDisk : Sequence(Placement) := levels->select(p | p.disk <> null); - var withGpu : Sequence(Placement) := levels->select(p | p.gpu <> null); - var withCapabilities : Sequence(Placement) := - levels->select(p | p.capabilities->notEmpty()); - var budgets : Sequence(String) := - Sequence{self.startupBudget, app.startupBudget, prj.startupBudget} - ->select(b | b <> null); - var cutovers : Sequence(Cutover) := - Sequence{self.cutover, app.cutover, prj.cutover} - ->select(c | c <> Cutover::absent); - } - - -- what identifies the Process, and is shared by nothing - name := self.name; - lifecycle := self.lifecycle; - image := self.image; - runtime := self.runtime; - if self.oclAsType(ECORE::EObject).states('engine') then engine := self.engine endif; - provides := self.provides->map copy(); - sidecars := self.sidecars->map copy(); - probes := self.probes.map copy(); - volumes := self.volumes->map copy(); - replicas := self.replicas.map copy(); - api := self.api.map copy(); - egress := self.egress.map copy(); - vpn := self.vpn.map copy(); - libraries := self.libraries->map copy(); - if self.description <> null then description := self.description endif; - if self.schedule <> null then schedule := self.schedule endif; - if self.parked <> null then parked := object Parked { reason := self.parked.reason; } endif; - command := self.command; - args := self.args; - spawns := self.spawns->map copyFor(self); - - -- Every copy is keyed on its Process: a mapping's result is cached per source - -- object, and a containment feature would move one shared copy to the last - -- Process that asked for it. - secrets := mergeGrants(mergeGrants(self.secrets, app.secrets), prj.secrets) - ->map copyFor(self); - dependsOn := mergeEdges(mergeEdges(self.dependsOn, app.dependsOn), prj.dependsOn) - ->map copyFor(self); - assets := mergeAssets(mergeAssets(self.assets, app.assets), prj.assets) - ->map copyFor(self); - -- a path is its own whole value, so the union is the merge - -- A path is its own identity, so the union is the merge, and a lower level's - -- declaration of a path is the one that holds. - writablePaths := mergePaths(mergePaths(self.writablePaths, app.writablePaths), prj.writablePaths) - ->map copyFor(self); - -- The Process's one file, its entries extended by every scope above, or none. - env := if self.env->union(app.env)->union(prj.env)->isEmpty() then Sequence{} - else Sequence{self.map envFor(app, prj)} endif; - - -- the single values, from the lowest level that declared one - if budgets->notEmpty() then startupBudget := budgets->first() endif; - -- A prepare Process cuts over nothing, so a shared answer does not reach it. - if self.lifecycle <> Lifecycle::prepare and self.lifecycle <> Lifecycle::scheduled - and cutovers->notEmpty() - then cutover := cutovers->first() endif; - - -- Key by key: each dimension from the lowest level that set it, the - -- quantities from the Process and nowhere else. - placement := if levels->isEmpty() then null else object Placement { - if quantities->notEmpty() and quantities->first().memory <> null - then memory := quantities->first().memory endif; - if quantities->notEmpty() and quantities->first().cpu <> null - then cpu := quantities->first().cpu endif; - arch := if withArch->isEmpty() then Sequence{} else withArch->first().arch endif; - if withSite->notEmpty() then site := withSite->first().site endif; - disk := if withDisk->isEmpty() then null - else withDisk->first().disk.map copyFor(self) endif; - gpu := if withGpu->isEmpty() then null - else withGpu->first().gpu.map copyFor(self) endif; - capabilities := if withCapabilities->isEmpty() then Sequence{} - else withCapabilities->first().capabilities endif; - } endif; -} - --- The entries of every file of one scope; no file varies by cluster. -query entriesIn(files : Collection(EnvFile)) : Sequence(EnvVariable) = - files->collect(f | f.entries)->asSequence(); - -query mergeEntries(own : Collection(EnvVariable), shared : Collection(EnvVariable)) - : Sequence(EnvVariable) = - own->asSequence()->union( - shared->asSequence()->select(e | own->forAll(m | m.name <> e.name))); - -mapping Process::envFor(in app : Application, in prj : Project) : EnvFile { - entries := mergeEntries( - mergeEntries(entriesIn(self.env), entriesIn(app.env)), - entriesIn(prj.env)) - ->map copyFor(self); -} - -mapping EnvVariable::copyFor(in owner : Process) : EnvVariable { - name := self.name; - value := self.value.map copyFor(owner); -} - -mapping EnvValue::copyFor(in owner : Process) : EnvValue - disjuncts EnvLiteral::copyFor, Placeholder::copyFor {} - -mapping EnvLiteral::copyFor(in owner : Process) : EnvLiteral { - text := self.text; -} - -mapping Placeholder::copyFor(in owner : Process) : Placeholder { - kind := self.kind; - -- Qualified: bare `source` is this transformation's input model parameter. - result.source := self.source; - if self.oclAsType(ECORE::EObject).states('suffix') then result.suffix := self.suffix endif; -} - --- The derived read path is the identity, so a `kv` grant and a `database` grant --- never collide. One boolean rather than a query per kind: a query redeclared on --- each subclass binds statically here, and every grant answered with the base. -query sameGrant(one : Grant, other : Grant) : Boolean = - (one.oclIsKindOf(KvGrant) and other.oclIsKindOf(KvGrant) - and one.oclAsType(KvGrant).path = other.oclAsType(KvGrant).path) - or (one.oclIsKindOf(DatabaseGrant) and other.oclIsKindOf(DatabaseGrant) - and one.oclAsType(DatabaseGrant).role = other.oclAsType(DatabaseGrant).role) - or (one.oclIsKindOf(TransitGrant) and other.oclIsKindOf(TransitGrant) - and one.oclAsType(TransitGrant).key = other.oclAsType(TransitGrant).key); - --- `own` and `shared` rather than `lower`: a parameter named `lower` shadows the --- transformation itself, and every call on it then resolves against the module. -query mergeGrants(own : Collection(Grant), shared : Collection(Grant)) : Sequence(Grant) = - own->asSequence()->union( - shared->asSequence()->select(g | own->forAll(m | not sameGrant(m, g)))); - --- `required` is excluded: the same edge declared twice is the same declaration. -query mergeEdges(own : Collection(DependencyEdge), shared : Collection(DependencyEdge)) - : Sequence(DependencyEdge) = - own->asSequence()->union( - shared->asSequence()->select(e | - own->forAll(m | m.application <> e.application or m.surface <> e.surface))); - --- Two files cannot arrive at one path, so where an Asset lands, mounted or --- seeded, is its identity. -query AssetDeclaration::landsAt() : String = - if self.oclIsKindOf(Asset) then self.oclAsType(Asset).mountAt - else self.oclAsType(SeededAsset).seedAt endif; - -query mergeAssets(own : Collection(AssetDeclaration), shared : Collection(AssetDeclaration)) - : Sequence(AssetDeclaration) = - own->asSequence()->union( - shared->asSequence()->select(a | own->forAll(m | m.landsAt() <> a.landsAt()))); - -query mergePaths(own : Collection(WritablePathDeclaration), shared : Collection(WritablePathDeclaration)) - : Sequence(WritablePathDeclaration) = - own->asSequence()->union( - shared->asSequence()->select(w | own->forAll(m | m.path <> w.path))); - -mapping WritablePathDeclaration::copyFor(in owner : Process) : WritablePathDeclaration - disjuncts PlainPath::copyFor, MemoryPath::copyFor {} - -mapping PlainPath::copyFor(in owner : Process) : PlainPath { - path := self.path; -} - -mapping MemoryPath::copyFor(in owner : Process) : MemoryPath { - path := self.path; - memory := self.memory; -} - --- A contained object has one container, so everything below is copied rather --- than referenced: the lowered model holds no pointer into the authored one. - -mapping Observability::copy() : Observability { - scrape := self.scrape.map copy(); -} - -mapping Scrape::copy() : Scrape { - path := self.path; - process := self.process.resolveone(Process); - surface := self.surface.resolveone(Surface); - if self.honorLabels <> null then honorLabels := self.honorLabels endif; -} - -mapping Exposure::copy() : Exposure { - name := self.name; - host := self.host; - audience := self.audience; - if self.oclAsType(ECORE::EObject).states('contentPolicy') - then contentPolicy := self.contentPolicy endif; - if self.proxied <> null then proxied := self.proxied endif; - routes := self.routes->map copy(); -} - -mapping Route::copy() : Route { - path := self.path; - match := self.match; - process := self.process.resolveone(Process); - surface := self.surface.resolveone(Surface); - if self.oclAsType(ECORE::EObject).states('audience') then audience := self.audience endif; - if self.redirectTo <> null then redirectTo := self.redirectTo endif; - rateLimit := self.rateLimit.map copy(); -} - -mapping RateLimit::copy() : RateLimit { - requests := self.requests; - per := self.per; -} - -mapping Surface::copy() : Surface { - key := self.key; - value := self.value; -} - -mapping Sidecar::copy() : Sidecar { - name := self.name; - image := self.image; - command := self.command; - args := self.args; - memory := self.memory; - cpu := self.cpu; - volumes := self.volumes->collect(v | object SidecarMount { claim := v.claim; mountAt := v.mountAt; }); - assets := self.assets->collect(a | object SidecarAsset { _from := a._from; mountAt := a.mountAt; }); - if self._init <> null then _init := self._init endif; -} - --- A spawn template is the Process's own, so it is copied whole. -mapping SpawnTemplate::copyFor(in owner : Process) : SpawnTemplate { - name := self.name; - image := self.image; - placement := object SpawnPlacement { memory := self.placement.memory; cpu := self.placement.cpu; }; - provides := self.provides->map copy(); - dependsOn := self.dependsOn->map copyFor(owner); - egress := self.egress.map copy(); -} - -mapping Client::copy() : Client { - signIn := self.signIn; - if self.exposure <> null then exposure := self.exposure endif; - if self.label <> null then label := self.label endif; - if self.description <> null then description := self.description endif; - if self.iconPath <> null then iconPath := self.iconPath endif; - if self.launchPath <> null then launchPath := self.launchPath endif; - redirectPaths := self.redirectPaths; - if self.protectedPath <> null then protectedPath := self.protectedPath endif; - if self.backChannelLogoutPath <> null then backChannelLogoutPath := self.backChannelLogoutPath endif; - if self.oclAsType(ECORE::EObject).states('credential') then credential := self.credential endif; - roles := self.roles; -} - --- The port's Process and surface are the lowered Process's, as a route's are. -mapping L4Exposure::copy() : L4Exposure { - address := self.address; - port := self.port; - protocol := self.protocol; - process := self.process.resolveone(Process); - surface := self.surface.resolveone(Surface); -} - -mapping DiskRequest::copyFor(in owner : Process) : DiskRequest { - media := self.media; -} - -mapping GpuRequest::copyFor(in owner : Process) : GpuRequest { - _class := self._class; - memory := self.memory; - vendor := self.vendor; - model := self.model; -} - -mapping DependencyEdge::copyFor(in owner : Process) : DependencyEdge { - application := self.application; - surface := self.surface; - if self.required <> null then required := self.required endif; - buckets := self.buckets; - credentials := self.credentials.map copyFor(owner); -} - -mapping Credentials::copyFor(in owner : Process) : Credentials { - if self.oclAsType(ECORE::EObject).states('delivery') then delivery := self.delivery endif; - if self.mountAt <> null then mountAt := self.mountAt endif; - if self.fileMode <> null then fileMode := self.fileMode endif; - rotation := self.rotation.map copyFor(owner); -} - -mapping AssetDeclaration::copyFor(in owner : Process) : AssetDeclaration - disjuncts Asset::copyFor, SeededAsset::copyFor {} - -mapping Asset::copyFor(in owner : Process) : Asset { - _from := self._from; - mountAt := self.mountAt; -} - -mapping SeededAsset::copyFor(in owner : Process) : SeededAsset { - _from := self._from; - seedAt := self.seedAt; -} - -mapping Volume::copy() : Volume { - claim := self.claim; - mountAt := self.mountAt; - if self.size <> null then size := self.size endif; - durability := self.durability; -} - -mapping LibraryMount::copy() : LibraryMount { - _library := self._library; - mountAt := self.mountAt; - if self.subPath <> null then subPath := self.subPath endif; - _access := self._access; -} - -mapping Egress::copy() : Egress { - to := self.to; - reason := self.reason; -} - -mapping VpnAttachment::copy() : VpnAttachment { - forwardedPort := self.forwardedPort; -} - -mapping ApiAccess::copy() : ApiAccess { - reason := self.reason; - rules := self.rules->collect(r | object ApiRule { - group := r.group; - objects := r.objects; - verbs := r.verbs; - if r.oclAsType(ECORE::EObject).states('scope') then scope := r.scope endif; - }); -} - -mapping Capacity::copy() : Capacity { - count := self.count; - reason := self.reason; - if self.oclAsType(ECORE::EObject).states('across') then across := self.across endif; -} - -mapping ProbePolicy::copy() : ProbePolicy - disjuncts Probes::copy, NoProbes::copy {} - -mapping Probes::copy() : Probes { - readiness := self.readiness.map copy(); - liveness := self.liveness.map copy(); -} - -mapping NoProbes::copy() : NoProbes {} - -mapping Probe::copy() : Probe - disjuncts HttpProbe::copy, TcpProbe::copy {} - -mapping HttpProbe::copy() : HttpProbe { - path := self.path; - port := self.port; -} - -mapping TcpProbe::copy() : TcpProbe { - tcp := self.tcp; -} - -mapping Grant::copyFor(in owner : Process) : Grant - disjuncts KvGrant::copyFor, DatabaseGrant::copyFor, TransitGrant::copyFor {} - -mapping KvGrant::copyFor(in owner : Process) : KvGrant { - path := self.path; - keys := self.keys->map copyFor(owner); - _access := self._access; - delivery := self.delivery; - if self.mountAt <> null then mountAt := self.mountAt endif; - if self.fileMode <> null then fileMode := self.fileMode endif; - rotation := self.rotation.map copyFor(owner); -} - -mapping KvKey::copyFor(in owner : Process) : KvKey - disjuncts PlainKey::copyFor, GeneratedKey::copyFor, OptionalKey::copyFor {} - -mapping OptionalKey::copyFor(in owner : Process) : OptionalKey { - name := self.name; - optional := self.optional; -} - -mapping PlainKey::copyFor(in owner : Process) : PlainKey { - name := self.name; -} - -mapping GeneratedKey::copyFor(in owner : Process) : GeneratedKey { - name := self.name; - generate := self.generate.map copyFor(owner); -} - -mapping Generate::copyFor(in owner : Process) : Generate { - if self.bytes <> null then bytes := self.bytes endif; - if self.adopt <> null then adopt := self.adopt endif; - if self.encoding <> KeyEncoding::absent then encoding := self.encoding endif; -} - -mapping DatabaseGrant::copyFor(in owner : Process) : DatabaseGrant { - engine := self.engine; - role := self.role; - delivery := self.delivery; - if self.mountAt <> null then mountAt := self.mountAt endif; - if self.fileMode <> null then fileMode := self.fileMode endif; - rotation := self.rotation.map copyFor(owner); -} - -mapping TransitGrant::copyFor(in owner : Process) : TransitGrant { - engine := self.engine; - key := self.key; - operations := self.operations; - delivery := self.delivery; - if self.mountAt <> null then mountAt := self.mountAt endif; - if self.fileMode <> null then fileMode := self.fileMode endif; - rotation := self.rotation.map copyFor(owner); -} - -mapping Rotation::copyFor(in owner : Process) : Rotation { - tolerates := self.tolerates; - if self.maxAge <> null then maxAge := self.maxAge endif; -} diff --git a/emf/bundles/resolve/model/resolution.qvto b/emf/bundles/resolve/model/resolution.qvto deleted file mode 100644 index 29e0ea0d9..000000000 --- a/emf/bundles/resolve/model/resolution.qvto +++ /dev/null @@ -1,4212 +0,0 @@ --- The resolution (spec/v1/20-resolved-deployment.md): one project of the lowered --- union, with the Platform document and the pinned inputs beside it, to its --- Resolved Deployment. It reads the Effective Intent and never the authored --- shape, so no derivation has to union three levels for itself --- (emf/docs/architecture.md#transformation). --- --- Every derived value is a mapping or a query here. Hashing is the one --- operation done outside the language, by the `Hashing` black box: a digest --- is a function of canonical bytes, which OCL has no way to produce. --- --- An input it cannot derive stops the run with a message naming what is missing, --- rather than write a model with a gap or a default in it. -import dev.jorisjonkers.deploykit.emf.hashing; - -modeltype PI uses 'https://jorisjonkers.dev/deploy-kit/project-intent/1'; -modeltype IN uses 'https://jorisjonkers.dev/deploy-kit/pinned-inputs/1'; -modeltype RD uses 'https://jorisjonkers.dev/deploy-kit/resolved-deployment/1'; -modeltype ECORE uses 'http://www.eclipse.org/emf/2002/Ecore'; - -transformation resolution(in intent : PI, in pinned : IN, out resolved : RD) - access library Hashing; - - --- The project of the union this run resolves, and the integrity the schema --- package it was rendered against records: both are inputs, never derived. -configuration property project : String; -configuration property integrity : String; - -property estate : Platform = intent.rootObjects()[Platform]->any(true); -property projects : Sequence(EffectiveProject) = - intent.rootObjects()[EffectiveProject]->sortedBy(p | p.project)->asSequence(); -property contract : NodeContract = pinned.rootObjects()[NodeContract]->any(true); -property lock : ImagesLock = pinned.rootObjects()[ImagesLock]->any(true); -property snapshot : ClusterState = pinned.rootObjects()[ClusterState]->any(true); --- Every proof written beside a project file of the union, and every Asset file. -property proofs : Sequence(ProvenApplication) = - pinned.rootObjects()[MigrationProof].applications->asSequence(); -property assetFiles : Sequence(AssetFile) = pinned.rootObjects()[AssetFile]->asSequence(); - --- Where an attached Process reads the port its provider forwards to it. -property FORWARDED_PORT_FILE : String = '/run/vpn/forwarded-port'; --- Why an attached Process reaches public addresses it declared no egress to. -property TUNNEL_REASON : String = 'the VPN\'s tunnel reaches its provider\'s servers'; --- The surface a Release Gate and a Secret Store answer on. -property HTTP_SURFACE : String = 'http'; - --- Where every Stable Address lives (spec/v1/16-dependencies.md#the-stable-address). -property STABLE_NAMESPACE : String = 'estate-system'; --- The path of the Reporter's `http` surface that receives Flux's events. -property EVENTS_PATH : String = '/flux'; --- Flux's notification controller, by the `app` label its own install gives its pods. -property FLUX_NOTIFIER : String = 'notification-controller'; --- How many hex digits of an Asset's content digest its name carries. -property CONTENT_DIGITS : Integer = 10; - --- A startup probe polls this often; its threshold covers the budget. -property STARTUP_PERIOD : Integer = 5; --- The deadline of a Process that declares no startup budget: the substrate's own. -property UNBUDGETED_DEADLINE : Integer = 600; --- The surface an exporting profile's collector receives on, and a gate answers on. -property OTLP_SURFACE : String = 'otlp'; -property DNS_PORT : Integer = 53; --- The runtime a backup identity's labels name: it runs no Runtime Profile. -property NO_RUNTIME : String = 'none'; --- The identity the Vault policy job runs as. -property POLICY_JOB : String = 'vault-policy'; --- How many hex digits of a revision its tag carries: what the migration Jobs are named by. -property TAG_DIGITS : Integer = 12; - --- What a library's volume and claim both state: a local volume holds a directory, never a size. -property LIBRARY_SIZE : String = '1Gi'; - --- The units an Application's routes wait on: the unit of each Project that declares a proxy one --- of its exposures' tiers names, unless it is the Application's own --- (spec/v1/20-resolved-deployment.md#the-reconcile-unit). -query proxiesAfter(app : EffectiveApplication, prj : String) : Sequence(String) = - app.exposure->collect(e | projectOf(tierFor(e.audience).traefik.id)) - ->select(p | p <> null and p <> prj)->collect(p | unitOf(p))->asSequence(); - --- Where a Project's own Vault policy job lands, and the documents it writes beside it. -query policyJobRoot(prj : String) : String = 'apps/' + prj + '/vault-policy/'; -query policiesOf(prj : String) : String = policyJobRoot(prj) + 'policies/'; - --- The unit a Project waits on before a Process of it may hold a credential: the unit of the --- Platform Project that declares the Secret Store each Project writes its own roles into --- (spec/v1/20-resolved-deployment.md#the-reconcile-unit). The store's own Project follows --- nothing, so it never reaches here. -query secretsAfter(prj : String) : Sequence(String) = - if estate.secretStore = null then Sequence{} else - let store : String = projectOf(estate.secretStore.id) in - if store = null then Sequence{} else Sequence{unitOf(store)} endif endif; - --- Whether `prj` declares the Secret Store. Its unit follows nothing: every unit that holds a --- grant follows it, so any unit it followed would close a cycle --- (spec/v1/20-resolved-deployment.md#the-reconcile-unit). -query holdsStore(prj : String) : Boolean = - estate.secretStore <> null and projectOf(estate.secretStore.id) = prj; - -main() { - assert fatal (unversioned()->isEmpty()) - with log(unversioned()->first() + ' records no version: E_IMAGE_VERSION_MISSING'); - -- The `node` Project is the Node Agents, which no project file declares. - if (project = NODE_PROJECT and not projects->exists(p | p.project = NODE_PROJECT)) { - estate.map nodeDeployment(); - } else { - projects->select(p | p.project = project)->any(true).map deployment(); - } endif; -} - --- Every alias the lock records no version for, sorted --- (spec/v1/20-resolved-deployment.md#the-images-lock): each refuses the set. -query unversioned() : Sequence(String) = - lock.images->select(i | i.version = null)->collect(i | i.alias)->sortedBy(a | a)->asSequence(); - --- ============================================================== the document - -mapping EffectiveProject::deployment() : ResolvedDeployment { - apiVersion := 'resolved.jorisjonkers.dev/v1'; - kind := 'ResolvedDeployment'; - -- The project's own unit, and every unit it must follow, which this - -- document carries so `after` is a reference and never a name. - reconcileUnits := Sequence{self.map unit()}->union(afterOf(self)->collect(n | object ReconcileUnit { name := n; })); - applications := self.applications->map application(self); - provenance := estate.map provenance(); - policyJob := policyJobOf(); - catalogJobs := catalogJobsOf(); - events := eventsRouteOf(); - deliverables := self.projectFiles() - ->union(self.applications->collect(a | a.applicationFiles(self))->flatten()) - ->union(self.vaultFiles()) - ->union(self.generatedKeysFiles()) - ->union(self.stableAddressFiles()) - ->union(platformFiles()); - end { - self.edgeFiles(result); - -- Only a complete element has a revision: it is the digest of all of it. - result.reconcileUnits->first().after := result.reconcileUnits->excluding(result.reconcileUnits->first()); - -- The revision is the production implementation's: the digest of the - -- Application's element in that implementation's canonical JSON, which - -- the rendered tree carries (spec/v1/20-resolved-deployment.md#the-application-revision). - self.applications->forEach(src) { - var res : ResolvedApplication := src.resolveone(ResolvedApplication); - res.revision := res.elementJson(src, self).rawDigestOf(); - }; - -- A migration's Jobs are named by the revision's tag, so only now do they have one. - result.deliverables[MigrationFile]->forEach(planned) { - planned.upTag := tagOf(planned.application.revision); - }; - -- A datastore this project runs applies its own catalog from this project's unit - -- (spec/v1/16-dependencies.md#applying-the-catalog). Its Vault documents stay the policy - -- job's, planned with it. - self.applications->forEach(app) { - app.processes->select(p | ownsDatabases(p) or ownsBuckets(p))->forEach(p) { - var root : String := 'apps/' + self.project + '/' + app.id + '/'; - result.catalogJobs->select(c | c.identity = p.name + '-catalog' - and c.namespace = namespaceOf(self.project))->forEach(c) { - result.deliverables += c.catalogFilesUnder(root); - var index : IndexFile := result.deliverables[IndexFile] - ->select(i | i.path = root + 'kustomization.yaml')->any(true); - -- Every Application's directory has its index: applicationFiles plans one. - assert fatal (index <> null) with log('no index under ' + root); - index.resources := index.resources->append(c.identity + '.yaml')->sortedBy(r | r); - -- Its own policy and role, which this Project's own job writes. - result.deliverables += object CatalogJobFile { - path := policiesOf(self.project) + c.role + '.policy.json'; - adapter := AdapterName::vaultPolicy; - part := 'policy'; job := c; }; - result.deliverables += object VaultRoleFile { - path := policiesOf(self.project) + c.role + '.role.json'; - adapter := AdapterName::vaultPolicy; - namespace := c.namespace; - identity := c.identity; }; - }; - }; - }; - -- The Project's own Vault policy job, where the platform names one and the Project holds - -- a document for it to write (spec/v1/20-resolved-deployment.md#the-vault-policy-job). - result.deliverables += policyJobFiles(result.policyJob, result.deliverables->select(d | - d.path.startsWith(policiesOf(self.project)))->asSequence(), policyJobRoot(self.project), namespaceOf(self.project)); - if (result.deliverables->exists(d | d.path = policyJobRoot(self.project) + 'kustomization.yaml')) { - var top : IndexFile := result.deliverables[IndexFile] - ->select(i | i.path = 'apps/' + self.project + '/kustomization.yaml')->any(true); - top.resources := top.resources->append('vault-policy')->sortedBy(r | r); - }; - -- The route Flux's events about this Project's unit take to the Reporter, where the - -- platform names one: its own Provider and Alert, in Flux's namespace, applied by this - -- Project's unit (spec/v1/55-delivery.md#rollouts). - if (result.events <> null) { - var root : String := 'apps/' + self.project + '/rollout-events/'; - result.deliverables += Sequence{'alert', 'provider'}->collect(piece | object EventsFile { - path := root + piece + '.yaml'; - adapter := AdapterName::kubernetes; - part := piece; - project := self.project; - events := result.events; - }.oclAsType(Deliverable)); - result.deliverables += object IndexFile { - path := root + 'kustomization.yaml'; - adapter := AdapterName::kubernetes; - resources := Sequence{'alert.yaml', 'provider.yaml'}; - }; - var index : IndexFile := result.deliverables[IndexFile] - ->select(i | i.path = 'apps/' + self.project + '/kustomization.yaml')->any(true); - index.resources := index.resources->append('rollout-events')->sortedBy(r | r); - }; - } -} - --- The Reconcile Unit of a project's Applications (spec/v1/20-resolved-deployment.md#the-reconcile-unit). -mapping EffectiveProject::unit() : ReconcileUnit { - name := unitOf(self.project); -} - -query unitOf(prj : String) : String = 'apps-' + prj; - --- The units that must be Ready first: every other project a required edge --- reaches, and the secrets-provisioning unit wherever a Process holds a grant --- (spec/v1/20-resolved-deployment.md#the-reconcile-unit). An optional edge --- orders nothing (spec/v1/55-delivery.md#release-order). -query afterOf(prj : EffectiveProject) : Sequence(String) = - if holdsStore(prj.project) then Sequence{} else - (prj.applications.processes.dependsOn - ->select(e | not (e.required = false)) - ->collect(e | projectOf(e.application)) - ->select(other | other <> null and other <> prj.project) - ->collect(other | unitOf(other)) - ->union(if prj.applications.processes->exists(p | p.secrets->notEmpty() or holdsClientGrants(p) or p.readsClientSecret() or p.vpn <> null - or p.dependsOn->exists(e | reachesDatabase(e))) - or prj.applications->exists(a | managed(a) or appliesCatalog(a)) - then secretsAfter(prj.project) else Sequence{} endif) - ->union(prj.applications->collect(a | proxiesAfter(a, prj.project))->flatten())) - ->asSet()->sortedBy(n | n)->asSequence() endif; - --- The project of the union that declares `application`, where one does. -query projectOf(application : String) : String = - let declaring : Sequence(EffectiveProject) = - projects->select(p | p.applications->exists(a | a.id = application)) in - if declaring->isEmpty() then null else declaring->first().project endif; - --- One digest per pinned input, then the render hash over them and the schema --- package's integrity (spec/v1/20-resolved-deployment.md#pinned-inputs). -mapping Platform::provenance() : Provenance { - schemaPackageIntegrity := integrity; - inputDigests := projects->collect(p | object InputDigest { - input := PinnedInput::intentFragment; - name := p.project; - digest := p.oclAsType(ECORE::EObject).digestOf(); - }) - ->append(object InputDigest { - input := PinnedInput::platformIntent; - name := estate.metadata.project; - digest := estate.oclAsType(ECORE::EObject).digestOf(); - }) - ->append(object InputDigest { - input := PinnedInput::nodeContract; - name := contract.cluster; - digest := contract.oclAsType(ECORE::EObject).digestOf(); - }) - ->append(object InputDigest { - input := PinnedInput::imagesLock; - name := lock.name; - digest := lock.oclAsType(ECORE::EObject).digestOf(); - }) - ->append(object InputDigest { - input := PinnedInput::clusterState; - name := snapshot.cluster; - digest := snapshot.oclAsType(ECORE::EObject).digestOf(); - }); - end { - -- The render hash covers everything above it and nothing else, so it is - -- taken before it is set. - result.renderHash := result.oclAsType(ECORE::EObject).digestOf(); - } -} - --- ========================================================= the Node Agents - --- The Project the Node Agents are (spec/v1/14-platform-intent.md#node-agents). -property NODE_PROJECT : String = 'node'; --- The time-sliced shares gpu-device advertises per GPU, of which gpu-metrics holds one. -property GPU_SHARES : Integer = 4; --- The vendor whose cards the GPU agents serve. -property GPU_AGENT_VENDOR : String = 'nvidia'; --- The address the speaker and its controller serve their metrics on. -property SPEAKER_PORT : Integer = 7472; - --- The `node` Project: every agent the node contract and the Platform document derive, and the --- pools its speaker announces, under its own namespace. -mapping Platform::nodeDeployment() : ResolvedDeployment { - apiVersion := 'resolved.jorisjonkers.dev/v1'; - kind := 'ResolvedDeployment'; - reconcileUnits := Sequence{object ReconcileUnit { name := unitOf(NODE_PROJECT); }}; - provenance := estate.map provenance(); - addressPools := speakerPools()->collect(t | object ResolvedAddressPool { - name := t.name; range := t.range; nodes := t.nodes; }); - nodeAgents := gpuAgents()->union(speakerAgents())->union(metricsAgents()); - policyJob := policyJobOf(); - end { - result.deliverables := nodeFiles(result)->union(nodeVaultFiles(result))->union(platformFiles()); - -- The speaker's memberlist key is this Project's own to generate, so its own policy job - -- writes it (spec/v1/14-platform-intent.md#node-agents). - result.deliverables += policyJobFiles(result.policyJob, result.deliverables->select(d | - d.path.startsWith(policiesOf(NODE_PROJECT)))->asSequence(), policyJobRoot(NODE_PROJECT), - namespaceOf(NODE_PROJECT)); - if (result.deliverables->exists(d | d.path = policyJobRoot(NODE_PROJECT) + 'kustomization.yaml')) { - var top : IndexFile := result.deliverables[IndexFile] - ->select(i | i.path = 'apps/' + NODE_PROJECT + '/kustomization.yaml')->any(true); - top.resources := top.resources->append('vault-policy')->sortedBy(r | r); - }; - } -} - --- Where the speaker runs memberlist: the operator's connection to the Secret Store, and the --- speaker's own policy and role reading its one document, beside the key this Project's policy --- job generates there. -query nodeVaultFiles(d : ResolvedDeployment) : Sequence(Deliverable) = - d.nodeAgents->select(a | a.memberlist <> null)->collect(a | - let ns : String = namespaceOf(NODE_PROJECT) in - let stem : String = policiesOf(NODE_PROJECT) + ns + '-' + a.name in - Sequence{ - object ConnectionFile { - path := 'apps/' + NODE_PROJECT + '/vaultconnection.yaml'; - adapter := AdapterName::vso; - namespace := ns; - address := a.memberlist.store; - }.oclAsType(Deliverable), - object VaultPolicyFile { - path := stem + '.policy.json'; - adapter := AdapterName::vaultPolicy; - namespace := ns; - identity := a.name; - paths := Sequence{allowing(a.memberlist.path, Sequence{'read'}), - allowing('secret/metadata/' + a.memberlist.path.substring(KV_DATA.size() + 1, a.memberlist.path.size()), - Sequence{'read'})}; - }.oclAsType(Deliverable), - object VaultRoleFile { - path := stem + '.role.json'; - adapter := AdapterName::vaultPolicy; - namespace := ns; - identity := a.name; - }.oclAsType(Deliverable), - -- Memberlist keys its traffic with the first 32 bytes of the value. - object GeneratedKeysFile { - path := policiesOf(NODE_PROJECT) + ns + '.generated.json'; - adapter := AdapterName::vaultPolicy; - keys := Sequence{object ResolvedGeneratedKey { - path := a.memberlist.path; key := a.memberlist.key; bytes := 32; encoding := 'hex'; }}; - }.oclAsType(Deliverable)})->flatten()->asSequence(); - --- Each pool, announced from the nodes of its site, in the order the Platform document names them. -query speakerPools() : Sequence(Tuple(name : String, range : String, nodes : Sequence(String))) = - estate.l4Addresses->select(a | a.value.oclIsKindOf(PoolAddress))->collect(a | - Tuple{name = a.key, range = a.value.oclAsType(PoolAddress).range, - nodes = contract.nodes->select(n | n.site = a.value.oclAsType(PoolAddress).site) - ->collect(n | n.name)->asSequence()})->asSequence(); - -query pinned(alias : String) : String = locked(alias).repository + '@' + locked(alias).digest; - -query gpuNodes() : Sequence(String) = - contract.nodes->select(n | n.gpus->exists(g | g.vendor = GPU_AGENT_VENDOR))->collect(n | n.name)->asSequence(); - -query gpuVendor() : GpuVendorPolicy = estate.gpus->select(g | g.key = GPU_AGENT_VENDOR)->any(true).value; - -query plainEntry(n : String, v : String) : EnvEntry = object EnvEntry { name := n; value := v; }; - --- The device plugin, which advertises each card as its shares, and the exporter, which holds one. -query gpuAgents() : Sequence(ResolvedNodeAgent) = - if gpuNodes()->isEmpty() or estate.nodeAgents = null then Sequence{} else - Sequence{ - object ResolvedNodeAgent { - name := 'gpu-device'; namespace := namespaceOf(NODE_PROJECT); application := NODE_PROJECT; - controller := ControllerKind::daemonSet; - image := pinned(estate.nodeAgents.gpuDevice.image); - memory := estate.nodeAgents.gpuDevice.memory; cpu := estate.nodeAgents.gpuDevice.cpu; - priorityClass := 'system-node-critical'; - runtimeClass := gpuVendor().runtimeClass; - hostProcesses := true; privileged := true; - eligibleNodes := gpuNodes(); - environment := Sequence{plainEntry('CONFIG_FILE', '/config/config.yaml'), - plainEntry('DEVICE_ID_STRATEGY', 'index'), plainEntry('FAIL_ON_INIT_ERROR', 'true'), - plainEntry('NVIDIA_VISIBLE_DEVICES', 'all'), - plainEntry('PASS_DEVICE_SPECS', 'true')}; - mounts := Sequence{ - object HostMount { name := 'device-plugins'; hostPath := '/var/lib/kubelet/device-plugins'; mountAt := '/var/lib/kubelet/device-plugins'; }, - object HostMount { name := 'cdi'; hostPath := '/var/run/cdi'; mountAt := '/var/run/cdi'; }}; - config := object AgentConfig { file := 'config.yaml'; mountAt := '/config'; - content := 'version: v1\nsharing:\n timeSlicing:\n resources:\n - name: ' + gpuVendor().resource - + '\n replicas: ' + GPU_SHARES.toString() + '\n'; }; - }, - object ResolvedNodeAgent { - name := 'gpu-metrics'; namespace := namespaceOf(NODE_PROJECT); application := NODE_PROJECT; - controller := ControllerKind::daemonSet; - image := pinned(estate.nodeAgents.gpuMetrics.image); - memory := estate.nodeAgents.gpuMetrics.memory; cpu := estate.nodeAgents.gpuMetrics.cpu; - priorityClass := 'system-node-critical'; - deviceShare := gpuVendor().resource; - runtimeClass := gpuVendor().runtimeClass; - nonRoot := false; uid := 0; - eligibleNodes := gpuNodes(); - environment := Sequence{plainEntry('DCGM_EXPORTER_KUBERNETES', 'true'), plainEntry('DCGM_EXPORTER_LISTEN', ':9400')}; - surfaces := Sequence{object ResolvedSurface { name := 'metrics'; port := 9400; }}; - addedPrivileges := Sequence{'SYS_ADMIN'}; - mounts := Sequence{object HostMount { name := 'pod-resources'; hostPath := '/var/lib/kubelet/pod-resources'; - mountAt := '/var/lib/kubelet/pod-resources'; readOnly := true; }}; - }} endif; - --- The node exporter, on every node, reading the host itself. -query metricsAgents() : Sequence(ResolvedNodeAgent) = - if contract.nodes->isEmpty() or estate.nodeAgents = null then Sequence{} else - Sequence{object ResolvedNodeAgent { - name := 'node-metrics'; namespace := namespaceOf(NODE_PROJECT); application := NODE_PROJECT; - controller := ControllerKind::daemonSet; - image := pinned(estate.nodeAgents.nodeMetrics.image); - memory := estate.nodeAgents.nodeMetrics.memory; cpu := estate.nodeAgents.nodeMetrics.cpu; - priorityClass := 'system-node-critical'; - hostNetwork := true; hostProcesses := true; nonRoot := true; confined := true; - eligibleNodes := contract.nodes->collect(n | n.name)->asSequence(); - arguments := Sequence{'--path.procfs=/host/proc', '--path.sysfs=/host/sys', '--path.rootfs=/host/root', - '--web.listen-address=:9100'}; - surfaces := Sequence{object ResolvedSurface { name := 'metrics'; port := 9100; }}; - mounts := Sequence{ - object HostMount { name := 'proc'; hostPath := '/proc'; mountAt := '/host/proc'; readOnly := true; }, - object HostMount { name := 'sys'; hostPath := '/sys'; mountAt := '/host/sys'; readOnly := true; }, - object HostMount { name := 'root'; hostPath := '/'; mountAt := '/host/root'; readOnly := true; propagated := true; }}; - }} endif; - -query apiRule(g : String, o : Sequence(String), v : Sequence(String)) : ResolvedApiRule = - object ResolvedApiRule { group := g; objects := o; verbs := v; }; - --- A rule that holds in the agents' own namespace alone. -query namespaceRule(g : String, o : Sequence(String), v : Sequence(String)) : ResolvedApiRule = - object ResolvedApiRule { group := g; objects := o; verbs := v; scope := RuleScope::_namespace; }; - --- The port the speakers' memberlist binds on the host, over TCP and UDP, and where the speaker --- reads its key, as a file named for the key. -property MEMBERLIST_PORT : Integer = 7946; -property MEMBERLIST_KEY_PATH : String = '/etc/ml_secret_key'; - --- How the speakers find each other fast (spec/v1/14-platform-intent.md#node-agents): memberlist, --- where a Vault policy job can generate its key under the `node` Project's own prefix. None --- without one: the speakers then find each other through the API alone. -query memberlistOf() : ResolvedMemberlist = - if policyJobOf() = null then null else object ResolvedMemberlist { - store := storeEndpoint(); - path := KV_DATA + namespaceOf(NODE_PROJECT) + '/l4-speaker'; - key := 'secretkey'; - secret := 'l4-speaker-memberlist'; - } endif; - --- The speaker, on every node of a pool's site, and its controller, which runs once. -query speakerAgents() : Sequence(ResolvedNodeAgent) = - let speakers : Sequence(String) = contract.nodes - ->select(n | speakerPools()->exists(t | t.nodes->includes(n.name)))->collect(n | n.name)->asSequence() in - let reads : Sequence(String) = Sequence{'get', 'list', 'watch'} in - let crds : Sequence(String) = Sequence{'ipaddresspools', 'l2advertisements', 'bgppeers', 'bgpadvertisements', - 'communities', 'bfdprofiles'} in - -- Where each copy records the configuration it last loaded, which both always watch. - let states : Sequence(String) = Sequence{'configurationstates', 'configurationstates/status'} in - let writes : Sequence(String) = Sequence{'get', 'list', 'watch', 'create', 'update', 'patch', 'delete'} in - -- What both watch in their own namespace alone: its Secrets and ConfigMaps. - let own : ResolvedApiRule = namespaceRule('core', Sequence{'secrets', 'configmaps'}, reads) in - let keyed : ResolvedMemberlist = memberlistOf() in - if speakers->isEmpty() or estate.nodeAgents = null or estate.nodeAgents.l4Speaker = null then Sequence{} else - Sequence{ - object ResolvedNodeAgent { - name := 'l4-speaker'; namespace := namespaceOf(NODE_PROJECT); application := NODE_PROJECT; - controller := ControllerKind::daemonSet; - image := pinned(estate.nodeAgents.l4Speaker.image); - memory := estate.nodeAgents.l4Speaker.memory; cpu := estate.nodeAgents.l4Speaker.cpu; - priorityClass := 'system-node-critical'; - identityToken := true; hostNetwork := true; confined := true; - eligibleNodes := speakers; - arguments := Sequence{'--port=' + SPEAKER_PORT.toString(), '--namespace=' + namespaceOf(NODE_PROJECT), '--log-level=info'}; - -- The speaker reads its own pod at start, by its name; with memberlist, it binds to its - -- pod's address and finds the other speakers by their name label. - environment := Sequence{object EnvEntry { name := 'METALLB_NODE_NAME'; field := 'spec.nodeName'; }, - object EnvEntry { name := 'METALLB_HOST'; field := 'status.hostIP'; }, - object EnvEntry { name := 'METALLB_POD_NAME'; field := 'metadata.name'; }} - ->union(if keyed = null then Sequence{} else Sequence{ - object EnvEntry { name := 'METALLB_ML_BIND_ADDR'; field := 'status.podIP'; }, - plainEntry('METALLB_ML_LABELS', 'app.kubernetes.io/name=l4-speaker'), - plainEntry('METALLB_ML_BIND_PORT', MEMBERLIST_PORT.toString()), - plainEntry('METALLB_ML_SECRET_KEY_PATH', MEMBERLIST_KEY_PATH)} endif); - memberlist := keyed; - surfaces := Sequence{object ResolvedSurface { name := 'metrics'; port := SPEAKER_PORT; }}; - addedPrivileges := Sequence{'NET_RAW'}; - rules := Sequence{ - apiRule('core', Sequence{'services', 'endpoints', 'nodes', 'namespaces', 'pods'}, reads), - apiRule('discovery.k8s.io', Sequence{'endpointslices'}, reads), - apiRule('core', Sequence{'events'}, Sequence{'create', 'patch'}), - apiRule('metallb.io', crds->append('servicel2statuses'), reads), - apiRule('metallb.io', Sequence{'servicel2statuses', 'servicel2statuses/status'}, - Sequence{'create', 'delete', 'update', 'patch'}), - apiRule('metallb.io', states, writes), - own, namespaceRule('metallb.io', Sequence{'servicebgpstatuses'}, reads)}; - }, - object ResolvedNodeAgent { - name := 'l4-controller'; namespace := namespaceOf(NODE_PROJECT); application := NODE_PROJECT; - controller := ControllerKind::deployment; replicas := 1; - image := pinned(estate.nodeAgents.l4Speaker.controller.image); - memory := estate.nodeAgents.l4Speaker.controller.memory; cpu := estate.nodeAgents.l4Speaker.controller.cpu; - priorityClass := 'system-cluster-critical'; - identityToken := true; nonRoot := true; confined := true; - uid := locked(estate.nodeAgents.l4Speaker.controller.image).uid; - gid := locked(estate.nodeAgents.l4Speaker.controller.image).gid; - eligibleNodes := speakers; - arguments := Sequence{'--port=' + SPEAKER_PORT.toString(), '--namespace=' + namespaceOf(NODE_PROJECT), - '--webhook-mode=disabled', '--log-level=info'}; - surfaces := Sequence{object ResolvedSurface { name := 'metrics'; port := SPEAKER_PORT; }}; - rules := Sequence{ - apiRule('core', Sequence{'services', 'namespaces', 'nodes'}, reads), - apiRule('core', Sequence{'services/status'}, Sequence{'update'}), - apiRule('core', Sequence{'events'}, Sequence{'create', 'patch'}), - apiRule('metallb.io', crds, reads), - apiRule('metallb.io', Sequence{'ipaddresspools/status'}, Sequence{'update'}), - apiRule('metallb.io', states, writes), - namespaceRule('core', Sequence{'secrets', 'configmaps'}, reads)}; - }} endif; - --- The `node` Project's tree: a directory per agent, the speaker's holding its controller and the --- pools it announces, each with the parts its agents need. -query nodeFiles(d : ResolvedDeployment) : Sequence(Deliverable) = - let root : String = 'apps/' + NODE_PROJECT + '/' in - let dirs : Sequence(String) = d.nodeAgents->reject(a | a.name = 'l4-controller')->collect(a | a.name)->asSequence() in - Sequence{ - object NamespaceFile { - path := root + 'namespace.yaml'; - adapter := AdapterName::kubernetes; - namespace := namespaceOf(NODE_PROJECT); - }.oclAsType(Deliverable), - object IndexFile { - path := root + 'kustomization.yaml'; - adapter := AdapterName::kubernetes; - resources := dirs->append('namespace.yaml') - ->union(if d.nodeAgents->exists(a | a.memberlist <> null) then Sequence{'vaultconnection.yaml'} - else Sequence{} endif)->sortedBy(r | r); - }.oclAsType(Deliverable)} - ->union(dirs->collect(dir | d.agentFilesOf(root + dir + '/', - d.nodeAgents->select(a | a.name = dir or (dir = 'l4-speaker' and a.name = 'l4-controller'))->asSequence())) - ->flatten()->asSequence()); - -query ResolvedDeployment::agentFilesOf(dir : String, held : Sequence(ResolvedNodeAgent)) : Sequence(Deliverable) = - let parts : Sequence(String) = (if held->exists(a | a.config <> null) then Sequence{'configmap'} else Sequence{} endif) - ->union(if held->exists(a | a.rules->notEmpty()) then Sequence{'rbac'} else Sequence{} endif) - ->union(Sequence{'serviceaccount'}) - ->union(if held->exists(a | a.memberlist <> null) then Sequence{'vso'} else Sequence{} endif) - ->union(Sequence{'workload'}) in - let announced : Sequence(ResolvedAddressPool) = self.addressPools->asSequence() in - let pooled : Boolean = held->exists(a | a.name = 'l4-speaker') and announced->notEmpty() in - parts->collect(piece | object NodeAgentFile { - path := dir + piece + '.yaml'; - adapter := AdapterName::kubernetes; - part := piece; - agents := held; - }.oclAsType(Deliverable)) - ->union(if pooled then Sequence{object AddressPoolFile { - path := dir + 'pools.yaml'; - adapter := AdapterName::kubernetes; - namespace := namespaceOf(NODE_PROJECT); - pools := announced; - }.oclAsType(Deliverable)} else Sequence{} endif) - ->append(object IndexFile { - path := dir + 'kustomization.yaml'; - adapter := AdapterName::kubernetes; - resources := parts->collect(p | p + '.yaml')->union(if pooled then Sequence{'pools.yaml'} else Sequence{} endif) - ->sortedBy(r | r); - }.oclAsType(Deliverable)); - --- =========================================================== the Application - -mapping EffectiveApplication::application(in prj : EffectiveProject) : ResolvedApplication { - id := self.id; - project := prj.project; - namespace := namespaceOf(prj.project); - reconcileUnit := prj.map unit(); - -- The Processes first: everything below refers to them. - processes := self.processes->map process(self, prj); - exposure := self.exposure->map exposure(self, prj); - if self.observability <> null and self.observability.scrape <> null then - scrape := object ResolvedScrape { - process := self.observability.scrape.process.resolveone(ResolvedProcess); - surface := self.observability.scrape.surface.key; - path := self.observability.scrape.path; - interval := estate.monitors.interval; - timeout := estate.monitors.timeout; - -- Kept as authored: true only where the scrape says so. - honorLabels := self.observability.scrape.honorLabels = true; - -- What the metrics stack selects its monitors by, as the platform names it. - labels := estate.monitors.labels->sortedBy(l | l.key) - ->collect(l | object KeyValue { key := l.key; value := l.value; }); - } - endif; - releaseGate := if gated(self) then self.map gate() else null endif; - if self.client <> null then client := self.map clientOf(prj) endif; - -- Each dashboard file as the set read it, in its Project's folder, for the Grafana - -- the Platform document names (spec/v1/10-project-intent.md#dashboards). - if self.dashboards->notEmpty() and estate.telemetry <> null and estate.telemetry.dashboards <> null then - dashboards := object ResolvedDashboards { - folder := prj.project; - instance := estate.telemetry.dashboards.instance->sortedBy(i | i.key) - ->collect(i | object KeyValue { key := i.key; value := i.value; }); - datasource := estate.telemetry.dashboards.datasource; - files := self.dashboards->collect(d | let read : String = fileOf(prj.project, d._from) in - object ResolvedDashboard { - name := dashboardName(self.id, uidOf(read)); - content := read; - inputs := inputsOf(read); - }); - } - endif; - grafana := grafanaOf(self, prj, result); - if managed(self) then migration := self.map migrationOf(prj) endif; - alertRules := Sequence{1..self.alertRules->size()}->collect(i | obsAlertRules(self.id, self.alertRules->at(i)._from, assetOf(prj.project, self.alertRules->at(i)._from))); - if obsAlerts(self) then alerting := obsAlerting(self) endif; - if obsFlux(self) then fluxScrape := obsFluxScrape() endif; - k3sScrape := k3sScrapeOf(self, prj); - -- The operator syncs from the Secret Store wherever a grant or a backup's - -- off-cluster or peer credential is delivered anywhere but to the Process itself, - -- and a migration reads its owner credential from the store itself. - if synced(result) or managed(self) then secretStore := storeEndpoint() endif; -} - --- Whether an Application moves its schema with a changelog the platform's runner applies. -query managed(app : EffectiveApplication) : Boolean = - app.migration <> null and app.migration.oclIsKindOf(ManagedMigration); - --- The tag of a revision (spec/v1/55-delivery.md#failure-and-undo): its first twelve hex digits. -query tagOf(revision : String) : String = revision.substring(8, 7 + TAG_DIGITS); - -query synced(app : ResolvedApplication) : Boolean = - app.processes->exists(p | p.secrets->notEmpty() or p.vpn <> null - or p.volumes->exists(v | v.backup <> null - and (v.backup.credential <> null or v.backup.peer <> null))); - --- A managed migration's plan (spec/v1/20-resolved-deployment.md#the-migration): --- its locked runner and the user it runs as, what the proof beside the project --- records about this release (an Application no proof names is a first --- release), and everything its Jobs run with, each a function of the --- Application id, the project and the Platform document. -mapping EffectiveApplication::migrationOf(in prj : EffectiveProject) : ResolvedMigration { - init { - var runnerImage : LockedImage := locked(self.id + '-migration'); - var proven : ProvenApplication := proofOf(self); - var held : Sequence(PolicyPeer) := datastoreOf(self); - var store : PolicyPeer := if held->isEmpty() then unreached(self.id) else held->first() endif; - var owned : String := prj.project; - } - runner := runnerImage.repository + '@' + runnerImage.digest; - runnerVersion := runnerImage.version; - uid := runnerImage.uid; - gid := runnerImage.gid; - if proven <> null and proven.testedAgainst <> null then testedAgainst := proven.testedAgainst endif; - nonTransactional := proven <> null and proven.nonTransactional; - identity := self.id + '-migration'; - deadline := estate.migration.deadline; - memory := estate.migration.memory; - cpu := estate.migration.cpu; - scratch := estate.ephemeral.size; - -- The runner mounts a writable /tmp and writes no HOME. - home := HOME_DIR; - database := object MigratedDatabase { - host := store.process + '.' + store.namespace + '.svc.cluster.local'; - port := store.port; - name := owned + '_db'; - }; - -- The runner reaches its datastore as every consumer does, by the label of the surface - -- the Application's edge names (spec/v1/16-dependencies.md#the-consumer-label). - consumes := Sequence{datastoreSurfacesOf(self)->first()}; - -- The owner role changes the schema, and only the migration holds it. - credential := object ResolvedGrant { - engine := 'database'; - delivery := 'self'; - paths := Sequence{object PolicyPath { - path := 'database/creds/' + owned + '-owner'; - allows := Sequence{'read'}; - }}; - }; - egress := Sequence{store}->union(storePeers())->append(object PolicyPeer { - rule := 'cluster-dns'; - namespace := estate.substrate.clusterDns; - port := DNS_PORT; - }); -} - --- Where the project's database answers --- (spec/v1/16-dependencies.md#the-database-catalog): each edge of the --- Application that reaches a Process whose engine owns databases, on the --- surface that edge names, the first of which is the datastore. -query datastoreOf(app : EffectiveApplication) : Sequence(PolicyPeer) = - app.processes.dependsOn->collect(e | - projects->collect(prj | prj.applications->select(a | a.id = e.application).processes - ->select(p | ownsDatabases(p) and p.provides->exists(s | s.key = e.surface)) - ->collect(p | object PolicyPeer { - rule := 'datastore'; - namespace := namespaceOf(prj.project); - process := p.name; - port := p.provides->select(s | s.key = e.surface)->any(true).value; - })))->flatten()->asSequence(); - --- The same edges' surfaces, as a consumer label names each, in the same order: the first --- is the datastore's. -query datastoreSurfacesOf(app : EffectiveApplication) : Sequence(String) = - app.processes.dependsOn->collect(e | - projects->collect(prj | prj.applications->select(a | a.id = e.application).processes - ->select(p | ownsDatabases(p) and p.provides->exists(s | s.key = e.surface)) - ->collect(p | e.application + '.' + e.surface)))->flatten()->asSequence(); - --- Whether a Process's inbound edges derive a database. -query ownsDatabases(p : PI::Process) : Boolean = - p.oclAsType(ECORE::EObject).states('engine') and p.engine = Engine::postgres; - --- Whether a Process's inbound edges name buckets in it: an object store. -query ownsBuckets(p : PI::Process) : Boolean = - p.oclAsType(ECORE::EObject).states('engine') and p.engine = Engine::s3; - --- The surface a datastore's catalog is applied over: its own, or the one its engine serves. -query catalogSurfaceOf(p : PI::Process) : String = - let policy : EnginePolicy = enginePolicyOf(p) in - if policy.catalogSurface <> null then policy.catalogSurface else policy.surface endif; - --- Whether an Application runs a datastore whose engine applies a catalog, where the platform --- names the Vault policy job: the method's role is written first --- (spec/v1/16-dependencies.md#applying-the-catalog). -query appliesCatalog(app : EffectiveApplication) : Boolean = - estate.policyJob <> null and app.processes->exists(p | (ownsDatabases(p) or ownsBuckets(p)) - and enginePolicyOf(p) <> null and enginePolicyOf(p).catalog <> null); - -query unreached(application : String) : PolicyPeer { - assert fatal (false) with log(application + ': a migration whose Application reaches no surface of the datastore holding its database is not checked yet'); - return null; -} - --- The image the lock holds for `alias`, or E_UNLOCKED_IMAGE refused the set. -query locked(alias : String) : LockedImage = - let found : Sequence(LockedImage) = lock.images->select(i | i.alias = alias)->asSequence() in - if found->isEmpty() then unlocked(alias) else found->first() endif; - -query unlocked(alias : String) : LockedImage { - assert fatal (false) with log(alias + ' is not locked: E_UNLOCKED_IMAGE'); - return null; -} - --- The Vault policy job (spec/v1/20-resolved-deployment.md#the-vault-policy-job): --- derived where the platform names it and a Secret Store answers, as one --- identity in the Secret Store's own namespace. Every project's document carries --- the same one, because it belongs to none of them. -query policyJobOf() : ResolvedPolicyJob = - if estate.policyJob = null or estate.secretStore = null or storePeers()->isEmpty() then null else - let own : LockedImage = locked(estate.policyJob.image) in - object ResolvedPolicyJob { - identity := POLICY_JOB; - namespace := storePeers()->first().namespace; - image := own.repository + '@' + own.digest; - imageVersion := own.version; - uid := own.uid; - gid := own.gid; - role := estate.policyJob.role; - address := storeEndpoint(); - memory := estate.policyJob.memory; - cpu := estate.policyJob.cpu; - deadline := inSeconds(seconds(estate.policyJob.deadline).floor()); - eligibleNodes := estateJobNodes(); - egress := storePeers()->union(Sequence{object PolicyPeer { - rule := 'cluster-dns'; namespace := estate.substrate.clusterDns; port := DNS_PORT; }}); - } endif; - --- The nodes a derived estate Job may land on --- (spec/v1/14-platform-intent.md#the-vault-policy-job): every node that fits what its one --- container asks for and holds no sdcard medium, since every unit that holds a grant waits --- on it. -query estateJobNodes() : Sequence(String) = - contract.nodes->select(n | mebibytes(n.allocatable.memory) >= mebibytes(estate.policyJob.memory) - and millicores(n.allocatable.cpu) >= millicores(estate.policyJob.cpu) - and not n.disks->exists(d | d.media = 'sdcard'))->collect(n | n.name)->asSequence(); - --- The methods that apply each datastore's database catalog --- (spec/v1/20-resolved-deployment.md#the-catalog-methods): where the engine names one and the --- platform names the Vault policy job, which writes each method's own role. Every project's --- document carries the same ones, as it carries the policy job. -query catalogJobsOf() : Sequence(ResolvedCatalogJob) = - if policyJobOf() = null then Sequence{} - else projects->collect(prj | prj.applications->collect(app | app.processes - ->select(p | (ownsDatabases(p) or ownsBuckets(p)) and enginePolicyOf(p) <> null - and enginePolicyOf(p).catalog <> null and catalogSurfaceOf(p) <> null) - ->collect(p | if ownsBuckets(p) then bucketCatalogJobOf(prj.project, app.id, p) - else catalogJobOf(prj.project, app.id, p) endif))) - ->flatten()->select(j | j <> null)->asSequence() endif; - --- The projects whose Processes name buckets in one object store, each with the buckets it --- names, as the store holds them (spec/v1/16-dependencies.md#the-bucket-catalog). -query bucketReadersOf(application : String) : Sequence(Tuple(name : String, buckets : Sequence(String))) = - projects->sortedBy(r | r.project)->collect(r | - Tuple{name = r.project, buckets = r.applications.processes.dependsOn - ->select(e | e.application = application)->collect(e | e.buckets)->flatten() - ->collect(b | r.project + '-' + b)->asSet()->sortedBy(b | b)->asSequence()}) - ->select(k | k.buckets->notEmpty())->asSequence(); - --- An object store's method: its catalog is the key each reading project is given, written by --- the derived admin token. -query bucketCatalogJobOf(prj : String, application : String, p : PI::Process) : ResolvedCatalogJob = - let ns : String = namespaceOf(prj) in - let proc : String = p.name in - let readers : Sequence(Tuple(name : String, buckets : Sequence(String))) = bucketReadersOf(application) in - if readers->isEmpty() then null else - let own : LockedImage = locked(enginePolicyOf(p).catalog) in - let surface : String = catalogSurfaceOf(p) in - let surfacePort : Integer = p.provides->select(s | s.key = surface)->any(true).value in - let named : String = p.name + '-catalog' in - object ResolvedCatalogJob { - identity := named; - namespace := ns; - image := own.repository + '@' + own.digest; - imageVersion := own.version; - uid := own.uid; - gid := own.gid; - role := ns + '-' + named; - address := storeEndpoint(); - memory := estate.policyJob.memory; - cpu := estate.policyJob.cpu; - deadline := inSeconds(seconds(estate.policyJob.deadline).floor()); - eligibleNodes := estateJobNodes(); - catalog := object ResolvedCatalog { - host := proc + '.' + ns + '.svc.cluster.local'; - port := surfacePort; - admin := object CatalogAdmin { - path := 'secret/data/' + prj + '/' + p.name + '/catalog'; - token := 'token'; - }; - keys := readers->collect(k | object CatalogKey { - name := k.name; - path := 'secret/data/' + k.name + '/' + p.name + '/s3'; - buckets := k.buckets; - }); - }; - consumes := Sequence{application + '.' + surface}; - policy := catalog.policy(); - egress := Sequence{object PolicyPeer { - rule := 'datastore'; namespace := ns; process := proc; port := surfacePort; }} - ->union(storePeers())->append(object PolicyPeer { - rule := 'cluster-dns'; namespace := estate.substrate.clusterDns; port := DNS_PORT; }); - } endif; - --- One datastore's method, where a project reads a database from it, signing in with the --- derived login. -query catalogJobOf(prj : String, application : String, p : PI::Process) : ResolvedCatalogJob = - let ns : String = namespaceOf(prj) in - let proc : String = p.name in - let readers : Sequence(String) = projects->select(r | - r.applications->exists(a | let d : Sequence(PolicyPeer) = datastoreOf(a) in - d->notEmpty() and d->first().namespace = ns and d->first().process = proc)) - ->collect(r | r.project)->sortedBy(n | n)->asSequence() in - if readers->isEmpty() then null else - let own : LockedImage = locked(estate.engines.postgres.catalog) in - let surfacePort : Integer = p.provides->select(s | s.key = estate.engines.postgres.surface)->any(true).value in - let named : String = p.name + '-catalog' in - object ResolvedCatalogJob { - identity := named; - namespace := ns; - image := own.repository + '@' + own.digest; - imageVersion := own.version; - uid := own.uid; - gid := own.gid; - role := ns + '-' + named; - address := storeEndpoint(); - memory := estate.policyJob.memory; - cpu := estate.policyJob.cpu; - deadline := inSeconds(seconds(estate.policyJob.deadline).floor()); - eligibleNodes := estateJobNodes(); - catalog := object ResolvedCatalog { - host := proc + '.' + ns + '.svc.cluster.local'; - port := surfacePort; - connection := p.name; - admin := object CatalogAdmin { - path := 'secret/data/' + prj + '/' + p.name + '/catalog'; - user := 'user'; - password := 'password'; - }; - databases := readers->collect(r | object CatalogDatabase { - name := r + '_db'; - owner := r + '-owner'; - data := r + '-data'; - }); - }; - -- The method reaches the datastore as every consumer does, by its surface's label. - consumes := Sequence{application + '.' + estate.engines.postgres.surface}; - policy := catalog.policy(); - egress := Sequence{object PolicyPeer { - rule := 'datastore'; namespace := ns; process := proc; port := surfacePort; }} - ->union(storePeers())->append(object PolicyPeer { - rule := 'cluster-dns'; namespace := estate.substrate.clusterDns; port := DNS_PORT; }); - } endif; - --- The Release Gate's endpoint: its `http` surface, which the platform names. --- Where Flux's events about every Project's unit go (spec/v1/55-delivery.md#rollouts): --- the Reporter's `http` surface, where the platform names a Reporter. The Reporter links --- only to an Application declared beside the gate, so the address is that one's. -query eventsRouteOf() : ResolvedEvents = - if estate.delivery = null or estate.delivery.reporter = null then null - else object ResolvedEvents { - namespace := estate.bootstrap.flux.sourceRef.substringBefore('/'); - address := 'http://' + surfaceAddress(estate.delivery.reporter.id, HTTP_SURFACE) + EVENTS_PATH; - } endif; - -query gateEndpoint() : String = - let address : String = if estate.delivery = null then null - else surfaceAddress(estate.delivery.gate.id, HTTP_SURFACE) endif in - if address = null then ungated() else 'http://' + address endif; - -query ungated() : String { - assert fatal (false) with log('a blue/green Process under a platform that names no Release Gate is E_UNKNOWN_RELEASE_GATE'); - return null; -} - --- The Secret Store's endpoint: its `http` surface, which the platform names. -query storeEndpoint() : String = - let address : String = if estate.secretStore = null then null - else surfaceAddress(estate.secretStore.id, HTTP_SURFACE) endif in - if address = null then unstored() else 'http://' + address endif; - -query unstored() : String { - assert fatal (false) with log('a grant under a platform that names no Secret Store'); - return null; -} - --- Whether any Process of the Application switches blue-green. -query gated(app : EffectiveApplication) : Boolean = - app.processes->exists(p | switchesBlueGreen(app, p)); - --- Only a serving Process switches at all: a job or a prepare Process has no switchover. -query switchesBlueGreen(app : EffectiveApplication, p : PI::Process) : Boolean = - p.lifecycle = Lifecycle::application and switchoverOf(app, p) = Switchover::blueGreen; - --- The release-gate inputs a blue/green switch reads --- (spec/v1/20-resolved-deployment.md#the-release-gate): one member per --- blue/green Process that publishes readiness, the platform's analysis cadence, --- and the slowest member's deadline. -mapping EffectiveApplication::gate() : ReleaseGate { - init { - var waiting : Sequence(PI::Process) := self.processes->select(p | - switchesBlueGreen(self, p) and readinessOf(p) <> null)->asSequence(); - var moved : String := self.id; - var proven : ProvenApplication := proofOf(self); - } - assert fatal (waiting->notEmpty()) - with log('a blue/green Application that publishes no readiness is E_RELEASE_UNIT_NO_READINESS'); - assert fatal (estate.delivery <> null) - with log('a blue/green Process under a platform with no delivery policy is E_NO_DELIVERY_POLICY'); - endpoint := gateEndpoint(); - deadline := inSeconds(waiting->collect(p | deadlineOf(p))->max()); - analysis := object GateAnalysis { - interval := estate.delivery.analysis.interval; - iterations := estate.delivery.analysis.iterations; - threshold := estate.delivery.analysis.threshold; - errorRate := estate.delivery.analysis.errorRate; - latency := estate.delivery.analysis.latency; - }; - members := waiting->collect(p | object GateMember { - process := p.resolveone(ResolvedProcess); - readiness := readinessOf(p).target(); - checks := if exportsTelemetry(p) then Sequence{AnalysisCheck::errorRate, AnalysisCheck::latency} - else Sequence{} endif; - waitsFor := waitsForOf(self, p)->collect(t | object GateProvider { - application := t.application; - process := t.process; - }); - }); - -- What the gate starts and may undo, where the Application has a migration. - if managed(self) then migration := object GateMigration { - identity := moved + '-migration'; - if proven <> null and proven.testedAgainst <> null then testedAgainst := proven.testedAgainst endif; - nonTransactional := proven <> null and proven.nonTransactional; - } endif; -} - --- What a member waits for before its new version starts --- (spec/v1/55-delivery.md#release-order): every Process of another Application of its own --- Project that one of its required edges reaches and that switches stop-start, by --- Application and then Process. A provider in another Project is its Reconcile Unit's to --- order, and a blue-green one keeps its old version serving. -query waitsForOf(app : EffectiveApplication, p : PI::Process) - : Sequence(Tuple(application : String, process : String)) = - let home : String = projectOf(app.id) in - -- The member's own Application is among them, and holds no stop-start Process: an - -- Application switches as one, or E_RELEASE_UNIT_MIXED_CUTOVER refused it. - projects->select(prj | prj.project = home).applications - ->collect(a | a.processes - ->select(q | q.lifecycle = Lifecycle::application and q.cutover = PI::Cutover::interrupted - and p.dependsOn->exists(e | not (e.required = false) and e.application = a.id - and q.provides->exists(s | s.key = e.surface))) - ->collect(q | Tuple{application = a.id, process = q.name}))->flatten() - -- A space sorts before any character a name may hold. - ->sortedBy(t | t.application + ' ' + t.process)->asSequence(); - --- What the proof beside the project records of an Application's release, or nothing. -query proofOf(app : EffectiveApplication) : ProvenApplication = - proofs->select(a | a.id = app.id)->any(true); - --- ================================================================ the Process - -mapping PI::Process::process(in app : EffectiveApplication, in prj : EffectiveProject) - : ResolvedProcess { - init { - var own : LockedImage := locked(self.image); - var declared : Probes := if self.probes <> null and self.probes.oclIsKindOf(Probes) - then self.probes.oclAsType(Probes) else null endif; - } - - name := self.name; - -- The Vault role and the ServiceAccount are both the Process's own name. - identity := self.name; - lifecycle := self.lifecycle.spelling(); - image := own.repository + '@' + own.digest; - imageVersion := own.version; - uid := own.uid; - gid := own.gid; - if self.cutover <> PI::Cutover::absent then cutover := self.cutover.resolvedCutover() endif; - if self.lifecycle = Lifecycle::application then switchover := switchoverOf(app, self) endif; - -- Flagger serves a blue-green Process from a primary it names and labels after the Process. - serving := if self.servesFromPrimary(app) then self.name + '-primary' else self.name endif; - servingLabel := if self.servesFromPrimary(app) then 'app.kubernetes.io/name' - else 'app.kubernetes.io/instance' endif; - deadline := inSeconds(deadlineOf(self)); - -- A scheduled run that starts more than the start deadline late is skipped. - if self.schedule <> null then schedule := self.schedule endif; - if self.schedule <> null then startDeadline := '300s' endif; - replicas := if self.parked <> null then 0 else if self.replicas = null then 1 else self.replicas.count endif endif; - parked := self.parked <> null; - spread := self.replicas <> null and self.replicas.oclAsType(ECORE::EObject).states('across'); - command := self.command->asSequence(); - arguments := self.args->asSequence()->union(edgeArgsOf(self)); - -- A path held in memory is memory the container holds. - memory := let held : Real = self.writablePaths->select(w | w.oclIsKindOf(MemoryPath)) - ->collect(w | mebibytes(w.oclAsType(MemoryPath).memory))->sum() in - if held = 0 then self.placement.memory else memoryOf(mebibytes(self.placement.memory) + held) endif; - cpu := self.placement.cpu; - if self.placement.gpu <> null then gpu := gpuOf(self) endif; - if self.vpn <> null then vpn := vpnOf(self) endif; - hardening := estate.hardening.spelling(); - secrets := self.secrets->collect(g | g.resolvedFor(self))->union(self.edgeCredentials(app, prj))->union(edgeGrantsOf(self))->union(obsReceiverGrants(self, app))->union(self.clientGrants(app))->union(bucketKeysOf(self, prj))->union(self.clientReadGrants(app, prj))->union(grafanaAdminOf(self, app, prj)); - -- The pod authenticates only where a grant is delivered `self`, or where it - -- holds Kubernetes API access. - priorityClass := priorityOf(self, app, prj); - identityToken := self.api <> null or edgeTiersOf(self)->notEmpty() - or self.secrets->exists(g | g.delivery = Delivery::selfDelivery) - or self.edgeCredentials(app, prj)->exists(g | g.delivery = 'self') - or self.clientGrants(app)->notEmpty() - or self.spawns->notEmpty(); - -- The platform admits the holder, or E_PROCESS_RBAC_GRANT refused it, so the - -- block that says where the API answers is there. - -- A spawn template derives access to create its pods in the Process's own namespace. - -- A tier's proxy reads its routes through the API, so the tier derives the access its - -- provider needs, before any the proxy declares itself (spec/v1/14-platform-intent.md#tiers). - if self.api <> null or self.spawns->notEmpty() or edgeTiersOf(self)->notEmpty() then api := object ResolvedApiAccess { - reason := if self.api <> null then self.api.reason - else if edgeTiersOf(self)->notEmpty() then PROXY_API_REASON - else 'it creates the pods its spawn templates declare' endif endif; - rules := (if edgeTiersOf(self)->isEmpty() then Sequence{} else proxyApiRules() endif) - ->union((if self.api = null then Sequence{} else self.api.rules->asSequence() endif)->collect(r | object ResolvedApiRule { - group := r.group; - objects := r.objects; - verbs := r.verbs->collect(v | v.toString()); - -- A rule reaches the cluster unless it says its own namespace. - scope := if r.scope = ApiScope::_namespace then RuleScope::_namespace else RuleScope::cluster endif; - }))->union(if self.spawns->isEmpty() then Sequence{} else Sequence{ - object ResolvedApiRule { group := 'core'; objects := Sequence{'pods'}; - verbs := Sequence{'get', 'list', 'watch', 'create', 'delete'}; scope := RuleScope::_namespace; }, - object ResolvedApiRule { group := 'core'; objects := Sequence{'pods/log'}; - verbs := Sequence{'get'}; scope := RuleScope::_namespace; }} endif); - server := estate.apiAccess.server->collect(range | object AdmittedRange { - cidr := range.cidr; - port := range.port; - }); - } endif; - if self.egress <> null then internetEgress := object InternetEgress { reason := self.egress.reason; } endif; - if self.egress = null and edgeAcme(self) then internetEgress := object InternetEgress { reason := ACME_REASON; } endif; - if self.egress = null and self.vpn <> null then internetEgress := object InternetEgress { reason := TUNNEL_REASON; } endif; - component := self.runtime.spelling(); - if declared <> null and declared.readiness <> null then readiness := declared.readiness.cadenced() endif; - if declared <> null and declared.liveness <> null then liveness := declared.liveness.cadenced() endif; - -- The startup probe polls liveness, so readiness alone derives none. - if declared <> null and declared.liveness <> null and self.startupBudget <> null then - startup := object StartupProbe { - target := declared.liveness.target(); - period := inSeconds(STARTUP_PERIOD); - timeout := estate.probes.timeout; - failures := ceiling(seconds(self.startupBudget) / STARTUP_PERIOD); - } - endif; - -- A surface exposed on a node's own address listens on the host's port too. - surfaces := self.provides->collect(s | object ResolvedSurface { - name := s.key; - port := s.value; - hostPort := hostPortOf(self, s); - }); - l4Services := l4ServicesOf(self); - -- A Process that serves DNS resolves through the platform's upstream nameservers. - if servesDns(self) then nameservers := estate.substrate.upstreamNameservers endif; - -- A `mongo` resolves its own Service's name to itself: its replica set member is configured by - -- the name its consumers reach it by (spec/v1/20-resolved-deployment.md#a-replica-set-member-finds-itself). - if self.oclAsType(ECORE::EObject).states('engine') and self.engine = Engine::mongo then - selfNames := Sequence{self.name + '.' + namespaceOf(prj.project) + '.svc.cluster.local'} - endif; - -- The Prometheus operator runs the monitoring stack's Prometheus and Alertmanager from objects - -- of its own (spec/v1/14-platform-intent.md#the-operators-objects). - operated := operatedOf(app, prj); - nodePorts := edgeNodePortsOf(self); - placement := object ResolvedPlacement { - eligibleNodes := contract.nodes->select(n | eligible(self, n))->collect(n | n.name); - -- A claim the snapshot records as bound holds the Process to that node. - if (boundOf(self) <> null) { - boundTo := boundOf(self).node; - _from := PinnedInput::clusterState; - } endif; - }; - volumes := self.volumes->collect(v | v.resolvedFor(self))->union(edgeVolumesOf(self)); - keepsAcmeState := edgeAcme(self); - libraries := self.libraries->collect(m | m.resolvedFor(prj)); - -- A seeded Asset lands on a volume or a writable path through the seeder's init step. - assets := self.assets->collect(a | a.resolvedFor(self, prj)); - if self.assets->exists(a | a.oclIsKindOf(SeededAsset)) and estate.seeder <> null then - seeder := self.seederOf(prj) endif; - sidecars := self.sidecars->collect(c | object ResolvedSidecar { - name := c.name; - image := locked(c.image).repository + '@' + locked(c.image).digest; - imageVersion := locked(c.image).version; - memory := c.memory; - cpu := c.cpu; - command := c.command->asSequence(); - arguments := c.args->asSequence(); - -- An init step runs to completion before the Process starts. - _init := c._init = true; - -- A volume of the Process, where the sidecar says; then a file beside the project, - -- mounted read-only from the Process's Asset ConfigMap. - mounts := c.volumes->collect(v | object ContainerMount { name := v.claim; mountAt := v.mountAt; }) - ->union(c.assets->collect(a | let read : String = fileOf(prj.project, a._from) in object ContainerMount { - name := self.name + '-' + spelled(a._from) + '-' - + read.textDigestOf().substring(8, 7 + CONTENT_DIGITS); - mountAt := a.mountAt; - subPath := a._from.substring(a._from.lastIndexOf('/') + 1, a._from.size()); - readOnly := true; - })); - if mountsTmp(self) and not namesHome(self, prj) then home := HOME_DIR endif; - }); - dependencies := self.dependsOn->collect(e | edgeOf(e, owner(self))); - -- The data sources the Grafana role's Process derives from its edges into the monitoring stack. - if isGrafana(self, app, prj) then assets := result.assets->asSequence()->union(datasourcesOf(result)) endif; - -- An edge to an Application's surface reaches a pod, which admits the label; one to a - -- Registered Unmanaged Surface reaches an address. - consumes := result.dependencies->select(d | d.peers->notEmpty()) - ->collect(d | d.application + '.' + d.surface); - -- A path held in memory is sized by what it holds; every other by the ephemeral policy. - writablePaths := self.writablePaths->collect(w | object WritablePath { - path := w.path; - size := if w.oclIsKindOf(MemoryPath) then w.oclAsType(MemoryPath).memory - else estate.ephemeral.size endif; - memory := w.oclIsKindOf(MemoryPath); - }); - -- A spawn template's pods run on its image, labelled for its Process and the surfaces it consumes. - spawns := self.spawns->collect(t | object ResolvedSpawn { - name := self.name + '-' + t.name; - surfaces := t.provides->collect(s | object ResolvedSurface { name := s.key; port := s.value; }); - dependencies := t.dependsOn->collect(e | edgeOf(e, owner(self))); - egress := Sequence{object PolicyPeer { rule := 'cluster-dns'; namespace := estate.substrate.clusterDns; port := DNS_PORT; }}; - if t.egress <> null then internetEgress := object InternetEgress { reason := t.egress.reason; } endif; - }); - environment := environmentOf(self, prj)->union(edgeEnvOf(self))->union(grafanaEnvOf(self, app, prj)) - ->union(self.spawns->collect(t | Sequence{ - object EnvEntry { name := spawnVariable(t.name, 'IMAGE'); - value := locked(t.image).repository + '@' + locked(t.image).digest; }, - object EnvEntry { name := spawnVariable(t.name, 'LABELS'); - value := Sequence{'deploy-kit.jorisjonkers.dev/spawned-from=' + self.name + '-' + t.name} - ->union(t.dependsOn->collect(e | 'consumes.deploy-kit.jorisjonkers.dev/' + e.application + '.' + e.surface + '=true')) - ->iterate(l; acc : String = '' | if acc = '' then l else acc + ',' + l endif); }})->flatten()) - ->sortedBy(e | e.name); - if mountsTmp(self) and not namesHome(self, prj) then home := HOME_DIR endif; - addedPrivileges := lowPrivileges(result); -} - --- `progressDeadlineSeconds`: three budgets, floored to a whole second, or for a --- prepare Process the budget itself, rounded up so it is never cut short. -query deadlineOf(p : PI::Process) : Integer = - (if p.startupBudget = null then UNBUDGETED_DEADLINE - else if p.lifecycle = Lifecycle::prepare then ceiling(seconds(p.startupBudget)) - else (seconds(p.startupBudget) * 3).floor() endif endif) + imagePull(); - --- The substrate's image pull, rounded up to a whole second, which every derived deadline --- allows since it runs from before the image is on the node; nothing where none is stated. -query imagePull() : Integer = - if estate.substrate.imagePull = null then 0 else ceiling(seconds(estate.substrate.imagePull)) endif; - --- How the new version replaces the old (spec/v1/55-delivery.md#switchover). -query PI::Process::servesFromPrimary(app : EffectiveApplication) : Boolean = - self.lifecycle = Lifecycle::application and switchoverOf(app, self) = Switchover::blueGreen; - -query switchoverOf(app : EffectiveApplication, p : PI::Process) : Switchover = - -- A parked Process runs no pod, so it has no release to gate: it stops and starts. - if p.cutover = PI::Cutover::interrupted or p.parked <> null then Switchover::stopStart - else if estate.delivery <> null and estate.delivery.machinery->exists(m | m.id = app.id) - then Switchover::rolling - else Switchover::blueGreen endif endif; - -query readinessOf(p : PI::Process) : Probe = - if p.probes <> null and p.probes.oclIsKindOf(Probes) - then p.probes.oclAsType(Probes).readiness else null endif; - --- Readiness and liveness take the Platform document's cadence. -query Probe::cadenced() : ResolvedProbe = object ResolvedProbe { - target := self.target(); - period := estate.probes.period; - timeout := estate.probes.timeout; - failures := estate.probes.failures; -}; - -query Probe::target() : ProbeTarget = - if self.oclIsKindOf(HttpProbe) then - object HttpTarget { - path := self.oclAsType(HttpProbe).path; - port := self.oclAsType(HttpProbe).port; - }.oclAsType(ProbeTarget) - else - object TcpTarget { tcp := self.oclAsType(TcpProbe).tcp; }.oclAsType(ProbeTarget) - endif; - --- The binding the snapshot records for a claim the Process holds, where one does. -query boundOf(p : PI::Process) : Binding = - let bound : Sequence(Binding) = - snapshot.bindings->select(b | p.volumes->exists(v | v.claim = b.claim))->asSequence() in - if bound->isEmpty() then null else bound->first() endif; - --- ==================================================================== grants - --- The Secret a grant's value is synced to: the Process, then the path below the mount. --- One grant per object store whose buckets the Process's edges name --- (spec/v1/16-dependencies.md#the-bucket-catalog): `read` on its project's key, --- synced to the environment its key coordinates read. -query bucketKeysOf(p : PI::Process, prj : EffectiveProject) : Sequence(ResolvedGrant) = - p.dependsOn->select(e | e.buckets->notEmpty()) - ->collect(e | projects.applications->select(a | a.id = e.application).processes - ->select(q | q.provides->exists(s | s.key = e.surface))->collect(q | q.name))->flatten() - ->asOrderedSet()->collect(store | let keyPath : String = 'secret/data/' + prj.project + '/' + store + '/s3' in - object ResolvedGrant { - path := keyPath; - keys := Sequence{'access-key-id', 'secret-access-key'}; - _access := 'read'; - delivery := 'env'; - destination := destinationOf(p.name, keyPath); - })->asSequence(); - -query destinationOf(holder : String, path : String) : String = - holder + '-' + (if path.startsWith('secret/data/') and path.size() > 12 then path.substring(13, path.size()) else path endif) - .replaceAll('/', '-'); - --- The credential the Process's first edge to a database derives --- (spec/v1/10-project-intent.md#migration): the project's data role, or its --- owner role where the Application migrates itself, delivered as the edge says. -query PI::Process::edgeCredentials(app : EffectiveApplication, prj : EffectiveProject) : Sequence(ResolvedGrant) = - let edges : Sequence(DependencyEdge) = self.dependsOn->select(e | reachesDatabase(e))->asSequence() in - if edges->isEmpty() then Sequence{} else - let edge : DependencyEdge = edges->first() in - let credential : String = 'database/creds/' + credentialRole(app, prj) in - let deliveredAs : String = if edge.credentials = null then 'self' - else if edge.credentials.delivery = Delivery::env then 'env' - else if edge.credentials.delivery = Delivery::file then 'file' else 'self' endif endif endif in - Sequence{object ResolvedGrant { - engine := 'database'; - delivery := deliveredAs; - paths := Sequence{object PolicyPath { path := credential; allows := Sequence{'read'}; }}; - if deliveredAs <> 'self' then destination := destinationOf(self.name, credential) endif; - -- The schema refused a file credential without both. - if deliveredAs = 'file' then mountAt := edge.credentials.mountAt endif; - if deliveredAs = 'file' then fileMode := edge.credentials.fileMode endif; - if edge.credentials <> null and edge.credentials.rotation.tolerates = Tolerance::restart then - restartTargets := Sequence{self.name} - endif; - }} endif; - --- The role a Process's edge to its project's database derives. -query credentialRole(app : EffectiveApplication, prj : EffectiveProject) : String = - prj.project + (if app.migration <> null and app.migration.oclIsKindOf(SelfMigration) then '-owner' else '-data' endif); - --- Whether an edge reaches a surface of a Process whose engine owns databases. -query reachesDatabase(e : DependencyEdge) : Boolean = - projects.applications->exists(a | a.id = e.application - and a.processes->exists(q | ownsDatabases(q) and q.provides->exists(s | s.key = e.surface))); - --- A `kv` grant keeps its path and keys; a `transit` or `database` grant becomes --- the paths its policy covers. A rotation that tolerates only a restart restarts --- the Process in place, and a reload restarts nothing. -query Grant::resolvedFor(p : PI::Process) : ResolvedGrant = object ResolvedGrant { - delivery := self.delivery.spelling(); - if (self.oclIsKindOf(KvGrant)) { - path := self.oclAsType(KvGrant).path; - keys := self.oclAsType(KvGrant).keys.name; - generated := self.oclAsType(KvGrant).keys->select(k | k.oclIsKindOf(GeneratedKey)) - ->collect(k | k.oclAsType(GeneratedKey).resolved()); - _access := self.oclAsType(KvGrant)._access.spelling(); - if self.delivery <> Delivery::selfDelivery then - destination := destinationOf(p.name, self.oclAsType(KvGrant).path) - endif; - } elif (self.oclIsKindOf(TransitGrant)) { - engine := 'transit'; - -- `read` is the key's public part and versions, which the key itself serves. - paths := self.oclAsType(TransitGrant).operations->collect(o | object PolicyPath { - path := if o = TransitOp::read then 'transit/keys/' + self.oclAsType(TransitGrant).key - else if o = TransitOp::rotate then 'transit/keys/' + self.oclAsType(TransitGrant).key + '/rotate' - else 'transit/' + o.spelling() + '/' + self.oclAsType(TransitGrant).key endif endif; - allows := Sequence{if o = TransitOp::read then 'read' else 'update' endif}; - }); - } else { - engine := 'database'; - paths := Sequence{object PolicyPath { - path := 'database/creds/' + self.oclAsType(DatabaseGrant).role; - allows := Sequence{'read'}; - }}; - } endif; - if self.mountAt <> null then mountAt := self.mountAt endif; - if self.fileMode <> null then fileMode := self.fileMode endif; - -- A synced value restarts its consumer once the operator syncs it, whatever the rotation - -- tolerates; read by the Process itself, a rotation restarts it, and a reload restarts nothing. - -- A scheduled Process reads its values afresh on every run, so nothing restarts it. - if p.lifecycle <> Lifecycle::scheduled - and (self.delivery <> Delivery::selfDelivery or self.rotation.tolerates = Tolerance::restart) then - restartTargets := Sequence{p.name} - endif; -}; - --- =================================================================== volumes - --- A volume, and the backup its Durability Class derives --- (spec/v1/10-project-intent.md#volumes): `reconstructible` earns none. -query Volume::resolvedFor(p : PI::Process) : ResolvedVolume = object ResolvedVolume { - claim := self.claim; - mountAt := self.mountAt; - size := self.size; - durability := self.durability.resolvedDurability(); - if self.durability <> PI::DurabilityClass::reconstructible then backup := self.backupFor(p) endif; -}; - --- A library the Process mounts, resolved against the Platform document that --- declares it (spec/v1/10-project-intent.md#libraries): every mounted library --- is declared, or E_UNKNOWN_LIBRARY refused it. -query LibraryMount::resolvedFor(prj : EffectiveProject) : ResolvedLibraryMount = object ResolvedLibraryMount { - _library := self._library; - claim := 'library-' + self._library; - volume := namespaceOf(prj.project) + '-' + self._library; - node := libraryOf(self._library).node; - path := libraryOf(self._library).path; - gid := libraryOf(self._library).gid; - mountAt := self.mountAt; - if self.subPath <> null then subPath := self.subPath endif; - _access := if self._access = LibraryAccess::write then 'write' else 'read' endif; -}; - --- The library the Platform document declares under `name`, or null. -query libraryOf(name : String) : LibraryDeclaration = - estate.libraries->select(l | l.key = name)->collect(l | l.value)->any(true); - -query Volume::backupFor(p : PI::Process) : BackupPlan = - let policy : DurabilityPolicy = if self.durability = PI::DurabilityClass::recoverable - then estate.durability.recoverable else estate.durability.irreplaceable endif in - let methodImage : LockedImage = locked(engineMethod(p)) in - -- A method that reads the volume alone runs as the Process that wrote it. - let runAs : LockedImage = if dumpedSurface(p) = null then locked(p.image) else methodImage endif in - let holder : String = p.name + '-backup' in - if policy = null or policy.schedule = null or policy.retain = null - then unplanned(self.claim) else - object BackupPlan { - schedule := policy.schedule; - retain := policy.retain; - method := methodImage.repository + '@' + methodImage.digest; - methodVersion := methodImage.version; - uid := runAs.uid; - gid := runAs.gid; - identity := holder; - claim := self.claim + '-backup'; - egress := backupEgress(p); - -- A method that dumps over the network is told where, and logs in with - -- a credential derived from the Process, which only its backups hold. - if (dumpedSurface(p) <> null) { - peer := object BackupPeer { - host := p.name + '.' + namespaceOf(owner(p)) + '.svc.cluster.local'; - port := p.provides->select(s | s.key = dumpedSurface(p))->any(true).value; - credential := object ResolvedGrant { - path := backupCredentialOf(p); - _access := 'read'; - delivery := 'env'; - destination := destinationOf(holder, backupCredentialOf(p)); - }; - }; - } endif; - if (policy.offCluster <> null) { - destinations := policy.offCluster.egress->collect(range | object AdmittedRange { - cidr := range.cidr; - port := range.port; - }); - offCluster := policy.offCluster.destination; - -- Where the copy lands below the destination, and the key it is encrypted to. - offClusterPath := owner(p) + '/' + p.name + '/' + self.claim; - offClusterRecipient := policy.offCluster.recipient; - credential := object ResolvedGrant { - path := policy.offCluster.credential; - _access := 'read'; - delivery := 'env'; - destination := destinationOf(holder, policy.offCluster.credential); - }; - } endif; - } endif; - --- Where a method that dumps a Process over the network reads the credential it --- logs in with: one path per Process, which its name keeps distinct within its project. -query backupCredentialOf(p : PI::Process) : String = - 'secret/data/' + owner(p) + '/' + p.name + '/backup'; - -query unplanned(claim : String) : BackupPlan { - assert fatal (false) with log(claim + ': its Durability Class derives a backup, and the platform names no schedule and retention for it'); - return null; -} - --- The backup method the platform names for the Process's engine, an image alias. --- What a backup identity's own policy admits --- (spec/v1/16-dependencies.md#the-backup-identitys-policy): the Process it --- dumps, on the surface the engine's method connects to, and the cluster's DNS. --- A method that reads the volume alone names no surface. Never the Secret --- Store: the operator reads the backup's credential for it. -query backupEgress(p : PI::Process) : Sequence(PolicyPeer) = - (if dumpedSurface(p) = null then Sequence{} else Sequence{object PolicyPeer { - rule := 'datastore'; - namespace := namespaceOf(owner(p)); - process := p.name; - port := p.provides->select(s | s.key = dumpedSurface(p))->any(true).value; - }} endif) - ->union(Sequence{object PolicyPeer { rule := 'cluster-dns'; namespace := estate.substrate.clusterDns; port := DNS_PORT; }}); - --- The surface the platform names for the Process's engine, where the Process is --- backed up at all and its method dumps one. -query dumpedSurface(p : PI::Process) : String = - if not p.oclAsType(ECORE::EObject).states('engine') - or not p.volumes->exists(v | v.durability <> PI::DurabilityClass::reconstructible) then null - else policySurface(enginePolicyOf(p)) endif; - --- The platform's policy for the Process's engine. -query enginePolicyOf(p : PI::Process) : EnginePolicy = - if p.engine = Engine::postgres then estate.engines.postgres - else if p.engine = Engine::rabbitmq then estate.engines.rabbitmq - else if p.engine = Engine::valkey then estate.engines.valkey - else if p.engine = Engine::mongo then estate.engines.mongo - else if p.engine = Engine::s3 then estate.engines.s3 - else estate.engines.files endif endif endif endif endif; - -query policySurface(policy : EnginePolicy) : String = - if policy = null then null else policy.surface endif; - --- The project a Process is declared in. -query owner(p : PI::Process) : String = - projects->select(prj | prj.applications.processes->includes(p))->first().project; - --- The Application a Process belongs to. -query applicationOf(p : PI::Process) : String = - projects.applications->select(a | a.processes->includes(p))->first().id; - -query engineMethod(p : PI::Process) : String = - if not p.oclAsType(ECORE::EObject).states('engine') then unengined(p) - else enginePolicyOf(p).backup endif; - -query unengined(p : PI::Process) : String { - assert fatal (false) with log(p.name + ' backs a volume up and declares no engine: E_DURABILITY_WITHOUT_ENGINE'); - return null; -} - --- ==================================================================== Assets - --- A settings file, by a name its content changes --- (spec/v1/10-project-intent.md#assets): the Process, the file, and the first --- digits of the content's digest. -query AssetDeclaration::resolvedFor(p : PI::Process, prj : EffectiveProject) : ResolvedAsset = - let found : Sequence(AssetFile) = - assetFiles->select(f | f.project = prj.project and f._from = self._from)->asSequence() in - let file : AssetFile = if found->isEmpty() then unfiled(self._from) else found->first() endif in - -- Only a placeholder of a kind the model reads is one; a `${VAR}` the image itself expands is text. - if file.content.matches('(?s).*\\$\\{(secret|dependency|exposure|identity|client):.*') then unplaced(self._from) else - object ResolvedAsset { - name := p.name + '-' + spelled(self._from) + '-' - + file.content.textDigestOf().substring(8, 7 + CONTENT_DIGITS); - _from := self._from; - if self.oclIsKindOf(Asset) then mountAt := self.oclAsType(Asset).mountAt endif; - if self.oclIsKindOf(SeededAsset) then seedAt := self.oclAsType(SeededAsset).seedAt endif; - content := file.content; - } endif; - --- The init step that seeds a Process's Assets onto its volumes and writable paths --- (spec/v1/10-project-intent.md#assets): each file is staged beside its place and moved --- over it, the copy it replaces kept as `.superseded`. -query PI::Process::seederOf(prj : EffectiveProject) : ResolvedSeeder = - let seeded : Sequence(ResolvedAsset) = self.assets->select(a | a.oclIsKindOf(SeededAsset)) - ->collect(a | a.resolvedFor(self, prj))->asSequence() in - let seedImage : LockedImage = locked(estate.seeder.image) in - object ResolvedSeeder { - image := seedImage.repository + '@' + seedImage.digest; - imageVersion := seedImage.version; - memory := estate.seeder.memory; - cpu := estate.seeder.cpu; - command := Sequence{'/bin/sh', '-c', - Sequence{'set -eu', 'umask 077'}->union(seeded->collect(a | seedScriptOf(a))->flatten()) - ->iterate(line; acc : String = '' | if acc = '' then line else acc + '\n' + line endif)}; - mounts := seeded->collect(a | object ContainerMount { name := a.name; mountAt := '/seed/' + a.name; readOnly := true; }) - ->union(self.volumes->select(v | seeded->exists(a | a.seedAt.startsWith(v.mountAt + '/'))) - ->collect(v | object ContainerMount { name := v.claim; mountAt := v.mountAt; })) - ->union(self.writablePaths->select(w | seeded->exists(a | a.seedAt.startsWith(w.path + '/'))) - ->collect(w | object ContainerMount { name := writableOf(w.path); mountAt := w.path; })); - }; - -query seedScriptOf(a : ResolvedAsset) : Sequence(String) = - let place : String = quotedWord(a.seedAt) in - let staged : String = quotedWord(a.seedAt + '.seeding') in - Sequence{ - 'mkdir -p ' + quotedWord(a.seedAt.substring(1, a.seedAt.lastIndexOf('/') - 1)), - 'if [ -e ' + place + ' ]; then cp -p ' + place + ' ' + quotedWord(a.seedAt + '.superseded') + '; fi', - 'cp ' + quotedWord('/seed/' + a.name + '/' + a._from.substring(a._from.lastIndexOf('/') + 1, a._from.size())) - + ' ' + staged, - 'chmod 0600 ' + staged, - 'mv ' + staged + ' ' + place}; - --- A word the shell reads as it stands. -query quotedWord(word : String) : String = '\'' + word.replaceAll('\'', '\'\\\\\'\'') + '\''; - --- The volume a writable path is, named after it. -query writableOf(path : String) : String = - 'writable-' + path.substring(2, path.size()).toLower().replaceAll('[^a-z0-9]+', '-'); - --- The endpoint the edge asks a tier's forward-auth at: its provider's Stable --- Address on the surface, at the port its Process provides it on, and the path --- (spec/v1/14-platform-intent.md#tiers). -query ForwardAuth::endpoint() : String = - let port : Integer = self.provider.processes.provides - ->select(s | s.key = self.surface)->any(true).value in - 'http://' + self.provider.id + '-' + self.surface + '.' + STABLE_NAMESPACE + '.svc.cluster.local:' - + port.toString() + self.path; - --- A file the project names, read from beside it. -query assetOf(project : String, source : String) : AssetFile = - let found : Sequence(AssetFile) = - assetFiles->select(f | f.project = project and f._from = source)->asSequence() in - if found->isEmpty() then unfiled(source) else found->first() endif; - --- The content of a file the project names, read from beside it. -query fileOf(project : String, source : String) : String = assetOf(project, source).content; - --- A dashboard's own uid: the string its JSON's top-level `uid` key holds, however the file is laid --- out. Its strings and brackets are read as tokens, so a nested object's uid is not taken for it, --- and neither is a bracket or a key spelled inside a string. -query uidOf(content : String) : String = - let found : String = content.replaceAll('("(?:[^"\\\\]|\\\\.)*"|[{}\\[\\]])', '\t$1\t').tokenize('\t') - ->iterate(t; acc : Tuple(depth : Integer, state : Integer, uid : String) = Tuple{depth = 0, state = 0, uid = ''} | - if acc.uid <> '' or t.trim() = '' then acc - else if t = '{' or t = '[' then Tuple{depth = acc.depth + 1, state = 0, uid = ''} - else if t = '}' or t = ']' then Tuple{depth = acc.depth - 1, state = 0, uid = ''} - else if acc.state = 2 and t.startsWith('"') then Tuple{depth = acc.depth, state = 0, uid = t.substring(2, t.size() - 1)} - else if acc.state = 1 and t.trim() = ':' then Tuple{depth = acc.depth, state = 2, uid = ''} - else if acc.depth = 1 and t = '"uid"' then Tuple{depth = acc.depth, state = 1, uid = ''} - else Tuple{depth = acc.depth, state = 0, uid = ''} endif endif endif endif endif endif).uid in - if found = '' then null else found endif; - --- A dashboard's name: its Application, then its uid in lower case, a hyphen for anything else. -query dashboardName(app : String, uid : String) : String = - app + '-' + uid.toLower().replaceAll('[^a-z0-9-]', '-'); - --- The data source inputs a vendored dashboard declares, by name. -query inputsOf(content : String) : Sequence(String) = - let at : Integer = content.indexOf('"__inputs"') in - if at <= 0 then Sequence{} else - let rest : String = content.substring(at, content.size()) in - let segment : String = rest.substring(1, rest.indexOf(']')) in - segment.tokenize('}')->select(e | e.indexOf('"type": "datasource"') > 0 and e.indexOf('"name": "') > 0) - ->collect(e | let named : String = e.substring(e.indexOf('"name": "') + 9, e.size()) in - named.substring(1, named.indexOf('"') - 1))->asSequence() endif; - -query spawnVariable(template : String, what : String) : String = - 'SPAWN_' + template.toUpper().replaceAll('[^A-Z0-9]', '_') + '_' + what; - -query unfiled(source : String) : AssetFile { - assert fatal (false) with log(source + ': an Asset whose file is not beside its project'); - return null; -} - -query unplaced(source : String) : ResolvedAsset { - assert fatal (false) with log(source + ': a placeholder in an Asset is not resolved yet'); - return null; -} - --- An Asset's file name, spelled as the part of an object name it becomes. -query spelled(path : String) : String = - path.substring(path.lastIndexOf('/') + 1, path.size()).toLower().replaceAll('[^a-z0-9]+', '-'); - --- ===================================================================== edges - --- A dependency edge resolved against the union, then the platform's register --- of providers (spec/v1/16-dependencies.md#dependency-edges): the pair names one --- Process, one port and one address, and the peer a policy admits. `consumer` --- is the project holding the edge, whose namespace the alias lives in. -query edgeOf(e : DependencyEdge, consumer : String) : ResolvedEdge = - let providers : Sequence(Tuple(project : String, process : PI::Process)) = - projects->collect(prj | prj.applications->select(a | a.id = e.application).processes - ->select(p | p.provides->exists(s | s.key = e.surface)) - ->collect(p | Tuple{project = prj.project, process = p}))->flatten() in - if providers->notEmpty() then - let first : Tuple(project : String, process : PI::Process) = providers->first() in - let at : Integer = first.process.provides->select(s | s.key = e.surface)->any(true).value in - let host : String = first.process.name + '.' - + namespaceOf(first.project) + '.svc.cluster.local' in - object ResolvedEdge { - application := e.application; - surface := e.surface; - address := dialled(e, host, consumer) + ':' + at.toString(); - target := aliasTarget(e, host, consumer); - peers := Sequence{object PolicyPeer { - namespace := namespaceOf(first.project); - process := first.process.name; - port := at; - }}; - } - else - let registered : Sequence(Provider) = estate.providers - ->select(r | r.name = e.application and r.surfaces->exists(s | s.key = e.surface))->asSequence() in - if registered->isEmpty() then unprovided(e) else - let host : String = registered->first().address in - object ResolvedEdge { - application := e.application; - surface := e.surface; - address := dialled(e, host, consumer) + ':' - + registered->first().surfaces->select(s | s.key = e.surface)->any(true).value.toString(); - target := aliasTarget(e, host, consumer); - } endif - endif; - --- Where a provider's surface is served, before any alias: its Process's Service in --- its home namespace, or the address the platform registers for it. -query homeHostOf(e : DependencyEdge) : String = - let providers : Sequence(Tuple(project : String, process : PI::Process)) = - projects->collect(prj | prj.applications->select(a | a.id = e.application).processes - ->select(p | p.provides->exists(s | s.key = e.surface)) - ->collect(p | Tuple{project = prj.project, process = p}))->flatten() in - if providers->notEmpty() then - providers->first().process.name + '.' - + namespaceOf(providers->first().project) + '.svc.cluster.local' - else - let registered : Sequence(Provider) = estate.providers - ->select(r | r.name = e.application and r.surfaces->exists(s | s.key = e.surface))->asSequence() in - if registered->isEmpty() then null else registered->first().address endif - endif; - --- The platform's own estate-scoped share, which every render holds: the two priority classes --- (spec/v1/14-platform-intent.md#priority) and a binding per Human Grant --- (spec/v1/14-platform-intent.md#human-grants). -query platformFiles() : Sequence(Deliverable) = - (if estate.priority = null then Sequence{} else Sequence{ - object PriorityClassFile { - path := 'estate/priority-classes/priorityclasses.yaml'; - adapter := AdapterName::kubernetes; - data := object ResolvedPriority { name := estate.priority.data.name; value := estate.priority.data.value; }; - critical := object ResolvedPriority { name := estate.priority.critical.name; value := estate.priority.critical.value; }; - }.oclAsType(Deliverable), - object IndexFile { - path := 'estate/priority-classes/kustomization.yaml'; - adapter := AdapterName::kubernetes; - resources := Sequence{'priorityclasses.yaml'}; - }.oclAsType(Deliverable)} endif) - ->union(if estate.humanGrants->isEmpty() then Sequence{} else Sequence{ - object HumanGrantFile { - path := 'estate/human-grants/clusterrolebindings.yaml'; - adapter := AdapterName::kubernetes; - grants := estate.humanGrants->collect(g | object HumanGrantBinding { - group := g.group; - clusterRole := g.clusterRole.spelling(); - }); - }.oclAsType(Deliverable), - object IndexFile { - path := 'estate/human-grants/kustomization.yaml'; - adapter := AdapterName::kubernetes; - resources := Sequence{'clusterrolebindings.yaml'}; - }.oclAsType(Deliverable)} endif); - -query HumanGrantRole::spelling() : String = - if self = HumanGrantRole::clusterAdmin then 'cluster-admin' - else if self = HumanGrantRole::admin then 'admin' - else if self = HumanGrantRole::edit then 'edit' else 'view' endif endif endif; - --- The Stable Addresses the project's aliases point at --- (spec/v1/16-dependencies.md#the-stable-address): one ExternalName Service per --- surface, in the estate's own namespace, naming where the surface is served. -query EffectiveProject::stableAddressFiles() : Sequence(Deliverable) = - let root : String = 'estate/stable-addresses/' in - let aliased : Sequence(DependencyEdge) = - self.applications.processes.dependsOn->asSequence() - ->select(e | homeHostOf(e) <> null and not isLiteral(homeHostOf(e))) in - let named : Sequence(DependencyEdge) = - aliased->select(e | aliased->select(o | o.application = e.application and o.surface = e.surface) - ->first() = e)->sortedBy(e | e.application + '-' + e.surface) in - if named->isEmpty() then Sequence{} else - Sequence{ - object StableAddressFile { - path := root + 'services.yaml'; - adapter := AdapterName::kubernetes; - namespace := STABLE_NAMESPACE; - addresses := named->collect(e | object Alias { name := e.application + '-' + e.surface; target := homeHostOf(e); }); - }.oclAsType(Deliverable), - object NamespaceFile { - path := root + 'namespace.yaml'; - adapter := AdapterName::kubernetes; - namespace := STABLE_NAMESPACE; - }.oclAsType(Deliverable), - object IndexFile { - path := root + 'kustomization.yaml'; - adapter := AdapterName::kubernetes; - resources := Sequence{'namespace.yaml', 'services.yaml'}; - }.oclAsType(Deliverable)} endif; - --- The name an edge's alias holds: what its consumer dials, up to the port. -query aliasName(e : ResolvedEdge) : String = e.address.substring(1, e.address.lastIndexOf(':') - 1); - --- The suffix a Service in `consumer`'s own namespace carries. -query localSuffix(consumer : String) : String = '.' + namespaceOf(consumer) + '.svc.cluster.local'; - -query isLocal(host : String, consumer : String) : Boolean = host.endsWith(localSuffix(consumer)); - --- An IP, which no name can stand for. -query isLiteral(host : String) : Boolean = host.replaceAll('[0-9.]', '') = '' or host.indexOf(':') > 0; - --- What the consumer dials (spec/v1/16-dependencies.md#the-alias): a provider in --- its own namespace by its own Service name, an IP as it stands, anything else by --- its alias. -query dialled(e : DependencyEdge, host : String, consumer : String) : String = - if isLocal(host, consumer) then host.substring(1, host.size() - localSuffix(consumer).size()) - else if isLiteral(host) then host - else aliasNameOf(e, consumer) endif endif; - --- Where an alias points, on an edge that derives one: the surface's Stable --- Address, so a provider that moves changes the Stable Address alone, never a --- consumer's render (spec/v1/16-dependencies.md#the-stable-address). -query aliasTarget(e : DependencyEdge, host : String, consumer : String) : String = - if isLocal(host, consumer) or isLiteral(host) then null - else e.application + '-' + e.surface + '.' + STABLE_NAMESPACE + '.svc.cluster.local' endif; - --- The alias's name: the Application Id, or the Id and the surface where the --- project's edges name several surfaces of it, since a name carries no port. -query aliasNameOf(e : DependencyEdge, consumer : String) : String = - let surfaces : Set(String) = projects->select(prj | prj.project = consumer).applications.processes.dependsOn - ->select(d | d.application = e.application)->collect(d | d.surface)->asSet() in - if surfaces->size() > 1 then e.application + '-' + e.surface else e.application endif; - -query unprovided(e : DependencyEdge) : ResolvedEdge { - assert fatal (false) with log(e.application + '.' + e.surface + ': no provider in the union'); - return null; -} - --- ============================================================== eligibility - --- The copies a node must fit: a continuous Process runs its new version beside its old one. -query copiesOf(p : PI::Process) : Integer = - if p.cutover = PI::Cutover::continuous then 2 else 1 endif; - --- Eligibility, not bin-packing: each Process against allocatable alone, on every --- dimension it declared (spec/v1/20-resolved-deployment.md#layer-2-does-not-assign-a-node). --- What one copy asks for is the Process and its sidecars together, the VPN container beside it --- where it attaches to one, the step that seeds its Assets where it seeds any, and the memory --- its writable paths hold. E_NO_VPN_POLICY and E_NO_SEEDER refused what the platform runs none of. -query seeds(p : PI::Process) : Boolean = - p.assets->exists(a | a.oclIsKindOf(SeededAsset)) and estate.seeder <> null; - -query requestedMemory(p : PI::Process) : Real = - p.sidecars->collect(c | mebibytes(c.memory))->sum() + mebibytes(p.placement.memory) - + (if p.vpn = null or estate.vpn = null then 0 else mebibytes(estate.vpn.memory) endif) - + (if seeds(p) then mebibytes(estate.seeder.memory) else 0 endif) - + p.writablePaths->select(w | w.oclIsKindOf(MemoryPath)) - ->collect(w | mebibytes(w.oclAsType(MemoryPath).memory))->sum(); - -query requestedCpu(p : PI::Process) : Integer = - p.sidecars->collect(c | millicores(c.cpu))->sum() + millicores(p.placement.cpu) - + (if p.vpn = null or estate.vpn = null then 0 else millicores(estate.vpn.cpu) endif) - + (if seeds(p) then millicores(estate.seeder.cpu) else 0 endif); - -query eligible(p : PI::Process, n : Node) : Boolean = - mebibytes(n.allocatable.memory) >= requestedMemory(p) * copiesOf(p) - and millicores(n.allocatable.cpu) >= requestedCpu(p) * copiesOf(p) - and (p.placement.arch->isEmpty() or p.placement.arch->exists(a | a.spelling() = n.arch)) - and (p.placement.site = null or p.placement.site = n.site) - and p.placement.capabilities->forAll(c | n.capabilities->includes(c)) - and (p.placement.gpu = null or matchingCards(p, n)->notEmpty()) - and (p.placement.disk = null or n.disks->exists(d | - p.placement.disk.media->exists(m | m.spelling() = d.media))) - -- A library the Process mounts holds it to the library's node. - and p.libraries->forAll(m | libraryOf(m._library) <> null and libraryOf(m._library).node = n.name) - -- Its L4 exposures hold it to the sites of its pools and the nodes of its node addresses. - and l4Of(p)->forAll(e | let a : L4AddressDeclaration = addressOf(e.address) in - if a.oclIsKindOf(PoolAddress) then a.oclAsType(PoolAddress).site = n.site - else a.oclAsType(NodeAddress).node = n.name endif); - --- The L4 exposures of the Process's Application that reach it. -query l4Of(p : PI::Process) : Sequence(Tuple(address : String, port : Integer, protocol : L4Protocol, surface : Surface)) = - p.oclAsType(ECORE::EObject).eContainer().oclAsType(EffectiveApplication).l4Exposure - ->select(e | e.process = p) - ->collect(e | Tuple{address = e.address, port = e.port, protocol = e.protocol, surface = e.surface}) - ->asSequence()->union(tierL4Of(p)); - --- The L4 Address the Platform document names. -query addressOf(name : String) : L4AddressDeclaration = - estate.l4Addresses->select(a | a.key = name)->any(true).value; - --- A Process's Services on the pools it is exposed on, one per address, each port by port --- (spec/v1/16-dependencies.md#l4-exposure). -query l4ServicesOf(p : PI::Process) : Sequence(ResolvedL4Service) = - let pooled : Sequence(Tuple(address : String, port : Integer, protocol : L4Protocol, surface : Surface)) = l4Of(p)->select(e | addressOf(e.address).oclIsKindOf(PoolAddress)) in - pooled.address->asSet()->sortedBy(a | a)->collect(address | object ResolvedL4Service { - name := p.name + '-' + address; - pool := address; - ports := pooled->select(e | e.address = address) - ->sortedBy(e | e.port * 2 + (if e.protocol = L4Protocol::tcp then 0 else 1 endif)) - ->collect(e | object L4Port { - name := e.protocol.toString() + '-' + e.port.toString(); - port := e.port; - protocol := e.protocol.toString().toUpper(); - targetPort := e.surface.value; - }); - })->asSequence(); - --- The VPN container beside an attached Process (spec/v1/20-resolved-deployment.md#the-vpn-attachment): --- the platform's image and quantities, its settings with the three values derived from the --- Process sorted in among them, and the credential only it reads. E_NO_VPN_POLICY refused an --- attachment with no Platform `vpn`. --- One key per Process: a provider takes a key for one device, so two tunnels on one key knock --- each other off. -query credentialOf(p : PI::Process) : String = - estate.vpn.credential + '/' + owner(p) + '-' + p.name; - -query vpnOf(p : PI::Process) : ResolvedVpn = - let policy : VpnPolicy = estate.vpn in - let locks : LockedImage = locked(policy.image) in - let ports : Sequence(Integer) = p.provides->collect(s | s.value)->asSet()->sortedBy(n | n)->asSequence() in - let fromProcess : Sequence(Tuple(name : String, value : String)) = - (if ports->isEmpty() then Sequence{} else Sequence{Tuple{name = 'FIREWALL_INPUT_PORTS', - value = ports->iterate(n; acc : String = '' | if acc = '' then n.toString() else acc + ',' + n.toString() endif)}} endif) - ->union(Sequence{Tuple{name = 'VPN_PORT_FORWARDING', value = if p.vpn.forwardedPort then 'on' else 'off' endif}}) - ->union(if p.vpn.forwardedPort then Sequence{Tuple{name = 'VPN_PORT_FORWARDING_UP_COMMAND', - value = '/bin/sh -c \'echo {{PORT}} > ' + FORWARDED_PORT_FILE + '\''}} else Sequence{} endif) in - let settings : Sequence(Tuple(name : String, value : String)) = - policy.settings->collect(e | Tuple{name = e.key, value = e.value})->asSequence() in - object ResolvedVpn { - image := locks.repository + '@' + locks.digest; - imageVersion := locks.version; - memory := policy.memory; - cpu := policy.cpu; - forwardedPort := p.vpn.forwardedPort; - environment := settings->union(fromProcess)->sortedBy(t | t.name)->collect(t | object EnvEntry { - name := t.name; - value := t.value; - }); - credential := object ResolvedGrant { - path := credentialOf(p); - _access := 'read'; - delivery := 'env'; - destination := destinationOf(p.name + '-vpn', credentialOf(p)); - }; - }; - --- The node's cards that match every term the Process's `gpu` declares. -query matchingCards(p : PI::Process, n : Node) : OrderedSet(Gpu) = - n.gpus->select(g | - (p.placement.gpu._class = null or g._class = p.placement.gpu._class) - and (p.placement.gpu.memory = null or g.memoryMib >= mebibytes(p.placement.gpu.memory)) - and (p.placement.gpu.vendor->isEmpty() or p.placement.gpu.vendor->includes(g.vendor)) - and (p.placement.gpu.model->isEmpty() or p.placement.gpu.model->includes(g.model))); - --- The Platform's entry for the vendor of the cards the Process may land on: --- E_GPU_VENDOR_AMBIGUOUS and E_NO_GPU_POLICY refused anything but one. -query gpuOf(p : PI::Process) : ResolvedGpu = - let vendor : String = contract.nodes->select(n | eligible(p, n)) - ->collect(n | matchingCards(p, n))->flatten()->any(true).vendor in - let policy : GpuVendorPolicy = estate.gpus->select(g | g.key = vendor)->collect(g | g.value)->any(true) in - object ResolvedGpu { - resource := policy.resource; - runtimeClass := policy.runtimeClass; - }; - --- =============================================================== environment - --- The env file a render for the platform's cluster reads: the base, overlaid by --- that cluster's own file; then the Runtime Profile's values. -query environmentOf(p : PI::Process, prj : EffectiveProject) : Sequence(EnvEntry) = - let authored : Sequence(EnvEntry) = authoredOf(p)->collect(v | v.entry(prj)), - profile : Sequence(EnvEntry) = profileOf(p) in - if authored->exists(a | profile->exists(f | f.name = a.name)) - then unwritten(p) - else authored->union(profile) endif; - --- A Runtime Profile key written in an env file is a build error the checks do not --- make yet, so the run stops rather than carry two values for one name. -query unwritten(p : PI::Process) : Sequence(EnvEntry) { - assert fatal (false) with log(p.name + ' writes a Runtime Profile key in an env file'); - return Sequence{}; -} - -query authoredOf(p : PI::Process) : Sequence(EnvVariable) = - p.env->collect(f | f.entries)->asSequence(); - -query EnvVariable::entry(prj : EffectiveProject) : EnvEntry = - if self.value.oclIsKindOf(EnvLiteral) then - object EnvEntry { name := self.name; value := self.value.oclAsType(EnvLiteral).text; } - else - self.value.oclAsType(Placeholder).entryFor(self.name, prj) - endif; - --- A placeholder's value (spec/v1/10-project-intent.md#secret-references): one --- key of a grant, one coordinate of the Process's own edge, one field of an --- exposure the union declares, or the Process's own identity; any literal text --- after it is kept, except after a secret. -query Placeholder::entryFor(variable : String, prj : EffectiveProject) : EnvEntry = - let owner : PI::Process = self.oclAsType(ECORE::EObject).eContainer().eContainer().eContainer() - .oclAsType(PI::Process) in - let suffix : String = if self.suffix = null then '' else self.suffix endif in - if self.kind = PlaceholderKind::secret and self.source.lastIndexOf('#') <= 0 then - unresolved(variable, 'a secret placeholder names no key') - else if self.kind = PlaceholderKind::secret then - let cut : Integer = self.source.lastIndexOf('#') in - let secretPath : String = self.source.substring(1, cut - 1) in - let secretKey : String = self.source.substring(cut + 1, self.source.size()) in - if owner.secrets->exists(g | g.oclIsKindOf(KvGrant) and g.oclAsType(KvGrant).path = secretPath - and g.delivery = Delivery::env and g.oclAsType(KvGrant).keys.name->includes(secretKey)) then - object EnvEntry { - name := variable; - -- A key the Process may start without is optional in the Secret it reads. - secret := object SecretReference { - path := secretPath; - key := secretKey; - optional := owner.secrets->exists(g | g.oclIsKindOf(KvGrant) and g.oclAsType(KvGrant).path = secretPath - and g.oclAsType(KvGrant).keys->exists(k | k.oclIsKindOf(OptionalKey) and k.name = secretKey)); - }; - } - else unresolved(variable, 'a placeholder no env grant of the Process holds is E_UNAUTHORISED_SECRET_REFERENCE') endif - else if self.kind = PlaceholderKind::client and self.source = 'secret' then - -- observability: the Client's secret is read as a `${secret:}` reference would be. - object EnvEntry { - name := variable; - secret := object SecretReference { - path := clientSecretPath(prj.project, owner.oclAsType(ECORE::EObject).eContainer().oclAsType(EffectiveApplication).id); - key := 'secret'; - optional := false; - }; - } - else if self.kind = PlaceholderKind::dependency and self.source.lastIndexOf('.') > 0 - and Sequence{'accessKeyId', 'secretAccessKey'}->includes( - self.source.substring(self.source.lastIndexOf('.') + 1, self.source.size())) then - -- A key to an object store is read from the project's key to the store the edge names - -- buckets in (spec/v1/16-dependencies.md#the-bucket-catalog). - let application : String = self.source.substring(1, self.source.lastIndexOf('.') - 1) in - let coordinate : String = self.source.substring(self.source.lastIndexOf('.') + 1, self.source.size()) in - let edge : DependencyEdge = owner.dependsOn->select(e | e.application = application)->any(true) in - let store : String = projects.applications->select(a | a.id = application).processes - ->select(p | p.provides->exists(s | s.key = edge.surface))->any(true).name in - object EnvEntry { - name := variable; - secret := object SecretReference { - path := 'secret/data/' + prj.project + '/' + store + '/s3'; - key := if coordinate = 'accessKeyId' then 'access-key-id' else 'secret-access-key' endif; - }; - } - else if self.kind = PlaceholderKind::dependency and self.source.lastIndexOf('.') > 0 - and Sequence{'username', 'password'}->includes(self.source.substring(self.source.lastIndexOf('.') + 1, self.source.size())) then - -- A login is read from the Secret the edge's credential is synced to, or - -- E_UNRESOLVED_PLACEHOLDER refused the placeholder. - object EnvEntry { - name := variable; - secret := object SecretReference { - path := 'database/creds/' + credentialRole( - owner.oclAsType(ECORE::EObject).eContainer().oclAsType(EffectiveApplication), prj); - key := self.source.substring(self.source.lastIndexOf('.') + 1, self.source.size()); - }; - } - else - object EnvEntry { name := variable; value := self.textFor(owner, prj) + suffix; } - endif endif endif endif endif; - -query Placeholder::textFor(owner : PI::Process, prj : EffectiveProject) : String = - if self.kind = PlaceholderKind::dependency then dependencyValue(self.source, owner) - else if self.kind = PlaceholderKind::exposure then exposureValue(self.source) - -- A Client hands its own Application the issuer it signs in with and its id, the Application Id. - else if self.kind = PlaceholderKind::client and self.source = 'issuer' then estate.signIn.issuer - else if self.kind = PlaceholderKind::client and self.source = 'id' - then owner.oclAsType(ECORE::EObject).eContainer().oclAsType(EffectiveApplication).id - else if self.source = 'namespace' then namespaceOf(prj.project) - -- The Secret Store has no namespaces, so the Vault role's name carries the one the Process - -- is unique in; the ServiceAccount is the Process's own name. - else if self.source = 'vaultRole' then namespaceOf(prj.project) + '-' + owner.name - else owner.name endif endif endif endif endif endif; - --- `${dependency:.}`: one coordinate of the Process's own edge. -query dependencyValue(source : String, owner : PI::Process) : String = - if source.lastIndexOf('.') <= 0 then - unresolvedText(source, 'a dependency placeholder names no coordinate') else - let cut : Integer = source.lastIndexOf('.') in - let application : String = source.substring(1, cut - 1) in - let coordinate : String = source.substring(cut + 1, source.size()) in - let edges : Sequence(DependencyEdge) = owner.dependsOn->select(e | e.application = application)->asSequence() in - if edges->size() <> 1 or (coordinate <> 'host' and coordinate <> 'port' and coordinate <> 'endpoint') - then unresolvedText(source, 'a dependency placeholder names no one edge of the Process and no coordinate of it') - else - let address : String = edgeOf(edges->first(), owner(owner)).address in - let colon : Integer = address.lastIndexOf(':') in - -- An object store is reached over HTTP at what the edge dials. - if coordinate = 'endpoint' then 'http://' + address - else if coordinate = 'host' then address.substring(1, colon - 1) - else address.substring(colon + 1, address.size()) endif endif - endif endif; - --- `${exposure:.#}`: one field of an exposure the union declares. -query exposureValue(source : String) : String = - if source.lastIndexOf('#') <= 0 or source.substring(1, source.lastIndexOf('#') - 1).lastIndexOf('.') <= 0 then - unresolvedText(source, 'an exposure placeholder names no field of an exposure') else - let hash : Integer = source.lastIndexOf('#') in - let head : String = source.substring(1, hash - 1) in - let dot : Integer = head.lastIndexOf('.') in - let application : String = head.substring(1, dot - 1) in - let name : String = head.substring(dot + 1, head.size()) in - let field : String = source.substring(hash + 1, source.size()) in - let exposures : Sequence(Exposure) = projects.applications->select(a | a.id = application) - .exposure->select(e | e.name = name)->asSequence() in - if exposures->isEmpty() or not Sequence{'url', 'host', 'scheme'}->includes(field) - then unresolvedText(source, 'an exposure placeholder names no exposure of the union and no field of it') - else - let exposure : Exposure = exposures->first() in - let scheme : String = if tierFor(exposure.audience).listener = Listener::tls then 'https' else 'http' endif in - if field = 'host' then exposure.host - else if field = 'scheme' then scheme - else scheme + '://' + exposure.host endif endif - endif endif; - -query unresolved(variable : String, message : String) : EnvEntry { - assert fatal (false) with log(variable + ': ' + message); - return null; -} - -query unresolvedText(source : String, message : String) : String { - assert fatal (false) with log(source + ': ' + message); - return null; -} - --- The Runtime Profile's values (spec/v1/10-project-intent.md#runtime-profiles). -query profileOf(p : PI::Process) : Sequence(EnvEntry) = - if not exportsTelemetry(p) then Sequence{} - else - Sequence{object EnvEntry { name := 'DEPLOYMENT_ENVIRONMENT'; value := estate.metadata.cluster; }} - ->union(if collectorEndpoint() = null then Sequence{} - else Sequence{object EnvEntry { name := 'OTEL_EXPORTER_OTLP_ENDPOINT'; value := collectorEndpoint(); }} endif) - ->append(object EnvEntry { name := 'OTEL_SERVICE_NAME'; value := p.name; }) - ->union(if p.provides->size() = 1 - then Sequence{object EnvEntry { name := 'PORT'; value := p.provides->any(true).value.toString(); }} - else Sequence{} endif) - endif; - --- Whether a runtime's profile exports telemetry and HTTP server metrics. -query exportsTelemetry(p : PI::Process) : Boolean = - p.runtime = Runtime::jvm or p.runtime = Runtime::node or p.runtime = Runtime::python; - --- The named collector's `otlp` surface, where the platform names one and the --- union declares it (spec/v1/14-platform-intent.md#telemetry). -query collectorEndpoint() : String = - if estate.telemetry = null then null - else let address : String = surfaceAddress(estate.telemetry.collector.id, OTLP_SURFACE) in - if address = null then null else 'http://' + address endif - endif; - --- The in-cluster address of the Process of `application` that provides `surface`. -query surfaceAddress(application : String, surface : String) : String = - let providers : Sequence(Tuple(project : String, process : PI::Process)) = - projects->collect(prj | prj.applications->select(a | a.id = application).processes - ->select(p | p.provides->exists(s | s.key = surface)) - ->collect(p | Tuple{project = prj.project, process = p}))->flatten() in - if providers->isEmpty() then null - else let first : Tuple(project : String, process : PI::Process) = providers->first() in - first.process.name + '.' + namespaceOf(first.project) - + '.svc.cluster.local:' + first.process.provides->select(s | s.key = surface)->any(true).value.toString() - endif; - --- ================================================================== exposure - --- The priority class a Process runs at (spec/v1/14-platform-intent.md#priority): the --- data class for one that runs an engine, the critical class for the foundation and --- the Applications the platform names, none otherwise. -query priorityOf(p : PI::Process, app : EffectiveApplication, prj : EffectiveProject) : String = - let policy : PriorityPolicy = estate.priority in - if policy = null then null - else if p.engine <> Engine::absent then policy.data.name - else if foundation()->includes(prj.project + '/' + app.id) - or policy.criticalApplications->exists(a | heldName(a) = prj.project + '/' + app.id) - then policy.critical.name - else null endif endif endif; - --- `/` of an Application a document declares. -query heldName(a : Application) : String = - a.oclAsType(ECORE::EObject).eContainer().oclAsType(Project).project + '/' + a.id; - --- The Applications the Platform document names in a privileged role. -query foundation() : Set(String) = - let none : Sequence(Application) = Sequence{} in - estate.tiers->collect(t | t.traefik)->asSequence() - ->union(if estate.delivery = null then none - else estate.delivery.machinery->asSequence()->append(estate.delivery.gate) endif) - ->union(if estate.delivery = null or estate.delivery.reporter = null then none - else Sequence{estate.delivery.reporter} endif) - ->union(if estate.apiAccess = null then none else estate.apiAccess.holders->asSequence() endif) - ->union(if estate.telemetry = null then none - else Sequence{estate.telemetry.collector, estate.telemetry.metrics} endif) - ->union(if estate.secretStore = null then none else Sequence{estate.secretStore} endif) - ->union(if estate.signIn = null then none else Sequence{estate.signIn.provider} endif) - ->collect(a | heldName(a))->asSet(); - --- The tier carrying an audience, or E_NO_TIER_FOR_AUDIENCE refused the set. -query tierFor(audience : Audience) : Tier = - estate.tiers->select(t | t.audiences->includes(audience))->first(); - -mapping Exposure::exposure(in app : EffectiveApplication, in prj : EffectiveProject) - : ResolvedExposure { - name := self.name; - host := self.host; - tier := tierFor(self.audience).name; - listener := if tierFor(self.audience).listener = Listener::tls then 'tls' else 'plain' endif; - certificates := if tierFor(self.audience).certificates = CertificateSource::acme then 'acme' else 'none' endif; - proxyApplication := tierFor(self.audience).traefik.id; - proxyNamespace := namespaceOf(projectOf(tierFor(self.audience).traefik.id)); - ingressClass := tierFor(self.audience).ingressClass; - -- The name the tier publishes the host behind, or, where the exposure is not - -- proxied, the tier's own address (spec/v1/14-platform-intent.md#tiers). - dns := let named : TierDns = tierFor(self.audience).dns in - if named = null then null - else if self.proxied = false then object ExposureDns { target := named.direct; proxied := false; } - else object ExposureDns { target := named.target; proxied := named.proxied; } endif endif; - routes := self.routes->collect(r | object ResolvedRoute { - path := r.path; - match := r.match.resolvedMatch(); - audience := r.audienceOf(self).spelling(); - precedence := precedenceWith(rankOf(r), exposureRanks(self, app)); - process := r.process.resolveone(ResolvedProcess); - surface := r.surface.key; - middleware := middlewareOf(r, self, app, prj); - })->union(if derivesGateRoute(app, self) then Sequence{gateRouteOf(self, app)} else Sequence{} endif); -} - -query Route::audienceOf(exposure : Exposure) : Audience = - if self.audience <> Audience::absent then self.audience else exposure.audience endif; - --- Where a route sorts: every `exact` before any `prefix`, a longer prefix before --- a shorter one, and its precedence is one more than the distinct ranks before it. -query rankOf(r : Route) : Integer = - if r.match = PI::Match::exact then -1000000 else -r.path.size() endif; - -query precedenceOf(r : Route, routes : Collection(Route)) : Integer = - routes->collect(o | rankOf(o))->asSet()->select(k | k < rankOf(r))->size() + 1; - --- The chain the tier, the audience and the content profile derive, each step named as the route --- names its Middleware: a shared one in the proxy's namespace, by its kind and content policy, or --- a route's own beside its IngressRoute, by the route's position. -query middlewareOf(r : Route, exposure : Exposure, app : EffectiveApplication, prj : EffectiveProject) - : Sequence(MiddlewareStep) = - let proxy : String = namespaceOf(projectOf(tierFor(exposure.audience).traefik.id)) in - let own : String = app.id + '-' + exposure.name + '-' + exposure.routes->indexOf(r).toString() in - (if r.audienceOf(exposure) = Audience::authenticated and asksTheGate(app, exposure) - then Sequence{object MiddlewareStep { - kind := MiddlewareKind::forwardAuth; - endpoint := tierFor(r.audienceOf(exposure)).forwardAuth.endpoint(); - name := 'forward-auth'; - namespace := proxy; - }} - else Sequence{} endif) - ->append(object MiddlewareStep { - kind := MiddlewareKind::securityHeaders; - if exposure.oclAsType(ECORE::EObject).states('contentPolicy') - then contentPolicy := exposure.contentPolicy.spelling() endif; - name := if contentPolicy = null then 'security-headers' - else 'security-headers-' + contentPolicy endif; - namespace := proxy; - }) - ->union(if r.redirectTo = null then Sequence{} - else Sequence{object MiddlewareStep { - kind := MiddlewareKind::redirect; - redirectTo := r.redirectTo; - name := own + '-redirect'; - namespace := namespaceOf(prj.project); - }} endif) - -- A client that has sent nothing may send its whole allowance at once, and the - -- tier decides which address a client is counted by. - ->union(if r.rateLimit = null then Sequence{} - else Sequence{object MiddlewareStep { - kind := MiddlewareKind::rateLimit; - allowance := r.rateLimit.requests; - per := r.rateLimit.per; - burst := r.rateLimit.requests; - -- A host published straight at the tier's own address meets its clients without the proxy. - clientAddress := if exposure.proxied <> false and tierFor(r.audienceOf(exposure)).oclAsType(ECORE::EObject).states('proxiedBy') - then 'cloudflare' else 'connection' endif; - name := own + '-rate-limit'; - namespace := namespaceOf(prj.project); - }} endif); - --- ============================================================ k3s's metrics - --- k3s's own components, on the metrics stack the Platform document names, where the bootstrap set --- records them (spec/v1/14-platform-intent.md#k3ss-metrics), scraped as the stack's first Process. -query k3sScrapeOf(app : EffectiveApplication, prj : EffectiveProject) : ResolvedK3sScrape = - if estate.bootstrap.k3s = null or estate.telemetry = null or estate.telemetry.metrics = null - or heldName(estate.telemetry.metrics) <> prj.project + '/' + app.id then null else - let metrics : K3sMetrics = estate.bootstrap.k3s.metrics in - object ResolvedK3sScrape { - identity := app.processes->first().name; - interval := estate.monitors.interval; - timeout := estate.monitors.timeout; - labels := estate.monitors.labels->collect(l | object KeyValue { key := l.key; value := l.value; }); - if metrics.kubelet <> null then kubeletPort := metrics.kubelet.port endif; - -- A holder-shaped reference, or the schema refused it. - if metrics.apiServer <> null then apiServerNamespace := metrics.apiServer.service.substringBefore('/') endif; - if metrics.apiServer <> null then apiServerService := metrics.apiServer.service.substringAfter('/') endif; - if metrics.apiServer <> null then apiServerPort := metrics.apiServer.port endif; - if metrics.coreDns <> null then coreDnsNamespace := estate.substrate.clusterDns endif; - if metrics.coreDns <> null then coreDnsPort := metrics.coreDns.port endif; - } endif; - --- ================================================================= Grafana - --- The monitoring stack's Grafana as the Grafana operator reaches it --- (spec/v1/14-platform-intent.md#grafanas-instance-and-data-sources): the admin credential the --- Vault policy job generates for it and both read, the instance every dashboard selects, and the --- data sources its edges into the monitoring stack derive. - --- The two keys of Grafana's admin credential, and the variables Grafana reads them from. -property GRAFANA_ADMIN : Sequence(Tuple(key : String, variable : String)) = Sequence{ - Tuple{key = 'user', variable = 'GF_SECURITY_ADMIN_USER'}, - Tuple{key = 'password', variable = 'GF_SECURITY_ADMIN_PASSWORD'}}; - --- Where Grafana provisions the data sources the render derives. -property DATASOURCES_AT : String = '/etc/grafana/provisioning/datasources/datasources.yaml'; - --- Whether the Process is the one the operator reaches: the Grafana role's first. -query isGrafana(p : PI::Process, app : EffectiveApplication, prj : EffectiveProject) : Boolean = - estate.monitoring <> null and heldName(estate.monitoring.grafana) = prj.project + '/' + app.id - and app.processes->first().name = p.name; - --- Where the admin credential of a Project's Grafana is generated: under the Project's own prefix. -query grafanaAdminPath(prj : EffectiveProject, app : EffectiveApplication) : String = - KV_DATA + namespaceOf(prj.project) + '/' + app.id + '-admin'; - --- The admin credential the Grafana role's Process holds: one generated document, read into the --- two variables Grafana creates its admin from. -query grafanaAdminOf(p : PI::Process, app : EffectiveApplication, prj : EffectiveProject) : Sequence(ResolvedGrant) = - if not isGrafana(p, app, prj) then Sequence{} else - let at : String = grafanaAdminPath(prj, app) in - Sequence{object ResolvedGrant { - path := at; - keys := GRAFANA_ADMIN->collect(a | a.key); - generated := GRAFANA_ADMIN->collect(a | object ResolvedGeneratedKey { key := a.key; bytes := 32; encoding := 'hex'; }); - _access := 'read'; - delivery := 'env'; - destination := destinationOf(p.name, at); - restartTargets := Sequence{p.name}; - }} endif; - -query grafanaEnvOf(p : PI::Process, app : EffectiveApplication, prj : EffectiveProject) : Sequence(EnvEntry) = - if not isGrafana(p, app, prj) then Sequence{} else - GRAFANA_ADMIN->collect(a | object EnvEntry { - name := a.variable; - secret := object SecretReference { path := grafanaAdminPath(prj, app); key := a.key; }; - }) endif; - --- The instance the Grafana operator imports every dashboard into: the Grafana role's Application, --- where the Platform document says which labels its dashboards select, reached at its Process's --- `http` surface and signed in to with the credential it generates. -query grafanaOf(app : EffectiveApplication, prj : EffectiveProject, res : ResolvedApplication) : ResolvedGrafana = - if estate.telemetry = null or estate.telemetry.dashboards = null or estate.monitoring = null - or heldName(estate.monitoring.grafana) <> prj.project + '/' + app.id then null else - let first : ResolvedProcess = res.processes->first() in - let http : Sequence(ResolvedSurface) = first.surfaces->select(s | s.name = HTTP_SURFACE)->asSequence() in - if http->isEmpty() then null else - object ResolvedGrafana { - labels := estate.telemetry.dashboards.instance->collect(i | object KeyValue { key := i.key; value := i.value; }); - url := 'http://' + first.name + '.' + namespaceOf(prj.project) + ':' + http->first().port.toString(); - secret := destinationOf(first.name, grafanaAdminPath(prj, app)); - user := 'user'; - password := 'password'; - } endif endif; - --- Each kind of data source, in the order Grafana lists them: its uid, its name and its type. -property DATASOURCE_KINDS : Sequence(Tuple(uid : String, name : String, type : String)) = Sequence{ - Tuple{uid = 'prometheus', name = 'Prometheus', type = 'prometheus'}, - Tuple{uid = 'loki', name = 'Loki', type = 'loki'}, - Tuple{uid = 'tempo', name = 'Tempo', type = 'tempo'}, - Tuple{uid = 'pyroscope', name = 'Pyroscope', type = 'grafana-pyroscope-datasource'}, - Tuple{uid = 'alertmanager', name = 'Alertmanager', type = 'alertmanager'}}; - --- The kind of data source the Application `id` is, as the Platform document names it; a later --- role names it over an earlier one. -query datasourceKind(id : String) : String = - let m : Monitoring = estate.monitoring in - let named : Sequence(Tuple(kind : String, app : Application)) = Sequence{ - Tuple{kind = 'prometheus', app = m.prometheus}, Tuple{kind = 'alertmanager', app = m.alertmanager}} - ->union(if m.stores = null then Sequence{} else Sequence{ - Tuple{kind = 'loki', app = m.stores.loki}, Tuple{kind = 'tempo', app = m.stores.tempo}, - Tuple{kind = 'pyroscope', app = m.stores.pyroscope}} endif) - ->select(t | t.app <> null and t.app.id = id) in - if named->isEmpty() then null else named->last().kind endif; - --- The data sources the Grafana role's Process derives: one per edge it declares into an --- Application the monitoring stack names, at that edge's address (a store reached twice at the --- later edge's), with the kind's own uid, linked to the others the set holds. None without one. -query datasourcesOf(p : ResolvedProcess) : Sequence(ResolvedAsset) = - let edges : Sequence(ResolvedEdge) = p.dependencies->select(e | datasourceKind(e.application) <> null)->asSequence() in - let held : Sequence(String) = DATASOURCE_KINDS->collect(k | k.uid) - ->select(k | edges->exists(e | datasourceKind(e.application) = k)) in - if held->isEmpty() then Sequence{} else - let written : String = pj(Sequence{ - Tuple{k = 'apiVersion', v = '1'}, - Tuple{k = 'datasources', v = pa(DATASOURCE_KINDS->select(k | held->includes(k.uid))->collect(k | pj(Sequence{ - Tuple{k = 'name', v = str(k.name)}, - Tuple{k = 'type', v = str(k.type)}, - Tuple{k = 'uid', v = str(k.uid)}, - Tuple{k = 'access', v = str('proxy')}, - Tuple{k = 'url', v = str('http://' + edges->select(e | datasourceKind(e.application) = k.uid)->last().address)}, - Tuple{k = 'isDefault', v = bool(k.uid = 'prometheus')}, - Tuple{k = 'editable', v = 'false'}, - Tuple{k = 'jsonData', v = datasourceLinks(k.uid, held)}}, 2)), 1)}}, 0) + '\n' in - Sequence{object ResolvedAsset { - name := p.name + '-datasources-yaml-' + written.textDigestOf().substring(8, 7 + CONTENT_DIGITS); - _from := 'datasources.yaml'; - mountAt := DATASOURCES_AT; - content := written; - }} endif; - --- What links one data source to the others the set holds: traces to logs, metrics and profiles. -query datasourceLinks(kind : String, held : Sequence(String)) : String = - let tags : String = pa(Sequence{pj(Sequence{Tuple{k = 'key', v = str('service.name')}, - Tuple{k = 'value', v = str('service_name')}}, 6)}, 5) in - if kind = 'prometheus' then pj(Sequence{ - Tuple{k = 'httpMethod', v = str('POST')}, - Tuple{k = 'exemplarTraceIdDestinations', v = if held->excludes('tempo') then null else - pa(Sequence{pj(Sequence{Tuple{k = 'name', v = str('traceID')}, Tuple{k = 'datasourceUid', v = str('tempo')}}, 5)}, 4) endif}}, 3) - else if kind = 'loki' then pj(Sequence{ - Tuple{k = 'derivedFields', v = if held->excludes('tempo') then null else - pa(Sequence{pj(Sequence{Tuple{k = 'name', v = str('trace_id')}, - Tuple{k = 'matcherRegex', v = str('"trace_id"\\s*:\\s*"([0-9a-f]+)"')}, - Tuple{k = 'datasourceUid', v = str('tempo')}, - Tuple{k = 'url', v = str('$${__value.raw}')}}, 5)}, 4) endif}}, 3) - else if kind = 'tempo' then pj(Sequence{ - Tuple{k = 'nodeGraph', v = pj(Sequence{Tuple{k = 'enabled', v = 'true'}}, 4)}, - Tuple{k = 'tracesToLogsV2', v = if held->excludes('loki') then null else pj(Sequence{ - Tuple{k = 'datasourceUid', v = str('loki')}, Tuple{k = 'filterByTraceID', v = 'true'}, - Tuple{k = 'tags', v = tags}}, 4) endif}, - Tuple{k = 'tracesToMetrics', v = if held->excludes('prometheus') then null else pj(Sequence{ - Tuple{k = 'datasourceUid', v = str('prometheus')}, Tuple{k = 'tags', v = tags}}, 4) endif}, - Tuple{k = 'serviceMap', v = if held->excludes('prometheus') then null else pj(Sequence{ - Tuple{k = 'datasourceUid', v = str('prometheus')}}, 4) endif}, - Tuple{k = 'tracesToProfilesV2', v = if held->excludes('pyroscope') then null else pj(Sequence{ - Tuple{k = 'datasourceUid', v = str('pyroscope')}, - Tuple{k = 'profileTypeId', v = str('process_cpu:cpu:nanoseconds:cpu:nanoseconds')}, - Tuple{k = 'tags', v = tags}}, 4) endif}}, 3) - else if kind = 'alertmanager' then pj(Sequence{ - Tuple{k = 'implementation', v = str('prometheus')}, - Tuple{k = 'handleGrafanaManagedAlerts', v = 'false'}}, 3) - else '{}' endif endif endif endif; - --- An object as JSON.stringify writes it with an indent of two, at `depth`, its keys in the order --- given and an entry with no value left out; and an array the same way. -query pj(entries : Sequence(Tuple(k : String, v : String)), depth : Integer) : String = - let present : Sequence(Tuple(k : String, v : String)) = entries->select(e | e.v <> null) in - if present->isEmpty() then '{}' else - '{\n' + present->collect(e | pad(depth + 1) + str(e.k) + ': ' + e.v) - ->iterate(i; acc : String = '' | if acc = '' then i else acc + ',\n' + i endif) - + '\n' + pad(depth) + '}' endif; - -query pa(items : Sequence(String), depth : Integer) : String = - if items->isEmpty() then '[]' else - '[\n' + items->collect(i | pad(depth + 1) + i) - ->iterate(i; acc : String = '' | if acc = '' then i else acc + ',\n' + i endif) - + '\n' + pad(depth) + ']' endif; - -query pad(depth : Integer) : String = - if depth = 0 then '' else Sequence{1..depth}->iterate(i; acc : String = '' | acc + ' ') endif; - --- ===================================================== the operator's objects - --- What the Prometheus operator runs an Application's one Process as, where the Application holds --- the monitoring stack's Prometheus or Alertmanager role (spec/v1/14-platform-intent.md#the-operators-objects). -query operatedOf(app : EffectiveApplication, prj : EffectiveProject) : ResolvedOperated = - let held : String = prj.project + '/' + app.id in - if estate.monitoring = null then null - else if heldName(estate.monitoring.alertmanager) = held then operatedAs('Alertmanager', app.processes->first()) - else if heldName(estate.monitoring.prometheus) = held then operatedAs('Prometheus', app.processes->first()) - else null endif endif endif; - --- The flags the operator's object of each kind carries as fields of its own; every other flag is --- an additional argument. E_OPERATED_PROCESS refused any argument that is not a flag, or that sets --- what the operator sets itself. -query operatedFields(kind : String) : Sequence(String) = - if kind = 'Prometheus' then Sequence{'enable-feature', 'storage.tsdb.retention.size', - 'storage.tsdb.retention.time', 'web.enable-remote-write-receiver'} - else Sequence{'data.retention'} endif; - -query operatedAs(role : String, p : PI::Process) : ResolvedOperated = - let args : Sequence(String) = p.args->asSequence() in - let prometheus : Boolean = role = 'Prometheus' in - object ResolvedOperated { - kind := role; - container := if prometheus then 'prometheus' else 'alertmanager' endif; - if prometheus then interval := estate.monitors.interval endif; - if prometheus then timeout := estate.monitors.timeout endif; - -- The labels the platform's monitors carry, as it names them. - if prometheus then monitors := estate.monitors.labels->collect(l | object KeyValue { key := l.key; value := l.value; }) endif; - if prometheus then alertmanager := operatedAlertmanager() endif; - additionalArgs := args->reject(a | operatedFields(role)->includes(flagName(a))) - ->collect(a | object OperatedFlag { name := flagName(a); value := flagValue(a); }); - -- A repeated flag is read as the binary reads it: its last value. - retention := lastFlag(args, if prometheus then 'storage.tsdb.retention.time' else 'data.retention' endif); - if prometheus then retentionSize := lastFlag(args, 'storage.tsdb.retention.size') endif; - remoteWriteReceiver := prometheus and args->exists(a | flagName(a) = 'web.enable-remote-write-receiver'); - if prometheus then features := args->select(a | flagName(a) = 'enable-feature' and flagValue(a) <> null) - ->collect(a | flagValue(a).tokenize(','))->flatten()->asOrderedSet()->asSequence() endif; - }; - --- The Alertmanager a Prometheus notifies: the Service of its role's one Process, on that Process's --- one surface, where the union holds its Project. -query operatedAlertmanager() : OperatedAlertmanager = - let home : String = heldName(estate.monitoring.alertmanager).substringBefore('/') in - let declared : Sequence(EffectiveProject) = projects->select(prj | prj.project = home) in - if declared->isEmpty() then null else - let served : PI::Process = declared->first().applications - ->select(a | a.id = estate.monitoring.alertmanager.id)->any(true).processes->first() in - object OperatedAlertmanager { - namespace := namespaceOf(home); - service := served.name; - port := served.provides->first().key; - } endif; - --- An argument as a flag (one or two dashes, then a name that opens on neither a dash nor `=`): what --- follows the dashes, or nothing where it is not one. -query flagBody(a : String) : String = - if a.size() > 2 and a.startsWith('--') and Sequence{'=', '-'}->excludes(a.substring(3, 3)) then a.substring(3, a.size()) - else if a.size() > 1 and a.startsWith('-') and Sequence{'=', '-'}->excludes(a.substring(2, 2)) then a.substring(2, a.size()) - else null endif endif; - -query flagName(a : String) : String = - let body : String = flagBody(a) in - if body = null then null else if body.indexOf('=') > 0 then body.substringBefore('=') else body endif endif; - -query flagValue(a : String) : String = - let body : String = flagBody(a) in - if body = null or body.indexOf('=') = 0 then null else body.substringAfter('=') endif; - -query lastFlag(args : Sequence(String), name : String) : String = - let named : Sequence(String) = args->select(a | flagName(a) = name) in - if named->isEmpty() then null else flagValue(named->last()) endif; - --- ============================================================ the path plan - --- What every project writes: its namespace, the index over it, the --- default-deny that selects every pod and belongs to no Process, and the --- operator's connection to the Secret Store where any Application syncs from it. -query EffectiveProject::projectFiles() : Sequence(Deliverable) = - let root : String = 'apps/' + self.project + '/' in - let stores : Sequence(ResolvedApplication) = self.applications - ->collect(a | a.resolveone(ResolvedApplication))->select(a | a.secretStore <> null) in - -- Every library a Process of the project mounts, once, by name. - let mounts : Sequence(ResolvedLibraryMount) = self.applications - ->collect(a | a.processes)->flatten()->collect(p | p.resolveone(ResolvedProcess)) - ->collect(p | p.libraries)->flatten()->asSequence() in - let held : Sequence(ResolvedLibraryMount) = mounts->collect(m | m._library)->asOrderedSet() - ->sortedBy(n | n)->collect(n | mounts->select(m | m._library = n)->first()) in - -- Every edge of the project that derives an alias, once per name it dials. - let aliased : Sequence(ResolvedEdge) = self.applications - ->collect(a | a.processes)->flatten()->collect(p | p.resolveone(ResolvedProcess)) - ->collect(p | p.dependencies)->flatten()->select(e | e.target <> null)->asSequence() in - let names : Sequence(String) = aliased->collect(e | aliasName(e))->asOrderedSet()->sortedBy(n | n)->asSequence() in - Sequence{ - object NamespaceFile { - path := root + 'namespace.yaml'; - adapter := AdapterName::kubernetes; - namespace := namespaceOf(self.project); - }.oclAsType(Deliverable), - object IndexFile { - path := root + 'kustomization.yaml'; - adapter := AdapterName::kubernetes; - resources := Sequence{'namespace.yaml'}->union(self.applications->collect(a | a.id)) - ->union(if stores->isEmpty() then Sequence{} else Sequence{'vaultconnection.yaml'} endif) - ->union(if held->isEmpty() then Sequence{} else Sequence{'libraries.yaml'} endif) - ->union(if names->isEmpty() then Sequence{} else Sequence{'aliases.yaml'} endif) - ->sortedBy(r | r); - }.oclAsType(Deliverable), - object NetworkPolicyFile { - path := root + 'networkpolicy.yaml'; - adapter := AdapterName::networking; - }.oclAsType(Deliverable) - } - ->union(if held->isEmpty() then Sequence{} else Sequence{object LibraryFile { - path := root + 'libraries.yaml'; - adapter := AdapterName::kubernetes; - namespace := namespaceOf(self.project); - size := LIBRARY_SIZE; - libraries := held; - }.oclAsType(Deliverable)} endif) - ->union(if names->isEmpty() then Sequence{} else Sequence{object AliasFile { - path := root + 'aliases.yaml'; - adapter := AdapterName::kubernetes; - namespace := namespaceOf(self.project); - aliases := names->collect(n | object Alias { - name := n; - target := aliased->select(e | aliasName(e) = n)->first().target; - }); - }.oclAsType(Deliverable)} endif) - ->union(if stores->isEmpty() then Sequence{} else Sequence{object ConnectionFile { - path := root + 'vaultconnection.yaml'; - adapter := AdapterName::vso; - namespace := stores->first().namespace; - address := stores->first().secretStore; - }.oclAsType(Deliverable)} endif); - --- What one Application writes under its own directory: its index over every --- file below that a kustomization applies, the workloads of its Processes, the --- Canaries of those that switch blue-green and the Services of those that do --- not, their identities, their claims, the Release Gate's inputs where it is --- gated and its Asset ConfigMaps, its backups, its monitor --- where it is scraped, what the operator syncs for it, and one policy per --- Process. A file that would hold no object is not written. -query EffectiveApplication::applicationFiles(prj : EffectiveProject) : Sequence(Deliverable) = - let root : String = 'apps/' + prj.project + '/' + self.id + '/' in - let served : Sequence(ResolvedProcess) = self.processes->collect(p | p.resolveone(ResolvedProcess)) in - let blueGreen : Sequence(ResolvedProcess) = - self.processes->select(p | switchesBlueGreen(self, p))->collect(p | p.resolveone(ResolvedProcess)) in - -- A blue-green Process's Services are Flagger's, save the L4 Services of its pools. - let reached : Sequence(ResolvedProcess) = served->select(p | - (p.switchover <> Switchover::blueGreen and p.surfaces->notEmpty()) or p.l4Services->notEmpty()) in - -- An api block with no rules binds no role: the token alone finds the API. - let holding : Sequence(ResolvedProcess) = served->select(p | p.api <> null and p.api.rules->notEmpty()) in - let claimed : Sequence(ResolvedProcess) = served->select(p | p.volumes->notEmpty()) in - let configured : Sequence(ResolvedProcess) = served->select(p | p.assets->notEmpty()) in - let backedUp : Sequence(ResolvedProcess) = served->select(p | p.volumes->exists(v | v.backup <> null)) in - let synced : Sequence(SecretHolder) = served->collect(p | holdersOf(p))->flatten() in - let scaled : Sequence(ResolvedProcess) = served->select(p | p.replicas > 1) in - let moved : ResolvedApplication = self.resolveone(ResolvedApplication) in - let monitor : Sequence(Deliverable) = monitorOf(self, root) in - -- The certificate a tier's proxy here reads, served from the default TLS store; one tier at - -- most names one, or E_CERTIFICATE_FROM_REPEATED refused it. - let stored : Sequence(String) = self.processes->collect(p | edgeTiersOf(p)->select(t | t.certificateFrom <> null) - ->collect(t | destinationOf(p.name, t.certificateFrom)))->flatten()->asSequence() in - let files : Sequence(Deliverable) = self.routeFiles(root)->union( - Sequence{object WorkloadFile { - path := root + 'workload.yaml'; - adapter := AdapterName::kubernetes; - processes := served; - controller := controllerOf(self.processes->first()); - strategy := strategyOf(self.processes->first()); - }.oclAsType(Deliverable)} - ->union(if blueGreen->notEmpty() then Sequence{object SwitchoverFile { - path := root + 'canary.yaml'; - adapter := AdapterName::kubernetes; - processes := blueGreen; - }.oclAsType(Deliverable)} else Sequence{} endif) - ->union(if reached->notEmpty() then Sequence{object ServiceFile { - path := root + 'service.yaml'; - adapter := AdapterName::kubernetes; - processes := reached; - }.oclAsType(Deliverable)} else Sequence{} endif) - ->append(object IdentityFile { - path := root + 'serviceaccount.yaml'; - adapter := AdapterName::kubernetes; - processes := served; - }.oclAsType(Deliverable)) - ->union(if claimed->notEmpty() then Sequence{object ClaimFile { - path := root + 'pvc.yaml'; - adapter := AdapterName::kubernetes; - processes := claimed; - }.oclAsType(Deliverable)} else Sequence{} endif) - ->union(if configured->notEmpty() or gated(self) or self.exposure->notEmpty() then Sequence{object ConfigMapFile { - path := root + 'configmap.yaml'; - adapter := AdapterName::kubernetes; - application := self.resolveone(ResolvedApplication); - processes := configured; - -- The element as the Release Gate reads it: canonical JSON, on one line. - releaseGate := if gated(self) then self.resolveone(ResolvedApplication).releaseGate.json() else null endif; - externalChecks := self.externalChecks(prj); - }.oclAsType(Deliverable)} else Sequence{} endif) - ->union(if self.client = null then Sequence{} else Sequence{object ClientFile { - path := root + 'client.yaml'; - application := moved; - }.oclAsType(Deliverable)} endif) - ->union(if self.resolveone(ResolvedApplication).k3sScrape = null then Sequence{} else - Sequence{object K3sMonitorsFile { - path := root + 'k3s-monitors.yaml'; - adapter := AdapterName::prometheus; - application := self.resolveone(ResolvedApplication); - }.oclAsType(Deliverable)} endif) - ->union(if self.resolveone(ResolvedApplication).grafana = null then Sequence{} else - Sequence{object GrafanaFile { - path := root + 'grafana.yaml'; - adapter := AdapterName::grafana; - application := self.resolveone(ResolvedApplication); - }.oclAsType(Deliverable)} endif) - ->union(if self.resolveone(ResolvedApplication).dashboards = null then Sequence{} else - Sequence{object DashboardFile { - path := root + 'dashboards.yaml'; - adapter := AdapterName::grafana; - application := self.resolveone(ResolvedApplication); - }.oclAsType(Deliverable)} endif) - ->union(if self.alertRules->isEmpty() then Sequence{} else Sequence{object AlertRulesFile {path := root + 'alertrules.yaml'; adapter := AdapterName::prometheus; application := self.resolveone(ResolvedApplication);}.oclAsType(Deliverable)} endif) - ->union(if obsAlerts(self) then Sequence{object AlertingFile {path := root + 'alertmanagerconfig.yaml'; adapter := AdapterName::prometheus; application := self.resolveone(ResolvedApplication);}.oclAsType(Deliverable)} else Sequence{} endif) - ->union(if obsFlux(self) then Sequence{object FluxMonitorFile {path := root + 'flux-podmonitor.yaml'; adapter := AdapterName::prometheus; application := self.resolveone(ResolvedApplication);}.oclAsType(Deliverable)} else Sequence{} endif) - ->union(if backedUp->notEmpty() then Sequence{object BackupFile { - path := root + 'backup.yaml'; - adapter := AdapterName::kubernetes; - processes := backedUp; - }.oclAsType(Deliverable)} else Sequence{} endif) - ->union(if scaled->notEmpty() then Sequence{object BudgetFile { - path := root + 'pdb.yaml'; - adapter := AdapterName::kubernetes; - processes := scaled; - }.oclAsType(Deliverable)} else Sequence{} endif) - ->union(if moved.migration <> null then Sequence{object MigrationFile { - path := root + 'migration.yaml'; - adapter := AdapterName::kubernetes; - application := moved; - -- A down returns to the revision the release was proven against; a first release has none. - if moved.migration.testedAgainst <> null then downTag := tagOf(moved.migration.testedAgainst) endif; - role := moved.namespace + '-' + moved.migration.identity; - }.oclAsType(Deliverable)} else Sequence{} endif) - ->union(if holding->notEmpty() then Sequence{object RbacFile { - path := root + 'rbac.yaml'; - adapter := AdapterName::kubernetes; - processes := holding; - }.oclAsType(Deliverable)} else Sequence{} endif) - ->union(monitor) - ->union(if stored->isEmpty() then Sequence{} else Sequence{object TlsStoreFile { - path := root + 'tlsstore.yaml'; - adapter := AdapterName::traefik; - namespace := namespaceOf(prj.project); - application := self.id; - secret := stored->first(); - }.oclAsType(Deliverable)} endif) - ->union(if synced->notEmpty() then Sequence{object SecretFile { - path := root + 'vso.yaml'; - adapter := AdapterName::vso; - application := self.resolveone(ResolvedApplication); - holders := synced; - }.oclAsType(Deliverable)} else Sequence{} endif)) in - Sequence{object IndexFile { - path := root + 'kustomization.yaml'; - adapter := AdapterName::kubernetes; - -- A policy file is listed nowhere while the policy stage is render-only. - resources := files->collect(f | f.path.substring(root.size() + 1, f.path.size()))->sortedBy(f | f); - }.oclAsType(Deliverable)} - ->union(files) - ->append(object NetworkPolicyFile { - path := root + 'networkpolicy.yaml'; - adapter := AdapterName::networking; - policies := self.processes->collect(p | object ProcessPolicy { - process := p.resolveone(ResolvedProcess); - ingress := ingressOf(p, self); - egress := egressOf(p); - }); - migration := moved.migration; - }.oclAsType(Deliverable)); - --- The monitor of a scraped Application (spec/v1/30-deliverables.md#adapters): a --- blue-green Process is scraped by its pods, because its Services are Flagger's --- and the canary's pods must be scraped for the Release Gate's checks; a --- stop-start one by a ServiceMonitor over the Service the render gives it. -query monitorOf(app : EffectiveApplication, root : String) : Sequence(Deliverable) = - if app.observability = null or app.observability.scrape = null then Sequence{} else - let scraped : ResolvedProcess = app.observability.scrape.process.resolveone(ResolvedProcess) in - let monitored : MonitorKind = if scraped.switchover <> Switchover::blueGreen - then MonitorKind::serviceMonitor else MonitorKind::podMonitor endif in - Sequence{object MonitorFile { - path := root + (if monitored = MonitorKind::serviceMonitor then 'servicemonitor.yaml' else 'podmonitor.yaml' endif); - adapter := AdapterName::prometheus; - process := scraped; - surface := app.observability.scrape.surface.key; - scrapePath := app.observability.scrape.path; - interval := estate.monitors.interval; - timeout := estate.monitors.timeout; - kind := monitored; - }.oclAsType(Deliverable)} endif; - --- The identities of one Process that sync a grant --- (spec/v1/16-dependencies.md#what-a-grant-confers): the Process itself for each --- grant delivered anywhere but to itself, and its backup identity for the --- off-cluster credential its backups share and the one its method dumps the --- Process with. A Process that syncs nothing holds nothing here. -query holdersOf(p : ResolvedProcess) : Sequence(SecretHolder) = - (if processGrants(p)->forAll(g | g.destination = null) then Sequence{} else - Sequence{object SecretHolder { - identity := p.identity; - component := p.component; - grants := processGrants(p)->select(g | g.destination <> null); - }} endif) - ->union(if backupGrants(p)->isEmpty() then Sequence{} else Sequence{object SecretHolder { - identity := p.volumes->select(v | v.backup <> null)->first().backup.identity; - component := NO_RUNTIME; - grants := backupGrants(p); - }} endif); - --- What a Process's own identity holds: its grants, and the VPN's credential --- where it attaches, which the VPN container beside it reads. -query processGrants(p : ResolvedProcess) : Sequence(ResolvedGrant) = - p.secrets->asSequence()->union(if p.vpn = null then Sequence{} else Sequence{p.vpn.credential} endif); - --- What a Process's backup identity holds: the off-cluster credential, where a --- backup copies off-cluster, then the peer's, where its method dumps over the --- network, which every backup of the Process shares. -query backupGrants(p : ResolvedProcess) : Sequence(ResolvedGrant) = - let plans : Sequence(BackupPlan) = p.volumes->select(v | v.backup <> null).backup->asSequence() in - (if backupOf(p) = null then Sequence{} else Sequence{backupOf(p).credential} endif) - ->union(if plans->isEmpty() or plans->first().peer = null then Sequence{} - else Sequence{plans->first().peer.credential} endif); - --- The plan whose off-cluster credential every backup of one Process shares, where one has it. -query backupOf(p : ResolvedProcess) : BackupPlan = - let credentialed : Sequence(ResolvedVolume) = - p.volumes->select(v | v.backup <> null and v.backup.credential <> null)->asSequence() in - if credentialed->isEmpty() then null else credentialed->first().backup endif; - --- The controller every serving Process runs under, and the strategy from --- `cutover`; the templates spell both. --- A scheduled Process runs from a CronJob, which has no rollout strategy. -query controllerOf(p : PI::Process) : ControllerKind = - if p.lifecycle = Lifecycle::scheduled then ControllerKind::cronJob else ControllerKind::deployment endif; - -query strategyOf(p : PI::Process) : String = - if p.lifecycle = Lifecycle::scheduled then 'none' - else if p.cutover = PI::Cutover::interrupted then 'Recreate' else 'RollingUpdate' endif endif; - --- Who may reach a Process (spec/v1/16-dependencies.md#the-derived-allow-set): --- the proxy of the tier each route's audience reaches, the metrics stack where --- the Process is scraped, every pod carrying the consumer label of one of its --- surfaces, its own backup identity and Flux's notifier, each at that surface's --- port. One named peer per namespace, Process and port, the first time it is --- reached. -query ingressOf(p : PI::Process, app : EffectiveApplication) : Sequence(PolicyPeer) = - named(app.exposure->collect(e | e.routes->select(r | r.process = p)->collect(r | - peersOf(tierFor(r.audienceOf(e)).traefik.id, r.surface.value, 'tier-proxy')))->flatten() - ->union(if app.observability <> null and app.observability.scrape <> null - and app.observability.scrape.process = p and estate.telemetry <> null - then peersOf(estate.telemetry.metrics.id, app.observability.scrape.surface.value, 'metrics-stack') - else Sequence{} endif)) - ->union(consumersOf(p, app)) - ->union(named(backupsOf(p)->union(eventsOf(p, app)))) - -- A blue-green Process that publishes readiness is a gate member, and admits the - -- Release Gate's own requests on its first surface - -- (spec/v1/16-dependencies.md#the-member-label). - ->union(if switchesBlueGreen(app, p) and readinessOf(p) <> null and estate.delivery <> null - and p.provides->notEmpty() - then named(peersOf(estate.delivery.gate.id, p.provides->first().value, 'release-gate')) - else Sequence{} endif) - -- A port exposed on an L4 Address admits any client at the Process's own port. - ->union(l4Of(p)->sortedBy(e | e.surface.value * 2 + (if e.protocol = L4Protocol::tcp then 0 else 1 endif)) - ->collect(e | Tuple{port = e.surface.value, udp = e.protocol = L4Protocol::udp}) - ->asOrderedSet()->collect(t | object PolicyPeer { - rule := 'l4'; - cidr := '0.0.0.0/0'; - port := t.port; - if t.udp then protocol := 'UDP' endif; - })->asSequence()); - --- Each peer a policy names, once, in the order first reached. -query named(peers : Sequence(Tuple(rule : String, namespace : String, process : String, port : Integer))) - : Sequence(PolicyPeer) = - peers->asOrderedSet()->asSequence() - ->collect(peer | object PolicyPeer { - rule := peer.rule; - namespace := peer.namespace; - process := peer.process; - port := peer.port; - }); - --- Flux's events about every Project's unit (spec/v1/55-delivery.md#rollouts): its --- notification controller reaches the Reporter where the Provider sends them, the first --- Process of the Reporter that provides the surface. -query eventsOf(p : PI::Process, app : EffectiveApplication) - : Sequence(Tuple(rule : String, namespace : String, process : String, port : Integer)) = - if estate.delivery = null or estate.delivery.reporter = null - or estate.delivery.reporter.id <> app.id then Sequence{} - else let receivers : Sequence(PI::Process) = - app.processes->select(c | c.provides->exists(s | s.key = HTTP_SURFACE))->asSequence() in - if receivers->isEmpty() or receivers->first() <> p then Sequence{} - else Sequence{Tuple{rule = 'flux-events', - namespace = estate.bootstrap.flux.sourceRef.substringBefore('/'), - process = FLUX_NOTIFIER, - port = p.provides->select(s | s.key = HTTP_SURFACE)->any(true).value}} endif endif; - --- The Process's own backup identity, on the surface its backups dump. -query backupsOf(p : PI::Process) - : Sequence(Tuple(rule : String, namespace : String, process : String, port : Integer)) = - if dumpedSurface(p) = null then Sequence{} else Sequence{Tuple{rule = 'backup', - namespace = namespaceOf(owner(p)), process = p.name + '-backup', - port = p.provides->select(s | s.key = dumpedSurface(p))->any(true).value}} endif; - --- Every pod carrying the consumer label of a surface this Process provides, whoever --- declares it (spec/v1/16-dependencies.md#the-consumer-label): read off the Process's --- own surfaces, never off the union's edges, so a consumer added or removed leaves the --- policy as it is. -query consumersOf(p : PI::Process, app : EffectiveApplication) : Sequence(PolicyPeer) = - p.provides->collect(s | object PolicyPeer { - rule := 'consumer'; - consumes := app.id + '.' + s.key; - port := s.value; - })->asSequence(); - --- What a Process may reach beyond its edges: the cluster's DNS, and the Secret --- Store where it holds a grant. -query egressOf(p : PI::Process) : Sequence(PolicyPeer) = - let app : EffectiveApplication = p.oclAsType(ECORE::EObject).eContainer().oclAsType(EffectiveApplication) in - -- A Process that serves DNS resolves through the upstream nameservers, never the cluster's DNS. - (if servesDns(p) then Sequence{} else - Sequence{object PolicyPeer { rule := 'cluster-dns'; namespace := estate.substrate.clusterDns; port := DNS_PORT; }} endif) - ->union(if p.secrets->isEmpty() and not edgeAcme(p) and not holdsClientGrants(p) and not p.readsClientSecret() then Sequence{} else storePeers() endif) - -- The Release Gate reaches every gate member's pods (spec/v1/16-dependencies.md#the-member-label). - ->union(if estate.delivery <> null and estate.delivery.gate.id = app.id - then Sequence{object PolicyPeer { rule := 'gate-members'; port := 0; }} else Sequence{} endif) - ->union(obsScrapeEgress(app)); - --- Whether a Process serves DNS on an L4 port and resolves through the platform's upstream nameservers. -query servesDns(p : PI::Process) : Boolean = - estate.substrate.upstreamNameservers->notEmpty() - and p.oclAsType(ECORE::EObject).eContainer().oclAsType(EffectiveApplication).l4Exposure - ->exists(e | e.process = p and e.port = DNS_PORT); - --- The one Process of the Secret Store that answers on `http`, at its own port. -query storePeers() : Sequence(PolicyPeer) = - let providers : Sequence(Tuple(project : String, process : PI::Process)) = - projects->collect(prj | prj.applications->select(a | a.id = estate.secretStore.id).processes - ->select(p | p.provides->exists(s | s.key = HTTP_SURFACE)) - ->collect(p | Tuple{project = prj.project, process = p}))->flatten() in - if providers->isEmpty() then Sequence{} else - let first : Tuple(project : String, process : PI::Process) = providers->first() in - Sequence{object PolicyPeer { - rule := 'secret-store'; - namespace := namespaceOf(first.project); - process := first.process.name; - port := first.process.provides->select(s | s.key = HTTP_SURFACE)->any(true).value; - }} - endif; - --- Every Process of `application` in the union, at `port`, as a value. -query peersOf(application : String, at : Integer, admits : String) - : Sequence(Tuple(rule : String, namespace : String, process : String, port : Integer)) = - projects->collect(prj | prj.applications->select(a | a.id = application).processes - ->collect(p | Tuple{rule = admits, namespace = namespaceOf(prj.project), - process = p.name, port = at})) - ->flatten(); - --- The port of `application`'s Process that provides this surface. -query String::portOf(application : String) : Integer = - projects.applications->select(a | a.id = application).processes.provides - ->select(s | s.key = self)->any(true).value; - --- The routes an exposure gives the tier proxy, in the tier's own directory of --- the estate-scoped edge, and one index per tier over every route in it. The --- index lists the resolved project's routes: composing the whole estate's edge --- is the composed estate's (JorisJonkers-dev/deploy-kit#203). --- Each exposure's IngressRoute, in its Application's own directory and namespace, so a --- Project's routes are its own and its unit applies them (spec/v1/30-deliverables.md#adapters). -query EffectiveApplication::routeFiles(root : String) : Sequence(Deliverable) = - self.exposure->collect(e | - let tier : Tier = tierFor(e.audience) in - object IngressRouteFile { - path := root + 'route-' + e.name + '.yaml'; - adapter := AdapterName::traefik; - exposure := e.resolveone(ResolvedExposure); - entryPoint := if tier.listener = Listener::tls then 'websecure' else 'web' endif; - -- A tier issuing through acme names its own resolver, and a tls listener ends TLS. - if tier.certificates = CertificateSource::acme then certificateResolver := tier.name endif; - terminatesTls := tier.listener = Listener::tls; - }.oclAsType(Deliverable))->asSequence(); - --- An Application's external checks (spec/v1/14-platform-intent.md#the-foundation-is-declared): --- one Gatus endpoint per route of each exposure, which fails on a 5xx or on no answer. -query EffectiveApplication::externalChecks(prj : EffectiveProject) : String = - if self.exposure->isEmpty() then null else - obj(Sequence{Tuple{k = 'endpoints', v = arr(self.exposure->collect(e | e.routes->collect(r | obj(Sequence{ - Tuple{k = 'name', v = str(self.id + '-' + e.name + '-' + e.routes->indexOf(r).toString())}, - Tuple{k = 'group', v = str(prj.project)}, - Tuple{k = 'url', v = str((if tierFor(e.audience).listener = Listener::tls then 'https' else 'http' endif) - + '://' + e.host + r.path)}, - Tuple{k = 'conditions', v = arr(Sequence{str('[STATUS] < 500')})}})) - ->append(if derivesGateRoute(self, e) then gateCheck(self, e, prj) else null endif) - ->select(c | c <> null))->flatten())}}) endif; - --- Per identity that holds a grant, one Vault policy over every grant it holds --- and one Kubernetes auth role bound to it, estate-scoped by namespace: the --- Process for all of its grants, and its backup identity for its credentials. -query EffectiveProject::vaultFiles() : Sequence(Deliverable) = - self.applications->collect(a | a.resolveone(ResolvedApplication))->collect(app | - app.processes->collect(p | - (if processGrants(p)->isEmpty() then Sequence{} else - vaultFilesOf(policiesOf(self.project), app.namespace, p.identity, processGrants(p)) endif) - ->union(if backupGrants(p)->isEmpty() then Sequence{} else - vaultFilesOf(policiesOf(self.project), app.namespace, - p.volumes->select(v | v.backup <> null)->first().backup.identity, - backupGrants(p)) endif)) - ->union(if app.migration = null then Sequence{} else - vaultFilesOf(policiesOf(self.project), app.namespace, app.migration.identity, Sequence{app.migration.credential}) endif)) - ->flatten(); - --- A generated key with its defaults filled in: 32 bytes, as hex. -query GeneratedKey::resolved() : ResolvedGeneratedKey = object ResolvedGeneratedKey { - key := self.name; - bytes := if self.generate.bytes = null then 32 else self.generate.bytes endif; - encoding := if self.generate.encoding = KeyEncoding::base64 then 'base64' - else if self.generate.encoding = KeyEncoding::base64url then 'base64url' else 'hex' endif endif; - -- The schema held the location to one path and one key, split at its `#`. - adoptPath := if self.generate.adopt = null then null - else self.generate.adopt.substring(1, self.generate.adopt.indexOf('#') - 1) endif; - adoptKey := if self.generate.adopt = null then null - else self.generate.adopt.substring(self.generate.adopt.indexOf('#') + 1, self.generate.adopt.size()) endif; -}; - --- The keys the Vault policy job generates for the project, once each, in path --- then key order: a grant every Process inherits names its keys once. -query EffectiveProject::generatedKeysFiles() : Sequence(Deliverable) = - let apps : Sequence(ResolvedApplication) = - self.applications->collect(a | a.resolveone(ResolvedApplication))->asSequence() in - let held : Sequence(Tuple(path : String, key : String, bytes : Integer, encoding : String, adoptPath : String, adoptKey : String)) = - apps.processes.secrets->select(g | g.path <> null)->collect(g | g.generated->collect(k | - Tuple{path = g.path, key = k.key, bytes = k.bytes, encoding = k.encoding, - adoptPath = k.adoptPath, adoptKey = k.adoptKey})) - ->asSet()->asSequence() in - let sorted : Sequence(Tuple(path : String, key : String, bytes : Integer, encoding : String, adoptPath : String, adoptKey : String)) = - held.path->asSet()->sortedBy(p | p)->collect(p | held->select(t | t.path = p)->sortedBy(t | t.key)) - ->asSequence() in - if sorted->isEmpty() then Sequence{} else Sequence{ - object GeneratedKeysFile { - path := policiesOf(self.project) + apps->first().namespace + '.generated.json'; - adapter := AdapterName::vaultPolicy; - keys := sorted->collect(t | object ResolvedGeneratedKey { - path := t.path; - key := t.key; - bytes := t.bytes; - encoding := t.encoding; - adoptPath := t.adoptPath; - adoptKey := t.adoptKey; - }); - }.oclAsType(Deliverable)} endif; - -query vaultFilesOf(policies : String, ns : String, holder : String, held : Sequence(ResolvedGrant)) : Sequence(Deliverable) = - -- Each document is written under the name Vault holds it by, so two identities that derive - -- one name claim one path. - let stem : String = policies + ns + '-' + holder in - Sequence{ - object VaultPolicyFile { - path := stem + '.policy.json'; - adapter := AdapterName::vaultPolicy; - namespace := ns; - identity := holder; - grants := held; - paths := held->collect(g | g.allowedPaths())->flatten(); - }.oclAsType(Deliverable), - object VaultRoleFile { - path := stem + '.role.json'; - adapter := AdapterName::vaultPolicy; - namespace := ns; - identity := holder; - }.oclAsType(Deliverable) - }; - -query routeFile(app : EffectiveApplication, exposure : Exposure) : String = - app.id + '-' + exposure.name + '.yaml'; - --- ================================================================ spellings - -query namespaceOf(prj : String) : String = prj + '-system'; - --- Whether the source states `feature`: an unset enumeration reads as its first literal. -query ECORE::EObject::states(feature : String) : Boolean = - self.eIsSet(self.eClass().getEStructuralFeature(feature)); - -query inSeconds(n : Integer) : String = n.toString() + 's'; - -query ceiling(r : Real) : Integer = -((-r).floor()); - --- A duration in seconds: `20s`, `30ms`, `5m` or `2h`. -query seconds(d : String) : Real = - if d.endsWith('ms') then d.substring(1, d.size() - 2).toReal() / 1000 - else if d.endsWith('s') then d.substring(1, d.size() - 1).toReal() - else if d.endsWith('m') then d.substring(1, d.size() - 1).toReal() * 60 - else if d.endsWith('h') then d.substring(1, d.size() - 1).toReal() * 3600 - else unread('a duration', d) endif endif endif endif; - --- A quantity no spelling of the model reads: the checks refuse it before --- resolution, so reaching here is a defect, and it stops the run. -query unread(what : String, q : String) : Real { - assert fatal (false) with log(q + ' is not ' + what + ' the model reads'); - return 0; -} - --- A cpu quantity in millicores: `50m`, or `2` whole cores. -query millicores(q : String) : Integer = - if q.endsWith('m') then q.substring(1, q.size() - 1).toInteger() else q.toInteger() * 1000 endif; - --- A memory quantity in MiB: `256Mi`, `2Gi`, `1Ti`, or bytes with no unit. --- A quantity in MiB, written as the production implementation writes it. -query memoryOf(mib : Real) : String = - let whole : Integer = mib.round() in - if whole.mod(1024) = 0 then (whole.div(1024)).toString() + 'Gi' else whole.toString() + 'Mi' endif; - -query mebibytes(q : String) : Real = - if q.endsWith('Mi') then q.substring(1, q.size() - 2).toReal() - else if q.endsWith('Gi') then q.substring(1, q.size() - 2).toReal() * 1024 - else if q.endsWith('Ti') then q.substring(1, q.size() - 2).toReal() * 1024 * 1024 - else if q.matches('[0-9]+') then q.toReal() / (1024 * 1024) - else unread('a memory quantity', q) endif endif endif endif; - -query PI::Cutover::resolvedCutover() : RD::Cutover = - if self = PI::Cutover::continuous then RD::Cutover::continuous else RD::Cutover::interrupted endif; - -query PI::Match::resolvedMatch() : RD::Match = - if self = PI::Match::exact then RD::Match::exact else RD::Match::prefix endif; - - -query Audience::spelling() : String = - if self = Audience::anonymous then 'anonymous' - else if self = Audience::authenticated then 'authenticated' - else if self = Audience::internal then 'internal' else 'lan' endif endif endif; - -query ContentPolicy::spelling() : String = - if self = ContentPolicy::strict then 'strict' - else if self = ContentPolicy::admin then 'admin' else 'workflow' endif endif; - --- `static` is a keyword of the language, so it is the literal no comparison names. -query Runtime::spelling() : String = - if self = Runtime::jvm then 'jvm' - else if self = Runtime::python then 'python' - else if self = Runtime::node then 'node' - else if self = Runtime::none then 'none' else 'static' endif endif endif endif; - -query HardeningClass::spelling() : String = 'restricted'; - -query Lifecycle::spelling() : String = - if self = Lifecycle::application then 'application' else if self = Lifecycle::job then 'job' - else if self = Lifecycle::scheduled then 'scheduled' else 'prepare' endif endif endif; - -query Delivery::spelling() : String = - if self = Delivery::env then 'env' else if self = Delivery::file then 'file' else 'self' endif endif; - -query AccessTier::spelling() : String = - if self = AccessTier::read then 'read' - else if self = AccessTier::selfRenew then 'self-renew' - else if self = AccessTier::selfRoll then 'self-roll' else 'custody' endif endif endif; - -query TransitOp::spelling() : String = - if self = TransitOp::sign then 'sign' - else if self = TransitOp::verify then 'verify' - else if self = TransitOp::encrypt then 'encrypt' - else if self = TransitOp::decrypt then 'decrypt' else 'rotate' endif endif endif endif; - -query PI::DurabilityClass::resolvedDurability() : RD::DurabilityClass = - if self = PI::DurabilityClass::reconstructible then RD::DurabilityClass::reconstructible - else if self = PI::DurabilityClass::recoverable then RD::DurabilityClass::recoverable - else RD::DurabilityClass::irreplaceable endif endif; - -query Arch::spelling() : String = if self = Arch::amd64 then 'amd64' else 'arm64' endif; - -query Media::spelling() : String = - if self = Media::nvme then 'nvme' else if self = Media::ssd then 'ssd' else 'hdd' endif endif; - --- =================================================== the production element - --- An Application's element as the production implementation writes it in --- `resolved.json`, without the keys that are not its own decisions, in that --- implementation's canonical JSON: keys sorted, no white space, absent values --- left out. Its digest is the revision, which the rendered tree carries, so --- the two implementations must compute it from the same text. -query ResolvedApplication::elementJson(src : EffectiveApplication, prj : EffectiveProject) : String = - let after : Sequence(String) = appAfterOf(src, prj) in - obj(Sequence{ - Tuple{k = 'id', v = str(self.id)}, - Tuple{k = 'project', v = str(self.project)}, - Tuple{k = 'namespace', v = str(self.namespace)}, - Tuple{k = 'reconcileUnit', v = str(self.reconcileUnit.name)}, - Tuple{k = 'reconcileAfter', v = if after->isEmpty() then null else arr(after->collect(n | str(n))) endif}, - Tuple{k = 'alertClass', v = opt(self.alertClass)}, - Tuple{k = 'scrape', v = if self.scrape = null then null else obj(Sequence{ - Tuple{k = 'process', v = str(self.scrape.process.name)}, - Tuple{k = 'surface', v = str(self.scrape.surface)}, - Tuple{k = 'path', v = str(self.scrape.path)}, - Tuple{k = 'interval', v = str(self.scrape.interval)}, - Tuple{k = 'timeout', v = str(self.scrape.timeout)}, - Tuple{k = 'labels', v = if self.scrape.labels->isEmpty() then null - else obj(self.scrape.labels->collect(l | Tuple{k = l.key, v = str(l.value)})) endif}}) endif}, - Tuple{k = 'releaseGate', v = if self.releaseGate = null then null else self.releaseGate.json() endif}, - Tuple{k = 'migration', v = if self.migration = null then null else obj(Sequence{ - Tuple{k = 'runner', v = str(self.migration.runner)}, - Tuple{k = 'runnerVersion', v = opt(self.migration.runnerVersion)}, - Tuple{k = 'uid', v = num(self.migration.uid)}, - Tuple{k = 'gid', v = num(self.migration.gid)}, - Tuple{k = 'testedAgainst', v = opt(self.migration.testedAgainst)}, - Tuple{k = 'nonTransactional', v = bool(self.migration.nonTransactional)}, - Tuple{k = 'identity', v = str(self.migration.identity)}, - Tuple{k = 'deadline', v = str(self.migration.deadline)}, - Tuple{k = 'memory', v = str(self.migration.memory)}, - Tuple{k = 'cpu', v = str(self.migration.cpu)}, - Tuple{k = 'scratch', v = str(self.migration.scratch)}, - Tuple{k = 'database', v = obj(Sequence{ - Tuple{k = 'host', v = str(self.migration.database.host)}, - Tuple{k = 'port', v = num(self.migration.database.port)}, - Tuple{k = 'name', v = str(self.migration.database.name)}})}, - Tuple{k = 'consumes', v = arr(self.migration.consumes->collect(c | str(c)))}, - Tuple{k = 'credential', v = self.migration.credential.json()}, - Tuple{k = 'egress', v = arr(self.migration.egress->collect(x | x.json()))}}) endif}, - Tuple{k = 'alertRules', v = if self.alertRules->isEmpty() then null else arr(Sequence{1..self.alertRules->size()}->collect(i | obsAlertRulesJson(self.alertRules->at(i), src.alertRules->at(i)._from))) endif}, - Tuple{k = 'alerting', v = if self.alerting = null then null else obsAlertingJson(self.alerting) endif}, - Tuple{k = 'fluxScrape', v = if self.fluxScrape = null then null else obsFluxJson(self.fluxScrape) endif}, - Tuple{k = 'secretStore', v = opt(self.secretStore)}, - Tuple{k = 'dashboards', v = if self.dashboards = null then null else obj(Sequence{ - Tuple{k = 'folder', v = str(self.dashboards.folder)}, - Tuple{k = 'datasource', v = str(self.dashboards.datasource)}, - Tuple{k = 'instance', v = obj(self.dashboards.instance->collect(i | Tuple{k = i.key, v = str(i.value)}))}, - Tuple{k = 'files', v = arr(src.dashboards->collect(d | let content : String = fileOf(prj.project, d._from) in - obj(Sequence{ - Tuple{k = 'uid', v = str(uidOf(content))}, - Tuple{k = 'from', v = str(d._from)}, - Tuple{k = 'content', v = str(content)}, - Tuple{k = 'inputs', v = arr(inputsOf(content)->collect(x | str(x)))}})))}}) endif}, - Tuple{k = 'k3sScrape', v = if self.k3sScrape = null then null else obj(Sequence{ - Tuple{k = 'identity', v = str(self.k3sScrape.identity)}, - Tuple{k = 'interval', v = str(self.k3sScrape.interval)}, - Tuple{k = 'timeout', v = str(self.k3sScrape.timeout)}, - Tuple{k = 'labels', v = if self.k3sScrape.labels->isEmpty() then null - else obj(self.k3sScrape.labels->collect(l | Tuple{k = l.key, v = str(l.value)})) endif}, - Tuple{k = 'kubelet', v = if self.k3sScrape.kubeletPort = null then null - else obj(Sequence{Tuple{k = 'port', v = num(self.k3sScrape.kubeletPort)}}) endif}, - Tuple{k = 'apiServer', v = if self.k3sScrape.apiServerService = null then null else obj(Sequence{ - Tuple{k = 'namespace', v = str(self.k3sScrape.apiServerNamespace)}, - Tuple{k = 'service', v = str(self.k3sScrape.apiServerService)}, - Tuple{k = 'port', v = str(self.k3sScrape.apiServerPort)}}) endif}, - Tuple{k = 'coreDns', v = if self.k3sScrape.coreDnsPort = null then null else obj(Sequence{ - Tuple{k = 'namespace', v = str(self.k3sScrape.coreDnsNamespace)}, - Tuple{k = 'port', v = num(self.k3sScrape.coreDnsPort)}}) endif}}) endif}, - Tuple{k = 'grafana', v = if self.grafana = null then null else obj(Sequence{ - Tuple{k = 'labels', v = obj(self.grafana.labels->collect(l | Tuple{k = l.key, v = str(l.value)}))}, - Tuple{k = 'url', v = str(self.grafana.url)}, - Tuple{k = 'credential', v = obj(Sequence{ - Tuple{k = 'secret', v = str(self.grafana.secret)}, - Tuple{k = 'user', v = str(self.grafana.user)}, - Tuple{k = 'password', v = str(self.grafana.password)}})}}) endif}, - Tuple{k = 'exposure', v = if self.exposure->isEmpty() then null - else arr(self.exposure->collect(e | e.json())) endif}, - Tuple{k = 'client', v = if self.client = null then null else self.client.json() endif}, - Tuple{k = 'processes', v = arr(self.processes->collect(p | p.json()))} - }); - --- The units an Application must follow, as the production implementation --- records them per Application: every other project its edges reach, and the --- secrets unit wherever one of its Processes holds a grant. -query appAfterOf(app : EffectiveApplication, prj : EffectiveProject) : Sequence(String) = - if holdsStore(prj.project) then Sequence{} else - (app.processes.dependsOn - -- An optional edge orders nothing (spec/v1/55-delivery.md#release-order). - ->select(e | not (e.required = false)) - ->collect(e | projectOf(e.application)) - ->select(other | other <> null and other <> prj.project) - ->collect(other | unitOf(other)) - ->union(if app.processes->exists(p | p.secrets->notEmpty() or holdsClientGrants(p) or p.readsClientSecret() or p.vpn <> null - or p.dependsOn->exists(e | reachesDatabase(e))) - or managed(app) or appliesCatalog(app) - then secretsAfter(prj.project) else Sequence{} endif) - ->union(proxiesAfter(app, prj.project))) - ->asSet()->sortedBy(n | n)->asSequence() endif; - -query ReleaseGate::json() : String = obj(Sequence{ - Tuple{k = 'endpoint', v = str(self.endpoint)}, - Tuple{k = 'deadline', v = str(self.deadline)}, - Tuple{k = 'analysis', v = obj(Sequence{ - Tuple{k = 'errorRate', v = str(self.analysis.errorRate)}, - Tuple{k = 'interval', v = str(self.analysis.interval)}, - Tuple{k = 'iterations', v = num(self.analysis.iterations)}, - Tuple{k = 'latency', v = str(self.analysis.latency)}, - Tuple{k = 'threshold', v = num(self.analysis.threshold)}})}, - Tuple{k = 'members', v = arr(self.members->collect(m | obj(Sequence{ - Tuple{k = 'process', v = str(m.process.name)}, - Tuple{k = 'readiness', v = m.readiness.json()}, - Tuple{k = 'checks', v = if m.checks->isEmpty() then null - else arr(m.checks->collect(c | str(c.spelling()))) endif}, - Tuple{k = 'waitsFor', v = if m.waitsFor->isEmpty() then null - else arr(m.waitsFor->collect(w | obj(Sequence{ - Tuple{k = 'application', v = str(w.application)}, - Tuple{k = 'process', v = str(w.process)}}))) endif}})))}, - Tuple{k = 'migration', v = if self.migration = null then null else obj(Sequence{ - Tuple{k = 'identity', v = str(self.migration.identity)}, - Tuple{k = 'testedAgainst', v = opt(self.migration.testedAgainst)}, - Tuple{k = 'nonTransactional', v = bool(self.migration.nonTransactional)}}) endif}, - Tuple{k = 'protectedPath', v = opt(self.protectedPathOf())}, - Tuple{k = 'protectedBy', v = opt(self.protectedByOf())} -}); - -query ResolvedExposure::json() : String = obj(Sequence{ - Tuple{k = 'name', v = str(self.name)}, - Tuple{k = 'host', v = str(self.host)}, - Tuple{k = 'tier', v = str(self.tier)}, - Tuple{k = 'listener', v = str(self.listener)}, - Tuple{k = 'certificates', v = str(self.certificates)}, - Tuple{k = 'ingressClass', v = opt(self.ingressClass)}, - Tuple{k = 'dns', v = if self.dns = null then null else obj(Sequence{ - Tuple{k = 'target', v = str(self.dns.target)}, - Tuple{k = 'proxied', v = bool(self.dns.proxied)}}) endif}, - Tuple{k = 'proxy', v = obj(Sequence{ - Tuple{k = 'application', v = str(self.proxyApplication)}, - Tuple{k = 'namespace', v = str(self.proxyNamespace)}})}, - Tuple{k = 'routes', v = arr(self.routes->collect(r | obj(Sequence{ - Tuple{k = 'path', v = str(r.path)}, - Tuple{k = 'match', v = str(r.match.spelling())}, - Tuple{k = 'process', v = if r.process = null then null else str(r.process.name) endif}, - Tuple{k = 'surface', v = opt(r.surface)}, - Tuple{k = 'gate', v = if r.gate = null then null else obj(Sequence{ - Tuple{k = 'name', v = str(r.gate.name)}, - Tuple{k = 'namespace', v = str(r.gate.namespace)}, - Tuple{k = 'port', v = num(r.gate.port)}}) endif}, - Tuple{k = 'audience', v = str(r.audience)}, - Tuple{k = 'precedence', v = num(r.precedence)}, - Tuple{k = 'middleware', v = arr(r.middleware->collect(m | obj(Sequence{ - Tuple{k = 'kind', v = str(m.kind.spelling())}, - Tuple{k = 'contentPolicy', v = opt(m.contentPolicy)}, - Tuple{k = 'endpoint', v = opt(m.endpoint)}, - Tuple{k = 'redirectTo', v = opt(m.redirectTo)}, - Tuple{k = 'allowance', v = if m.allowance = null then null else num(m.allowance) endif}, - Tuple{k = 'per', v = opt(m.per)}, - Tuple{k = 'burst', v = if m.burst = null then null else num(m.burst) endif}, - Tuple{k = 'clientAddress', v = opt(m.clientAddress)}})))}})))} -}); - -query ResolvedProcess::json() : String = - let policy : Sequence(ProcessPolicy) = self.oclAsType(ECORE::EObject).eContainer().eContainer() - .oclAsType(ResolvedDeployment).deliverables[NetworkPolicyFile].policies - ->select(pp | pp.process = self)->asSequence() in - let ingress : Sequence(PolicyPeer) = if policy->isEmpty() then Sequence{} else policy->first().ingress->asSequence() endif in - let egress : Sequence(PolicyPeer) = if policy->isEmpty() then Sequence{} else policy->first().egress->asSequence() endif in - obj(Sequence{ - Tuple{k = 'name', v = str(self.name)}, - Tuple{k = 'lifecycle', v = str(self.lifecycle)}, - Tuple{k = 'runtime', v = str(self.component)}, - Tuple{k = 'identity', v = str(self.identity)}, - Tuple{k = 'image', v = str(self.image)}, - Tuple{k = 'imageVersion', v = opt(self.imageVersion)}, - Tuple{k = 'uid', v = num(self.uid)}, - Tuple{k = 'gid', v = num(self.gid)}, - Tuple{k = 'cutover', v = if self.oclAsType(ECORE::EObject).states('cutover') - then str(self.cutover.spelling()) else null endif}, - Tuple{k = 'switchover', v = if self.oclAsType(ECORE::EObject).states('switchover') - then str(self.switchover.spelling()) else null endif}, - Tuple{k = 'command', v = let src : PI::Process = self.invresolveone(PI::Process) in - if src = null or src.command->isEmpty() then null else arr(src.command->collect(x | str(x))) endif}, - Tuple{k = 'args', v = if self.arguments->isEmpty() then null else arr(self.arguments->collect(x | str(x))) endif}, - Tuple{k = 'schedule', v = opt(self.schedule)}, - Tuple{k = 'startDeadline', v = opt(self.startDeadline)}, - Tuple{k = 'deadline', v = str(self.deadline)}, - Tuple{k = 'replicas', v = num(self.replicas)}, - Tuple{k = 'parked', v = if self.parked then bool(true) else null endif}, - Tuple{k = 'spreadAcross', v = if self.spread then str('node') else null endif}, - Tuple{k = 'memory', v = str(self.memory)}, - Tuple{k = 'cpu', v = str(self.cpu)}, - Tuple{k = 'gpu', v = if self.gpu = null then null else obj(Sequence{ - Tuple{k = 'resource', v = str(self.gpu.resource)}, - Tuple{k = 'runtimeClass', v = str(self.gpu.runtimeClass)}}) endif}, - Tuple{k = 'vpn', v = if self.vpn = null then null else obj(Sequence{ - Tuple{k = 'image', v = str(self.vpn.image)}, - Tuple{k = 'imageVersion', v = opt(self.vpn.imageVersion)}, - Tuple{k = 'memory', v = str(self.vpn.memory)}, - Tuple{k = 'cpu', v = str(self.vpn.cpu)}, - Tuple{k = 'forwardedPort', v = bool(self.vpn.forwardedPort)}, - Tuple{k = 'environment', v = arr(self.vpn.environment->collect(x | obj(Sequence{ - Tuple{k = 'name', v = str(x.name)}, - Tuple{k = 'value', v = str(x.value)}})))}, - Tuple{k = 'credential', v = self.vpn.credential.json()}}) endif}, - Tuple{k = 'hardening', v = str(self.hardening)}, - Tuple{k = 'priorityClass', v = opt(self.priorityClass)}, - Tuple{k = 'nameservers', v = if self.nameservers->isEmpty() then null else arr(self.nameservers->collect(x | str(x))) endif}, - Tuple{k = 'selfNames', v = if self.selfNames->isEmpty() then null else arr(self.selfNames->collect(x | str(x))) endif}, - Tuple{k = 'operated', v = if self.operated = null then null else obj(Sequence{ - Tuple{k = 'kind', v = str(self.operated.kind)}, - Tuple{k = 'interval', v = opt(self.operated.interval)}, - Tuple{k = 'timeout', v = opt(self.operated.timeout)}, - Tuple{k = 'monitors', v = if self.operated.monitors->isEmpty() then null - else obj(self.operated.monitors->collect(l | Tuple{k = l.key, v = str(l.value)})) endif}, - Tuple{k = 'alertmanager', v = if self.operated.alertmanager = null then null else obj(Sequence{ - Tuple{k = 'namespace', v = str(self.operated.alertmanager.namespace)}, - Tuple{k = 'service', v = str(self.operated.alertmanager.service)}, - Tuple{k = 'port', v = str(self.operated.alertmanager.port)}}) endif}}) endif}, - Tuple{k = 'l4Exposure', v = let src : PI::Process = self.invresolveone(PI::Process) in - if src = null or l4Of(src)->isEmpty() then null else arr(l4Of(src).address->asSet()->sortedBy(a | a) - ->collect(address | let declared : L4AddressDeclaration = addressOf(address) in obj(Sequence{ - Tuple{k = 'address', v = str(address)}, - Tuple{k = 'kind', v = str(declared.kind)}, - Tuple{k = 'node', v = if declared.oclIsKindOf(NodeAddress) then str(declared.oclAsType(NodeAddress).node) else null endif}, - Tuple{k = 'site', v = if declared.oclIsKindOf(PoolAddress) then str(declared.oclAsType(PoolAddress).site) else null endif}, - Tuple{k = 'range', v = if declared.oclIsKindOf(PoolAddress) then str(declared.oclAsType(PoolAddress).range) else null endif}, - Tuple{k = 'service', v = if declared.oclIsKindOf(PoolAddress) then str(src.name + '-' + address) else null endif}, - Tuple{k = 'ports', v = arr(l4Of(src)->select(e | e.address = address) - ->sortedBy(e | e.port * 2 + (if e.protocol = L4Protocol::tcp then 0 else 1 endif)) - ->collect(e | obj(Sequence{ - Tuple{k = 'name', v = str(e.protocol.toString() + '-' + e.port.toString())}, - Tuple{k = 'port', v = num(e.port)}, - Tuple{k = 'protocol', v = str(e.protocol.toString())}, - Tuple{k = 'surface', v = str(e.surface.key)}, - Tuple{k = 'targetPort', v = num(e.surface.value)}})))}}))) endif}, - Tuple{k = 'identityToken', v = bool(self.identityToken)}, - Tuple{k = 'internetEgress', v = if self.internetEgress = null then null else obj(Sequence{ - Tuple{k = 'reason', v = str(self.internetEgress.reason)}}) endif}, - Tuple{k = 'api', v = if self.api = null then null else obj(Sequence{ - Tuple{k = 'reason', v = str(self.api.reason)}, - Tuple{k = 'rules', v = arr(self.api.rules->collect(r | obj(Sequence{ - Tuple{k = 'group', v = str(r.group)}, - Tuple{k = 'objects', v = arr(r.objects->collect(x | str(x)))}, - Tuple{k = 'verbs', v = arr(r.verbs->collect(x | str(x)))}, - Tuple{k = 'scope', v = str(if r.scope = RuleScope::_namespace then 'namespace' else 'cluster' endif)}})))}, - Tuple{k = 'server', v = arr(self.api.server->collect(x | obj(Sequence{ - Tuple{k = 'cidr', v = str(x.cidr)}, - Tuple{k = 'port', v = num(x.port)}})))}}) endif}, - Tuple{k = 'readiness', v = if self.readiness = null then null else self.readiness.json() endif}, - Tuple{k = 'liveness', v = if self.liveness = null then null else self.liveness.json() endif}, - Tuple{k = 'startup', v = if self.startup = null then null else self.startup.json() endif}, - Tuple{k = 'placement', v = obj(Sequence{ - Tuple{k = 'eligibleNodes', v = arr(self.placement.eligibleNodes->collect(n | str(n)))}, - Tuple{k = 'boundTo', v = opt(self.placement.boundTo)}, - Tuple{k = 'from', v = if self.placement.boundTo = null then null else str(self.placement._from.spelling()) endif}})}, - Tuple{k = 'volumes', v = if self.volumes->isEmpty() then null else arr(self.volumes->collect(x | x.json())) endif}, - Tuple{k = 'libraries', v = if self.libraries->isEmpty() then null else arr(self.libraries->collect(x | obj(Sequence{ - Tuple{k = 'library', v = str(x._library)}, - Tuple{k = 'claim', v = str(x.claim)}, - Tuple{k = 'volume', v = str(x.volume)}, - Tuple{k = 'node', v = str(x.node)}, - Tuple{k = 'path', v = str(x.path)}, - Tuple{k = 'gid', v = num(x.gid)}, - Tuple{k = 'mountAt', v = str(x.mountAt)}, - Tuple{k = 'subPath', v = opt(x.subPath)}, - Tuple{k = 'access', v = str(x._access)}}))) endif}, - Tuple{k = 'secrets', v = if self.secrets->isEmpty() then null else arr(self.secrets->collect(x | x.json())) endif}, - Tuple{k = 'assets', v = if self.assets->isEmpty() then null else arr(self.assets->collect(x | obj(Sequence{ - Tuple{k = 'name', v = str(x.name)}, - Tuple{k = 'from', v = str(x._from)}, - Tuple{k = 'mountAt', v = opt(x.mountAt)}, - Tuple{k = 'seedAt', v = opt(x.seedAt)}, - Tuple{k = 'content', v = str(x.content)}}))) endif}, - Tuple{k = 'seeder', v = if self.seeder = null then null else obj(Sequence{ - Tuple{k = 'image', v = str(self.seeder.image)}, - Tuple{k = 'imageVersion', v = opt(self.seeder.imageVersion)}, - Tuple{k = 'memory', v = str(self.seeder.memory)}, - Tuple{k = 'cpu', v = str(self.seeder.cpu)}}) endif}, - Tuple{k = 'sidecars', v = if self.sidecars->isEmpty() then null else arr(self.sidecars->collect(x | - let src : Sidecar = self.invresolveone(PI::Process).sidecars->select(c | c.name = x.name)->any(true) in - obj(Sequence{ - Tuple{k = 'name', v = str(x.name)}, - Tuple{k = 'image', v = str(x.image)}, - Tuple{k = 'imageVersion', v = opt(x.imageVersion)}, - Tuple{k = 'command', v = if src.command->isEmpty() then null else arr(src.command->collect(c | str(c))) endif}, - Tuple{k = 'args', v = if src.args->isEmpty() then null else arr(src.args->collect(c | str(c))) endif}, - Tuple{k = 'memory', v = str(x.memory)}, - Tuple{k = 'cpu', v = str(x.cpu)}, - Tuple{k = 'volumes', v = if src.volumes->isEmpty() then null else arr(src.volumes->collect(m | obj(Sequence{ - Tuple{k = 'claim', v = str(m.claim)}, Tuple{k = 'mountAt', v = str(m.mountAt)}}))) endif}, - Tuple{k = 'assets', v = if src.assets->isEmpty() then null else arr(src.assets->collect(m | obj(Sequence{ - Tuple{k = 'from', v = str(m._from)}, Tuple{k = 'mountAt', v = str(m.mountAt)}}))) endif}, - Tuple{k = 'init', v = if x._init then bool(true) else null endif}}))) endif}, - Tuple{k = 'dependencies', v = if self.dependencies->isEmpty() then null else arr(self.dependencies->collect(x | obj(Sequence{ - Tuple{k = 'application', v = str(x.application)}, - Tuple{k = 'surface', v = str(x.surface)}, - Tuple{k = 'address', v = str(x.address)}, - Tuple{k = 'target', v = opt(x.target)}, - Tuple{k = 'peers', v = if x.peers->isEmpty() then null else arr(x.peers->collect(q | q.json())) endif}}))) endif}, - Tuple{k = 'consumes', v = if self.consumes->isEmpty() then null else arr(self.consumes->collect(c | str(c))) endif}, - Tuple{k = 'writablePaths', v = if self.writablePaths->isEmpty() then null else arr(self.writablePaths->collect(x | obj(Sequence{ - Tuple{k = 'path', v = str(x.path)}, - Tuple{k = 'size', v = str(x.size)}, - Tuple{k = 'medium', v = if x.memory then str('memory') else null endif}}))) endif}, - Tuple{k = 'environment', v = if self.environment->isEmpty() then null else arr(self.environment->collect(x | obj(Sequence{ - Tuple{k = 'name', v = str(x.name)}, - Tuple{k = 'value', v = opt(x.value)}, - Tuple{k = 'secret', v = if x.secret = null then null else obj(Sequence{ - Tuple{k = 'path', v = str(x.secret.path)}, - Tuple{k = 'key', v = str(x.secret.key)}}) endif}}))) endif}, - Tuple{k = 'surfaces', v = if self.surfaces->isEmpty() then null else arr(self.surfaces->collect(x | obj(Sequence{ - Tuple{k = 'name', v = str(x.name)}, - Tuple{k = 'port', v = num(x.port)}}))) endif}, - -- An L4 client is the adapter's to admit, read off the exposure; the element carries the exposure. - Tuple{k = 'ingress', v = let own : Sequence(PolicyPeer) = ingress->reject(x | x.rule = 'l4') in - if own->isEmpty() then null else arr(own->collect(x | x.json())) endif}, - Tuple{k = 'egress', v = arr(egress->collect(x | x.json()))} - }); - -query ProbeTarget::fields() : Sequence(Tuple(k : String, v : String)) = - if self.oclIsKindOf(HttpTarget) then Sequence{ - Tuple{k = 'path', v = str(self.oclAsType(HttpTarget).path)}, - Tuple{k = 'port', v = num(self.oclAsType(HttpTarget).port)}} - else Sequence{Tuple{k = 'tcp', v = num(self.oclAsType(TcpTarget).tcp)}} endif; - -query ProbeTarget::json() : String = obj(self.fields()); - -query ResolvedProbe::json() : String = obj(self.target.fields()->union(Sequence{ - Tuple{k = 'period', v = str(self.period)}, - Tuple{k = 'timeout', v = str(self.timeout)}, - Tuple{k = 'failures', v = num(self.failures)}})); - -query StartupProbe::json() : String = obj(self.target.fields()->union(Sequence{ - Tuple{k = 'period', v = str(self.period)}, - Tuple{k = 'timeout', v = str(self.timeout)}, - Tuple{k = 'failures', v = num(self.failures)}})); - -query PolicyPeer::json() : String = obj(Sequence{ - Tuple{k = 'rule', v = opt(self.rule)}, - Tuple{k = 'namespace', v = opt(self.namespace)}, - Tuple{k = 'process', v = opt(self.process)}, - Tuple{k = 'consumes', v = opt(self.consumes)}, - -- The gate's members are pods, not one port. - Tuple{k = 'port', v = if self.rule = 'gate-members' then null else num(self.port) endif}}); - -query ResolvedVolume::json() : String = obj(Sequence{ - Tuple{k = 'claim', v = str(self.claim)}, - Tuple{k = 'mountAt', v = str(self.mountAt)}, - Tuple{k = 'size', v = str(self.size)}, - Tuple{k = 'durability', v = str(self.durability.spelling())}, - Tuple{k = 'backup', v = if self.backup = null then null else obj(Sequence{ - Tuple{k = 'schedule', v = str(self.backup.schedule)}, - Tuple{k = 'retain', v = num(self.backup.retain)}, - Tuple{k = 'offCluster', v = if self.backup.offCluster = null then null else obj(Sequence{ - Tuple{k = 'destination', v = str(self.backup.offCluster)}, - Tuple{k = 'path', v = str(self.backup.offClusterPath)}, - Tuple{k = 'recipient', v = str(self.backup.offClusterRecipient)}}) endif}, - Tuple{k = 'method', v = str(self.backup.method)}, - Tuple{k = 'methodVersion', v = opt(self.backup.methodVersion)}, - Tuple{k = 'uid', v = num(self.backup.uid)}, - Tuple{k = 'gid', v = num(self.backup.gid)}, - Tuple{k = 'identity', v = str(self.backup.identity)}, - Tuple{k = 'claim', v = str(self.backup.claim)}, - Tuple{k = 'credential', v = if self.backup.credential = null then null else self.backup.credential.json() endif}, - Tuple{k = 'peer', v = if self.backup.peer = null then null else obj(Sequence{ - Tuple{k = 'host', v = str(self.backup.peer.host)}, - Tuple{k = 'port', v = num(self.backup.peer.port)}, - Tuple{k = 'credential', v = self.backup.peer.credential.json()}}) endif}, - Tuple{k = 'egress', v = arr(self.backup.egress->collect(x | x.json()))}, - Tuple{k = 'destinations', v = if self.backup.destinations->isEmpty() then null - else arr(self.backup.destinations->collect(x | obj(Sequence{ - Tuple{k = 'cidr', v = str(x.cidr)}, - Tuple{k = 'port', v = num(x.port)}}))) endif}}) endif}}); - -query ResolvedGrant::json() : String = obj(Sequence{ - Tuple{k = 'path', v = opt(self.path)}, - Tuple{k = 'keys', v = if self.keys->isEmpty() then null else arr(self.keys->collect(x | str(x))) endif}, - Tuple{k = 'access', v = opt(self._access)}, - Tuple{k = 'client', v = opt(self.clientNamed())}, - Tuple{k = 'engine', v = opt(self.engine)}, - Tuple{k = 'paths', v = if self.paths->isEmpty() then null else arr(self.paths->collect(x | obj(Sequence{ - Tuple{k = 'path', v = str(x.path)}, - Tuple{k = 'allows', v = arr(x.allows->collect(a | str(a)))}}))) endif}, - Tuple{k = 'delivery', v = str(self.delivery)}, - Tuple{k = 'destination', v = opt(self.destination)}, - Tuple{k = 'mountAt', v = opt(self.mountAt)}, - Tuple{k = 'fileMode', v = opt(self.fileMode)}, - Tuple{k = 'restartTargets', v = if self.restartTargets->isEmpty() then null - else arr(self.restartTargets->collect(x | str(x))) endif}, - Tuple{k = 'generated', v = if self.generated->isEmpty() then null - else arr(self.generated->collect(x | obj(Sequence{ - Tuple{k = 'key', v = str(x.key)}, - Tuple{k = 'bytes', v = num(x.bytes)}, - Tuple{k = 'encoding', v = str(x.encoding)}, - Tuple{k = 'adopt', v = if x.adoptPath = null then null else obj(Sequence{ - Tuple{k = 'path', v = str(x.adoptPath)}, - Tuple{k = 'key', v = str(x.adoptKey)}}) endif}}))) endif}}); - --- ================================================ a Vault policy job's files - --- One Vault policy job's files under `root`, its objects in `ns`, handed the documents among --- `held` and named by their digest and everything its pod runs with: a Job's template never --- changes once created, so any change to either is a new name. None where it holds no document. -query policyJobFiles(planned : ResolvedPolicyJob, held : Sequence(Deliverable), root : String, ns : String) : Sequence(Deliverable) = - let docs : Sequence(Tuple(file : String, json : String)) = held - ->collect(d | d.documentOf())->select(d | d <> null)->asSequence()->sortedBy(d | d.file) in - if planned = null or docs->isEmpty() then Sequence{} else - let digest : String = obj(Sequence{ - Tuple{k = 'documents', v = '{' + joined(docs->collect(d | str(d.file) + ':' + d.json)) + '}'}, - Tuple{k = 'image', v = str(planned.image)}, - Tuple{k = 'uid', v = planned.uid.toString()}, - Tuple{k = 'gid', v = planned.gid.toString()}, - Tuple{k = 'memory', v = str(planned.memory)}, - Tuple{k = 'cpu', v = str(planned.cpu)}, - Tuple{k = 'deadline', v = str(planned.deadline)}, - Tuple{k = 'eligibleNodes', v = arr(planned.eligibleNodes->collect(n | str(n)))}}).rawDigestOf() in - let named : String = planned.identity + '-' - + digest.substring(ALGORITHM.size() + 1, ALGORITHM.size() + NAME_DIGITS) in - Sequence{'configmap', 'job', 'cronjob', 'serviceaccount', 'networkpolicy'} - ->collect(piece | object PolicyJobFile { - path := root + piece + '.yaml'; - adapter := if piece = 'networkpolicy' then AdapterName::networking else AdapterName::vaultPolicy endif; - part := piece; - name := named; - namespace := ns; - job := planned; - documents := docs->collect(d | object PolicyDocument { file := d.file; json := d.json; }); - }.oclAsType(Deliverable)) - -- A policy file is listed nowhere while the policy stage is render-only. - ->append(object IndexFile { - path := root + 'kustomization.yaml'; - adapter := AdapterName::kubernetes; - resources := Sequence{'configmap.yaml', 'cronjob.yaml', 'job.yaml', 'serviceaccount.yaml'}; - }.oclAsType(Deliverable)) endif; - --- A Vault document as a job is handed it: its file name, and its content as canonical JSON. --- Any other Deliverable is none. -query Deliverable::documentOf() : Tuple(file : String, json : String) = - if self.oclIsKindOf(VaultPolicyFile) then - Tuple{file = fileOf(self.path), json = self.oclAsType(VaultPolicyFile).policyJson()} - else if self.oclIsKindOf(VaultRoleFile) then - Tuple{file = fileOf(self.path), json = self.oclAsType(VaultRoleFile).roleJson()} - else if self.oclIsKindOf(GeneratedKeysFile) then - Tuple{file = fileOf(self.path), json = self.oclAsType(GeneratedKeysFile).keysJson()} - else if self.oclIsKindOf(CatalogJobFile) and self.oclAsType(CatalogJobFile).part = 'policy' then - Tuple{file = fileOf(self.path), json = self.oclAsType(CatalogJobFile).job.catalogPolicyJson()} - else null endif endif endif endif; - --- A catalog method's own policy: it reads its login, and writes each database role it names. -query ResolvedCatalogJob::catalogPolicyJson() : String = pathsJson(self.policy); - --- A catalog method's own policy: it reads its login and its metadata, and creates, reads and --- updates each database role the catalog names, in the catalog's order. -query ResolvedCatalog::policy() : Sequence(PolicyPath) = - Sequence{allowing(self.admin.path, Sequence{'read'}), - allowing('secret/metadata/' + self.admin.path.substring(KV_DATA.size() + 1, self.admin.path.size()), - Sequence{'read'})} - ->union(self.databases->collect(d | Sequence{d.owner, d.data})->flatten() - ->collect(r | allowing('database/roles/' + r, Sequence{'create', 'read', 'update'}))->asSequence()) - ->union(self.keys->collect(k | allowing(k.path, Sequence{'create', 'read', 'update'}))->asSequence()); - --- What each grant may do: the paths a transit or database grant's engine derives, or `read` on --- a kv grant's path and on the same document's metadata. -query VaultPolicyFile::policyJson() : String = pathsJson(self.paths); - -query pathsJson(paths : Collection(PolicyPath)) : String = - obj(Sequence{Tuple{k = 'path', v = obj(paths->collect(p | - Tuple{k = p.path, v = capabilities(p.allows->asSequence())})->asSequence())}}); - --- What a grant allows: its engine's own paths, or `read` on a kv grant's document and on the same --- document's metadata. -query ResolvedGrant::allowedPaths() : Sequence(PolicyPath) = - if self.engine <> null or self.paths->notEmpty() then self.paths->collect(p | allowing(p.path, p.allows->asSequence())) - else Sequence{allowing(self.path, Sequence{'read'}), - allowing('secret/metadata/' + self.path.substring(KV_DATA.size() + 1, self.path.size()), - Sequence{'read'})} endif; - -query allowing(at : String, capabilities : Sequence(String)) : PolicyPath = - object PolicyPath { path := at; allows := capabilities; }; - -property KV_DATA : String = 'secret/data/'; - -query capabilities(allows : Sequence(String)) : String = - obj(Sequence{Tuple{k = 'capabilities', v = arr(allows->collect(a | str(a)))}}); - --- Each key a job generates, where, and how. -query GeneratedKeysFile::keysJson() : String = - obj(Sequence{Tuple{k = 'keys', v = arr(self.keys->collect(x | obj(Sequence{ - Tuple{k = 'path', v = str(x.path)}, - Tuple{k = 'key', v = str(x.key)}, - Tuple{k = 'bytes', v = x.bytes.toString()}, - Tuple{k = 'encoding', v = str(x.encoding)}} - ->union(if x.adoptPath = null then Sequence{} else Sequence{ - Tuple{k = 'adopt', v = obj(Sequence{ - Tuple{k = 'path', v = str(x.adoptPath)}, - Tuple{k = 'key', v = str(x.adoptKey)}})}} endif))))}}); - --- The role that binds the identity's ServiceAccount, in its namespace, to the one policy of its name. -query VaultRoleFile::roleJson() : String = - obj(Sequence{ - Tuple{k = 'bound_service_account_names', v = arr(Sequence{str(self.identity)})}, - Tuple{k = 'bound_service_account_namespaces', v = arr(Sequence{str(self.namespace)})}, - Tuple{k = 'token_policies', v = arr(Sequence{str(self.namespace + '-' + self.identity)})}}); - --- The last segment of a path: the name a document is mounted and written under. -query fileOf(path : String) : String = path.substring(path.lastIndexOf('/') + 1, path.size()); - --- ===================================================== a catalog method's files - --- How many hex digits of a digest a derived name carries, after the algorithm it opens with. -property ALGORITHM : String = 'sha256:'; -property NAME_DIGITS : Integer = 12; - --- A catalog method's objects and its own policy, under one directory: its Job is named by the --- digest of the catalog and of everything its pod runs with, so a changed one is a new Job. -query ResolvedCatalogJob::catalogFilesUnder(root : String) : Sequence(Deliverable) = - let catalog : String = self.catalog.catalogJson() in - let digest : String = obj(Sequence{ - Tuple{k = 'catalog', v = catalog}, - Tuple{k = 'image', v = str(self.image)}, - Tuple{k = 'uid', v = self.uid.toString()}, - Tuple{k = 'gid', v = self.gid.toString()}, - Tuple{k = 'memory', v = str(self.memory)}, - Tuple{k = 'cpu', v = str(self.cpu)}, - Tuple{k = 'deadline', v = str(self.deadline)}, - Tuple{k = 'eligibleNodes', v = arr(self.eligibleNodes->collect(n | str(n)))}}).rawDigestOf() in - Sequence{ - object CatalogJobFile { - path := root + self.identity + '.yaml'; - adapter := AdapterName::kubernetes; - part := 'objects'; - name := self.identity + '-' + digest.substring(ALGORITHM.size() + 1, ALGORITHM.size() + NAME_DIGITS); - catalogJson := catalog; - job := self; - }.oclAsType(Deliverable), - object CatalogJobFile { - path := root + self.identity + '-networkpolicy.yaml'; - adapter := AdapterName::networking; - part := 'networkpolicy'; - job := self; - }.oclAsType(Deliverable)}; - --- A catalog as its method is handed it. -query ResolvedCatalog::catalogJson() : String = - if self.keys->notEmpty() then obj(Sequence{ - Tuple{k = 'admin', v = obj(Sequence{ - Tuple{k = 'path', v = str(self.admin.path)}, - Tuple{k = 'token', v = str(self.admin.token)}})}, - Tuple{k = 'host', v = str(self.host)}, - Tuple{k = 'keys', v = arr(self.keys->collect(x | obj(Sequence{ - Tuple{k = 'buckets', v = arr(x.buckets->collect(b | str(b))->asSequence())}, - Tuple{k = 'name', v = str(x.name)}, - Tuple{k = 'path', v = str(x.path)}}))->asSequence())}, - Tuple{k = 'port', v = self.port.toString()}}) - else obj(Sequence{ - Tuple{k = 'admin', v = obj(Sequence{ - Tuple{k = 'path', v = str(self.admin.path)}, - Tuple{k = 'user', v = str(self.admin.user)}, - Tuple{k = 'password', v = str(self.admin.password)}})}, - Tuple{k = 'connection', v = str(self.connection)}, - Tuple{k = 'databases', v = arr(self.databases->collect(d | obj(Sequence{ - Tuple{k = 'name', v = str(d.name)}, - Tuple{k = 'owner', v = str(d.owner)}, - Tuple{k = 'data', v = str(d.data)}}))->asSequence())}, - Tuple{k = 'host', v = str(self.host)}, - Tuple{k = 'port', v = self.port.toString()}}) endif; - --- ===================================================== canonical JSON text - --- An object of the entries whose value is present, in key order. -query obj(entries : Sequence(Tuple(k : String, v : String))) : String = - '{' + joined(entries->select(e | e.v <> null)->sortedBy(e | e.k)->collect(e | str(e.k) + ':' + e.v)) + '}'; - -query arr(items : Sequence(String)) : String = '[' + joined(items) + ']'; - --- The items, comma-separated; no item is empty, since each is a JSON value. -query joined(items : Sequence(String)) : String = - items->iterate(i; acc : String = '' | if acc = '' then i else acc + ',' + i endif); - --- A JSON string, escaped as JSON.stringify escapes it. -query str(s : String) : String = - '"' + s.substituteAll('\\', '\\\\').substituteAll('"', '\\"').substituteAll('\n', '\\n') - .substituteAll('\r', '\\r').substituteAll('\t', '\\t') + '"'; - -query opt(s : String) : String = if s = null then null else str(s) endif; - -query num(n : Integer) : String = n.toString(); - -query bool(b : Boolean) : String = if b then 'true' else 'false' endif; - -query Switchover::spelling() : String = - if self = Switchover::blueGreen then 'blue-green' - else if self = Switchover::stopStart then 'stop-start' else 'rolling' endif endif; - -query RD::Cutover::spelling() : String = - if self = RD::Cutover::continuous then 'continuous' else 'interrupted' endif; - -query RD::Match::spelling() : String = if self = RD::Match::exact then 'exact' else 'prefix' endif; - -query MiddlewareKind::spelling() : String = - if self = MiddlewareKind::forwardAuth then 'forward-auth' - else if self = MiddlewareKind::securityHeaders then 'security-headers' - else if self = MiddlewareKind::redirect then 'redirect' else 'rate-limit' endif endif endif; - -query RD::DurabilityClass::spelling() : String = - if self = RD::DurabilityClass::reconstructible then 'reconstructible' - else if self = RD::DurabilityClass::recoverable then 'recoverable' else 'irreplaceable' endif endif; - -query PinnedInput::spelling() : String = - if self = PinnedInput::clusterState then 'cluster-state' - else if self = PinnedInput::nodeContract then 'node-contract' - else if self = PinnedInput::imagesLock then 'images-lock' - else if self = PinnedInput::platformIntent then 'platform-intent' else 'intent-fragment' endif endif endif endif; - -query AnalysisCheck::spelling() : String = - if self = AnalysisCheck::errorRate then 'error-rate' else 'latency' endif; - --- ================================================================== edge --- edge: a tier's proxy (spec/v1/14-platform-intent.md#tiers): the L4 ports, the claim, the token, --- the arguments and the shared Middlewares its tiers derive on it, which no project file writes. - -property ACME_REASON : String = 'ACME issuance and its DNS challenge'; --- The claim an acme tier derives on its proxy's Process is named for it, `-acme`: a --- Project's Processes share one namespace, so two proxies never share one. -property ACME_CLAIM : String = '-acme'; -property ACME_MOUNT : String = '/acme'; -property ACME_SIZE : String = '16Mi'; -property DNS_TOKEN_KEY : String = 'CF_DNS_API_TOKEN'; - --- The surfaces a listener's ports are answered on. -query listenerSurfaces(l : Listener) : Sequence(String) = - if l = Listener::tls then Sequence{'web', 'websecure'} else Sequence{'web'} endif; - --- The Process of an Application that provides every surface a listener names, if any does. -query listenedBy(app : EffectiveApplication, l : Listener) : String = - app.processes->select(q | listenerSurfaces(l)->forAll(s | q.provides->exists(e | e.key = s))) - ->collect(q | q.name)->any(true); - --- The tiers whose proxy is this Process. -query edgeTiersOf(p : PI::Process) : Sequence(Tier) = - let app : EffectiveApplication = p.oclAsType(ECORE::EObject).eContainer().oclAsType(EffectiveApplication) in - let prj : EffectiveProject = app.oclAsType(ECORE::EObject).eContainer().oclAsType(EffectiveProject) in - estate.tiers->select(t | heldName(t.traefik) = prj.project + '/' + app.id - and listenedBy(app, t.listener) = p.name)->asSequence(); - --- What a tier's proxy asks of the Kubernetes API: its provider reads every route, middleware and --- TLS object, and the Services, endpoints and Secrets they name, in every namespace --- (spec/v1/14-platform-intent.md#tiers). -property PROXY_API_REASON : String = 'the proxy reads every route of its tier and what each names, cluster-wide'; - -query proxyApiRules() : Sequence(ResolvedApiRule) = - let reads : Sequence(String) = Sequence{'get', 'list', 'watch'} in - Sequence{ - apiRule('core', Sequence{'services', 'secrets', 'nodes', 'configmaps', 'namespaces'}, reads), - apiRule('core', Sequence{'pods'}, Sequence{'get'}), - apiRule('discovery.k8s.io', Sequence{'endpointslices'}, reads), - apiRule('traefik.io', Sequence{'ingressroutes', 'ingressroutetcps', 'ingressrouteudps', 'middlewares', - 'middlewaretcps', 'serverstransports', 'serverstransporttcps', 'tlsoptions', 'tlsstores', - 'traefikservices'}, reads)}; - --- Whether the Process answers an acme tier. -query edgeAcme(p : PI::Process) : Boolean = - edgeTiersOf(p)->exists(t | t.certificates = CertificateSource::acme); - --- The L4 exposures its tiers derive: each port the listener derives, on the tier's address. -query tierL4Of(p : PI::Process) : Sequence(Tuple(address : String, port : Integer, protocol : L4Protocol, surface : Surface)) = - edgeTiersOf(p)->select(t | t.address <> null)->collect(t | - listenerSurfaces(t.listener)->collect(s | Tuple{address = t.address, - port = if s = 'web' then 80 else 443 endif, protocol = L4Protocol::tcp, - surface = p.provides->select(e | e.key = s)->any(true)}))->asSequence(); - --- The ports on a node's own address that are not a surface's own number over TCP. --- The host port a surface's own entry carries: the first TCP port a client dials on a node's own --- address to reach it, whatever port that is, so a container port and protocol appear once, as --- server-side apply keys the list by them. -query hostPortOf(p : PI::Process, s : Surface) : Integer = - let ports : Sequence(Integer) = l4Of(p)->select(e | e.surface = s - and addressOf(e.address).oclIsKindOf(NodeAddress) and e.protocol = L4Protocol::tcp) - ->collect(e | e.port)->asSequence() in - if ports->isEmpty() then null else ports->min() endif; - --- Every port a client dials on a node's own address that no surface's own entry carries. -query edgeNodePortsOf(p : PI::Process) : Sequence(L4Port) = - l4Of(p)->select(e | addressOf(e.address).oclIsKindOf(NodeAddress) - and not (e.protocol = L4Protocol::tcp and e.port = hostPortOf(p, e.surface))) - ->sortedBy(e | e.port * 2 + (if e.protocol = L4Protocol::tcp then 0 else 1 endif)) - ->collect(e | object L4Port { - name := e.protocol.toString() + '-' + e.port.toString(); - port := e.port; - protocol := e.protocol.toString().toUpper(); - targetPort := e.surface.value; - })->asSequence(); - -query edgeVolumesOf(p : PI::Process) : Sequence(ResolvedVolume) = - if edgeAcme(p) then Sequence{object ResolvedVolume { - claim := p.name + ACME_CLAIM; - mountAt := ACME_MOUNT; - size := ACME_SIZE; - durability := RD::DurabilityClass::reconstructible; - }} else Sequence{} endif; - -query edgeGrantsOf(p : PI::Process) : Sequence(ResolvedGrant) = - (if edgeAcme(p) then Sequence{object ResolvedGrant { - path := estate.acme.token; - keys := Sequence{DNS_TOKEN_KEY}; - _access := 'read'; - delivery := 'env'; - destination := destinationOf(p.name, estate.acme.token); - restartTargets := Sequence{p.name}; - }} else Sequence{} endif) - ->union(heldCertificatesOf(p)); - --- The certificate a tier that issues none reads from the Secret Store, synced beside its proxy for --- the default TLS store to name (spec/v1/14-platform-intent.md#tiers). The proxy reads it through --- the API, so nothing is injected and a new certificate restarts nothing. -query heldCertificatesOf(p : PI::Process) : Sequence(ResolvedGrant) = - edgeTiersOf(p)->select(t | t.certificateFrom <> null)->collect(t | object ResolvedGrant { - path := t.certificateFrom; - keys := Sequence{'tls.crt', 'tls.key'}; - _access := 'read'; - delivery := 'env'; - destination := destinationOf(p.name, t.certificateFrom); - }); - -query edgeEnvOf(p : PI::Process) : Sequence(EnvEntry) = - if edgeAcme(p) then Sequence{object EnvEntry { - name := DNS_TOKEN_KEY; - secret := object SecretReference { path := estate.acme.token; key := DNS_TOKEN_KEY; }; - }} else Sequence{} endif; - -query edgeSurfacePort(p : PI::Process, name : String) : Integer = - p.provides->select(e | e.key = name)->collect(e | e.value)->any(true); - --- A tier proxy's static configuration, as Traefik's arguments --- (spec/v1/30-deliverables.md#the-edge-proxy), after the authored ones. -query edgeArgsOf(p : PI::Process) : Sequence(String) = - let app : EffectiveApplication = p.oclAsType(ECORE::EObject).eContainer().oclAsType(EffectiveApplication) in - let prj : EffectiveProject = app.oclAsType(ECORE::EObject).eContainer().oclAsType(EffectiveProject) in - let t : Tier = estate.tiers->select(x | heldName(x.traefik) = prj.project + '/' + app.id - and x.ingressClass <> null)->any(true) in - if t = null or edgeSurfacePort(p, 'web') = null then Sequence{} else - let websecure : Integer = edgeSurfacePort(p, 'websecure') in - let admin : Integer = edgeSurfacePort(p, 'admin') in - Sequence{'--entryPoints.web.address=:' + edgeSurfacePort(p, 'web').toString() + '/tcp'} - ->union(if websecure = null then Sequence{} - else Sequence{'--entryPoints.websecure.address=:' + websecure.toString() + '/tcp'} endif) - ->union(if t.listener = Listener::tls and websecure <> null - then Sequence{'--entryPoints.websecure.http.tls=true'} else Sequence{} endif) - ->union(if admin = null then Sequence{} else Sequence{ - '--entryPoints.traefik.address=:' + admin.toString() + '/tcp', - '--ping=true', '--ping.entryPoint=traefik', - '--metrics.prometheus=true', '--metrics.prometheus.entryPoint=traefik'} endif) - ->union(Sequence{'--providers.kubernetescrd=true', - '--providers.kubernetescrd.ingressClass=' + t.ingressClass, - '--providers.kubernetescrd.allowCrossNamespace=true', - '--providers.kubernetescrd.allowEmptyServices=true'}) - ->union(if t.certificates = CertificateSource::acme then Sequence{ - '--certificatesresolvers.' + t.name + '.acme.email=' + estate.acme.email, - '--certificatesresolvers.' + t.name + '.acme.storage=' + ACME_MOUNT + '/' + t.name + '.json', - '--certificatesresolvers.' + t.name + '.acme.dnschallenge.provider=' + estate.acme.dnsProvider.toString()} - else Sequence{} endif) - ->union(Sequence{'--log.format=json', '--accesslog=true', '--accesslog.format=json'}) - endif; - --- The Middlewares every route names, in the namespace of the Project's tier proxies, rendered once --- by the first proxy by name, with the forward-auth the first tier of the namespace names; and its --- place in that Application's index. -helper EffectiveProject::edgeFiles(inout plan : ResolvedDeployment) : OclVoid { - var proxies : Sequence(String) := estate.tiers->collect(t | heldName(t.traefik)) - ->select(h | h.startsWith(self.project + '/'))->asSet()->asSequence()->sortedBy(h | h); - if (proxies->notEmpty()) { - var home : String := proxies->first().substring(self.project.size() + 2, proxies->first().size()); - var asked : Tier := estate.tiers->select(t | t.forwardAuth <> null - and heldName(t.traefik).startsWith(self.project + '/'))->any(true); - plan.deliverables += object SharedMiddlewareFile { - path := 'apps/' + self.project + '/' + home + '/middlewares.yaml'; - adapter := AdapterName::traefik; - namespace := namespaceOf(self.project); - application := home; - if (asked <> null) { - forwardAuth := object ForwardAuthEndpoint { address := asked.forwardAuth.endpoint(); }; - } endif; - policies := Sequence{ - object ContentPolicyHeaders { name := 'strict'; contentSecurityPolicy := 'default-src \'self\''; }, - object ContentPolicyHeaders { name := 'admin'; - contentSecurityPolicy := 'default-src \'self\'; style-src \'self\' \'unsafe-inline\''; }, - object ContentPolicyHeaders { name := 'workflow'; - contentSecurityPolicy := 'default-src \'self\'; connect-src \'self\' https:'; }}; - }; - var index : IndexFile := plan.deliverables[IndexFile] - ->select(i | i.path = 'apps/' + self.project + '/' + home + '/kustomization.yaml')->any(true); - if (index <> null) { - index.resources := index.resources->append('middlewares.yaml')->sortedBy(m | m); - }; - }; -} - --- ==================================================================== observability --- observability: rule groups, the Alertmanager's routing, and Flux's metrics scrape. - -query obsAlerts(app : EffectiveApplication) : Boolean = - estate.monitoring <> null and estate.monitoring.alertmanager.id = app.id; - -query obsFlux(app : EffectiveApplication) : Boolean = - estate.bootstrap.flux.metrics <> null and estate.telemetry <> null and estate.telemetry.metrics.id = app.id; - -query obsFluxScrape() : ResolvedFluxScrape = - object ResolvedFluxScrape { - namespace := estate.bootstrap.flux.sourceRef.substringBefore('/'); - port := estate.bootstrap.flux.metrics.port; - path := estate.bootstrap.flux.metrics.path; - interval := estate.monitors.interval; - timeout := estate.monitors.timeout; - labels := estate.monitors.labels->sortedBy(l | l.key) - ->collect(l | object KeyValue { key := l.key; value := l.value; }); - }; - -query obsAlerting(app : EffectiveApplication) : ResolvedAlerting = - object ResolvedAlerting { - routes := estate.monitoring.routes->collect(r | object AlertRoute { - severity := r.severity; receiver := r.receiver; repeat := r.repeat; }); - receivers := estate.monitoring.receivers->collect(r | object AlertReceiver { - name := r.name; - secret := destinationOf(app.processes->first().name, r.discord.webhook.path); - key := r.discord.webhook.key; }); - }; - --- The rule name: the Application, then the file's base name without its extension. -query obsRuleName(app : String, source : String) : String = - let base : String = source.substring(source.lastIndexOf('/') + 1, source.size()) in - app + '-' + (if base.endsWith('.yaml') then base.substring(1, base.size() - 5) - else if base.endsWith('.yml') then base.substring(1, base.size() - 4) else base endif endif) - .toLower().replaceAll('[^a-z0-9-]', '-'); - --- A rule-group file's groups, as the file writes them: the list its top-level `groups` holds, which --- the file was refused without (E_ALERT_RULES_WITHOUT_GROUPS). -query obsAlertRules(app : String, source : String, file : AssetFile) : ResolvedAlertRules = - object ResolvedAlertRules { - name := obsRuleName(app, source); - groups := file.rules.oclAsType(IN::DatumMap).entries->select(e | e.key = 'groups')->first() - .value.oclAsType(IN::DatumList).items->collect(d | d.copied()); - }; - --- A value of a rule-group file, as the Resolved Deployment carries it. -query IN::Datum::copied() : RD::Datum = - if self.oclIsKindOf(IN::DatumMap) then - object RD::DatumMap { - entries := self.oclAsType(IN::DatumMap).entries->collect(e | - object RD::DatumEntry { key := e.key; value := e.value.copied(); }); - }.oclAsType(RD::Datum) - else if self.oclIsKindOf(IN::DatumList) then - object RD::DatumList { items := self.oclAsType(IN::DatumList).items->collect(i | i.copied()); }.oclAsType(RD::Datum) - else - let scalar : IN::DatumScalar = self.oclAsType(IN::DatumScalar) in - object RD::DatumScalar { text := scalar.text; kind := scalar.kind.copied(); }.oclAsType(RD::Datum) - endif endif; - -query IN::DatumKind::copied() : RD::DatumKind = - if self = IN::DatumKind::string then RD::DatumKind::string - else if self = IN::DatumKind::number then RD::DatumKind::number - else if self = IN::DatumKind::boolean then RD::DatumKind::boolean - else RD::DatumKind::empty endif endif endif; - --- A value of a rule-group file as JSON: a string as a JSON string, and a number, a boolean or a null --- as its own text. -query RD::Datum::json() : String = - if self.oclIsKindOf(RD::DatumMap) then - obj(self.oclAsType(RD::DatumMap).entries->collect(e | Tuple{k = e.key, v = e.value.json()})) - else if self.oclIsKindOf(RD::DatumList) then - arr(self.oclAsType(RD::DatumList).items->collect(i | i.json())) - else - let scalar : RD::DatumScalar = self.oclAsType(RD::DatumScalar) in - if scalar.kind = RD::DatumKind::string then str(scalar.text) else scalar.text endif - endif endif; - -query obsKvJson(items : Sequence(KeyValue)) : String = - if items->isEmpty() then null else obj(items->collect(i | Tuple{k = i.key, v = str(i.value)})) endif; - -query obsAlertRulesJson(rules : ResolvedAlertRules, source : String) : String = - obj(Sequence{ - Tuple{k = 'from', v = str(source)}, - Tuple{k = 'groups', v = arr(rules.groups->collect(g | g.json()))}}); - -query obsAlertingJson(alerting : ResolvedAlerting) : String = - obj(Sequence{ - Tuple{k = 'receivers', v = arr(alerting.receivers->collect(r | obj(Sequence{ - Tuple{k = 'name', v = str(r.name)}, - Tuple{k = 'discord', v = obj(Sequence{ - Tuple{k = 'secret', v = str(r.secret)}, - Tuple{k = 'key', v = str(r.key)}})}}))->asSequence())}, - Tuple{k = 'routes', v = arr(alerting.routes->collect(r | obj(Sequence{ - Tuple{k = 'severity', v = str(r.severity)}, - Tuple{k = 'receiver', v = str(r.receiver)}, - Tuple{k = 'repeat', v = str(r.repeat)}}))->asSequence())}}); - -query obsFluxJson(flux : ResolvedFluxScrape) : String = - obj(Sequence{ - Tuple{k = 'namespace', v = str(flux.namespace)}, - Tuple{k = 'port', v = num(flux.port)}, - Tuple{k = 'path', v = str(flux.path)}, - Tuple{k = 'interval', v = str(flux.interval)}, - Tuple{k = 'timeout', v = str(flux.timeout)}, - Tuple{k = 'labels', v = obsKvJson(flux.labels->asSequence())}}); - --- Each receiver's webhook, read onto the Alertmanager's first Process through the one secret delivery. -query obsReceiverGrants(p : PI::Process, app : EffectiveApplication) : Sequence(ResolvedGrant) = - if not obsAlerts(app) or app.processes->first() <> p then Sequence{} else - estate.monitoring.receivers->collect(r | object ResolvedGrant { - path := r.discord.webhook.path; - keys := Sequence{r.discord.webhook.key}; - _access := 'read'; - delivery := 'env'; - destination := destinationOf(p.name, r.discord.webhook.path); - })->asSequence() endif; - --- What the metrics stack scrapes: every Application's scrape target, where it runs, in one --- order, then Flux's controllers on the port the bootstrap set records. The order is the --- production implementation's collation of namespace, Process and port, which puts a name before --- itself with a hyphen added (`grafana-operator` before `grafana`): a separator that sorts after --- the hyphen and before every digit and letter does the same. -query obsScrapeEgress(app : EffectiveApplication) : Sequence(PolicyPeer) = - if estate.telemetry = null or estate.telemetry.metrics.id <> app.id then Sequence{} else - let targets : Sequence(Tuple(rule : String, namespace : String, process : String, port : Integer)) = - projects->collect(prj | prj.applications->select(a | a.observability <> null and a.observability.scrape <> null) - ->collect(a | Tuple{rule = 'scrape-target', namespace = namespaceOf(prj.project), - process = a.observability.scrape.process.name, - port = a.observability.scrape.surface.value}))->flatten() in - named(targets->asOrderedSet()->asSequence()->sortedBy(t | t.namespace + '/' + t.process + '/' + t.port.toString())->asSequence()) - ->union(if estate.bootstrap.flux.metrics = null then Sequence{} else Sequence{object PolicyPeer { - rule := 'flux-metrics'; - namespace := estate.bootstrap.flux.sourceRef.substringBefore('/'); - port := estate.bootstrap.flux.metrics.port; - }} endif) - endif; - --- ============================================================ identity: sign-in - --- identity: the exposure an Application's Client names, or the only one it declares. -query clientExposureOf(app : EffectiveApplication) : Exposure = - if app.client.oclAsType(ECORE::EObject).states('exposure') - then app.exposure->select(e | e.name = app.client.exposure)->any(true) - else app.exposure->any(true) endif; - --- identity: the Client an Application's `client` block derives (spec/v1/17-sign-in.md#the-client). -mapping EffectiveApplication::clientOf(in prj : EffectiveProject) : ResolvedClient { - init { - var hostName : String := clientExposureOf(self).host; - } - signIn := self.client.signIn.toString(); - host := hostName; - -- A token Client has no tile, so nothing launches it. - if self.client.signIn <> SignInMode::token then - launchUrl := 'https://' + hostName + (if self.client.oclAsType(ECORE::EObject).states('launchPath') - then self.client.launchPath else '/' endif) - endif; - if self.client.oclAsType(ECORE::EObject).states('iconPath') then - iconUrl := 'https://' + hostName + self.client.iconPath endif; - redirectUris := self.client.redirectPaths->collect(p | 'https://' + hostName + p); - if self.client.oclAsType(ECORE::EObject).states('backChannelLogoutPath') then - backChannelLogoutUri := 'https://' + hostName + self.client.backChannelLogoutPath endif; - if self.client.oclAsType(ECORE::EObject).states('credential') then - credential := self.client.credential.toString() endif; - if self.client.oclAsType(ECORE::EObject).states('credential') and self.client.credential = ClientCredential::secret then - secretPath := clientSecretPath(prj.project, self.id) endif; - roles := Sequence{'user'}->union(self.client.roles->asSequence()); - if self.client.oclAsType(ECORE::EObject).states('label') then label := self.client.label endif; - if self.client.oclAsType(ECORE::EObject).states('description') then description := self.client.description endif; -} - --- identity: where a Client holding a secret keeps it, in its Application's own namespace subtree. -query clientSecretPath(prj : String, application : String) : String = - 'secret/data/' + namespaceOf(prj) + '/' + application + '/client'; - --- identity: every Client of the union holding a secret, by its credential path, in path order. -query clientSecrets() : Sequence(Tuple(client : String, path : String)) = - projects->collect(prj | prj.applications->select(a | a.client <> null - and a.client.oclAsType(ECORE::EObject).states('credential') - and a.client.credential = ClientCredential::secret) - ->collect(a | Tuple{client = a.id, path = clientSecretPath(prj.project, a.id)})) - ->flatten()->sortedBy(c | c.path)->asSequence(); - --- identity: whether an Application is the sign-in provider, whose Processes write every Client credential. -query providerHolds(app : EffectiveApplication) : Boolean = - estate.signIn <> null and projects->exists(prj | prj.applications->includes(app) - and prj.project + '/' + app.id = heldName(estate.signIn.provider)); - -query holdsClientGrants(p : PI::Process) : Boolean = - providerHolds(p.oclAsType(ECORE::EObject).eContainer().oclAsType(EffectiveApplication)) - and clientSecrets()->notEmpty(); - --- identity: the grants a Client derives on a Process of its provider: write on every client --- credential of the union, delivered to no one (the provider reads it through its own token). -query PI::Process::clientGrants(app : EffectiveApplication) : Sequence(ResolvedGrant) = - if not providerHolds(app) then Sequence{} else - clientSecrets()->collect(c | object ResolvedGrant { - delivery := 'self'; - paths := Sequence{object PolicyPath { path := c.path; allows := Sequence{'create', 'read', 'update'}; }}; - }) endif; - --- identity: the Client a grant of the provider writes, found by the path it holds. -query ResolvedGrant::clientNamed() : String = - if self.engine <> null or self.path <> null or self.paths->size() <> 1 then null else - let found : Sequence(Tuple(client : String, path : String)) = - clientSecrets()->select(c | c.path = self.paths->first().path) in - if found->isEmpty() then null else found->first().client endif endif; - --- identity: whether an exposure's authenticated routes ask the tier's forward-auth: only where the --- Client that names the exposure is gated. -query asksTheGate(app : EffectiveApplication, exposure : Exposure) : Boolean = - if app.client = null then true - else if clientExposureOf(app) <> exposure then true - else app.client.signIn = SignInMode::gated endif endif; - --- identity: the Application a gate belongs to, as the source reads it. -query ReleaseGate::sourceOf() : EffectiveApplication = - let id : String = self.oclAsType(ECORE::EObject).eContainer().oclAsType(ResolvedApplication).id in - projects->select(p | p.project = project).applications->select(a | a.id = id)->any(true); - --- identity: a native Client's protected path, which the gate asks anonymously before it switches. -query ReleaseGate::protectedPathOf() : String = - let app : EffectiveApplication = self.sourceOf() in - if app.client = null or app.client.signIn <> SignInMode::native then null - else app.client.protectedPath endif; - --- identity: the Process the longest Route of the Client's exposure takes that path to. -query ReleaseGate::protectedByOf() : String = - let app : EffectiveApplication = self.sourceOf() in - if self.protectedPathOf() = null then null else - let path : String = self.protectedPathOf() in - let reaching : Sequence(Route) = clientExposureOf(app).routes->select(r | r.redirectTo = null - and (if r.match = PI::Match::exact then path = r.path else path.startsWith(r.path) endif))->asSequence() in - if reaching->isEmpty() then null - else reaching->sortedBy(r | -r.path.size())->first().process.name endif endif; - --- identity: the Client as the element records it. -query ResolvedClient::json() : String = obj(Sequence{ - Tuple{k = 'signIn', v = str(self.signIn)}, - Tuple{k = 'host', v = str(self.host)}, - Tuple{k = 'launchUrl', v = opt(self.launchUrl)}, - Tuple{k = 'iconUrl', v = opt(self.iconUrl)}, - Tuple{k = 'redirectUris', v = if self.redirectUris->isEmpty() then null - else arr(self.redirectUris->collect(u | str(u))) endif}, - Tuple{k = 'backChannelLogoutUri', v = opt(self.backChannelLogoutUri)}, - Tuple{k = 'credential', v = opt(self.credential)}, - Tuple{k = 'secretPath', v = opt(self.secretPath)}, - Tuple{k = 'roles', v = arr(self.roles->collect(r | str(r)))}, - Tuple{k = 'label', v = opt(self.label)}, - Tuple{k = 'description', v = opt(self.description)} -}); - --- ================================================================== posture --- posture (1.3.1): a low port earns NET_BIND_SERVICE, and a writable /tmp is the home --- (docs/adr/model/0141). - -property HOME_DIR : String = '/tmp'; -property FIRST_UNPRIVILEGED_PORT : Integer = 1024; - --- Whether the Process's container mounts a writable /tmp. -query mountsTmp(p : PI::Process) : Boolean = - p.writablePaths->exists(w | w.path = HOME_DIR) or p.volumes->exists(v | v.mountAt = HOME_DIR); - --- Whether the container's own variables name HOME, which an authored one wins. -query namesHome(p : PI::Process, prj : EffectiveProject) : Boolean = - environmentOf(p, prj)->exists(e | e.name = 'HOME'); - --- NET_BIND_SERVICE, where the container listens below 1024. -query lowPrivileges(p : ResolvedProcess) : Sequence(String) = - if p.surfaces->exists(s | s.port < FIRST_UNPRIVILEGED_PORT) - or p.nodePorts->exists(x | x.targetPort < FIRST_UNPRIVILEGED_PORT) - then Sequence{'NET_BIND_SERVICE'} else Sequence{} endif; - --- ================================================================== identity: the gate route --- identity: the Gate's /.auth/ route a gated Client's exposure gains (spec/v1/17-sign-in.md#what-the-edge-derives). - -property GATE_PATH : String = '/.auth/'; - --- Whether the exposure the Client names is authenticated and the Client gated. -query derivesGateRoute(app : EffectiveApplication, exposure : Exposure) : Boolean = - app.client <> null and clientExposureOf(app) = exposure - and exposure.audience = Audience::authenticated and app.client.signIn = SignInMode::gated; - --- The ranks of the exposure's routes, with the gate route's, a prefix of its length. -query exposureRanks(exposure : Exposure, app : EffectiveApplication) : Set(Integer) = - exposure.routes->collect(o | rankOf(o))->asSet() - ->union(if derivesGateRoute(app, exposure) then Set{-GATE_PATH.size()} else Set{} endif); - -query precedenceWith(rank : Integer, ranks : Set(Integer)) : Integer = - ranks->select(k | k < rank)->size() + 1; - -query gateProcessOf(exposure : Exposure) : PI::Process = - let fa : ForwardAuth = tierFor(exposure.audience).forwardAuth in - fa.provider.processes->select(p | p.provides->exists(s | s.key = fa.surface))->first(); - --- The derived route: the Gate's Service, with the exposure's security headers and no forward-auth. -query gateRouteOf(exposure : Exposure, app : EffectiveApplication) : ResolvedRoute = - let fa : ForwardAuth = tierFor(exposure.audience).forwardAuth in - let proxy : String = namespaceOf(projectOf(tierFor(exposure.audience).traefik.id)) in - object ResolvedRoute { - path := GATE_PATH; - match := RD::Match::prefix; - audience := Audience::authenticated.spelling(); - precedence := precedenceWith(-GATE_PATH.size(), exposureRanks(exposure, app)); - gate := object GateRoute { - name := gateProcessOf(exposure).name; - namespace := namespaceOf(projectOf(fa.provider.id)); - port := fa.surface.portOf(fa.provider.id); - }; - middleware := Sequence{object MiddlewareStep { - kind := MiddlewareKind::securityHeaders; - if exposure.oclAsType(ECORE::EObject).states('contentPolicy') - then contentPolicy := exposure.contentPolicy.spelling() endif; - name := if contentPolicy = null then 'security-headers' - else 'security-headers-' + contentPolicy endif; - namespace := proxy; - }}; - }; - --- The external check of the derived route, numbered after the exposure's own routes. -query gateCheck(app : EffectiveApplication, e : Exposure, prj : EffectiveProject) : String = - obj(Sequence{ - Tuple{k = 'name', v = str(app.id + '-' + e.name + '-' + (e.routes->size() + 1).toString())}, - Tuple{k = 'group', v = str(prj.project)}, - Tuple{k = 'url', v = str((if tierFor(e.audience).listener = Listener::tls then 'https' else 'http' endif) - + '://' + e.host + GATE_PATH)}, - Tuple{k = 'conditions', v = arr(Sequence{str('[STATUS] < 500')})}}); - --- ================================================================== observability: the Client's secret read --- observability: a Process that references `${client:secret}` is granted read on the Client's credential --- path, delivered as a `${secret:}` reference's grant is (spec/v1/17-sign-in.md#credentials-and-placeholders). -query PI::Process::readsClientSecret() : Boolean = - self.env->exists(f | f.entries->exists(v | v.value.oclIsKindOf(Placeholder) - and v.value.oclAsType(Placeholder).kind = PlaceholderKind::client - and v.value.oclAsType(Placeholder).source = 'secret')); - -query PI::Process::clientReadGrants(app : EffectiveApplication, prj : EffectiveProject) : Sequence(ResolvedGrant) = - if not self.readsClientSecret() then Sequence{} else - Sequence{object ResolvedGrant { - delivery := 'env'; - path := clientSecretPath(prj.project, app.id); - keys := Sequence{'id', 'secret'}; - _access := 'read'; - destination := destinationOf(self.name, clientSecretPath(prj.project, app.id)); - if self.lifecycle <> Lifecycle::scheduled then restartTargets := Sequence{self.name} endif; - }} endif; diff --git a/emf/bundles/resolve/plugin.xml b/emf/bundles/resolve/plugin.xml deleted file mode 100644 index 031a13d67..000000000 --- a/emf/bundles/resolve/plugin.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - diff --git a/emf/bundles/resolve/pom.xml b/emf/bundles/resolve/pom.xml deleted file mode 100644 index 878c0d354..000000000 --- a/emf/bundles/resolve/pom.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - 4.0.0 - - - dev.jorisjonkers.deploykit.emf - emf-parent - 0.1.0-SNAPSHOT - ../../pom.xml - - - dev.jorisjonkers.deploykit.emf.resolve - eclipse-plugin - deploy-kit model-driven resolve - diff --git a/emf/bundles/resolve/resolution.launch b/emf/bundles/resolve/resolution.launch deleted file mode 100644 index 1a7355168..000000000 --- a/emf/bundles/resolve/resolution.launch +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/emf/bundles/resolve/src/main/java/dev/jorisjonkers/deploykit/emf/resolve/Hashing.java b/emf/bundles/resolve/src/main/java/dev/jorisjonkers/deploykit/emf/resolve/Hashing.java deleted file mode 100644 index e71decd4c..000000000 --- a/emf/bundles/resolve/src/main/java/dev/jorisjonkers/deploykit/emf/resolve/Hashing.java +++ /dev/null @@ -1,41 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.resolve; - -import dev.jorisjonkers.deploykit.emf.metamodel.revision.ModelDigest; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.m2m.qvt.oml.blackbox.java.Operation; -import org.eclipse.m2m.qvt.oml.blackbox.java.Operation.Kind; - -/** - * The one black box {@code resolution.qvto} calls: a digest is a function of canonical bytes, and OCL - * has no way to produce bytes, let alone hash them. Everything else the resolution derives, it - * derives in the language. - */ -public class Hashing { - - /** The unit {@code resolution.qvto} imports this module as. */ - public static final String UNIT = "dev.jorisjonkers.deploykit.emf.hashing"; - - /** The executor instantiates a module itself, through a public constructor, or refuses the unit. */ - public Hashing() {} - - /** The digest of a pinned input's model, or of any object, over its canonical JSON. */ - @Operation(contextual = true, kind = Kind.QUERY) - public static String digestOf(EObject model) { - return ModelDigest.of(model); - } - - /** - * The digest of a text, over its canonical JSON: a string as a JSON string, so an Asset's - * content-hashed name is the one the production implementation gives it. - */ - @Operation(contextual = true, kind = Kind.QUERY) - public static String textDigestOf(String text) { - return ModelDigest.ofText(text); - } - - /** The digest of a text exactly as written: its UTF-8 bytes, for a JSON text already canonical. */ - @Operation(contextual = true, kind = Kind.QUERY) - public static String rawDigestOf(String text) { - return ModelDigest.ofBytes(text); - } -} diff --git a/emf/bundles/resolve/src/main/java/dev/jorisjonkers/deploykit/emf/resolve/Lowering.java b/emf/bundles/resolve/src/main/java/dev/jorisjonkers/deploykit/emf/resolve/Lowering.java deleted file mode 100644 index 5f7c0ca13..000000000 --- a/emf/bundles/resolve/src/main/java/dev/jorisjonkers/deploykit/emf/resolve/Lowering.java +++ /dev/null @@ -1,47 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.resolve; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EffectiveProject; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import java.util.Collections; -import org.eclipse.emf.common.util.URI; -import org.eclipse.m2m.qvt.oml.BasicModelExtent; -import org.eclipse.m2m.qvt.oml.ExecutionContextImpl; -import org.eclipse.m2m.qvt.oml.TransformationExecutor; - -/** - * The lowering, {@code lower.qvto}, run on one Project: Project Intent in, the Effective Intent out - * (spec/v1/10-project-intent.md#the-effective-intent). The transformation is carried beside this - * class, so a caller needs no path on the machine that runs it. - * - *

It is loaded once per JVM, on the first call, and every call after it reuses it with an execution - * context and model extents of its own: loading is most of what a lowering costs - * (emf/docs/benchmarks.md). Calls are sequential; nothing in this implementation lowers on two threads. - */ -public final class Lowering { - - private static final String TRANSFORMATION = "/lower.qvto"; - - private Lowering() {} - - /** The loaded transformation, made on first use. */ - private static final class Loaded { - static final TransformationExecutor EXECUTOR = load(); - - private static TransformationExecutor load() { - ProjectIntentPackage.eINSTANCE.getName(); - return new TransformationExecutor( - URI.createURI(Lowering.class.getResource(TRANSFORMATION).toString())); - } - } - - /** {@code project}, lowered; the source is left as it was. */ - public static EffectiveProject lower(Project project) { - BasicModelExtent source = new BasicModelExtent(Collections.singletonList(project)); - BasicModelExtent target = new BasicModelExtent(); - Loaded.EXECUTOR.execute(new ExecutionContextImpl(), source, target); - // Every refusal the lowering depends on fires before it, so a run that writes no Effective - // Intent is a defect, and it fails here rather than handing on an empty model. - return (EffectiveProject) target.getContents().get(0); - } -} diff --git a/emf/bundles/resolve/src/main/java/dev/jorisjonkers/deploykit/emf/resolve/Resolution.java b/emf/bundles/resolve/src/main/java/dev/jorisjonkers/deploykit/emf/resolve/Resolution.java deleted file mode 100644 index 0c9c73bea..000000000 --- a/emf/bundles/resolve/src/main/java/dev/jorisjonkers/deploykit/emf/resolve/Resolution.java +++ /dev/null @@ -1,84 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.resolve; - -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.PinnedInputsPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeploymentPackage; -import java.util.ArrayList; -import java.util.List; -import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EcorePackage; -import org.eclipse.m2m.qvt.oml.BasicModelExtent; -import org.eclipse.m2m.qvt.oml.ExecutionContextImpl; -import org.eclipse.m2m.qvt.oml.ExecutionDiagnostic; -import org.eclipse.m2m.qvt.oml.TransformationExecutor; - -/** - * The resolution, {@code resolution.qvto}, run on one project of a lowered union: the Effective Intent - * of every project and the Platform document in, the pinned inputs beside them, and that project's - * Resolved Deployment out (spec/v1/20-resolved-deployment.md). The transformation is carried beside - * this class, as the lowering's is. - */ -public final class Resolution { - - private static final String TRANSFORMATION = "/resolution.qvto"; - - private Resolution() {} - - /** - * The loaded transformation, made on first use, with the blackbox it imports registered first. A - * load stays reachable for the life of the JVM, so one load serves every call - * (emf/docs/benchmarks.md). Each call still gets an execution context and model extents of its - * own, and calls are sequential. - */ - private static final class Loaded { - static final TransformationExecutor EXECUTOR = load(); - - private static TransformationExecutor load() { - ProjectIntentPackage.eINSTANCE.getName(); - PinnedInputsPackage.eINSTANCE.getName(); - ResolvedDeploymentPackage.eINSTANCE.getName(); - TransformationExecutor.BlackboxRegistry.INSTANCE.registerModule( - Hashing.class, - // `resolve` is a keyword of the language, so the unit is not named for this package. - Hashing.UNIT, - Hashing.class.getSimpleName(), - new String[] {EcorePackage.eNS_URI, ResolvedDeploymentPackage.eNS_URI}); - return new TransformationExecutor( - URI.createURI(Resolution.class.getResource(TRANSFORMATION).toString())); - } - } - - /** - * {@code project} of {@code intent}, resolved against {@code pinned}, recording {@code - * schemaPackageIntegrity} in its provenance. A run the transformation stops is a derivation this - * implementation does not reach yet, and it fails with what the transformation said. - */ - public static ResolvedDeployment resolve( - List intent, List pinned, String project, String schemaPackageIntegrity) { - ExecutionContextImpl context = new ExecutionContextImpl(); - context.setConfigProperty("project", project); - context.setConfigProperty("integrity", schemaPackageIntegrity); - BasicModelExtent target = new BasicModelExtent(); - ExecutionDiagnostic run = Loaded.EXECUTOR.execute( - context, - // An extent asks its list whether it holds a null, which an immutable list refuses to answer. - new BasicModelExtent(new ArrayList<>(intent)), - new BasicModelExtent(new ArrayList<>(pinned)), - target); - if (run.getSeverity() != Diagnostic.OK || target.getContents().isEmpty()) { - throw new IllegalStateException(failure(project, run)); - } - return (ResolvedDeployment) target.getContents().get(0); - } - - /** Why {@code project} did not resolve: the run, then each of its children on a line of its own. */ - static String failure(String project, Diagnostic run) { - // A transformation that does not compile says why only in its children. - StringBuilder why = new StringBuilder(project + " did not resolve: " + run); - run.getChildren().forEach(child -> why.append("\n ").append(child.getMessage())); - return why.toString(); - } -} diff --git a/emf/bundles/resolve/src/test/java/dev/jorisjonkers/deploykit/emf/resolve/LoweringTest.java b/emf/bundles/resolve/src/test/java/dev/jorisjonkers/deploykit/emf/resolve/LoweringTest.java deleted file mode 100644 index bf31704ba..000000000 --- a/emf/bundles/resolve/src/test/java/dev/jorisjonkers/deploykit/emf/resolve/LoweringTest.java +++ /dev/null @@ -1,255 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.resolve; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.groups.Tuple.tuple; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Credentials; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Cutover; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.DependencyEdge; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EffectiveApplication; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EffectiveProject; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EnvFile; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EnvLiteral; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EnvVariable; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.KvGrant; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Lifecycle; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ManagedMigration; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Placement; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.PlainKey; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.PlainPath; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Process; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Rotation; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Tolerance; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.WritablePathDeclaration; -import java.util.List; -import org.junit.jupiter.api.Test; - -/** - * REQ-036: Shared Intent declared at the Project or an Application reaches every Process below it, - * lists extend each other, and the lowest declaration of one thing holds - * (spec/v1/10-project-intent.md#the-effective-intent). - */ -class LoweringTest { - - private static final ProjectIntentFactory MODEL = ProjectIntentFactory.eINSTANCE; - - /** One declaration of each shape the merge has to get right. */ - private static Project source() { - Project project = MODEL.createProject(); - project.setApiVersion("intent.jorisjonkers.dev/v1"); - project.setKind("Project"); - project.setSchemaVersion("1.0.0"); - project.setProject("refusals"); - project.setOwner("joris"); - project.getSecrets().add(grant("secret/data/refusals/estate-ca")); - project.getWritablePaths().add(path("/tmp")); - project.setPlacement(dimensions("enschede")); - - Application application = MODEL.createApplication(); - application.setId("shared-intent-merged"); - application.getSecrets().add(grant("secret/data/refusals/queue")); - application.setCutover(Cutover.INTERRUPTED); - - Process api = process("shared-intent-merged-api", "128Mi", "25m"); - api.getSecrets().add(grant("secret/data/refusals/bearer")); - api.getWritablePaths().add(path("/var/cache/api")); - - Process worker = process("shared-intent-merged-worker", "64Mi", "10m"); - worker.getPlacement().setSite("frankfurt"); - - application.getProcesses().add(api); - application.getProcesses().add(worker); - project.getApplications().add(application); - return project; - } - - private static KvGrant grant(String path) { - KvGrant grant = MODEL.createKvGrant(); - grant.setPath(path); - PlainKey key = MODEL.createPlainKey(); - key.setName("token"); - grant.getKeys().add(key); - return grant; - } - - private static PlainPath path(String written) { - PlainPath path = MODEL.createPlainPath(); - path.setPath(written); - return path; - } - - private static Placement dimensions(String site) { - Placement placement = MODEL.createPlacement(); - placement.setSite(site); - return placement; - } - - private static Process process(String name, String memory, String cpu) { - Process process = MODEL.createProcess(); - process.setName(name); - process.setLifecycle(Lifecycle.APPLICATION); - process.setImage(name); - Placement placement = MODEL.createPlacement(); - placement.setMemory(memory); - placement.setCpu(cpu); - process.setPlacement(placement); - return process; - } - - private static EffectiveProject lower(Project project) { - return Lowering.lower(project); - } - - private static Process lowered(EffectiveProject project, String name) { - EffectiveApplication application = project.getApplications().get(0); - return application.getProcesses().stream() - .filter(process -> name.equals(process.getName())) - .findFirst() - .orElseThrow(); - } - - private static List paths(Process process) { - return process.getSecrets().stream() - .map(KvGrant.class::cast) - .map(KvGrant::getPath) - .sorted() - .toList(); - } - - @Test - void everyProcessHoldsTheGrantsOfEveryLevelAboveItExtendedByItsOwn() { - EffectiveProject lowered = lower(source()); - - assertThat(paths(lowered(lowered, "shared-intent-merged-api"))) - .containsExactly( - "secret/data/refusals/bearer", "secret/data/refusals/estate-ca", "secret/data/refusals/queue"); - // A sibling holds fewer, so the lists extend rather than have to match. - assertThat(paths(lowered(lowered, "shared-intent-merged-worker"))) - .containsExactly("secret/data/refusals/estate-ca", "secret/data/refusals/queue"); - } - - @Test - void eachNodeDimensionComesFromTheLowestLevelThatSetItAndTheQuantitiesFromTheProcess() { - EffectiveProject lowered = lower(source()); - - Placement api = lowered(lowered, "shared-intent-merged-api").getPlacement(); - assertThat(api.getMemory()).isEqualTo("128Mi"); - assertThat(api.getSite()).isEqualTo("enschede"); - // The Process replaces `site`: each key merges on its own. - Placement worker = lowered(lowered, "shared-intent-merged-worker").getPlacement(); - assertThat(worker.getMemory()).isEqualTo("64Mi"); - assertThat(worker.getSite()).isEqualTo("frankfurt"); - } - - @Test - void theMigrationStaysOnTheApplicationAndAnEdgeKeepsItsCredentials() { - Project project = source(); - Application application = project.getApplications().get(0); - ManagedMigration migration = MODEL.createManagedMigration(); - migration.setChangelog("db/changelog.yml"); - application.setMigration(migration); - DependencyEdge edge = MODEL.createDependencyEdge(); - edge.setApplication("platform-postgres"); - edge.setSurface("postgres"); - Credentials credentials = MODEL.createCredentials(); - Rotation rotation = MODEL.createRotation(); - rotation.setTolerates(Tolerance.RESTART); - credentials.setRotation(rotation); - edge.setCredentials(credentials); - application.getProcesses().get(0).getDependsOn().add(edge); - - EffectiveApplication lowered = lower(project).getApplications().get(0); - - assertThat(((ManagedMigration) lowered.getMigration()).getChangelog()).isEqualTo("db/changelog.yml"); - assertThat(lowered.getProcesses().get(0).getDependsOn()) - .singleElement() - .satisfies( - copy -> assertThat(copy.getCredentials().getRotation().getTolerates()) - .isEqualTo(Tolerance.RESTART)); - } - - @Test - void theCutoverQuestionIsAnsweredOnceForTheReleaseUnitThatSwitchesTogether() { - EffectiveProject lowered = lower(source()); - - assertThat(lowered.getApplications().get(0).getProcesses()) - .allSatisfy(process -> assertThat(process.getCutover()).isEqualTo(Cutover.INTERRUPTED)); - } - - @Test - void aPrepareProcessTakesNoSharedCutoverBecauseItCutsOverNothing() { - Project project = source(); - Process seed = process("seed", "64Mi", "10m"); - seed.setLifecycle(Lifecycle.PREPARE); - project.getApplications().get(0).getProcesses().add(seed); - - EffectiveProject lowered = lower(project); - - assertThat(lowered.getApplications().get(0).getProcesses()) - .extracting(Process::getName, Process::getCutover) - .containsExactly( - tuple("shared-intent-merged-api", Cutover.INTERRUPTED), - tuple("shared-intent-merged-worker", Cutover.INTERRUPTED), - tuple("seed", Cutover.ABSENT)); - } - - @Test - void theWritablePathsExtendAndTheLoweredLevelsHoldOnlyWhatDefinesThem() { - EffectiveProject lowered = lower(source()); - - assertThat(lowered(lowered, "shared-intent-merged-api").getWritablePaths()) - .extracting(WritablePathDeclaration::getPath) - .containsExactly("/var/cache/api", "/tmp"); - assertThat(lowered(lowered, "shared-intent-merged-worker").getWritablePaths()) - .extracting(WritablePathDeclaration::getPath) - .containsExactly("/tmp"); - // No SharedIntent at all, which is what makes the wrong level unreadable. - assertThat(ProjectIntentPackage.eINSTANCE.getEffectiveApplication().getEAllStructuralFeatures()) - .extracting(feature -> feature.getName()) - .containsExactlyInAnyOrder( - "id", - "description", - "client", - "l4Exposure", - "dashboards", - "alertRules", - "migration", - "observability", - "exposure", - "processes"); - } - - @Test - void leavesTheDocumentHeaderBehind() { - assertThat(ProjectIntentPackage.eINSTANCE.getEffectiveProject().getEAllStructuralFeatures()) - .extracting(feature -> feature.getName()) - .containsExactly("project", "owner", "applications"); - assertThat(lower(source()).getProject()).isEqualTo("refusals"); - } - - @Test - void anEnvVariableKeepsItsValueOnTheProcessItReaches() { - Project project = source(); - EnvFile file = MODEL.createEnvFile(); - EnvVariable variable = MODEL.createEnvVariable(); - variable.setName("NODE_ENV"); - EnvLiteral literal = MODEL.createEnvLiteral(); - literal.setText("production"); - variable.setValue(literal); - file.getEntries().add(variable); - project.getEnv().add(file); - - Process api = lowered(lower(project), "shared-intent-merged-api"); - - assertThat(api.getEnv()).singleElement().satisfies(lowered -> { - assertThat(lowered.getEntries()).singleElement().satisfies(entry -> { - assertThat(entry.getName()).isEqualTo("NODE_ENV"); - assertThat(((EnvLiteral) entry.getValue()).getText()).isEqualTo("production"); - }); - }); - } -} diff --git a/emf/bundles/resolve/src/test/java/dev/jorisjonkers/deploykit/emf/resolve/ResolutionTest.java b/emf/bundles/resolve/src/test/java/dev/jorisjonkers/deploykit/emf/resolve/ResolutionTest.java deleted file mode 100644 index ca4e404f2..000000000 --- a/emf/bundles/resolve/src/test/java/dev/jorisjonkers/deploykit/emf/resolve/ResolutionTest.java +++ /dev/null @@ -1,216 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.resolve; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.AssetFile; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.ClusterState; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.ImagesLock; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.LockedImage; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.Node; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.NodeContract; -import dev.jorisjonkers.deploykit.emf.metamodel.pinnedinputs.PinnedInputsFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Asset; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.DependencyEdge; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EffectiveApplication; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.EffectiveProject; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.HardeningClass; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Lifecycle; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Process; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentFactory; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Runtime; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ReconcileUnit; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedApplication; -import dev.jorisjonkers.deploykit.emf.metamodel.resolveddeployment.ResolvedDeployment; -import java.util.List; -import org.eclipse.emf.common.util.BasicDiagnostic; -import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.emf.ecore.EObject; -import org.junit.jupiter.api.Test; - -/** - * The resolution run through its executor, on the smallest union it resolves: one project of one - * job, under a Platform document with one node to place it on. The worked examples are resolved - * through the pipeline, which reads them; this is the transformation's own seam. - */ -class ResolutionTest { - - private static final ProjectIntentFactory INTENT = ProjectIntentFactory.eINSTANCE; - private static final PinnedInputsFactory PINNED = PinnedInputsFactory.eINSTANCE; - private static final String INTEGRITY = "sha256:" + "5e".repeat(32); - - private static EffectiveProject project() { - Process worker = INTENT.createProcess(); - worker.setName("worker"); - worker.setLifecycle(Lifecycle.JOB); - worker.setImage("worker"); - worker.setRuntime(Runtime.NONE); - worker.setPlacement(INTENT.createPlacement()); - worker.getPlacement().setMemory("64Mi"); - worker.getPlacement().setCpu("10m"); - Asset settings = INTENT.createAsset(); - settings.setFrom("config/worker.conf"); - settings.setMountAt("/etc/worker.conf"); - worker.getAssets().add(settings); - EffectiveApplication application = INTENT.createEffectiveApplication(); - application.setId("batch"); - application.getProcesses().add(worker); - EffectiveProject project = INTENT.createEffectiveProject(); - project.setProject("jobs"); - project.setOwner("joris"); - project.getApplications().add(application); - return project; - } - - private static Platform platform() { - Platform platform = INTENT.createPlatform(); - platform.setMetadata(INTENT.createPlatformMetadata()); - platform.getMetadata().setCluster("production"); - platform.getMetadata().setProject("jorisjonkers.dev"); - platform.setSubstrate(INTENT.createSubstrate()); - platform.getSubstrate().setClusterDns("kube-system"); - platform.setHardening(HardeningClass.RESTRICTED); - return platform; - } - - private static List pinned() { - NodeContract contract = PINNED.createNodeContract(); - contract.setCluster("production"); - Node node = PINNED.createNode(); - node.setName("enschede-pi-1"); - node.setArch("arm64"); - node.setAllocatable(PINNED.createAllocatable()); - node.getAllocatable().setMemory("1Gi"); - node.getAllocatable().setCpu("2"); - contract.getNodes().add(node); - ImagesLock lock = PINNED.createImagesLock(); - lock.setName("estate"); - LockedImage image = PINNED.createLockedImage(); - image.setAlias("worker"); - image.setRepository("ghcr.io/jorisjonkers-dev/jobs/worker"); - image.setDigest("sha256:" + "ab".repeat(32)); - image.setUid(1000); - image.setGid(1000); - image.setVersion("1.0.0"); - lock.getImages().add(image); - ClusterState snapshot = PINNED.createClusterState(); - snapshot.setCluster("production"); - AssetFile settings = PINNED.createAssetFile(); - settings.setProject("jobs"); - settings.setFrom("config/worker.conf"); - settings.setContent("threads = 4\n"); - return List.of(contract, lock, snapshot, settings); - } - - @Test - void theSmallestUnionResolvesToADeploymentWhoseApplicationRecordsItsOwnRevision() { - ResolvedDeployment deployment = Resolution.resolve(List.of(project(), platform()), pinned(), "jobs", INTEGRITY); - - ResolvedApplication batch = deployment.getApplications().get(0); - assertThat(batch.getNamespace()).isEqualTo("jobs-system"); - assertThat(batch.getProcesses().get(0).getImage()) - .isEqualTo("ghcr.io/jorisjonkers-dev/jobs/worker@sha256:" + "ab".repeat(32)); - assertThat(batch.getProcesses().get(0).getPlacement().getEligibleNodes()) - .containsExactly("enschede-pi-1"); - // An Asset is named for its Process, its file and the first digits of its content's digest. - assertThat(batch.getProcesses().get(0).getAssets().get(0).getName()).matches("worker-worker-conf-[0-9a-f]{10}"); - // The one black box: the revision is the digest of the element, the provenance of its inputs. - assertThat(batch.getRevision()).matches("sha256:[0-9a-f]{64}"); - assertThat(deployment.getProvenance().getRenderHash()).startsWith("sha256:"); - assertThat(deployment.getProvenance().getSchemaPackageIntegrity()).isEqualTo(INTEGRITY); - } - - /** A second project, `observability`, whose `observer` serves `http`. */ - private static EffectiveProject observability() { - Process observer = INTENT.createProcess(); - observer.setName("observer"); - observer.setLifecycle(Lifecycle.JOB); - observer.setImage("worker"); - observer.setRuntime(Runtime.NONE); - observer.setPlacement(INTENT.createPlacement()); - observer.getPlacement().setMemory("64Mi"); - observer.getPlacement().setCpu("10m"); - observer.getProvides().put("http", 8080); - EffectiveApplication application = INTENT.createEffectiveApplication(); - application.setId("observer"); - application.getProcesses().add(observer); - EffectiveProject project = INTENT.createEffectiveProject(); - project.setProject("observability"); - project.setOwner("joris"); - project.getApplications().add(application); - return project; - } - - /** The jobs project with its worker's one edge to the observer, required or not. */ - private static EffectiveProject reaching(Boolean required) { - EffectiveProject project = project(); - DependencyEdge edge = INTENT.createDependencyEdge(); - edge.setApplication("observer"); - edge.setSurface("http"); - edge.setRequired(required); - project.getApplications().get(0).getProcesses().get(0).getDependsOn().add(edge); - return project; - } - - private static List unitsFollowed(EffectiveProject project) { - ResolvedDeployment deployment = - Resolution.resolve(List.of(project, observability(), platform()), pinned(), "jobs", INTEGRITY); - return deployment.getReconcileUnits().get(0).getAfter().stream() - .map(ReconcileUnit::getName) - .toList(); - } - - @Test - void aUnitFollowsAnotherProjectOnlyThroughARequiredEdge() { - // An optional edge orders nothing (spec/v1/55-delivery.md#release-order), so two projects - // naming each other optionally never wait on each other. - assertThat(unitsFollowed(reaching(false))).isEmpty(); - assertThat(unitsFollowed(reaching(true))).containsExactly("apps-observability"); - } - - @Test - void aProjectTheUnionDoesNotHoldResolvesToNothingAndSaysSo() { - assertThatThrownBy(() -> Resolution.resolve(List.of(project(), platform()), pinned(), "absent", INTEGRITY)) - .isInstanceOf(IllegalStateException.class) - .hasMessageStartingWith("absent did not resolve"); - } - - @Test - void aLockEntryThatRecordsNoVersionRefusesTheSetByItsAlias() { - List pinned = pinned(); - ((ImagesLock) pinned.get(1)).getImages().get(0).setVersion(null); - - assertThatThrownBy(() -> Resolution.resolve(List.of(project(), platform()), pinned, "jobs", INTEGRITY)) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("worker records no version: E_IMAGE_VERSION_MISSING"); - } - - @Test - void aDerivationTheInputsCannotCompleteStopsTheRunWithWhatIsMissing() { - // The Asset names a file no pinned input carries, so its content and name cannot be derived. - EffectiveProject project = project(); - project.getApplications() - .get(0) - .getProcesses() - .get(0) - .getAssets() - .get(0) - .setFrom("config/absent.conf"); - - assertThatThrownBy(() -> Resolution.resolve(List.of(project, platform()), pinned(), "jobs", INTEGRITY)) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("config/absent.conf: an Asset whose file is not beside its project"); - } - - @Test - void aRunThatFailsSaysWhyThroughEachOfItsChildren() { - // A transformation that does not compile reports only in its children, which no input can provoke. - BasicDiagnostic run = new BasicDiagnostic(Diagnostic.ERROR, "qvto", 0, "compilation failed", null); - run.add(new BasicDiagnostic(Diagnostic.ERROR, "qvto", 0, "unknown operation planned()", null)); - - assertThat(Resolution.failure("jobs", run)) - .startsWith("jobs did not resolve: ") - .endsWith("\n unknown operation planned()"); - } -} diff --git a/emf/bundles/syntax/META-INF/MANIFEST.MF b/emf/bundles/syntax/META-INF/MANIFEST.MF deleted file mode 100644 index 69e7c4e85..000000000 --- a/emf/bundles/syntax/META-INF/MANIFEST.MF +++ /dev/null @@ -1,26 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: deploy-kit model-driven syntax -Bundle-SymbolicName: dev.jorisjonkers.deploykit.emf.syntax;singleton:=true -Bundle-Version: 0.1.0.qualifier -Bundle-RequiredExecutionEnvironment: JavaSE-21 -Automatic-Module-Name: dev.jorisjonkers.deploykit.emf.syntax -Export-Package: dev.jorisjonkers.deploykit.emf.syntax, - dev.jorisjonkers.deploykit.emf.syntax.blocks, - dev.jorisjonkers.deploykit.emf.syntax.linking, - dev.jorisjonkers.deploykit.emf.syntax.schema, - dev.jorisjonkers.deploykit.emf.syntax.values, - dev.jorisjonkers.deploykit.emf.syntax.parser.antlr, - dev.jorisjonkers.deploykit.emf.syntax.services -Require-Bundle: dev.jorisjonkers.deploykit.emf.metamodel, - org.eclipse.xtext, - org.eclipse.xtext.util, - org.eclipse.xtext.xbase.lib, - org.eclipse.emf.ecore, - org.eclipse.emf.common, - org.antlr.runtime;bundle-version="[3.2.0,3.2.1)", - org.eclipse.xtext.xtext.generator, - org.eclipse.emf.mwe2.launch, - org.eclipse.emf.mwe.core, - org.eclipse.emf.mwe.utils, - org.eclipse.emf.mwe2.lib diff --git a/emf/bundles/syntax/build.properties b/emf/bundles/syntax/build.properties deleted file mode 100644 index 93a361e6f..000000000 --- a/emf/bundles/syntax/build.properties +++ /dev/null @@ -1,4 +0,0 @@ -source.. = src/main/java/,\ - target/generated-sources/xtext/ -bin.includes = META-INF/,\ - . diff --git a/emf/bundles/syntax/pom.xml b/emf/bundles/syntax/pom.xml deleted file mode 100644 index be19a78e5..000000000 --- a/emf/bundles/syntax/pom.xml +++ /dev/null @@ -1,164 +0,0 @@ - - - 4.0.0 - - - dev.jorisjonkers.deploykit.emf - emf-parent - 0.1.0-SNAPSHOT - ../../pom.xml - - - dev.jorisjonkers.deploykit.emf.syntax - eclipse-plugin - deploy-kit model-driven syntax - - - - - - org.jacoco - jacoco-maven-plugin - - - prepare-agent - - - dev.jorisjonkers.deploykit.emf.syntax.ProjectIntent* - dev.jorisjonkers.deploykit.emf.syntax.AbstractProjectIntent* - dev.jorisjonkers.deploykit.emf.syntax.PlatformIntent* - dev.jorisjonkers.deploykit.emf.syntax.AbstractPlatformIntent* - dev.jorisjonkers.deploykit.emf.syntax.MigrationProof* - dev.jorisjonkers.deploykit.emf.syntax.AbstractMigrationProof* - dev.jorisjonkers.deploykit.emf.syntax.ClusterState* - dev.jorisjonkers.deploykit.emf.syntax.AbstractClusterState* - dev.jorisjonkers.deploykit.emf.syntax.ImagesLock* - dev.jorisjonkers.deploykit.emf.syntax.AbstractImagesLock* - dev.jorisjonkers.deploykit.emf.syntax.NodeContract* - dev.jorisjonkers.deploykit.emf.syntax.AbstractNodeContract* - dev.jorisjonkers.deploykit.emf.syntax.parser.* - dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.* - dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.internal.* - dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.lexer.* - dev.jorisjonkers.deploykit.emf.syntax.serializer.* - dev.jorisjonkers.deploykit.emf.syntax.services.* - dev.jorisjonkers.deploykit.emf.syntax.scoping.* - dev.jorisjonkers.deploykit.emf.syntax.validation.* - - - - - report - - - dev/jorisjonkers/deploykit/emf/syntax/ProjectIntent*.class - dev/jorisjonkers/deploykit/emf/syntax/AbstractProjectIntent*.class - dev/jorisjonkers/deploykit/emf/syntax/PlatformIntent*.class - dev/jorisjonkers/deploykit/emf/syntax/AbstractPlatformIntent*.class - dev/jorisjonkers/deploykit/emf/syntax/MigrationProof*.class - dev/jorisjonkers/deploykit/emf/syntax/AbstractMigrationProof*.class - dev/jorisjonkers/deploykit/emf/syntax/ClusterState*.class - dev/jorisjonkers/deploykit/emf/syntax/AbstractClusterState*.class - dev/jorisjonkers/deploykit/emf/syntax/ImagesLock*.class - dev/jorisjonkers/deploykit/emf/syntax/AbstractImagesLock*.class - dev/jorisjonkers/deploykit/emf/syntax/NodeContract*.class - dev/jorisjonkers/deploykit/emf/syntax/AbstractNodeContract*.class - dev/jorisjonkers/deploykit/emf/syntax/parser/** - dev/jorisjonkers/deploykit/emf/syntax/serializer/** - dev/jorisjonkers/deploykit/emf/syntax/services/** - dev/jorisjonkers/deploykit/emf/syntax/scoping/** - dev/jorisjonkers/deploykit/emf/syntax/validation/** - - - - - coverage-floor - - - dev/jorisjonkers/deploykit/emf/syntax/ProjectIntent*.class - dev/jorisjonkers/deploykit/emf/syntax/AbstractProjectIntent*.class - dev/jorisjonkers/deploykit/emf/syntax/PlatformIntent*.class - dev/jorisjonkers/deploykit/emf/syntax/AbstractPlatformIntent*.class - dev/jorisjonkers/deploykit/emf/syntax/MigrationProof*.class - dev/jorisjonkers/deploykit/emf/syntax/AbstractMigrationProof*.class - dev/jorisjonkers/deploykit/emf/syntax/ClusterState*.class - dev/jorisjonkers/deploykit/emf/syntax/AbstractClusterState*.class - dev/jorisjonkers/deploykit/emf/syntax/ImagesLock*.class - dev/jorisjonkers/deploykit/emf/syntax/AbstractImagesLock*.class - dev/jorisjonkers/deploykit/emf/syntax/NodeContract*.class - dev/jorisjonkers/deploykit/emf/syntax/AbstractNodeContract*.class - dev/jorisjonkers/deploykit/emf/syntax/parser/** - dev/jorisjonkers/deploykit/emf/syntax/serializer/** - dev/jorisjonkers/deploykit/emf/syntax/services/** - dev/jorisjonkers/deploykit/emf/syntax/scoping/** - dev/jorisjonkers/deploykit/emf/syntax/validation/** - - - - - - - org.pitest - pitest-maven - - - dev.jorisjonkers.deploykit.emf.syntax.*ProjectIntent* - dev.jorisjonkers.deploykit.emf.syntax.*PlatformIntent* - dev.jorisjonkers.deploykit.emf.syntax.*MigrationProof* - dev.jorisjonkers.deploykit.emf.syntax.*ClusterState* - dev.jorisjonkers.deploykit.emf.syntax.*ImagesLock* - dev.jorisjonkers.deploykit.emf.syntax.*NodeContract* - dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.lexer.* - dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.internal.* - dev.jorisjonkers.deploykit.emf.syntax.parser.* - dev.jorisjonkers.deploykit.emf.syntax.serializer.* - dev.jorisjonkers.deploykit.emf.syntax.services.* - dev.jorisjonkers.deploykit.emf.syntax.scoping.* - dev.jorisjonkers.deploykit.emf.syntax.validation.* - - - - - - org.codehaus.mojo - exec-maven-plugin - - - generate-language - generate-sources - java - - - - org.eclipse.emf.mwe2.launch.runtime.Mwe2Launcher - - /${project.basedir}/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateProjectIntent.mwe2 - -p - rootPath=/${project.basedir}/.. - - compile - true - false - - ${project.basedir}/src/main/java - - - - - - org.eclipse.xtext - xtext-antlr-generator - 2.1.1 - - - - - - diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ClusterState.xtext b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ClusterState.xtext deleted file mode 100644 index aa8ba0329..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ClusterState.xtext +++ /dev/null @@ -1,34 +0,0 @@ -grammar dev.jorisjonkers.deploykit.emf.syntax.ClusterState with dev.jorisjonkers.deploykit.emf.syntax.ProjectIntent - hidden(WS, SL_COMMENT) - -import "https://jorisjonkers.dev/deploy-kit/pinned-inputs/1" -import "http://www.eclipse.org/emf/2002/Ecore" as ecore - -// The ClusterState snapshot, in the YAML subset the project language reads: -// its terminals, its block tokens and its scalars are inherited, as the -// Platform document's are. An empty list is an empty block. - -ClusterState returns ClusterState: - (('apiVersion' ':' apiVersion=Text) - & ('kind' ':' kind=Text) - & ('schemaVersion' ':' schemaVersion=Text) - & ('cluster' ':' cluster=Text) - & ('capturedAt' ':' capturedAt=Text) - & ('bindings' ':' BEGIN (DASH BEGIN bindings+=Binding END)* END) - & ('placements' ':' BEGIN (DASH BEGIN placements+=CurrentPlacement END)* END)); - -Binding returns Binding: - (('claim' ':' claim=Text) - & ('node' ':' node=Text)); - -CurrentPlacement returns CurrentPlacement: - (('process' ':' process=Text) - & ('node' ':' node=Text)); - -// Every keyword this document adds is also a scalar, as the project language's are. -@Override -Text returns ecore::EString: - SCALAR | STRING | INT | Keyword | ClusterStateKeyword; - -ClusterStateKeyword: - 'bindings' | 'capturedAt' | 'placements'; diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ClusterStateRuntimeModule.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ClusterStateRuntimeModule.java deleted file mode 100644 index 5597decfb..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ClusterStateRuntimeModule.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * generated by Xtext, then owned here: the value converters are the project language's. - */ -package dev.jorisjonkers.deploykit.emf.syntax; - -import dev.jorisjonkers.deploykit.emf.syntax.values.ProjectIntentValueConverters; -import org.eclipse.xtext.conversion.IValueConverterService; - -/** Registers the components the ClusterState snapshot language runs with: the project language's own, reused. */ -public class ClusterStateRuntimeModule extends AbstractClusterStateRuntimeModule { - - /** Quotes are syntax: see {@link ProjectIntentValueConverters}. */ - @Override - public Class bindIValueConverterService() { - return ProjectIntentValueConverters.class; - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ClusterStateStandaloneSetup.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ClusterStateStandaloneSetup.java deleted file mode 100644 index e17be61ff..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ClusterStateStandaloneSetup.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * generated by Xtext - */ -package dev.jorisjonkers.deploykit.emf.syntax; - -/** - * Initialization support for running Xtext languages without Equinox extension registry. - */ -public class ClusterStateStandaloneSetup extends ClusterStateStandaloneSetupGenerated { - - public static void doSetup() { - new ClusterStateStandaloneSetup().createInjectorAndDoEMFRegistration(); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateProjectIntent.mwe2 b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateProjectIntent.mwe2 deleted file mode 100644 index 93b9bb3f8..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/GenerateProjectIntent.mwe2 +++ /dev/null @@ -1,115 +0,0 @@ -module dev.jorisjonkers.deploykit.emf.syntax.GenerateProjectIntent - -import org.eclipse.emf.mwe.utils.* -import org.eclipse.xtext.xtext.generator.* -import org.eclipse.xtext.xtext.generator.model.project.* - -var rootPath = ".." -var generated = "${rootPath}/syntax/target/generated-sources/xtext" - -// Every generated file lands under target/ except the stubs the generator -// writes once per language and this tree then owns: the runtime module, the -// standalone setup and the token source, in src/main/java (emf/docs/architecture.md#concrete-syntax). -Workflow { - bean = StandaloneSetup { - scanClassPath = true - projectMapping = { - projectName = "dev.jorisjonkers.deploykit.emf.metamodel" - path = "${rootPath}/metamodel" - } - projectMapping = { projectName = "syntax" path = "${rootPath}/syntax" } - } - component = XtextGenerator { - configuration = { - project = StandardProjectConfig { - baseName = "syntax" - rootPath = rootPath - runtime = { - root = "${rootPath}/syntax" - src = "${rootPath}/syntax/src/main/java" - srcGen = generated - ecoreModel = "${generated}-model" - } - runtimeTest = { enabled = false } - eclipsePlugin = { enabled = false } - createEclipseMetaData = false - } - code = { - encoding = "UTF-8" - lineDelimiter = "\n" - preferXtendStubs = false - } - } - language = StandardLanguage { - name = "dev.jorisjonkers.deploykit.emf.syntax.ProjectIntent" - grammarUri = "classpath:/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntent.xtext" - fileExtensions = "yml" - referencedResource = "platform:/resource/dev.jorisjonkers.deploykit.emf.metamodel/model/project-intent.genmodel" - serializer = { generateStub = false } - validator = { generateStub = false } - scopeProvider = { generateStub = false } - generator = { generateStub = false } - } - // The Platform document inherits the project language's terminals and - // block tokens, and adds only its own rules. - language = StandardLanguage { - name = "dev.jorisjonkers.deploykit.emf.syntax.PlatformIntent" - grammarUri = "classpath:/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntent.xtext" - fileExtensions = "yml" - referencedResource = "platform:/resource/dev.jorisjonkers.deploykit.emf.metamodel/model/project-intent.genmodel" - // Both languages' keywords make a lexer whose state table outgrows one Java method. - parserGenerator = { options = { classSplitting = true } } - serializer = { generateStub = false } - validator = { generateStub = false } - scopeProvider = { generateStub = false } - generator = { generateStub = false } - } - // The pinned inputs resolution reads inherit the same terminals and block - // tokens; their classes are the pinned-inputs metamodel's (issue #90). - language = StandardLanguage { - name = "dev.jorisjonkers.deploykit.emf.syntax.NodeContract" - grammarUri = "classpath:/dev/jorisjonkers/deploykit/emf/syntax/NodeContract.xtext" - fileExtensions = "yml" - referencedResource = "platform:/resource/dev.jorisjonkers.deploykit.emf.metamodel/model/project-intent.genmodel" - referencedResource = "platform:/resource/dev.jorisjonkers.deploykit.emf.metamodel/model/pinned-inputs.genmodel" - serializer = { generateStub = false } - validator = { generateStub = false } - scopeProvider = { generateStub = false } - generator = { generateStub = false } - } - language = StandardLanguage { - name = "dev.jorisjonkers.deploykit.emf.syntax.ImagesLock" - grammarUri = "classpath:/dev/jorisjonkers/deploykit/emf/syntax/ImagesLock.xtext" - fileExtensions = "yml" - referencedResource = "platform:/resource/dev.jorisjonkers.deploykit.emf.metamodel/model/project-intent.genmodel" - referencedResource = "platform:/resource/dev.jorisjonkers.deploykit.emf.metamodel/model/pinned-inputs.genmodel" - serializer = { generateStub = false } - validator = { generateStub = false } - scopeProvider = { generateStub = false } - generator = { generateStub = false } - } - language = StandardLanguage { - name = "dev.jorisjonkers.deploykit.emf.syntax.ClusterState" - grammarUri = "classpath:/dev/jorisjonkers/deploykit/emf/syntax/ClusterState.xtext" - fileExtensions = "yml" - referencedResource = "platform:/resource/dev.jorisjonkers.deploykit.emf.metamodel/model/project-intent.genmodel" - referencedResource = "platform:/resource/dev.jorisjonkers.deploykit.emf.metamodel/model/pinned-inputs.genmodel" - serializer = { generateStub = false } - validator = { generateStub = false } - scopeProvider = { generateStub = false } - generator = { generateStub = false } - } - language = StandardLanguage { - name = "dev.jorisjonkers.deploykit.emf.syntax.MigrationProof" - grammarUri = "classpath:/dev/jorisjonkers/deploykit/emf/syntax/MigrationProof.xtext" - fileExtensions = "yml" - referencedResource = "platform:/resource/dev.jorisjonkers.deploykit.emf.metamodel/model/project-intent.genmodel" - referencedResource = "platform:/resource/dev.jorisjonkers.deploykit.emf.metamodel/model/pinned-inputs.genmodel" - serializer = { generateStub = false } - validator = { generateStub = false } - scopeProvider = { generateStub = false } - generator = { generateStub = false } - } - - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ImagesLock.xtext b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ImagesLock.xtext deleted file mode 100644 index 400d841d9..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ImagesLock.xtext +++ /dev/null @@ -1,34 +0,0 @@ -grammar dev.jorisjonkers.deploykit.emf.syntax.ImagesLock with dev.jorisjonkers.deploykit.emf.syntax.ProjectIntent - hidden(WS, SL_COMMENT) - -import "https://jorisjonkers.dev/deploy-kit/pinned-inputs/1" -import "http://www.eclipse.org/emf/2002/Ecore" as ecore - -// The images lock, in the YAML subset the project language reads. `images` is -// a mapping keyed by alias, so each entry is its key and the block below it. -// Every entry records its `version`, but one that does not still reads: resolution -// refuses it by its alias as E_IMAGE_VERSION_MISSING, not as a syntax error. - -ImagesLock returns ImagesLock: - (('apiVersion' ':' apiVersion=Text) - & ('kind' ':' kind=Text) - & ('schemaVersion' ':' schemaVersion=Text) - & ('name' ':' name=Text) - & ('images' ':' BEGIN images+=LockedImage* END)); - -LockedImage returns LockedImage: - alias=Text ':' BEGIN - (('repository' ':' repository=Text) - & ('digest' ':' digest=Text) - & ('uid' ':' uid=Port) - & ('gid' ':' gid=Port) - & ('version' ':' version=Text)?) - END; - -// Every keyword this document adds is also a scalar, as the project language's are. -@Override -Text returns ecore::EString: - SCALAR | STRING | INT | Keyword | ImagesLockKeyword; - -ImagesLockKeyword: - 'digest' | 'gid' | 'images' | 'repository' | 'uid' | 'version'; diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ImagesLockRuntimeModule.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ImagesLockRuntimeModule.java deleted file mode 100644 index 5ed081dcf..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ImagesLockRuntimeModule.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * generated by Xtext, then owned here: the value converters are the project language's. - */ -package dev.jorisjonkers.deploykit.emf.syntax; - -import dev.jorisjonkers.deploykit.emf.syntax.values.ProjectIntentValueConverters; -import org.eclipse.xtext.conversion.IValueConverterService; - -/** Registers the components the images lock language runs with: the project language's own, reused. */ -public class ImagesLockRuntimeModule extends AbstractImagesLockRuntimeModule { - - /** Quotes are syntax: see {@link ProjectIntentValueConverters}. */ - @Override - public Class bindIValueConverterService() { - return ProjectIntentValueConverters.class; - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ImagesLockStandaloneSetup.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ImagesLockStandaloneSetup.java deleted file mode 100644 index b0a9bfc6f..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ImagesLockStandaloneSetup.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * generated by Xtext - */ -package dev.jorisjonkers.deploykit.emf.syntax; - -/** - * Initialization support for running Xtext languages without Equinox extension registry. - */ -public class ImagesLockStandaloneSetup extends ImagesLockStandaloneSetupGenerated { - - public static void doSetup() { - new ImagesLockStandaloneSetup().createInjectorAndDoEMFRegistration(); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/MigrationProof.xtext b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/MigrationProof.xtext deleted file mode 100644 index 5f7000076..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/MigrationProof.xtext +++ /dev/null @@ -1,27 +0,0 @@ -grammar dev.jorisjonkers.deploykit.emf.syntax.MigrationProof with dev.jorisjonkers.deploykit.emf.syntax.ProjectIntent - hidden(WS, SL_COMMENT) - -import "https://jorisjonkers.dev/deploy-kit/pinned-inputs/1" -import "http://www.eclipse.org/emf/2002/Ecore" as ecore - -// The migration proof an Application's CI writes beside the project file, in the -// YAML subset the project language reads. - -MigrationProof returns MigrationProof: - (('apiVersion' ':' apiVersion=Text) - & ('kind' ':' kind=Text) - & ('schemaVersion' ':' schemaVersion=Text) - & ('applications' ':' BEGIN (DASH BEGIN applications+=ProvenApplication END)* END)); - -ProvenApplication returns ProvenApplication: - (('id' ':' id=Text) - & ('testedAgainst' ':' testedAgainst=Text)? - & ('nonTransactional' ':' nonTransactional=Bool)); - -// Every keyword this document adds is also a scalar, as the project language's are. -@Override -Text returns ecore::EString: - SCALAR | STRING | INT | Keyword | MigrationProofKeyword; - -MigrationProofKeyword: - 'nonTransactional' | 'testedAgainst'; diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/MigrationProofRuntimeModule.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/MigrationProofRuntimeModule.java deleted file mode 100644 index 9af84ddb6..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/MigrationProofRuntimeModule.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * generated by Xtext, then owned here: the value converters are the project language's. - */ -package dev.jorisjonkers.deploykit.emf.syntax; - -import dev.jorisjonkers.deploykit.emf.syntax.values.ProjectIntentValueConverters; -import org.eclipse.xtext.conversion.IValueConverterService; - -/** Registers the components the migration proof language runs with: the project language's own, reused. */ -public class MigrationProofRuntimeModule extends AbstractMigrationProofRuntimeModule { - - /** Quotes are syntax: see {@link ProjectIntentValueConverters}. */ - @Override - public Class bindIValueConverterService() { - return ProjectIntentValueConverters.class; - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/MigrationProofStandaloneSetup.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/MigrationProofStandaloneSetup.java deleted file mode 100644 index eb9023c52..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/MigrationProofStandaloneSetup.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * generated by Xtext - */ -package dev.jorisjonkers.deploykit.emf.syntax; - -/** - * Initialization support for running Xtext languages without Equinox extension registry. - */ -public class MigrationProofStandaloneSetup extends MigrationProofStandaloneSetupGenerated { - - public static void doSetup() { - new MigrationProofStandaloneSetup().createInjectorAndDoEMFRegistration(); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/NodeContract.xtext b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/NodeContract.xtext deleted file mode 100644 index 3c9504a2d..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/NodeContract.xtext +++ /dev/null @@ -1,47 +0,0 @@ -grammar dev.jorisjonkers.deploykit.emf.syntax.NodeContract with dev.jorisjonkers.deploykit.emf.syntax.ProjectIntent - hidden(WS, SL_COMMENT) - -import "https://jorisjonkers.dev/deploy-kit/pinned-inputs/1" -import "http://www.eclipse.org/emf/2002/Ecore" as ecore - -// The node contract, in the YAML subset the project language reads: what each -// node can hold, in the order the contract lists them. - -NodeContract returns NodeContract: - (('apiVersion' ':' apiVersion=Text) - & ('kind' ':' kind=Text) - & ('schemaVersion' ':' schemaVersion=Text) - & ('cluster' ':' cluster=Text) - & ('labelPrefix' ':' labelPrefix=Text) - & ('nodes' ':' BEGIN (DASH BEGIN nodes+=Node END)+ END)); - -Node returns Node: - (('name' ':' name=Text) - & ('site' ':' site=Text) - & ('arch' ':' arch=Text) - & ('allocatable' ':' BEGIN allocatable=Allocatable END) - & ('capabilities' ':' BEGIN (DASH BEGIN capabilities+=Text END | capabilities+=Text)* END)? - & ('gpus' ':' BEGIN (DASH BEGIN gpus+=Gpu END)* END)? - & ('disks' ':' BEGIN (DASH BEGIN disks+=Disk END)* END)?); - -Allocatable returns Allocatable: - (('cpu' ':' cpu=Text) - & ('memory' ':' memory=Text)); - -Gpu returns Gpu: - (('vendor' ':' vendor=Text) - & ('model' ':' model=Text) - & ('class' ':' class=Text) - & ('memory_mib' ':' memoryMib=Port)); - -Disk returns Disk: - (('media' ':' media=Text) - & ('usable_gib' ':' usableGib=Port)); - -// Every keyword this document adds is also a scalar, as the project language's are. -@Override -Text returns ecore::EString: - SCALAR | STRING | INT | Keyword | NodeContractKeyword; - -NodeContractKeyword: - 'allocatable' | 'disks' | 'gpus' | 'labelPrefix' | 'memory_mib' | 'nodes' | 'usable_gib'; diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/NodeContractRuntimeModule.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/NodeContractRuntimeModule.java deleted file mode 100644 index e700ed615..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/NodeContractRuntimeModule.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * generated by Xtext, then owned here: the value converters are the project language's. - */ -package dev.jorisjonkers.deploykit.emf.syntax; - -import dev.jorisjonkers.deploykit.emf.syntax.values.ProjectIntentValueConverters; -import org.eclipse.xtext.conversion.IValueConverterService; - -/** Registers the components the node contract language runs with: the project language's own, reused. */ -public class NodeContractRuntimeModule extends AbstractNodeContractRuntimeModule { - - /** Quotes are syntax: see {@link ProjectIntentValueConverters}. */ - @Override - public Class bindIValueConverterService() { - return ProjectIntentValueConverters.class; - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/NodeContractStandaloneSetup.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/NodeContractStandaloneSetup.java deleted file mode 100644 index 0cd54b799..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/NodeContractStandaloneSetup.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * generated by Xtext - */ -package dev.jorisjonkers.deploykit.emf.syntax; - -/** - * Initialization support for running Xtext languages without Equinox extension registry. - */ -public class NodeContractStandaloneSetup extends NodeContractStandaloneSetupGenerated { - - public static void doSetup() { - new NodeContractStandaloneSetup().createInjectorAndDoEMFRegistration(); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntent.xtext b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntent.xtext deleted file mode 100644 index 3c7bcdb25..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntent.xtext +++ /dev/null @@ -1,429 +0,0 @@ -grammar dev.jorisjonkers.deploykit.emf.syntax.PlatformIntent with dev.jorisjonkers.deploykit.emf.syntax.ProjectIntent - hidden(WS, SL_COMMENT) - -import "https://jorisjonkers.dev/deploy-kit/project-intent/1" -import "http://www.eclipse.org/emf/2002/Ecore" as ecore - -// The Platform document, in the YAML subset the project language reads: its -// terminals, its block tokens and its scalars are inherited, and only the -// document's own rules are here. A policy keyed by a closed vocabulary is a -// block with one optional key per literal, so a missing policy is an absent key. - -Platform returns Platform: - (('apiVersion' ':' apiVersion=Text) - & ('kind' ':' kind=Text) - & ('schemaVersion' ':' schemaVersion=Text) - & ('owner' ':' owner=Text) - & ('metadata' ':' BEGIN metadata=PlatformMetadata END) - & ('substrate' ':' BEGIN substrate=Substrate END) - & ('bootstrap' ':' BEGIN bootstrap=Bootstrap END) - & ('tiers' ':' BEGIN (DASH BEGIN tiers+=Tier END)+ END) - & ('durability' ':' BEGIN durability=DurabilityPolicies END) - & ('engines' ':' BEGIN engines=EnginePolicies END) - & ('monitors' ':' BEGIN monitors=MonitorCadence END) - & ('telemetry' ':' BEGIN telemetry=TelemetryPolicy END)? - & ('secretStore' ':' secretStore=[Application|Text])? - & ('hardening' ':' hardening=HardeningClass) - & ('probes' ':' BEGIN probes=ProbeCadence END) - & ('ephemeral' ':' BEGIN ephemeral=EphemeralPolicy END) - & ('migration' ':' BEGIN migration=MigrationPolicy END)? - & ('delivery' ':' BEGIN delivery=DeliveryPolicy END)? - & ('apiAccess' ':' BEGIN apiAccess=ApiAccessPolicy END)? - & ('policyJob' ':' BEGIN policyJob=VaultPolicyJob END)? - & ('providers' ':' BEGIN (DASH BEGIN providers+=Provider END)+ END)? - & ('libraries' ':' BEGIN libraries+=Library+ END)? - & ('gpus' ':' BEGIN gpus+=GpuVendor+ END)? - & ('vpn' ':' BEGIN vpn=VpnPolicy END)? - & ('monitoring' ':' BEGIN monitoring=Monitoring END)? - & ('signIn' ':' BEGIN signIn=SignIn END)? - & ('mesh' ':' BEGIN mesh=Mesh END)? - & ('seeder' ':' BEGIN seeder=Seeder END)? - & ('nodeAgents' ':' BEGIN nodeAgents=NodeAgents END)? - & ('acme' ':' BEGIN acme=AcmePolicy END)? - & ('humanGrants' ':' BEGIN (DASH BEGIN humanGrants+=HumanGrant END)+ END)? - & ('priority' ':' BEGIN priority=PriorityPolicy END)? - & ('l4Addresses' ':' BEGIN l4Addresses+=L4Address+ END)?); - -PlatformMetadata returns PlatformMetadata: - (('cluster' ':' cluster=Text) - & ('project' ':' project=Text) - & ('nodeContract' ':' nodeContract=Text)); - -Substrate returns Substrate: - (('kubernetesVersion' ':' kubernetesVersion=Text) - & ('datastore' ':' datastore=Datastore) - & ('serverCount' ':' serverCount=Port) - & ('secretsEncryption' ':' secretsEncryption=Bool) - & ('cni' ':' cni=Text) - & ('networkPolicyController' ':' networkPolicyController=PolicyController) - & ('clusterDns' ':' clusterDns=Text) - & ('imagePull' ':' imagePull=Text)? - & ('upstreamNameservers' ':' BEGIN (DASH BEGIN upstreamNameservers+=Text END | upstreamNameservers+=Text)+ END)?); - -Bootstrap returns Bootstrap: - (('k3s' ':' BEGIN k3s=K3sInstall END)? - & ('flux' ':' BEGIN flux=FluxSource END) - & ('vault' ':' BEGIN vault=VaultState END) - & ('crds' ':' BEGIN (DASH BEGIN crds+=Text END | crds+=Text)+ END)); - -// Where k3s serves its own metrics: each component the set records is scraped. -K3sInstall returns K3sInstall: - 'metrics' ':' BEGIN metrics=K3sMetrics END; - -K3sMetrics returns K3sMetrics: - {K3sMetrics} - (('kubelet' ':' BEGIN kubelet=KubeletMetrics END)? - & ('apiServer' ':' BEGIN apiServer=ApiServerMetrics END)? - & ('coreDns' ':' BEGIN coreDns=CoreDnsMetrics END)?); - -KubeletMetrics returns KubeletMetrics: - 'port' ':' port=Port; - -ApiServerMetrics returns ApiServerMetrics: - (('service' ':' service=Text) - & ('port' ':' port=Text)); - -CoreDnsMetrics returns CoreDnsMetrics: - 'port' ':' port=Port; - -FluxSource returns FluxSource: - (('sourceRef' ':' sourceRef=Text) - & ('artifacts' ':' BEGIN artifacts=RenderedArtifacts END) - & ('metrics' ':' BEGIN metrics=FluxMetrics END)?); - -// Where Flux's controllers serve their metrics, as its install sets them. -FluxMetrics returns FluxMetrics: - (('port' ':' port=Port) - & ('path' ':' path=Text)); - -RenderedArtifacts returns RenderedArtifacts: - (('repository' ':' repository=Text) - & ('signer' ':' BEGIN signer=ArtifactSigner END) - & ('pullSecret' ':' pullSecret=Text)?); - -ArtifactSigner returns ArtifactSigner: - (('issuer' ':' issuer=Text) - & ('subject' ':' subject=Text)); - -VaultState returns VaultState: - 'unsealed' ':' unsealed=Bool; - -// A tier's proxy is an Application a project file declares: a reference into -// another document, linked across the set of documents read together. -Tier returns Tier: - (('name' ':' name=Text) - & ('audiences' ':' BEGIN (DASH BEGIN audiences+=Audience END | audiences+=Audience)+ END) - & ('listener' ':' listener=Listener) - & ('certificates' ':' certificates=CertificateSource) - & ('certificateFrom' ':' certificateFrom=Text)? - & ('forwardAuth' ':' BEGIN forwardAuth=ForwardAuth END)? - & ('proxiedBy' ':' proxiedBy=ProxiedBy)? - & ('traefik' ':' traefik=[Application|Text]) - & ('ingressClass' ':' ingressClass=Text)? - & ('dns' ':' BEGIN dns=TierDns END)? - & ('address' ':' address=Text)?); - -// The sign-in provider's endpoint a tier asks before a gated route. -ForwardAuth returns ForwardAuth: - (('provider' ':' provider=[Application|Text]) - & ('surface' ':' surface=Text) - & ('path' ':' path=Text) - & ('responseHeaders' ':' BEGIN (DASH BEGIN responseHeaders+=Text END | responseHeaders+=Text)+ END)?); - -TierDns returns TierDns: - (('target' ':' target=Text) - & ('proxied' ':' proxied=Bool) - & ('direct' ':' direct=Text)?); - -DurabilityPolicies returns DurabilityPolicies: - {DurabilityPolicies} - (('reconstructible' ':' BEGIN reconstructible=DurabilityPolicy END)? - & ('recoverable' ':' BEGIN recoverable=DurabilityPolicy END)? - & ('irreplaceable' ':' BEGIN irreplaceable=DurabilityPolicy END)?); - -DurabilityPolicy returns DurabilityPolicy: - {DurabilityPolicy} - (('schedule' ':' schedule=Text)? - & ('retain' ':' retain=Port)? - & ('offCluster' ':' BEGIN offCluster=OffClusterCopy END)?); - -OffClusterCopy returns OffClusterCopy: - (('destination' ':' destination=Text) - & ('credential' ':' credential=Text) - & ('recipient' ':' recipient=Text) - & ('egress' ':' BEGIN (DASH BEGIN egress+=DestinationRange END)+ END)); - -// Where an off-cluster copy goes, as a network policy can say it: a range and a port. -DestinationRange returns DestinationRange: - (('cidr' ':' cidr=Text) - & ('port' ':' port=Port)); - -EnginePolicies returns EnginePolicies: - {EnginePolicies} - (('postgres' ':' BEGIN postgres=EnginePolicy END)? - & ('rabbitmq' ':' BEGIN rabbitmq=EnginePolicy END)? - & ('valkey' ':' BEGIN valkey=EnginePolicy END)? - & ('mongo' ':' BEGIN mongo=EnginePolicy END)? - & ('files' ':' BEGIN files=EnginePolicy END)? - & ('s3' ':' BEGIN s3=EnginePolicy END)?); - -// The method image, and the surface of the Process it dumps where it dumps over the network; and -// for an engine that owns databases, the method that applies their catalog. -EnginePolicy returns EnginePolicy: - (('backup' ':' backup=Text) - & ('surface' ':' surface=Text)? - & ('catalog' ':' catalog=Text)? - & ('catalogSurface' ':' catalogSurface=Text)?); - -MonitorCadence returns MonitorCadence: - (('interval' ':' interval=Text) - & ('timeout' ':' timeout=Text) - & ('labels' ':' BEGIN labels+=MonitorLabel+ END)?); - -MonitorLabel returns MonitorLabel: - key=Text ':' value=Text; - -// The collector names an Application a project file declares, linked across the -// documents read together, as a tier's proxy is. -TelemetryPolicy returns TelemetryPolicy: - (('collector' ':' collector=[Application|Text]) - & ('metrics' ':' metrics=[Application|Text]) - & ('dashboards' ':' BEGIN dashboards=DashboardPolicy END)?); - -DashboardPolicy returns DashboardPolicy: - (('instance' ':' BEGIN instance+=DashboardInstance+ END) - & ('datasource' ':' datasource=Text)); - -DashboardInstance returns DashboardInstance: - key=Text ':' value=Text; - -ProbeCadence returns ProbeCadence: - (('period' ':' period=Text) - & ('timeout' ':' timeout=Text) - & ('failures' ':' failures=Port)); - -EphemeralPolicy returns EphemeralPolicy: - 'size' ':' size=Text; - -// Who may hold Kubernetes API access, and where the API answers. A holder names an -// Application a project file declares, linked across the documents read together, as the -// machinery is. -ApiAccessPolicy returns ApiAccessPolicy: - (('holders' ':' BEGIN (DASH BEGIN holders+=[Application|Text] END | holders+=[Application|Text])+ END) - & ('namespaceHolders' ':' BEGIN (DASH BEGIN namespaceHolders+=[Application|Text] END | namespaceHolders+=[Application|Text])+ END)? - & ('server' ':' BEGIN (DASH BEGIN server+=DestinationRange END)+ END)); - -// The machinery names Applications a project file declares, linked across the -// documents read together, as a tier's proxy is. -DeliveryPolicy returns DeliveryPolicy: - (('machinery' ':' BEGIN (DASH BEGIN machinery+=[Application|Text] END | machinery+=[Application|Text])+ END) - & ('gate' ':' gate=[Application|Text]) - & ('reporter' ':' reporter=[Application|Text])? - & ('analysis' ':' BEGIN analysis=AnalysisPolicy END)); - -AnalysisPolicy returns AnalysisPolicy: - (('interval' ':' interval=Text) - & ('iterations' ':' iterations=Port) - & ('threshold' ':' threshold=Port) - & ('errorRate' ':' errorRate=Text) - & ('latency' ':' latency=Text)); - -MigrationPolicy returns MigrationPolicy: - (('runner' ':' runner=Text) - & ('deadline' ':' deadline=Text) - & ('memory' ':' memory=Text) - & ('cpu' ':' cpu=Text)); - -// The job that writes the rendered Vault policies and auth roles into the Secret Store: its -// image alias, the Vault role it logs in as, what it requests and how long it may take. -VaultPolicyJob returns VaultPolicyJob: - (('image' ':' image=Text) - & ('role' ':' role=Text) - & ('memory' ':' memory=Text) - & ('cpu' ':' cpu=Text) - & ('deadline' ':' deadline=Text)); - -Provider returns Provider: - (('name' ':' name=Text) - & ('address' ':' address=Text) - & ('surfaces' ':' BEGIN surfaces+=ProviderSurface+ END)); - -ProviderSurface returns ProviderSurface: - key=Text ':' value=Port; - -// A directory on one node, keyed by the library's name, and the projects it is granted to. -Library returns Library: - key=Text ':' BEGIN value=LibraryDeclaration END; - -LibraryDeclaration returns LibraryDeclaration: - (('node' ':' node=Text) - & ('path' ':' path=Text) - & ('gid' ':' gid=Port) - & ('grants' ':' BEGIN grants+=LibraryGrant+ END)); - -LibraryGrant returns LibraryGrant: - key=Text ':' value=LibraryAccess; - -// What a Process that requires a GPU of one vendor is handed, keyed by the vendor. -GpuVendor returns GpuVendor: - key=Text ':' BEGIN value=GpuVendorPolicy END; - -GpuVendorPolicy returns GpuVendorPolicy: - (('resource' ':' resource=Text) - & ('runtimeClass' ':' runtimeClass=Text)); - -// The VPN beside every attached Process: its image, credential, quantities and literal settings. -VpnPolicy returns VpnPolicy: - (('image' ':' image=Text) - & ('credential' ':' credential=Text) - & ('memory' ':' memory=Text) - & ('cpu' ':' cpu=Text) - & ('settings' ':' BEGIN settings+=VpnSetting+ END)?); - -VpnSetting returns VpnSetting: - key=Text ':' value=Text; - -// The monitoring stack and where its alerts go. -Monitoring returns Monitoring: - (('grafana' ':' grafana=[Application|Text]) - & ('prometheus' ':' prometheus=[Application|Text]) - & ('alertmanager' ':' alertmanager=[Application|Text]) - & ('stores' ':' BEGIN stores=MonitoringStores END)? - & ('receivers' ':' BEGIN (DASH BEGIN receivers+=Receiver END)+ END) - & ('routes' ':' BEGIN (DASH BEGIN routes+=SeverityRoute END)+ END)); - -// The stores Grafana reads beside the stack. -MonitoringStores returns MonitoringStores: - {MonitoringStores} - (('loki' ':' loki=[Application|Text])? - & ('tempo' ':' tempo=[Application|Text])? - & ('pyroscope' ':' pyroscope=[Application|Text])?); - -Receiver returns Receiver: - (('name' ':' name=Text) - & ('discord' ':' BEGIN discord=DiscordReceiver END)); - -DiscordReceiver returns DiscordReceiver: - 'webhook' ':' BEGIN webhook=VaultValue END; - -VaultValue returns VaultValue: - (('path' ':' path=Text) - & ('key' ':' key=Text)); - -SeverityRoute returns SeverityRoute: - (('severity' ':' severity=Text) - & ('receiver' ':' receiver=Text) - & ('repeat' ':' repeat=Text)); - -SignIn returns SignIn: - (('issuer' ':' issuer=Text) - & ('provider' ':' provider=[Application|Text]) - & ('contract' ':' contract=Text)?); - -Mesh returns Mesh: - 'enrolled' ':' BEGIN (DASH BEGIN enrolled+=Text END | enrolled+=Text)+ END; - -Seeder returns Seeder: - (('image' ':' image=Text) - & ('memory' ':' memory=Text) - & ('cpu' ':' cpu=Text)); - -NodeAgents returns NodeAgents: - {NodeAgents} - (('gpu-device' ':' BEGIN gpuDevice=NodeAgentPolicy END)? - & ('gpu-metrics' ':' BEGIN gpuMetrics=NodeAgentPolicy END)? - & ('node-metrics' ':' BEGIN nodeMetrics=NodeAgentPolicy END)? - & ('l4-speaker' ':' BEGIN l4Speaker=SpeakerPolicy END)?); - -NodeAgentPolicy returns NodeAgentPolicy: - (('image' ':' image=Text) - & ('memory' ':' memory=Text) - & ('cpu' ':' cpu=Text)); - -SpeakerPolicy returns SpeakerPolicy: - (('image' ':' image=Text) - & ('memory' ':' memory=Text) - & ('cpu' ':' cpu=Text) - & ('controller' ':' BEGIN controller=NodeAgentPolicy END)); - -AcmePolicy returns AcmePolicy: - (('email' ':' email=Text) - & ('dnsProvider' ':' dnsProvider=DnsProvider) - & ('token' ':' token=Text)); - -HumanGrant returns HumanGrant: - (('group' ':' group=Text) - & ('clusterRole' ':' clusterRole=HumanGrantRole) - & ('reason' ':' reason=Text)); - -PriorityPolicy returns PriorityPolicy: - (('data' ':' BEGIN data=PriorityClass END) - & ('critical' ':' BEGIN critical=PriorityClass END) - & ('criticalApplications' ':' BEGIN (DASH BEGIN criticalApplications+=[Application|Text] END | criticalApplications+=[Application|Text])+ END)?); - -PriorityClass returns PriorityClass: - (('name' ':' name=Text) - & ('value' ':' value=Port)); - -// An address an L4 port is served on, keyed by its name: a range of a site's pool, or one node's. -L4Address returns L4Address: - key=Text ':' BEGIN value=L4AddressDeclaration END; - -// Spelled out key order by key order: `kind` says which, wherever it is written. -L4AddressDeclaration returns L4AddressDeclaration: - {PoolAddress} 'kind' ':' kind='pool' 'site' ':' site=Text 'range' ':' range=Text - | {PoolAddress} 'kind' ':' kind='pool' 'range' ':' range=Text 'site' ':' site=Text - | {PoolAddress} 'site' ':' site=Text 'kind' ':' kind='pool' 'range' ':' range=Text - | {PoolAddress} 'site' ':' site=Text 'range' ':' range=Text 'kind' ':' kind='pool' - | {PoolAddress} 'range' ':' range=Text 'kind' ':' kind='pool' 'site' ':' site=Text - | {PoolAddress} 'range' ':' range=Text 'site' ':' site=Text 'kind' ':' kind='pool' - | {NodeAddress} 'kind' ':' kind='node' 'node' ':' node=Text - | {NodeAddress} 'node' ':' node=Text 'kind' ':' kind='node'; - -// Every keyword this document adds is also a scalar, as the project language's are. -@Override -Text returns ecore::EString: - SCALAR | STRING | INT | Keyword | PlatformKeyword; - -PlatformKeyword: - 'acme' | 'alertmanager' | 'analysis' | 'apiAccess' | 'apiServer' | 'artifacts' | 'audiences' | 'backup' | - 'bootstrap' | 'catalog' | 'catalogSurface' | 'certificateFrom' | 'certificates' | 'cidr' | 'cloudflare' | - 'cluster-admin' | 'clusterDns' | 'clusterRole' | 'cni' | 'collector' | 'contract' | 'controller' | 'coreDns' | 'crds' | - 'critical' | 'criticalApplications' | 'data' | 'datasource' | 'datastore' | 'deadline' | 'destination' | 'direct' | - 'discord' | 'dns' | 'dnsProvider' | 'edit' | 'email' | 'embedded' | 'engines' | 'enrolled' | 'ephemeral' | 'errorRate' | - 'etcd' | 'failures' | 'flux' | 'forwardAuth' | 'gate' | 'gid' | 'gpu-device' | 'gpu-metrics' | 'gpus' | 'grafana' | - 'grants' | 'hardening' | 'holders' | 'humanGrants' | 'imagePull' | 'ingressClass' | 'instance' | 'interval' | 'issuer' | - 'iterations' | 'k3s' | 'kubelet' | 'kubernetesVersion' | 'l4-speaker' | 'l4Addresses' | 'labels' | 'latency' | - 'listener' | 'loki' | 'machinery' | 'mesh' | 'metadata' | 'metrics' | 'monitoring' | 'monitors' | - 'namespaceHolders' | 'networkPolicyController' | 'node-metrics' | 'nodeAgents' | 'nodeContract' | - 'offCluster' | 'period' | 'plain' | 'policyJob' | 'pool' | 'priority' | 'prometheus' | 'provider' | 'providers' | - 'proxiedBy' | 'pullSecret' | 'pyroscope' | 'range' | 'receiver' | 'receivers' | 'recipient' | 'repeat' | 'reporter' | - 'repository' | 'resource' | 'responseHeaders' | 'restricted' | 'retain' | 'runner' | - 'runtimeClass' | 'secretsEncryption' | 'secretStore' | 'seeder' | 'server' | 'serverCount' | 'service' | - 'settings' | 'severity' | 'signer' | 'sourceRef' | 'sqlite' | 'stores' | 'subject' | 'substrate' | 'surfaces' | - 'target' | 'telemetry' | 'tempo' | 'threshold' | 'tiers' | 'timeout' | 'tls' | 'traefik' | 'unsealed' | - 'upstreamNameservers' | 'value' | 'vault' | 'view' | 'webhook'; - -enum Datastore returns Datastore: - sqlite='sqlite' | etcd='etcd'; - -enum PolicyController returns PolicyController: - none='none' | embedded='embedded' | cni='cni'; - -enum ProxiedBy returns ProxiedBy: - cloudflare='cloudflare'; - -enum Listener returns Listener: - tls='tls' | plain='plain'; - -enum CertificateSource returns CertificateSource: - acme='acme' | none='none'; - -enum DnsProvider returns DnsProvider: - cloudflare='cloudflare'; - -enum HumanGrantRole returns HumanGrantRole: - clusterAdmin='cluster-admin' | admin='admin' | edit='edit' | view='view'; - -enum HardeningClass returns HardeningClass: - restricted='restricted'; diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntentRuntimeModule.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntentRuntimeModule.java deleted file mode 100644 index 930c0e7f2..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntentRuntimeModule.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * generated by Xtext, then owned here: the value converters and the linking are the project language's. - */ -package dev.jorisjonkers.deploykit.emf.syntax; - -import dev.jorisjonkers.deploykit.emf.syntax.linking.ProjectIntentScopes; -import dev.jorisjonkers.deploykit.emf.syntax.linking.UnlinkedNames; -import dev.jorisjonkers.deploykit.emf.syntax.values.ProjectIntentValueConverters; -import org.eclipse.xtext.conversion.IValueConverterService; -import org.eclipse.xtext.linking.ILinkingDiagnosticMessageProvider; -import org.eclipse.xtext.scoping.IScopeProvider; - -/** Registers the components the Platform language runs with: the project language's own, reused. */ -public class PlatformIntentRuntimeModule extends AbstractPlatformIntentRuntimeModule { - - /** Quotes are syntax and a boolean is a boolean: see {@link ProjectIntentValueConverters}. */ - @Override - public Class bindIValueConverterService() { - return ProjectIntentValueConverters.class; - } - - /** A tier's proxy links to an Application of the documents read with it: see {@link ProjectIntentScopes}. */ - @Override - public Class bindIScopeProvider() { - return ProjectIntentScopes.class; - } - - /** A proxy that links to nothing carries its specification code: see {@link UnlinkedNames}. */ - public Class bindILinkingDiagnosticMessageProvider() { - return UnlinkedNames.class; - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntentStandaloneSetup.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntentStandaloneSetup.java deleted file mode 100644 index 0c3a24a20..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/PlatformIntentStandaloneSetup.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * generated by Xtext - */ -package dev.jorisjonkers.deploykit.emf.syntax; - -/** - * Initialization support for running Xtext languages without Equinox extension registry. - */ -public class PlatformIntentStandaloneSetup extends PlatformIntentStandaloneSetupGenerated { - - public static void doSetup() { - new PlatformIntentStandaloneSetup().createInjectorAndDoEMFRegistration(); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntent.xtext b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntent.xtext deleted file mode 100644 index 83812a2da..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntent.xtext +++ /dev/null @@ -1,486 +0,0 @@ -grammar dev.jorisjonkers.deploykit.emf.syntax.ProjectIntent hidden(WS, SL_COMMENT) - -import "https://jorisjonkers.dev/deploy-kit/project-intent/1" -import "http://www.eclipse.org/emf/2002/Ecore" as ecore - -// The YAML subset the authored project files use. Block structure arrives as -// the synthetic BEGIN and END tokens the blocks package produces, so an -// indented block, a flow mapping and a flow sequence parse through one rule. -// Keys are unordered groups, because the order of keys in a mapping is not -// meaning. A union in the model is a union here. - -Project returns Project: - (('apiVersion' ':' apiVersion=Text) - & ('kind' ':' kind=Text) - & ('schemaVersion' ':' schemaVersion=Text) - & ('project' ':' project=Text) - & ('owner' ':' owner=Text) - & ('secrets' ':' BEGIN (DASH BEGIN secrets+=Grant END)+ END)? - & ('dependsOn' ':' BEGIN (DASH BEGIN dependsOn+=DependencyEdge END)+ END)? - & ('assets' ':' BEGIN (DASH BEGIN assets+=AssetDeclaration END)+ END)? - & ('writablePaths' ':' BEGIN (DASH BEGIN writablePaths+=WritablePath END | writablePaths+=PlainPath | BEGIN writablePaths+=MemoryPath END)+ END)? - & ('placement' ':' BEGIN placement=Placement END)? - & ('startupBudget' ':' startupBudget=Text)? - & ('cutover' ':' cutover=Cutover)? - & ('applications' ':' BEGIN (DASH BEGIN applications+=Application END)+ END)); - -Application returns Application: - (('id' ':' id=Text) - & ('description' ':' description=Text)? - & ('client' ':' BEGIN client=Client END)? - & ('l4Exposure' ':' BEGIN (DASH BEGIN l4Exposure+=L4Exposure END | BEGIN l4Exposure+=L4Exposure END)+ END)? - & ('dashboards' ':' BEGIN (DASH BEGIN dashboards+=Dashboard END | BEGIN dashboards+=Dashboard END)+ END)? - & ('alertRules' ':' BEGIN (DASH BEGIN alertRules+=AlertRules END | BEGIN alertRules+=AlertRules END)+ END)? - & ('migration' ':' migration=Migration)? - & ('observability' ':' BEGIN observability=Observability END)? - & ('exposure' ':' BEGIN (DASH BEGIN exposure+=Exposure END)+ END)? - & ('secrets' ':' BEGIN (DASH BEGIN secrets+=Grant END)+ END)? - & ('dependsOn' ':' BEGIN (DASH BEGIN dependsOn+=DependencyEdge END)+ END)? - & ('assets' ':' BEGIN (DASH BEGIN assets+=AssetDeclaration END)+ END)? - & ('writablePaths' ':' BEGIN (DASH BEGIN writablePaths+=WritablePath END | writablePaths+=PlainPath | BEGIN writablePaths+=MemoryPath END)+ END)? - & ('placement' ':' BEGIN placement=Placement END)? - & ('startupBudget' ':' startupBudget=Text)? - & ('cutover' ':' cutover=Cutover)? - & ('processes' ':' BEGIN (DASH BEGIN processes+=Process END)+ END)); - -Observability returns Observability: - 'scrape' ':' BEGIN scrape=Scrape END; - -// How an Application signs its users in through the platform's provider. -Client returns Client: - (('signIn' ':' signIn=SignInMode) - & ('exposure' ':' exposure=Text)? - & ('label' ':' label=Text)? - & ('description' ':' description=Text)? - & ('iconPath' ':' iconPath=Text)? - & ('launchPath' ':' launchPath=Text)? - & ('redirectPaths' ':' BEGIN (DASH BEGIN redirectPaths+=Text END | redirectPaths+=Text)+ END)? - & ('protectedPath' ':' protectedPath=Text)? - & ('backChannelLogoutPath' ':' backChannelLogoutPath=Text)? - & ('credential' ':' credential=ClientCredential)? - & ('roles' ':' BEGIN (DASH BEGIN roles+=Text END | roles+=Text)+ END)?); - -L4Exposure returns L4Exposure: - (('address' ':' address=Text) - & ('port' ':' port=Port) - & ('protocol' ':' protocol=L4Protocol) - & ('process' ':' process=[Process|Text]) - & ('surface' ':' surface=[Surface|Text])); - -Dashboard returns Dashboard: - 'from' ':' from=Text; - -AlertRules returns AlertRules: - 'from' ':' from=Text; - -Scrape returns Scrape: - (('process' ':' process=[Process|Text]) - & ('surface' ':' surface=[Surface|Text]) - & ('path' ':' path=Text) - & ('honorLabels' ':' honorLabels=Bool)?); - -Exposure returns Exposure: - (('name' ':' name=Text) - & ('host' ':' host=Text) - & ('audience' ':' audience=Audience) - & ('contentPolicy' ':' contentPolicy=ContentPolicy)? - & ('proxied' ':' proxied=Bool)? - & ('routes' ':' BEGIN (DASH BEGIN routes+=Route END)+ END)); - -Route returns Route: - (('path' ':' path=Text) - & ('match' ':' match=Match) - & ('process' ':' process=[Process|Text]) - & ('surface' ':' surface=[Surface|Text]) - & ('audience' ':' audience=Audience)? - & ('redirectTo' ':' redirectTo=Text)? - & ('rateLimit' ':' BEGIN rateLimit=RateLimit END)?); - -// How many requests one client may send a route over a period. -RateLimit returns RateLimit: - (('requests' ':' requests=Port) - & ('per' ':' per=Text)); - -Process returns Process: - (('name' ':' name=Text) - & ('lifecycle' ':' lifecycle=Lifecycle) - & ('image' ':' image=Text) - & ('runtime' ':' runtime=Runtime) - & ('engine' ':' engine=Engine)? - & ('provides' ':' BEGIN provides+=Surface+ END)? - & ('placement' ':' BEGIN placement=Placement END)? - & ('writablePaths' ':' BEGIN (DASH BEGIN writablePaths+=WritablePath END | writablePaths+=PlainPath | BEGIN writablePaths+=MemoryPath END)+ END)? - & ('sidecars' ':' BEGIN (DASH BEGIN sidecars+=Sidecar END)+ END)? - & ('dependsOn' ':' BEGIN (DASH BEGIN dependsOn+=DependencyEdge END)+ END)? - & ('assets' ':' BEGIN (DASH BEGIN assets+=AssetDeclaration END)+ END)? - & ('probes' ':' probes=ProbePolicy)? - & ('volumes' ':' BEGIN (DASH BEGIN volumes+=Volume END)+ END)? - & ('libraries' ':' BEGIN (DASH BEGIN libraries+=LibraryMount END)+ END)? - & ('replicas' ':' BEGIN replicas=Capacity END)? - & ('api' ':' BEGIN api=ApiAccess END)? - & ('egress' ':' BEGIN egress=Egress END)? - & ('vpn' ':' BEGIN vpn=VpnAttachment END)? - & ('secrets' ':' BEGIN (DASH BEGIN secrets+=Grant END)+ END)? - & ('startupBudget' ':' startupBudget=Text)? - & ('cutover' ':' cutover=Cutover)? - & ('description' ':' description=Text)? - & ('schedule' ':' schedule=Text)? - & ('parked' ':' BEGIN parked=Parked END)? - & ('command' ':' BEGIN (DASH BEGIN command+=Text END | command+=Text)+ END)? - & ('args' ':' BEGIN (DASH BEGIN args+=Text END | args+=Text)+ END)? - & ('spawns' ':' BEGIN (DASH BEGIN spawns+=SpawnTemplate END)+ END)?); - -Parked returns Parked: - 'reason' ':' reason=Text; - -// A pod the Process creates through the API, from a template the platform renders. -SpawnTemplate returns SpawnTemplate: - (('name' ':' name=Text) - & ('image' ':' image=Text) - & ('placement' ':' BEGIN placement=SpawnPlacement END) - & ('provides' ':' BEGIN provides+=Surface+ END)? - & ('dependsOn' ':' BEGIN (DASH BEGIN dependsOn+=DependencyEdge END)+ END)? - & ('egress' ':' BEGIN egress=Egress END)?); - -SpawnPlacement returns SpawnPlacement: - (('memory' ':' memory=Text) - & ('cpu' ':' cpu=Text)); - -// A path the Process may write: plain, or held in memory at a size. -WritablePath returns WritablePathDeclaration: - PlainPath | MemoryPath; - -PlainPath returns PlainPath: - path=Text; - -MemoryPath returns MemoryPath: - (('path' ':' path=Text) - & ('memory' ':' memory=Text)); - -Surface returns Surface: - key=Text ':' value=Port; - -Placement returns Placement: - (('memory' ':' memory=Text)? - & ('cpu' ':' cpu=Text)? - & ('arch' ':' BEGIN (DASH BEGIN arch+=Arch END | arch+=Arch)+ END)? - & ('site' ':' site=Text)? - & ('disk' ':' BEGIN disk=DiskRequest END)? - & ('gpu' ':' BEGIN gpu=GpuRequest END)? - & ('capabilities' ':' BEGIN (DASH BEGIN capabilities+=Text END | capabilities+=Text)+ END)?); - -DiskRequest returns DiskRequest: - 'media' ':' BEGIN (DASH BEGIN media+=Media END | media+=Media)+ END; - -// Every term is optional, so `gpu: {}` is any card. -GpuRequest returns GpuRequest: - {GpuRequest} - (('class' ':' class=Text)? - & ('memory' ':' memory=Text)? - & ('vendor' ':' BEGIN (DASH BEGIN vendor+=Text END | vendor+=Text)+ END)? - & ('model' ':' BEGIN (DASH BEGIN model+=Text END | model+=Text)+ END)?); - -Sidecar returns Sidecar: - (('name' ':' name=Text) - & ('image' ':' image=Text) - & ('command' ':' BEGIN (DASH BEGIN command+=Text END | command+=Text)+ END)? - & ('args' ':' BEGIN (DASH BEGIN args+=Text END | args+=Text)+ END)? - & ('memory' ':' memory=Text) - & ('cpu' ':' cpu=Text) - & ('volumes' ':' BEGIN (DASH BEGIN volumes+=SidecarMount END | BEGIN volumes+=SidecarMount END)+ END)? - & ('assets' ':' BEGIN (DASH BEGIN assets+=SidecarAsset END | BEGIN assets+=SidecarAsset END)+ END)? - & ('init' ':' init=Bool)?); - -SidecarMount returns SidecarMount: - (('claim' ':' claim=Text) - & ('mountAt' ':' mountAt=Text)); - -SidecarAsset returns SidecarAsset: - (('from' ':' from=Text) - & ('mountAt' ':' mountAt=Text)); - -DependencyEdge returns DependencyEdge: - (('application' ':' application=Text) - & ('surface' ':' surface=Text) - & ('required' ':' required=Bool)? - & ('buckets' ':' BEGIN (DASH BEGIN buckets+=Text END | buckets+=Text)+ END)? - & ('credentials' ':' BEGIN credentials=Credentials END)?); - -Credentials returns Credentials: - (('delivery' ':' delivery=Delivery)? - & ('mountAt' ':' mountAt=Text)? - & ('fileMode' ':' fileMode=Text)? - & ('rotation' ':' BEGIN rotation=Rotation END)); - -// How an Application's schema moves: `self`, `none`, or a changelog block. -Migration returns Migration: - SelfMigration | NoMigration | ManagedMigration; - -SelfMigration returns SelfMigration: - {SelfMigration} 'self'; - -NoMigration returns NoMigration: - {NoMigration} 'none'; - -ManagedMigration returns ManagedMigration: - BEGIN 'changelog' ':' changelog=Text END; - -// A file beside the project: mounted read-only, or seeded once onto a volume. -// Spelled out key order by key order: the two kinds share `from`, and only the -// key after it says which one a block is. -AssetDeclaration returns AssetDeclaration: - {Asset} 'from' ':' from=Text 'mountAt' ':' mountAt=Text - | {Asset} 'mountAt' ':' mountAt=Text 'from' ':' from=Text - | {SeededAsset} 'from' ':' from=Text 'seedAt' ':' seedAt=Text - | {SeededAsset} 'seedAt' ':' seedAt=Text 'from' ':' from=Text; - -ProbePolicy returns ProbePolicy: - NoProbes | Probes; - -NoProbes returns NoProbes: - {NoProbes} 'none'; - -Probes returns Probes: - BEGIN - (('readiness' ':' BEGIN readiness=Probe END)? - & ('liveness' ':' BEGIN liveness=Probe END)?) - END; - -Probe returns Probe: - HttpProbe | TcpProbe; - -HttpProbe returns HttpProbe: - (('path' ':' path=Text) - & ('port' ':' port=Port)); - -TcpProbe returns TcpProbe: - 'tcp' ':' tcp=Port; - -Volume returns Volume: - (('claim' ':' claim=Text) - & ('mountAt' ':' mountAt=Text) - & ('size' ':' size=Text) - & ('durability' ':' durability=DurabilityClass)); - -// A library the Platform document grants, mounted by its name. -LibraryMount returns LibraryMount: - (('library' ':' library=Text) - & ('mountAt' ':' mountAt=Text) - & ('subPath' ':' subPath=Text)? - & ('access' ':' access=LibraryAccess)); - -Capacity returns Capacity: - (('count' ':' count=Port) - & ('reason' ':' reason=Text) - & ('across' ':' across=Spread)?); - -// The Kubernetes API access a Process needs: what it may ask of which objects, and why. -// Whether the provider forwards the attached Process a port. -VpnAttachment returns VpnAttachment: - 'forwardedPort' ':' forwardedPort=Bool; - -Egress returns Egress: - (('to' ':' to=EgressTarget) - & ('reason' ':' reason=Text)); - -ApiAccess returns ApiAccess: - (('reason' ':' reason=Text) - & ('rules' ':' BEGIN (DASH BEGIN rules+=ApiRule END)+ END)?); - -ApiRule returns ApiRule: - (('group' ':' group=Text) - & ('objects' ':' BEGIN (DASH BEGIN objects+=Text END | objects+=Text)+ END) - & ('verbs' ':' BEGIN (DASH BEGIN verbs+=ApiVerb END | verbs+=ApiVerb)+ END) - & ('scope' ':' scope=ApiScope)?); - -Grant returns Grant: - KvGrant | DatabaseGrant | TransitGrant; - -KvGrant returns KvGrant: - (('path' ':' path=Text) - & ('keys' ':' BEGIN (DASH BEGIN keys+=KvKey END | keys+=PlainKey | BEGIN keys+=BlockKey END)+ END) - & ('access' ':' access=AccessTier) - & ('delivery' ':' delivery=Delivery) - & ('mountAt' ':' mountAt=Text)? - & ('fileMode' ':' fileMode=Text)? - & ('rotation' ':' BEGIN rotation=Rotation END)); - -// A key is its name, or a block naming it and how the Vault policy job generates it. -KvKey returns KvKey: - PlainKey | BlockKey; - -// A generated key or one the Process starts without when the Secret Store holds no -// value for it, spelled out key order by key order: both open on `name`. -BlockKey returns KvKey: - {GeneratedKey} 'name' ':' name=Text 'generate' ':' BEGIN ^generate=Generate END - | {GeneratedKey} 'generate' ':' BEGIN ^generate=Generate END 'name' ':' name=Text - | {OptionalKey} 'name' ':' name=Text 'optional' ':' optional=Bool - | {OptionalKey} 'optional' ':' optional=Bool 'name' ':' name=Text; - -PlainKey returns PlainKey: - name=Text; - -Generate returns Generate: - {Generate} - (('bytes' ':' bytes=Port)? - & ('encoding' ':' encoding=KeyEncoding)? - & ('adopt' ':' adopt=Text)?); - -DatabaseGrant returns DatabaseGrant: - 'engine' ':' engine=DatabaseEngine - (('role' ':' role=Text) - & ('delivery' ':' delivery=Delivery) - & ('mountAt' ':' mountAt=Text)? - & ('fileMode' ':' fileMode=Text)? - & ('rotation' ':' BEGIN rotation=Rotation END)); - -TransitGrant returns TransitGrant: - 'engine' ':' engine=TransitEngine - (('key' ':' key=Text) - & ('operations' ':' BEGIN (DASH BEGIN operations+=TransitOp END | operations+=TransitOp)+ END) - & ('delivery' ':' delivery=Delivery) - & ('mountAt' ':' mountAt=Text)? - & ('fileMode' ':' fileMode=Text)? - & ('rotation' ':' BEGIN rotation=Rotation END)); - -Rotation returns Rotation: - (('tolerates' ':' tolerates=Tolerance) - & ('maxAge' ':' maxAge=Text)?); - -Port returns ecore::EInt: - INT; - -Bool returns ecore::EBooleanObject: - 'true' | 'false'; - -// A scalar, quoted, folded or plain. Every keyword above is also a scalar, so a -// value that happens to read like a key is still a value. -Text returns ecore::EString: - SCALAR | STRING | INT | Keyword; - -Keyword: - 'access' | 'across' | 'address' | 'admin' | 'adopt' | 'alertRules' | 'amd64' | 'anonymous' | 'api' | 'apiVersion' | - 'application' | 'applications' | 'arch' | 'args' | 'arm64' | 'assets' | 'audience' | 'authenticated' | 'backChannelLogoutPath' | - 'base64' | 'base64url' | 'buckets' | 'bytes' | 'capabilities' | 'changelog' | 'claim' | 'class' | 'client' | 'cluster' | - 'command' | 'contentPolicy' | 'continuous' | 'count' | 'cpu' | 'create' | 'credential' | 'credentials' | 'custody' | 'cutover' | - 'dashboards' | 'database' | 'decrypt' | 'delete' | 'deletecollection' | 'delivery' | 'dependsOn' | 'description' | 'disk' | - 'durability' | 'egress' | 'encoding' | 'encrypt' | 'engine' | 'env' | 'exact' | 'exposure' | 'false' | 'file' | 'fileMode' | - 'files' | 'forwardedPort' | 'from' | 'gated' | 'generate' | 'get' | 'gpu' | 'group' | 'hdd' | 'hex' | - 'honorLabels' | 'host' | 'iconPath' | 'id' | 'image' | 'init' | 'internal' | 'internet' | 'interrupted' | 'irreplaceable' | - 'job' | 'jvm' | 'key' | 'keys' | 'kind' | 'kv' | 'l4Exposure' | 'label' | 'lan' | 'launchPath' | 'libraries' | 'library' | - 'lifecycle' | 'list' | 'liveness' | 'match' | 'maxAge' | 'media' | 'memory' | 'migration' | 'model' | 'mongo' | 'mountAt' | - 'name' | 'namespace' | 'native' | 'node' | 'none' | 'nvme' | 'objects' | 'observability' | 'operations' | 'optional' | 'owner' | - 'parked' | 'patch' | 'path' | 'per' | 'pkce' | 'placement' | 'port' | 'postgres' | 'prefix' | 'prepare' | 'probes' | 'process' | - 'processes' | 'project' | 'protectedPath' | 'protocol' | 'provides' | 'proxied' | 'python' | 'rabbitmq' | 'rateLimit' | 'read' | - 'readiness' | 'reason' | 'reconstructible' | 'recoverable' | 'redirectPaths' | 'redirectTo' | 'reload' | 'replicas' | - 'requests' | 'required' | 'restart' | 'role' | 'roles' | 'rotate' | 'rotation' | 'routes' | 'rules' | 'runtime' | - 's3' | 'schedule' | 'scheduled' | 'schemaVersion' | 'scope' | 'scrape' | 'secret' | 'secrets' | 'seedAt' | 'self' | - 'self-renew' | 'self-roll' | 'sidecars' | 'sign' | 'signIn' | 'site' | 'size' | 'spawns' | 'ssd' | 'startupBudget' | 'static' | - 'strict' | 'subPath' | 'surface' | 'tcp' | 'to' | 'token' | 'tolerates' | 'transit' | 'true' | 'udp' | 'update' | 'valkey' | - 'vendor' | 'verbs' | 'verify' | 'volumes' | 'vpn' | 'watch' | 'workflow' | 'writablePaths' | 'write'; - -enum Lifecycle returns Lifecycle: - application='application' | job='job' | prepare='prepare' | scheduled='scheduled'; - -enum Runtime returns Runtime: - jvm='jvm' | python='python' | node='node' | static='static' | none='none'; - -enum Engine returns Engine: - postgres='postgres' | rabbitmq='rabbitmq' | valkey='valkey' | mongo='mongo' | files='files' | s3='s3'; - -enum Cutover returns Cutover: - continuous='continuous' | interrupted='interrupted'; - -enum DurabilityClass returns DurabilityClass: - reconstructible='reconstructible' | recoverable='recoverable' | irreplaceable='irreplaceable'; - -enum Arch returns Arch: - amd64='amd64' | arm64='arm64'; - -enum Media returns Media: - nvme='nvme' | ssd='ssd' | hdd='hdd'; - -enum ApiScope returns ApiScope: - namespace='namespace' | cluster='cluster'; - -enum Spread returns Spread: - node='node'; - -enum L4Protocol returns L4Protocol: - tcp='tcp' | udp='udp'; - -enum SignInMode returns SignInMode: - native='native' | gated='gated' | token='token'; - -enum ClientCredential returns ClientCredential: - secret='secret' | pkce='pkce'; - -enum Audience returns Audience: - anonymous='anonymous' | authenticated='authenticated' | internal='internal' | lan='lan'; - -enum ContentPolicy returns ContentPolicy: - strict='strict' | admin='admin' | workflow='workflow'; - -enum Match returns Match: - prefix='prefix' | exact='exact'; - -enum DatabaseEngine returns DatabaseEngine: - database='database'; - -enum TransitEngine returns TransitEngine: - transit='transit'; - -enum AccessTier returns AccessTier: - read='read' | selfRenew='self-renew' | selfRoll='self-roll' | custody='custody'; - -enum ApiVerb returns ApiVerb: - get='get' | list='list' | watch='watch' | create='create' | update='update' | patch='patch' | delete='delete' | - deletecollection='deletecollection'; - -enum EgressTarget returns EgressTarget: - internet='internet'; - -enum LibraryAccess returns LibraryAccess: - read='read' | write='write'; - -enum TransitOp returns TransitOp: - sign='sign' | verify='verify' | encrypt='encrypt' | decrypt='decrypt' | rotate='rotate' | read='read'; - -enum Delivery returns Delivery: - env='env' | file='file' | selfDelivery='self'; - -enum KeyEncoding returns KeyEncoding: - hex='hex' | base64='base64' | base64url='base64url'; - -enum Tolerance returns Tolerance: - restart='restart' | reload='reload'; - -terminal BEGIN: 'synthetic:BEGIN'; -terminal END: 'synthetic:END'; - -// The block markers the token source rewrites: a dash opens a sequence item, a -// flow collection opens and closes a block on one line, and a fold introduces a -// scalar written over several lines. The parser sees none of them: they arrive -// as BEGIN, END and SCALAR. -terminal DASH: '-'; -terminal FLOW_BEGIN: '{'; -terminal FLOW_END: '}'; -terminal FLOW_SEP: ','; -terminal LIST_BEGIN: '['; -terminal LIST_END: ']'; -terminal FOLD: ('>' | '|') '-'?; - -terminal INT returns ecore::EInt: ('0'..'9')+; - -terminal SCALAR: - (!(' ' | '\t' | '\r' | '\n' | ':' | ',' | '{' | '}' | '[' | ']' | '#' | '"' | "'" | '-' | '>' | '|') - | '-' !(' ' | '\t' | '\r' | '\n' | ':' | ',' | '{' | '}' | '[' | ']' | '#' | '"' | "'" | '-' | '>' | '|') - | '--' !(' ' | '\t' | '\r' | '\n' | ':' | ',' | '{' | '}' | '[' | ']' | '#' | '"' | "'" | '-' | '>' | '|')) - (!(' ' | '\t' | '\r' | '\n' | ':' | ',' | '{' | '}' | '[' | ']' | '#'))*; - -terminal STRING: - '"' !('"')* '"' | "'" !("'")* "'"; - -terminal SL_COMMENT: '#' !('\n' | '\r')*; - -terminal WS: (' ' | '\t' | '\r' | '\n')+; diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentRuntimeModule.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentRuntimeModule.java deleted file mode 100644 index 512c1917e..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentRuntimeModule.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * generated by Xtext, then owned here: the value converters and the linking are this language's. - */ -package dev.jorisjonkers.deploykit.emf.syntax; - -import dev.jorisjonkers.deploykit.emf.syntax.linking.ProjectIntentScopes; -import dev.jorisjonkers.deploykit.emf.syntax.linking.UnlinkedNames; -import dev.jorisjonkers.deploykit.emf.syntax.values.ProjectIntentValueConverters; -import org.eclipse.xtext.conversion.IValueConverterService; -import org.eclipse.xtext.linking.ILinkingDiagnosticMessageProvider; -import org.eclipse.xtext.scoping.IScopeProvider; - -/** Registers the components this language runs with, outside the Eclipse extension registry. */ -public class ProjectIntentRuntimeModule extends AbstractProjectIntentRuntimeModule { - - /** Quotes are syntax and a boolean is a boolean: see {@link ProjectIntentValueConverters}. */ - @Override - public Class bindIValueConverterService() { - return ProjectIntentValueConverters.class; - } - - /** A route's and a scrape's names link inside their Application: see {@link ProjectIntentScopes}. */ - @Override - public Class bindIScopeProvider() { - return ProjectIntentScopes.class; - } - - /** A name that links to nothing carries its specification code: see {@link UnlinkedNames}. */ - public Class bindILinkingDiagnosticMessageProvider() { - return UnlinkedNames.class; - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentStandaloneSetup.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentStandaloneSetup.java deleted file mode 100644 index 2023b8eff..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/ProjectIntentStandaloneSetup.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * generated by Xtext - */ -package dev.jorisjonkers.deploykit.emf.syntax; - -/** - * Initialization support for running Xtext languages without Equinox extension registry. - */ -public class ProjectIntentStandaloneSetup extends ProjectIntentStandaloneSetupGenerated { - - public static void doSetup() { - new ProjectIntentStandaloneSetup().createInjectorAndDoEMFRegistration(); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSource.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSource.java deleted file mode 100644 index 8ac67d905..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSource.java +++ /dev/null @@ -1,352 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.blocks; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Deque; -import java.util.List; -import java.util.Queue; -import java.util.stream.Collectors; -import org.antlr.runtime.CommonToken; -import org.antlr.runtime.Token; -import org.antlr.runtime.TokenSource; - -/** - * Turns the block structure of the authored YAML into the synthetic BEGIN and END tokens the grammar - * reads, so the grammar states the model's shape rather than the file's layout - * (emf/docs/architecture.md#concrete-syntax). - * - *

A scalar introduced by {@code >} or {@code |} is folded: the indented lines under it become one - * scalar token, so the grammar reads a value rather than a layout. - * - *

A line indented further than the line before it opens a block, and every level it falls back - * closes one. A dash opens a block of its own around the item that follows it, so the first key of - * an item sits in the same block as the keys under it. A flow collection opens and closes a block on - * one line, and the comma between its entries becomes whitespace. Inside a flow collection - * indentation says nothing, so it is not read. - */ -public class BlockTokenSource implements TokenSource { - - private final TokenSource delegate; - /** The colon that ends a key, after which a value of several words is one plain scalar. */ - private static final String KEY = ":"; - - private final BlockTokens types; - private final Deque blocks = new ArrayDeque<>(); - private final Queue pending = new ArrayDeque<>(); - /** Tokens read ahead of the one being decided and handed back, which are read before the delegate's next. */ - private final Deque ahead = new ArrayDeque<>(); - - private boolean lineStart = true; - private boolean afterDash = false; - private int flowDepth = 0; - private int lineColumn = 0; - private int colonLine = -1; - - public BlockTokenSource(TokenSource delegate, BlockTokens types) { - this.delegate = delegate; - this.types = types; - blocks.push(0); - } - - @Override - public Token nextToken() { - while (pending.isEmpty()) { - read(pull()); - } - return pending.remove(); - } - - /** The next token: one handed back first, then the delegate's. */ - private Token pull() { - return ahead.isEmpty() ? delegate.nextToken() : ahead.pop(); - } - - @Override - public String getSourceName() { - return delegate.getSourceName(); - } - - private void read(Token token) { - if (token.getType() == Token.EOF) { - closeTo(0, token); - pending.add(token); - } else if (token.getType() == types.whitespace() || token.getType() == types.comment()) { - lineStart |= token.getText().indexOf('\n') >= 0; - pending.add(token); - } else if (token.getType() == types.separator()) { - pending.add(hidden(token)); - } else { - significant(token); - } - } - - private void significant(Token token) { - if (lineStart && flowDepth == 0) { - indent(token); - lineColumn = token.getCharPositionInLine(); - } - lineStart = false; - if (token.getType() == types.fold()) { - folded(token); - return; - } - if (token.getLine() == colonLine && plain(token)) { - return; - } - colonLine = KEY.equals(token.getText()) ? token.getLine() : -1; - if (types.opensFlow(token.getType())) { - afterDash = false; - flowDepth++; - pending.add(marker(types.begin(), token)); - // The brace stays in the stream as whitespace, so every character still has its token. - pending.add(hidden(token)); - } else if (types.closesFlow(token.getType())) { - flowDepth--; - pending.add(marker(types.end(), token)); - pending.add(hidden(token)); - } else { - if (afterDash) { - afterDash = false; - blocks.push(token.getCharPositionInLine()); - pending.add(marker(types.begin(), token)); - } - afterDash = token.getType() == types.dash(); - if (afterDash) { - pending.add(token); - } else { - joined(token); - } - } - } - - /** - * A plain scalar whose parts a colon or a comma joins with no space between them: the parts become - * one scalar token spanning them, as YAML reads them. A colon is content where no space follows it - * ({@code 0.0.0.0:80}, {@code http://x}), and a comma wherever no flow collection is open ({@code - * - --a=b,c}). A token nothing joins is left as it is, and a colon that ends a key is still read as - * one. - */ - private void joined(Token first) { - Token last = first; - Token next = pull(); - while (touches(next)) { - if (inScalar(last) || inScalar(next)) { - last = next; - next = pull(); - } else if (KEY.equals(next.getText())) { - Token after = pull(); - if (!touches(after)) { - ahead.push(after); - break; - } - last = after; - next = pull(); - } else { - break; - } - } - emit(first, last); - read(next); - } - - /** Whether {@code token} is a comma YAML reads as content: one outside any flow collection. */ - private boolean inScalar(Token token) { - return flowDepth == 0 && token.getType() == types.separator(); - } - - /** {@code first} as it is, or with every token up to {@code last} as one scalar. */ - private void emit(Token first, Token last) { - pending.add(first == last ? first : spanning(first, last)); - } - - /** - * Whether {@code next} can be part of the scalar the token before it ends: anything but the end of - * the file, a space, a comment or a bracket. Every character of the file has its token, so a token - * that is none of those starts where the one before it ends. - */ - private boolean touches(Token next) { - int type = next.getType(); - return type != Token.EOF - && type != types.whitespace() - && type != types.comment() - && !types.opensFlow(type) - && !types.closesFlow(type); - } - - /** One scalar token covering the source from {@code first} to {@code last}, where {@code first} sits. */ - private CommonToken spanning(Token first, Token last) { - CommonToken start = (CommonToken) first; - CommonToken end = (CommonToken) last; - CommonToken scalar = new CommonToken( - types.scalar(), start.getInputStream().substring(start.getStartIndex(), end.getStopIndex())); - scalar.setLine(start.getLine()); - scalar.setCharPositionInLine(start.getCharPositionInLine()); - scalar.setStartIndex(start.getStartIndex()); - scalar.setStopIndex(end.getStopIndex()); - return scalar; - } - - /** - * A plain scalar of several words, from the value after a key to the end of its line, or in a flow - * collection to the next separator: the words become one scalar token spanning them, so the grammar - * reads a value rather than its words. A value of one word is left as the token it is, so a keyword - * and a vocabulary literal still read as themselves. Returns whether it wrote the value. - */ - private boolean plain(Token first) { - colonLine = -1; - if (types.opensFlow(first.getType()) || types.closesFlow(first.getType()) || first.getType() == types.dash()) { - return false; - } - List words = new ArrayList<>(List.of(first)); - List between = new ArrayList<>(); - Token next = pull(); - while (continues(next)) { - if (next.getType() == types.whitespace()) { - between.add(next); - } else { - between.clear(); - words.add(next); - } - next = pull(); - } - if (words.size() == 1) { - pending.add(first); - afterDash = false; - } else { - pending.add(spanning(first, words.get(words.size() - 1))); - afterDash = false; - } - between.forEach(this::read); - read(next); - return true; - } - - /** Whether {@code token} is still part of a plain value: on its line, and before a separator in a flow. */ - private boolean continues(Token token) { - if (token.getType() == Token.EOF || token.getType() == types.comment()) { - return false; - } - if (token.getType() == types.whitespace()) { - return token.getText().indexOf('\n') < 0; - } - return flowDepth == 0 || !(token.getType() == types.separator() || types.closesFlow(token.getType())); - } - - /** - * One scalar from the lines under a fold marker: every line indented further than the key's own - * line, with the indentation removed, joined by a space for {@code >} and by a line break for - * {@code |}. A trailing {@code -} drops the final line break, as YAML says it does. - */ - private void folded(Token fold) { - CommonToken marker = (CommonToken) fold; - List trailing = new ArrayList<>(); - Token last = marker; - Token next = pull(); - while (next.getType() != Token.EOF && inBlock(next)) { - if (next.getType() == types.whitespace()) { - trailing.add(next); - } else { - trailing.clear(); - last = next; - } - next = pull(); - } - int end = ((CommonToken) last).getStopIndex(); - String raw = marker.getInputStream().substring(marker.getStartIndex(), end); - // The token's text is the source it covers, so every node after it sits where its text is; - // the value the lines fold to is the value converter's to read (valueOf). - CommonToken scalar = new CommonToken(types.scalar(), raw); - scalar.setLine(marker.getLine()); - scalar.setCharPositionInLine(marker.getCharPositionInLine()); - scalar.setStartIndex(marker.getStartIndex()); - scalar.setStopIndex(end); - pending.add(scalar); - lineStart = true; - trailing.forEach(this::read); - read(next); - } - - /** - * Whether {@code token} still belongs to the block under the fold marker: whitespace always, and - * anything else while it is indented further than the key that opened the block. A {@code #} inside - * the block is content, as YAML says it is; one at or left of the key is a comment on what follows. - */ - private boolean inBlock(Token token) { - return token.getType() == types.whitespace() || token.getCharPositionInLine() > lineColumn; - } - - /** - * The value a scalar token's text stands for: a block scalar's lines folded as its marker says, and - * any other text as it is. Only a block scalar opens on {@code >} or {@code |}, which no plain - * scalar may. - */ - public static String valueOf(String text) { - if (text.isEmpty() || (text.charAt(0) != '>' && text.charAt(0) != '|')) { - return text; - } - return fold(text.length() > 1 && text.charAt(1) == '-' ? text.substring(0, 2) : text.substring(0, 1), text); - } - - /** - * The value of a block scalar, from the marker's own line onwards: the lines under it with their - * common indentation removed, - * joined by a line break under {@code |} and by a space under {@code >}, where a blank line is - * the paragraph break the subset does not carry. A trailing {@code -} drops the final line break. - */ - private static String fold(String marker, String raw) { - List lines = new ArrayList<>(List.of(raw.split("\n", -1))); - lines.remove(0); // the marker's own line, which carries no content - int indent = lines.stream() - .filter(line -> !line.isBlank()) - .mapToInt(line -> line.length() - line.stripLeading().length()) - .min() - .orElse(0); - List content = lines.stream() - .map(line -> line.isBlank() ? "" : line.substring(indent).stripTrailing()) - .toList(); - String joined = marker.startsWith("|") - ? String.join("\n", content) - : content.stream().filter(line -> !line.isEmpty()).collect(Collectors.joining(" ")); - return marker.endsWith("-") ? joined : joined + "\n"; - } - - /** Opens or closes the blocks the column of the line's first token asks for. */ - private void indent(Token token) { - int column = token.getCharPositionInLine(); - if (column > current()) { - blocks.push(column); - pending.add(marker(types.begin(), token)); - } else { - closeTo(column, token); - } - } - - private void closeTo(int column, Token token) { - while (current() > column) { - blocks.pop(); - pending.add(marker(types.end(), token)); - } - } - - private int current() { - return blocks.element(); - } - - /** A zero-width token at {@code at}, so the node model's text stays the file's. The lexer's tokens are - * {@link CommonToken}s, the end of file included. */ - private Token marker(int type, Token at) { - CommonToken marker = new CommonToken(type, ""); - marker.setLine(at.getLine()); - marker.setCharPositionInLine(at.getCharPositionInLine()); - int start = ((CommonToken) at).getStartIndex(); - marker.setStartIndex(start); - marker.setStopIndex(start - 1); - return marker; - } - - private Token hidden(Token token) { - CommonToken copy = new CommonToken(token); - copy.setType(types.whitespace()); - return copy; - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokens.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokens.java deleted file mode 100644 index 222d1a0de..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokens.java +++ /dev/null @@ -1,42 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.blocks; - -/** - * The token types {@link BlockTokenSource} rewrites, as the generated parser numbers them. - * - * @param begin the synthetic token that opens a block - * @param end the synthetic token that closes one - * @param whitespace whitespace, which carries the line breaks and the indentation - * @param comment a comment, which is hidden and never opens a block - * @param dash the marker of a block sequence item - * @param flowBegin an opening brace - * @param flowEnd a closing brace - * @param listBegin an opening bracket - * @param listEnd a closing bracket - * @param separator the comma between flow entries - * @param fold the marker of a scalar written over several lines - * @param scalar a plain scalar, which is what a folded one becomes - */ -public record BlockTokens( - int begin, - int end, - int whitespace, - int comment, - int dash, - int flowBegin, - int flowEnd, - int listBegin, - int listEnd, - int separator, - int fold, - int scalar) { - - /** Whether {@code type} opens a flow collection, which is a block on one line. */ - public boolean opensFlow(int type) { - return type == flowBegin || type == listBegin; - } - - /** Whether {@code type} closes one. */ - public boolean closesFlow(int type) { - return type == flowEnd || type == listEnd; - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/linking/ProjectIntentScopes.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/linking/ProjectIntentScopes.java deleted file mode 100644 index e8d407b3e..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/linking/ProjectIntentScopes.java +++ /dev/null @@ -1,120 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.linking; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.DeliveryPolicy; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ForwardAuth; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import java.util.List; -import java.util.Map; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.emf.ecore.resource.ResourceSet; -import org.eclipse.xtext.EcoreUtil2; -import org.eclipse.xtext.naming.QualifiedName; -import org.eclipse.xtext.scoping.IScope; -import org.eclipse.xtext.scoping.IScopeProvider; -import org.eclipse.xtext.scoping.Scopes; - -/** - * What a route's or a scrape's names can link to (spec/v1/10-project-intent.md#what-is-checked): a - * Process of the Application that holds it, and a surface that Process provides. Nothing outside the - * Application is in scope; a dependency edge's names reach other documents and are not linked here. - * - *

A tier's proxy, a name of the delivery machinery and the telemetry collector reach another - * document: every Application a project file read in the same set declares, each named - * {@code /}, so a name links only to the Application the named Project - * declares and an id alone binds no privileged role (spec/v1/14-platform-intent.md#privileged-roles). The collector's scope holds only the Applications whose - * Process provides an {@code otlp} surface, so one that receives nothing is a name that links to - * nothing, and is refused as one (spec/v1/14-platform-intent.md#telemetry). The Release Gate's scope - * holds the Applications that provide {@code http}, which is where every Canary asks it, and the - * Secret Store's the same, which is where every grant is read from - * (spec/v1/14-platform-intent.md#the-secret-store). - */ -public class ProjectIntentScopes implements IScopeProvider { - - @Override - public IScope getScope(EObject context, EReference reference) { - if (reference == ProjectIntentPackage.Literals.FORWARD_AUTH__PROVIDER) { - return providing(context, ((ForwardAuth) context).getSurface()); - } - if (reference == ProjectIntentPackage.Literals.TELEMETRY_POLICY__COLLECTOR) { - return providing(context, OTLP); - } - if (reference == ProjectIntentPackage.Literals.DELIVERY_POLICY__REPORTER) { - return besideTheGate((DeliveryPolicy) context); - } - if (reference == ProjectIntentPackage.Literals.DELIVERY_POLICY__GATE - || reference == ProjectIntentPackage.Literals.PLATFORM__SECRET_STORE) { - return providing(context, HTTP); - } - if (reference.getEReferenceType() == ProjectIntentPackage.Literals.APPLICATION) { - return Scopes.scopeFor( - applications(context.eResource().getResourceSet()), ProjectIntentScopes::held, IScope.NULLSCOPE); - } - if (reference.getEReferenceType() == ProjectIntentPackage.Literals.PROCESS) { - Application application = EcoreUtil2.getContainerOfType(context, Application.class); - return Scopes.scopeFor(application.getProcesses()); - } - EObject process = (EObject) context.eGet(context.eClass().getEStructuralFeature("process")); - if (process.eIsProxy()) { - return IScope.NULLSCOPE; - } - List provides = (List) process.eGet(ProjectIntentPackage.Literals.PROCESS__PROVIDES); - return Scopes.scopeFor( - provides.stream().map(EObject.class::cast).toList(), - surface -> QualifiedName.create(String.valueOf(((Map.Entry) surface).getKey())), - IScope.NULLSCOPE); - } - - /** The Applications of the set one of whose Processes provides {@code surface}. */ - private static IScope providing(EObject context, String surface) { - return providing(applications(context.eResource().getResourceSet()), surface); - } - - /** Those of {@code candidates} one of whose Processes provides {@code surface}. */ - private static IScope providing(List candidates, String surface) { - return Scopes.scopeFor( - candidates.stream() - .filter(application -> application.getProcesses().stream() - .anyMatch(process -> process.getProvides().containsKey(surface))) - .toList(), - ProjectIntentScopes::held, - IScope.NULLSCOPE); - } - - /** The name a privileged role links an Application by: its Project, then its id. */ - private static QualifiedName held(EObject application) { - Project project = EcoreUtil2.getContainerOfType(application, Project.class); - return QualifiedName.create(project.getProject() + "/" + ((Application) application).getId()); - } - - /** - * The Applications the Reporter may be: those declared in the project document that - * declares the Release Gate, one of whose Processes provides {@code http}. The name alone - * binds nothing, so a project file that declares an Application called what the platform - * calls its Reporter gains nothing by it (spec/v1/14-platform-intent.md#delivery-policy). - */ - private static IScope besideTheGate(DeliveryPolicy delivery) { - Application gate = delivery.getGate(); - if (gate == null || gate.eIsProxy()) { - return IScope.NULLSCOPE; - } - return providing(EcoreUtil2.getContainerOfType(gate, Project.class).getApplications(), HTTP); - } - - /** The surface a telemetry collector receives on. */ - private static final String OTLP = "otlp"; - - /** The surface the Release Gate answers every Canary on, and the Secret Store every grant on. */ - private static final String HTTP = "http"; - - /** Every Application the project documents of {@code documents} declare, in the order they were read. */ - private static List applications(ResourceSet documents) { - return documents.getResources().stream() - .flatMap(resource -> resource.getContents().stream()) - .filter(Project.class::isInstance) - .flatMap(project -> ((Project) project).getApplications().stream()) - .toList(); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/linking/UnlinkedNames.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/linking/UnlinkedNames.java deleted file mode 100644 index 2e263ab11..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/linking/UnlinkedNames.java +++ /dev/null @@ -1,184 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.linking; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import java.util.List; -import java.util.Map; -import java.util.Set; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.xtext.diagnostics.DiagnosticMessage; -import org.eclipse.xtext.diagnostics.Severity; -import org.eclipse.xtext.linking.impl.LinkingDiagnosticMessageProvider; -import org.eclipse.xtext.nodemodel.util.NodeModelUtils; - -/** - * A name that links to nothing, as the code the specification gives it: `E_UNKNOWN_PROCESS` for a - * Process, `E_UNKNOWN_SURFACE` for a surface, `E_UNKNOWN_TIER_PROXY` for a tier's proxy Application, - * `E_UNKNOWN_MACHINERY` for an Application the delivery machinery names, `E_UNKNOWN_API_HOLDER` for one - * the platform admits to hold Kubernetes API access, `E_UNKNOWN_TELEMETRY_COLLECTOR` for - * the Application the telemetry block names, `E_UNKNOWN_SECRET_STORE` for the Application the Secret - * Store names. A surface whose Process did not link is not reported - * as well: there is no Process to look it up in, and the Process's own refusal already says so. - */ -public class UnlinkedNames extends LinkingDiagnosticMessageProvider { - - public static final String UNKNOWN_PROCESS = "E_UNKNOWN_PROCESS"; - public static final String UNKNOWN_SURFACE = "E_UNKNOWN_SURFACE"; - public static final String UNKNOWN_TIER_PROXY = "E_UNKNOWN_TIER_PROXY"; - public static final String UNKNOWN_MACHINERY = "E_UNKNOWN_MACHINERY"; - public static final String UNKNOWN_API_HOLDER = "E_UNKNOWN_API_HOLDER"; - public static final String UNKNOWN_TELEMETRY_COLLECTOR = "E_UNKNOWN_TELEMETRY_COLLECTOR"; - public static final String UNKNOWN_METRICS_STACK = "E_UNKNOWN_METRICS_STACK"; - public static final String UNKNOWN_RELEASE_GATE = "E_UNKNOWN_RELEASE_GATE"; - public static final String UNKNOWN_REPORTER = "E_UNKNOWN_REPORTER"; - public static final String UNKNOWN_SECRET_STORE = "E_UNKNOWN_SECRET_STORE"; - public static final String UNKNOWN_FORWARD_AUTH_PROVIDER = "E_UNKNOWN_FORWARD_AUTH_PROVIDER"; - public static final String UNKNOWN_SIGN_IN_PROVIDER = "E_UNKNOWN_SIGN_IN_PROVIDER"; - public static final String UNKNOWN_MONITORING_APPLICATION = "E_UNKNOWN_MONITORING_APPLICATION"; - public static final String UNKNOWN_CRITICAL_APPLICATION = "E_UNKNOWN_CRITICAL_APPLICATION"; - - /** The codes of names that link into another document, reported only when the documents are read together. */ - public static final Set ACROSS_DOCUMENTS = Set.of( - UNKNOWN_TIER_PROXY, - UNKNOWN_MACHINERY, - UNKNOWN_API_HOLDER, - UNKNOWN_TELEMETRY_COLLECTOR, - UNKNOWN_METRICS_STACK, - UNKNOWN_RELEASE_GATE, - UNKNOWN_REPORTER, - UNKNOWN_SECRET_STORE, - UNKNOWN_FORWARD_AUTH_PROVIDER, - UNKNOWN_SIGN_IN_PROVIDER, - UNKNOWN_MONITORING_APPLICATION, - UNKNOWN_CRITICAL_APPLICATION); - - @Override - public DiagnosticMessage getUnresolvedProxyMessage(ILinkingDiagnosticContext context) { - String name = context.getLinkText(); - EReference reference = context.getReference(); - if (reference == ProjectIntentPackage.Literals.SIGN_IN__PROVIDER) { - return new DiagnosticMessage( - "no project file declares the sign-in provider " + name, Severity.ERROR, UNKNOWN_SIGN_IN_PROVIDER); - } - // A name under a Project the set does not compose is one only a set that holds it can judge - // (spec/v1/14-platform-intent.md#privileged-roles), so it is not refused here. - if (COMPOSED_ONLY.containsKey(reference)) { - return composes(context.getContext(), name) - ? new DiagnosticMessage( - "no project file declares the Application " + name + COMPOSED_ONLY.get(reference), - Severity.ERROR, - CODES.get(reference), - suffix(context.getContext(), reference, name)) - : null; - } - if (context.getReference() == ProjectIntentPackage.Literals.DELIVERY_POLICY__MACHINERY) { - return new DiagnosticMessage( - "no project file declares the Application " + name + " the delivery machinery names", - Severity.ERROR, - UNKNOWN_MACHINERY); - } - if (context.getReference() == ProjectIntentPackage.Literals.API_ACCESS_POLICY__HOLDERS - || context.getReference() == ProjectIntentPackage.Literals.API_ACCESS_POLICY__NAMESPACE_HOLDERS) { - return new DiagnosticMessage( - "no project file declares the Application " + name - + " the platform admits to hold Kubernetes API access", - Severity.ERROR, - UNKNOWN_API_HOLDER); - } - if (context.getReference() == ProjectIntentPackage.Literals.TELEMETRY_POLICY__COLLECTOR) { - return new DiagnosticMessage( - "no project file declares an Application " + name + " whose Process provides an `otlp` surface", - Severity.ERROR, - UNKNOWN_TELEMETRY_COLLECTOR); - } - if (context.getReference() == ProjectIntentPackage.Literals.TELEMETRY_POLICY__METRICS) { - return new DiagnosticMessage( - "no project file declares the Application " + name + " the metrics stack names", - Severity.ERROR, - UNKNOWN_METRICS_STACK); - } - if (context.getReference() == ProjectIntentPackage.Literals.DELIVERY_POLICY__GATE) { - return new DiagnosticMessage( - "no project file declares an Application " + name + " whose Process provides an `http` surface", - Severity.ERROR, - UNKNOWN_RELEASE_GATE); - } - if (context.getReference() == ProjectIntentPackage.Literals.DELIVERY_POLICY__REPORTER) { - return new DiagnosticMessage( - "the project file that declares the Release Gate declares no Application " + name - + " whose Process provides an `http` surface", - Severity.ERROR, - UNKNOWN_REPORTER); - } - if (context.getReference() == ProjectIntentPackage.Literals.PLATFORM__SECRET_STORE) { - return new DiagnosticMessage( - "no project file declares an Application " + name + " whose Process provides an `http` surface", - Severity.ERROR, - UNKNOWN_SECRET_STORE); - } - if (context.getReference().getEReferenceType() == ProjectIntentPackage.Literals.APPLICATION) { - return new DiagnosticMessage( - "no project file declares the Application " + name, Severity.ERROR, UNKNOWN_TIER_PROXY); - } - if (context.getReference().getEReferenceType() == ProjectIntentPackage.Literals.PROCESS) { - return new DiagnosticMessage( - "no Process of this Application is named " + name, Severity.ERROR, UNKNOWN_PROCESS); - } - EObject owner = context.getContext(); - EObject process = (EObject) owner.eGet(owner.eClass().getEStructuralFeature("process")); - if (process.eIsProxy()) { - return null; - } - return new DiagnosticMessage("the Process provides no surface named " + name, Severity.ERROR, UNKNOWN_SURFACE); - } - - /** The references a set judges only where it composes the named Project, each by what the name stands for. */ - private static final Map COMPOSED_ONLY = Map.of( - ProjectIntentPackage.Literals.FORWARD_AUTH__PROVIDER, " that answers the forward-auth surface", - ProjectIntentPackage.Literals.MONITORING__GRAFANA, " the monitoring stack's grafana names", - ProjectIntentPackage.Literals.MONITORING__PROMETHEUS, " the monitoring stack's prometheus names", - ProjectIntentPackage.Literals.MONITORING__ALERTMANAGER, " the monitoring stack's alertmanager names", - ProjectIntentPackage.Literals.MONITORING_STORES__LOKI, " the monitoring stack's stores/loki names", - ProjectIntentPackage.Literals.MONITORING_STORES__TEMPO, " the monitoring stack's stores/tempo names", - ProjectIntentPackage.Literals.MONITORING_STORES__PYROSCOPE, - " the monitoring stack's stores/pyroscope names", - ProjectIntentPackage.Literals.PRIORITY_POLICY__CRITICAL_APPLICATIONS, " the platform names critical"); - - private static final Map CODES = Map.of( - ProjectIntentPackage.Literals.FORWARD_AUTH__PROVIDER, UNKNOWN_FORWARD_AUTH_PROVIDER, - ProjectIntentPackage.Literals.MONITORING__GRAFANA, UNKNOWN_MONITORING_APPLICATION, - ProjectIntentPackage.Literals.MONITORING__PROMETHEUS, UNKNOWN_MONITORING_APPLICATION, - ProjectIntentPackage.Literals.MONITORING__ALERTMANAGER, UNKNOWN_MONITORING_APPLICATION, - ProjectIntentPackage.Literals.MONITORING_STORES__LOKI, UNKNOWN_MONITORING_APPLICATION, - ProjectIntentPackage.Literals.MONITORING_STORES__TEMPO, UNKNOWN_MONITORING_APPLICATION, - ProjectIntentPackage.Literals.MONITORING_STORES__PYROSCOPE, UNKNOWN_MONITORING_APPLICATION, - ProjectIntentPackage.Literals.PRIORITY_POLICY__CRITICAL_APPLICATIONS, UNKNOWN_CRITICAL_APPLICATION); - - /** Whether a project file of the set declares the Project {@code name} is written under. */ - private static boolean composes(EObject owner, String name) { - String project = name.substring(0, Math.max(name.indexOf('/'), 0)); - return owner.eResource().getResourceSet().getResources().stream() - .flatMap(resource -> resource.getContents().stream()) - .anyMatch(root -> root instanceof Project declared && project.equals(declared.getProject())); - } - - /** - * Where below its owner the name sits, as the diagnostic's path writes it: nothing where the owner - * is the name's own block, the key of a role, and the key and position of a list's entry. - */ - private static String suffix(EObject owner, EReference reference, String name) { - if (reference == ProjectIntentPackage.Literals.FORWARD_AUTH__PROVIDER) { - return ""; - } - if (!reference.isMany()) { - return "/" + reference.getName(); - } - List written = NodeModelUtils.findNodesForFeature(owner, reference).stream() - .map(NodeModelUtils::getTokenText) - .toList(); - // A name written in quotes is not written as its text: such a name is placed last. - int found = written.indexOf(name); - return "/" + reference.getName() + "/" + (found < 0 ? written.size() - 1 : found); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ClusterStateTokenSource.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ClusterStateTokenSource.java deleted file mode 100644 index 095228926..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ClusterStateTokenSource.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * generated by Xtext, then owned here: the block rules are the project language's, not the generator's. - */ -package dev.jorisjonkers.deploykit.emf.syntax.parser.antlr; - -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokenSource; -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokens; -import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.internal.InternalClusterStateParser; -import org.antlr.runtime.TokenSource; - -public class ClusterStateTokenSource extends BlockTokenSource { - - /** The same block tokens as the project language's, as this language's generated parser numbers them. */ - public static final BlockTokens TYPES = new BlockTokens( - InternalClusterStateParser.RULE_BEGIN, - InternalClusterStateParser.RULE_END, - InternalClusterStateParser.RULE_WS, - InternalClusterStateParser.RULE_SL_COMMENT, - InternalClusterStateParser.RULE_DASH, - InternalClusterStateParser.RULE_FLOW_BEGIN, - InternalClusterStateParser.RULE_FLOW_END, - InternalClusterStateParser.RULE_LIST_BEGIN, - InternalClusterStateParser.RULE_LIST_END, - InternalClusterStateParser.RULE_FLOW_SEP, - InternalClusterStateParser.RULE_FOLD, - InternalClusterStateParser.RULE_SCALAR); - - public ClusterStateTokenSource(TokenSource delegate) { - super(delegate, TYPES); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ImagesLockTokenSource.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ImagesLockTokenSource.java deleted file mode 100644 index c3c691db5..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ImagesLockTokenSource.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * generated by Xtext, then owned here: the block rules are the project language's, not the generator's. - */ -package dev.jorisjonkers.deploykit.emf.syntax.parser.antlr; - -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokenSource; -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokens; -import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.internal.InternalImagesLockParser; -import org.antlr.runtime.TokenSource; - -public class ImagesLockTokenSource extends BlockTokenSource { - - /** The same block tokens as the project language's, as this language's generated parser numbers them. */ - public static final BlockTokens TYPES = new BlockTokens( - InternalImagesLockParser.RULE_BEGIN, - InternalImagesLockParser.RULE_END, - InternalImagesLockParser.RULE_WS, - InternalImagesLockParser.RULE_SL_COMMENT, - InternalImagesLockParser.RULE_DASH, - InternalImagesLockParser.RULE_FLOW_BEGIN, - InternalImagesLockParser.RULE_FLOW_END, - InternalImagesLockParser.RULE_LIST_BEGIN, - InternalImagesLockParser.RULE_LIST_END, - InternalImagesLockParser.RULE_FLOW_SEP, - InternalImagesLockParser.RULE_FOLD, - InternalImagesLockParser.RULE_SCALAR); - - public ImagesLockTokenSource(TokenSource delegate) { - super(delegate, TYPES); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/MigrationProofTokenSource.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/MigrationProofTokenSource.java deleted file mode 100644 index eea1bce1d..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/MigrationProofTokenSource.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * generated by Xtext, then owned here: the block rules are the project language's, not the generator's. - */ -package dev.jorisjonkers.deploykit.emf.syntax.parser.antlr; - -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokenSource; -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokens; -import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.internal.InternalMigrationProofParser; -import org.antlr.runtime.TokenSource; - -public class MigrationProofTokenSource extends BlockTokenSource { - - /** The same block tokens as the project language's, as this language's generated parser numbers them. */ - public static final BlockTokens TYPES = new BlockTokens( - InternalMigrationProofParser.RULE_BEGIN, - InternalMigrationProofParser.RULE_END, - InternalMigrationProofParser.RULE_WS, - InternalMigrationProofParser.RULE_SL_COMMENT, - InternalMigrationProofParser.RULE_DASH, - InternalMigrationProofParser.RULE_FLOW_BEGIN, - InternalMigrationProofParser.RULE_FLOW_END, - InternalMigrationProofParser.RULE_LIST_BEGIN, - InternalMigrationProofParser.RULE_LIST_END, - InternalMigrationProofParser.RULE_FLOW_SEP, - InternalMigrationProofParser.RULE_FOLD, - InternalMigrationProofParser.RULE_SCALAR); - - public MigrationProofTokenSource(TokenSource delegate) { - super(delegate, TYPES); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/NodeContractTokenSource.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/NodeContractTokenSource.java deleted file mode 100644 index d2e8adc1b..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/NodeContractTokenSource.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * generated by Xtext, then owned here: the block rules are the project language's, not the generator's. - */ -package dev.jorisjonkers.deploykit.emf.syntax.parser.antlr; - -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokenSource; -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokens; -import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.internal.InternalNodeContractParser; -import org.antlr.runtime.TokenSource; - -public class NodeContractTokenSource extends BlockTokenSource { - - /** The same block tokens as the project language's, as this language's generated parser numbers them. */ - public static final BlockTokens TYPES = new BlockTokens( - InternalNodeContractParser.RULE_BEGIN, - InternalNodeContractParser.RULE_END, - InternalNodeContractParser.RULE_WS, - InternalNodeContractParser.RULE_SL_COMMENT, - InternalNodeContractParser.RULE_DASH, - InternalNodeContractParser.RULE_FLOW_BEGIN, - InternalNodeContractParser.RULE_FLOW_END, - InternalNodeContractParser.RULE_LIST_BEGIN, - InternalNodeContractParser.RULE_LIST_END, - InternalNodeContractParser.RULE_FLOW_SEP, - InternalNodeContractParser.RULE_FOLD, - InternalNodeContractParser.RULE_SCALAR); - - public NodeContractTokenSource(TokenSource delegate) { - super(delegate, TYPES); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/PlatformIntentTokenSource.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/PlatformIntentTokenSource.java deleted file mode 100644 index 4095fcd8e..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/PlatformIntentTokenSource.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * generated by Xtext, then owned here: the block rules are the project language's, not the generator's. - */ -package dev.jorisjonkers.deploykit.emf.syntax.parser.antlr; - -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokenSource; -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokens; -import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.internal.InternalPlatformIntentParser; -import org.antlr.runtime.TokenSource; - -public class PlatformIntentTokenSource extends BlockTokenSource { - - /** The same block tokens as the project language's, as this language's generated parser numbers them. */ - public static final BlockTokens TYPES = new BlockTokens( - InternalPlatformIntentParser.RULE_BEGIN, - InternalPlatformIntentParser.RULE_END, - InternalPlatformIntentParser.RULE_WS, - InternalPlatformIntentParser.RULE_SL_COMMENT, - InternalPlatformIntentParser.RULE_DASH, - InternalPlatformIntentParser.RULE_FLOW_BEGIN, - InternalPlatformIntentParser.RULE_FLOW_END, - InternalPlatformIntentParser.RULE_LIST_BEGIN, - InternalPlatformIntentParser.RULE_LIST_END, - InternalPlatformIntentParser.RULE_FLOW_SEP, - InternalPlatformIntentParser.RULE_FOLD, - InternalPlatformIntentParser.RULE_SCALAR); - - public PlatformIntentTokenSource(TokenSource delegate) { - super(delegate, TYPES); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ProjectIntentTokenSource.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ProjectIntentTokenSource.java deleted file mode 100644 index 248eba808..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/parser/antlr/ProjectIntentTokenSource.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * generated by Xtext, then owned here: the block rules are this language's, not the generator's. - */ -package dev.jorisjonkers.deploykit.emf.syntax.parser.antlr; - -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokenSource; -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokens; -import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.internal.InternalProjectIntentParser; -import org.antlr.runtime.TokenSource; - -public class ProjectIntentTokenSource extends BlockTokenSource { - - public static final BlockTokens TYPES = new BlockTokens( - InternalProjectIntentParser.RULE_BEGIN, - InternalProjectIntentParser.RULE_END, - InternalProjectIntentParser.RULE_WS, - InternalProjectIntentParser.RULE_SL_COMMENT, - InternalProjectIntentParser.RULE_DASH, - InternalProjectIntentParser.RULE_FLOW_BEGIN, - InternalProjectIntentParser.RULE_FLOW_END, - InternalProjectIntentParser.RULE_LIST_BEGIN, - InternalProjectIntentParser.RULE_LIST_END, - InternalProjectIntentParser.RULE_FLOW_SEP, - InternalProjectIntentParser.RULE_FOLD, - InternalProjectIntentParser.RULE_SCALAR); - - public ProjectIntentTokenSource(TokenSource delegate) { - super(delegate, TYPES); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/schema/Shapes.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/schema/Shapes.java deleted file mode 100644 index 8573e1644..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/schema/Shapes.java +++ /dev/null @@ -1,353 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.schema; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.regex.Pattern; -import java.util.stream.Stream; -import java.util.stream.StreamSupport; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.xtext.AbstractElement; -import org.eclipse.xtext.AbstractRule; -import org.eclipse.xtext.Alternatives; -import org.eclipse.xtext.Assignment; -import org.eclipse.xtext.CompoundElement; -import org.eclipse.xtext.CrossReference; -import org.eclipse.xtext.EnumLiteralDeclaration; -import org.eclipse.xtext.EnumRule; -import org.eclipse.xtext.Grammar; -import org.eclipse.xtext.GrammarUtil; -import org.eclipse.xtext.Group; -import org.eclipse.xtext.Keyword; -import org.eclipse.xtext.ParserRule; -import org.eclipse.xtext.RuleCall; -import org.eclipse.xtext.UnorderedGroup; - -/** - * The shape of an authored file, checked against the grammar's own rules: which keys a mapping may - * hold, which it must, what each value may be. The grammar is read as data, so the schema is never - * written twice. Where the parser stops at its first error, this reads the whole file and names every - * node that is wrong by its JSON pointer, as the schema's refusals do. - */ -public final class Shapes { - - /** One refusal: the pointer to the node, and what is wrong with it. */ - public record Issue(String path, String message) {} - - private record Entry(String key, boolean required, List value) {} - - private record Form(String rule, String literal, boolean plain, Map entries, Entry any) {} - - private record Value(boolean sequence, List targets, List literals) {} - - /** An age public key: {@code age1} and 58 more characters of the bech32 alphabet. */ - private static final String AGE_RECIPIENT = "age1[02-9ac-hj-np-z]{58}"; - - /** The longest description: one short sentence, not a paragraph. */ - private static final int DESCRIPTION_LENGTH = 160; - - /** A description of one short sentence: neither empty nor a paragraph. */ - private static final Predicate DESCRIBED = - node -> !node.text.isEmpty() && node.text.length() <= DESCRIPTION_LENGTH; - - /** What a container runs: at least one word, none of them empty. */ - private static final Predicate COMMAND = - node -> !node.list.isEmpty() && node.list.stream().noneMatch(word -> word.text.isEmpty()); - - /** What a container is handed: at least one word, where an empty one is an argument too. */ - private static final Predicate ARGUMENTS = node -> !node.list.isEmpty(); - - /** - * Constraints the grammar cannot say, by the rule and key they hold: a count of at least one, a - * period in whole units, a description of one short sentence, what a container runs as at least one - * word, an optional key that is optional, and the age public key an off-cluster copy is encrypted to. - * Each is a value of its own, written where it is held, so building the table runs no code a test - * could tell apart from its absence. - */ - private static final Map> CONSTRAINTS = Map.ofEntries( - Map.entry("RateLimit.requests", node -> !node.text.matches("0+")), - Map.entry("RateLimit.per", node -> Pattern.matches("[1-9][0-9]*(s|m|h)", node.text)), - Map.entry("Application.description", DESCRIBED), - Map.entry("Process.description", DESCRIBED), - Map.entry("Process.command", COMMAND), - Map.entry("Sidecar.command", COMMAND), - Map.entry("Process.args", ARGUMENTS), - Map.entry("Sidecar.args", ARGUMENTS), - Map.entry("BlockKey.optional", node -> "true".equals(node.text)), - Map.entry("OffClusterCopy.recipient", node -> Pattern.matches(AGE_RECIPIENT, node.text))); - - private final Grammar grammar; - private final Map> forms = new HashMap<>(); - - private Shapes(Grammar grammar) { - this.grammar = grammar; - } - - /** Every refusal in {@code text} against {@code grammar}'s first rule. */ - public static List check(String text, Grammar grammar) { - List issues = new ArrayList<>(); - Yaml.Node root; - try { - root = Yaml.read(text); - } catch (Yaml.Unsupported e) { - issues.add(new Issue("", "outside the YAML subset: " + e.getMessage())); - return issues; - } catch (RuntimeException e) { - return List.of(); - } - Shapes shapes = new Shapes(grammar); - ParserRule start = (ParserRule) grammar.getRules().get(0); - shapes.candidates(root, new Value(false, List.of(start), List.of()), "", issues); - return issues; - } - - // ---- forms - - private List

formsOf(ParserRule rule) { - List known = forms.get(rule); - if (known == null) { - forms.put(rule, List.of()); - known = new ArrayList<>(); - flatten(rule.getAlternatives(), rule, (List) known); - forms.put(rule, known); - } - return known; - } - - private void flatten(AbstractElement element, ParserRule rule, List out) { - if (element instanceof Alternatives alternatives) { - alternatives.getElements().forEach(e -> flatten(e, rule, out)); - } else if (element instanceof RuleCall call) { - out.addAll(formsOf((ParserRule) call.getRule())); - } else { - Map entries = new LinkedHashMap<>(); - walk(element, entries); - Entry any = entries.isEmpty() ? anyKey(element) : null; - String literal = entries.isEmpty() && any == null ? firstKeyword(element) : null; - boolean plain = entries.isEmpty() && any == null && literal == null; - out.add(new Form(rule.getName(), literal, plain, entries, any)); - } - } - - /** The keyword a form is made of, when it is one word: {@code 'self'}, {@code 'none'}. */ - private static String firstKeyword(AbstractElement element) { - return Stream.concat( - Stream.of((EObject) element), - StreamSupport.stream(((Iterable) element::eAllContents).spliterator(), false)) - .filter(Keyword.class::isInstance) - .map(e -> ((Keyword) e).getValue()) - .findFirst() - .orElse(null); - } - - /** {@code key=Text ':' value=Port}: a mapping whose every key is data. */ - private static Entry anyKey(AbstractElement element) { - if (element instanceof Group group) { - List children = group.getElements(); - for (int i = 1; i < children.size(); i++) { - if (isColon(children.get(i))) { - return new Entry("*", true, children.subList(i + 1, children.size())); - } - } - } - return null; - } - - private static boolean isColon(AbstractElement element) { - return element instanceof Keyword keyword && keyword.getValue().equals(":"); - } - - private static boolean startsKey(List children, int i) { - return children.get(i) instanceof Keyword && i + 1 < children.size() && isColon(children.get(i + 1)); - } - - /** - * The keys of a form, in the order written. A key is required unless the group it opens is - * {@code ?}; the grammar never nests an unordered group inside an optional one. - */ - private void walk(AbstractElement element, Map entries) { - if (element instanceof UnorderedGroup group) { - group.getElements().forEach(child -> walk(child, entries)); - } else if (element instanceof Group group) { - boolean optional = "?".equals(group.getCardinality()); - List children = group.getElements(); - String key = null; - List value = new ArrayList<>(); - for (int i = 0; i < children.size(); i++) { - AbstractElement child = children.get(i); - if (startsKey(children, i)) { - close(key, optional, value, entries); - key = ((Keyword) child).getValue(); - value = new ArrayList<>(); - i++; - } else if (child instanceof UnorderedGroup) { - close(key, optional, value, entries); - key = null; - walk(child, entries); - } else if (key != null) { - value.add(child); - } - } - close(key, optional, value, entries); - } - } - - private static void close(String key, boolean optional, List value, Map entries) { - if (key != null) { - entries.put(key, new Entry(key, !optional, value)); - } - } - - // ---- values - - private Value describe(List elements) { - boolean[] dash = {false}; - List targets = new ArrayList<>(); - List literals = new ArrayList<>(); - elements.forEach(e -> scan(e, dash, targets, literals, false)); - return new Value(dash[0], targets, literals); - } - - private void scan( - AbstractElement element, - boolean[] dash, - List targets, - List literals, - boolean assigned) { - if (element instanceof Assignment assignment) { - scan(assignment.getTerminal(), dash, targets, literals, true); - } else if (element instanceof Keyword keyword) { - literals.add(keyword.getValue()); - } else if (element instanceof CrossReference) { - targets.add(textRule()); - } else if (element instanceof RuleCall call) { - if (assigned) { - targets.add(call.getRule()); - } else if ("DASH".equals(call.getRule().getName())) { - dash[0] = true; - } - } else { - ((CompoundElement) element).getElements().forEach(e -> scan(e, dash, targets, literals, assigned)); - } - } - - private AbstractRule textRule() { - return GrammarUtil.findRuleForName(grammar, "Text"); - } - - private void value(Yaml.Node node, List elements, String path, List out) { - Value value = describe(elements); - if (value.sequence()) { - if (!node.isList()) { - out.add(new Issue(path, "expected a sequence")); - return; - } - for (int i = 0; i < node.list.size(); i++) { - candidates(node.list.get(i), value, path + "/" + i, out); - } - } else { - candidates(node, value, path, out); - } - } - - private static boolean accepts(AbstractRule rule, Yaml.Node node) { - if (!node.isScalar()) { - return false; - } - if (rule instanceof EnumRule enumeration) { - return EcoreUtilLiterals.of(enumeration).contains(node.text) && !node.quoted; - } - return switch (rule.getName()) { - case "Port" -> !node.quoted && node.text.matches("[0-9]+"); - case "Bool" -> !node.quoted && (node.text.equals("true") || node.text.equals("false")); - default -> true; - }; - } - - private void candidates(Yaml.Node node, Value expected, String path, List out) { - if (node.isScalar() && !node.quoted && expected.literals().contains(node.text)) { - return; - } - List shapes = new ArrayList<>(); - for (AbstractRule target : expected.targets()) { - if (target instanceof ParserRule parser && !GrammarUtil.isDatatypeRule(parser)) { - shapes.addAll(formsOf(parser)); - } else if (accepts(target, node)) { - return; - } - } - if (node.isScalar()) { - for (Form form : shapes) { - if (form.plain() || !node.quoted && node.text.equals(form.literal())) { - return; - } - } - } else if (node.isMap()) { - List best = null; - for (Form form : shapes) { - if (form.plain() || form.literal() != null) { - continue; - } - List errors = new ArrayList<>(); - mapping(node, form, path, errors); - if (errors.isEmpty()) { - return; - } - if (best == null || errors.size() < best.size()) { - best = errors; - } - } - if (best != null) { - out.addAll(best); - return; - } - } - out.add(new Issue(path, "does not match any shape the schema allows here")); - } - - private void mapping(Yaml.Node node, Form form, String path, List out) { - for (Map.Entry pair : node.map.entrySet()) { - String child = path + "/" + pointer(pair.getKey()); - Entry entry = form.entries().get(pair.getKey()); - if (entry == null) { - entry = form.any(); - } - if (entry == null) { - out.add(new Issue(child, "unknown field `" + pair.getKey() + "`")); - continue; - } - int before = out.size(); - value(pair.getValue(), entry.value(), child, out); - Predicate constraint = CONSTRAINTS.get(form.rule() + "." + pair.getKey()); - if (out.size() == before && constraint != null && !constraint.test(pair.getValue())) { - out.add(new Issue(child, "`" + pair.getKey() + "` is out of range")); - } - } - for (Entry entry : form.entries().values()) { - if (entry.required() && !node.map.containsKey(entry.key())) { - out.add(new Issue( - path + "/" + pointer(entry.key()), "required field `" + entry.key() + "` is missing")); - } - } - } - - private static String pointer(String key) { - return key.replace("~", "~0").replace("/", "~1"); - } - - /** The literals of an enum rule. */ - private static final class EcoreUtilLiterals { - static List of(EnumRule rule) { - List literals = new ArrayList<>(); - for (java.util.Iterator it = rule.eAllContents(); it.hasNext(); ) { - if (it.next() instanceof EnumLiteralDeclaration declaration) { - literals.add(declaration.getLiteral().getValue()); - } - } - return literals; - } - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/schema/Yaml.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/schema/Yaml.java deleted file mode 100644 index f8600ff5d..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/schema/Yaml.java +++ /dev/null @@ -1,319 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.schema; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -/** - * The YAML subset the authored files use, read into a plain tree so a refusal can name the node it - * is about by its JSON pointer. It reads block and flow mappings and sequences, plain, quoted and - * folded scalars and comments, and refuses an anchor, an alias, a tag or a second document as - * {@link Unsupported}: the reader has no meaning for them. - */ -public final class Yaml { - - /** One node: a mapping, a sequence or a scalar. */ - public static final class Node { - public final Map map; - public final List list; - public final String text; - public final boolean quoted; - - private Node(Map map, List list, String text, boolean quoted) { - this.map = map; - this.list = list; - this.text = text; - this.quoted = quoted; - } - - public boolean isMap() { - return map != null; - } - - public boolean isList() { - return list != null; - } - - public boolean isScalar() { - return text != null; - } - } - - /** Text the subset does not cover. */ - public static final class Unsupported extends RuntimeException { - private static final long serialVersionUID = 1L; - - Unsupported(String message) { - super(message); - } - } - - private final List lines = new ArrayList<>(); - private int at; - - private Yaml(String text) { - for (String raw : text.split("\r?\n", -1)) { - String line = stripComment(raw); - if (line.isBlank()) { - continue; - } - if (line.equals("---") || line.startsWith("--- ") || line.equals("...")) { - if (!lines.isEmpty()) { - throw new Unsupported("more than one document"); - } - continue; - } - lines.add(line.stripTrailing()); - } - } - - public static Node read(String text) { - Yaml yaml = new Yaml(text); - if (yaml.lines.isEmpty()) { - throw new Unsupported("no document"); - } - Node root = yaml.block(indent(yaml.lines.get(0))); - if (yaml.at < yaml.lines.size()) { - throw new Unsupported("unexpected content"); - } - return root; - } - - private static String stripComment(String line) { - char quote = 0; - for (int i = 0; i < line.length(); i++) { - char c = line.charAt(i); - if (quote != 0) { - if (c == quote) { - quote = 0; - } - } else if (c == '"' || c == '\'') { - if (i == 0 || " \t[{,:-".indexOf(line.charAt(i - 1)) >= 0) { - quote = c; - } - } else if (c == '#' && (i == 0 || Character.isWhitespace(line.charAt(i - 1)))) { - return line.substring(0, i); - } - } - return line; - } - - private static int indent(String line) { - int n = 0; - while (n < line.length() && line.charAt(n) == ' ') { - n++; - } - return n; - } - - private static boolean dash(String line, int indent) { - return line.startsWith("-", indent) && (line.length() == indent + 1 || line.charAt(indent + 1) == ' '); - } - - private Node block(int indent) { - return dash(lines.get(at), indent) ? sequence(indent) : mapping(indent); - } - - private Node sequence(int indent) { - List items = new ArrayList<>(); - while (at < lines.size() && indent(lines.get(at)) == indent && dash(lines.get(at), indent)) { - String line = lines.get(at); - String rest = line.substring(indent + 1); - int inner = indent + 1 + indent(rest); - rest = rest.strip(); - if (rest.isEmpty()) { - at++; - if (at < lines.size() && indent(lines.get(at)) > indent) { - items.add(block(indent(lines.get(at)))); - } else { - items.add(new Node(null, null, "", false)); - } - } else if (dash(rest, 0) || keyed(rest)) { - lines.set(at, " ".repeat(inner) + rest); - items.add(block(inner)); - } else { - at++; - items.add(value(rest, indent)); - } - } - return new Node(null, items, null, false); - } - - /** Whether {@code text} opens with {@code key:}. */ - private static boolean keyed(String text) { - return keyEnd(text) >= 0; - } - - private static int keyEnd(String text) { - if (text.startsWith("{") || text.startsWith("[")) { - return -1; - } - int i = 0; - if (text.startsWith("\"") || text.startsWith("'")) { - int close = text.indexOf(text.charAt(0), 1); - if (close == -1) { - return -1; - } - i = close + 1; - } else { - while (i < text.length() && text.charAt(i) != ':') { - i++; - } - } - if (i < text.length() && text.charAt(i) == ':' && (i + 1 == text.length() || text.charAt(i + 1) == ' ')) { - return i; - } - return -1; - } - - private Node mapping(int indent) { - Map entries = new LinkedHashMap<>(); - while (at < lines.size() && indent(lines.get(at)) == indent && !dash(lines.get(at), indent)) { - String text = lines.get(at).substring(indent); - int colon = keyEnd(text); - if (colon < 0) { - throw new Unsupported("not a mapping entry: " + text); - } - String key = unquote(text.substring(0, colon).strip()); - String rest = text.substring(colon + 1).strip(); - at++; - Node child; - if (rest.isEmpty()) { - if (at < lines.size() && indent(lines.get(at)) > indent) { - child = block(indent(lines.get(at))); - } else if (at < lines.size() && indent(lines.get(at)) == indent && dash(lines.get(at), indent)) { - child = sequence(indent); - } else { - child = new Node(null, null, "", false); - } - } else { - child = value(rest, indent); - } - entries.put(key, child); - } - return new Node(entries, null, null, false); - } - - /** A value that opens on the line already consumed. */ - private Node value(String rest, int indent) { - if (rest.startsWith("{") || rest.startsWith("[")) { - StringBuilder flow = new StringBuilder(rest); - while (depth(flow) > 0 && at != lines.size()) { - flow.append(' ').append(lines.get(at++).strip()); - } - int[] pos = {0}; - Node node = flow(flow.toString(), pos); - return node; - } - if (rest.matches("[>|][-+]?")) { - StringBuilder folded = new StringBuilder(); - while (at < lines.size() && indent(lines.get(at)) > indent) { - folded.append(folded.length() == 0 ? "" : " ") - .append(lines.get(at++).strip()); - } - return new Node(null, null, folded.toString(), false); - } - return scalar(rest); - } - - private static int depth(CharSequence flow) { - int depth = 0; - char quote = 0; - for (int i = 0; i < flow.length(); i++) { - char c = flow.charAt(i); - if (quote != 0) { - if (c == quote) { - quote = 0; - } - } else if (c == '"' || c == '\'') { - quote = c; - } else if (c == '{' || c == '[') { - depth++; - } else if (c == '}' || c == ']') { - depth--; - } - } - return depth; - } - - private static Node scalar(String text) { - String t = text.strip(); - if (t.startsWith("&") || t.startsWith("*") || t.startsWith("!")) { - throw new Unsupported("anchor, alias or tag: " + t); - } - if (t.startsWith("\"") || t.startsWith("'")) { - return new Node(null, null, unquote(t), true); - } - return new Node(null, null, t, false); - } - - private static String unquote(String t) { - if (t.length() >= 2 && (t.startsWith("\"") && t.endsWith("\"") || t.startsWith("'") && t.endsWith("'"))) { - return t.substring(1, t.length() - 1); - } - return t; - } - - // The flow readers scan without an end check: value() reads lines until its brackets balance, so a - // closing bracket always stops a scan, and an unbalanced text runs off its end into an exception - // that leaves the verdict to the parser. - - private static void skip(String s, int[] pos) { - while (s.charAt(pos[0]) == ' ') { - pos[0]++; - } - } - - private static Node flow(String s, int[] pos) { - skip(s, pos); - char c = s.charAt(pos[0]); - if (c == '{') { - pos[0]++; - Map entries = new LinkedHashMap<>(); - skip(s, pos); - while (s.charAt(pos[0]) != '}') { - String key = unquote(token(s, pos, ":").strip()); - pos[0]++; - entries.put(key, flow(s, pos)); - skip(s, pos); - if (s.charAt(pos[0]) == ',') { - pos[0]++; - skip(s, pos); - } - } - pos[0]++; - return new Node(entries, null, null, false); - } - if (c == '[') { - pos[0]++; - List items = new ArrayList<>(); - skip(s, pos); - while (s.charAt(pos[0]) != ']') { - items.add(flow(s, pos)); - skip(s, pos); - if (s.charAt(pos[0]) == ',') { - pos[0]++; - skip(s, pos); - } - } - pos[0]++; - return new Node(null, items, null, false); - } - return scalar(token(s, pos, ",}]")); - } - - private static String token(String s, int[] pos, String stops) { - int start = pos[0]; - char first = s.charAt(start); - if (first == '"' || first == '\'') { - int close = s.indexOf(first, start + 1); - pos[0] = close + 1; - return s.substring(start, pos[0]); - } - while (stops.indexOf(s.charAt(pos[0])) < 0) { - pos[0]++; - } - return s.substring(start, pos[0]); - } -} diff --git a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/values/ProjectIntentValueConverters.java b/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/values/ProjectIntentValueConverters.java deleted file mode 100644 index c7aa5551d..000000000 --- a/emf/bundles/syntax/src/main/java/dev/jorisjonkers/deploykit/emf/syntax/values/ProjectIntentValueConverters.java +++ /dev/null @@ -1,53 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.values; - -import dev.jorisjonkers.deploykit.emf.syntax.blocks.BlockTokenSource; -import org.eclipse.xtext.common.services.DefaultTerminalConverters; -import org.eclipse.xtext.conversion.IValueConverter; -import org.eclipse.xtext.conversion.ValueConverter; -import org.eclipse.xtext.conversion.ValueConverterException; -import org.eclipse.xtext.nodemodel.INode; - -/** What the authored text of a scalar means: quotes are syntax, and a boolean is a boolean. */ -public class ProjectIntentValueConverters extends DefaultTerminalConverters { - - @ValueConverter(rule = "Text") - public IValueConverter text() { - return new IValueConverter<>() { - @Override - public String toValue(String string, INode node) { - return unquote(BlockTokenSource.valueOf(string)); - } - - @Override - public String toString(String value) { - return value; - } - }; - } - - @ValueConverter(rule = "Bool") - public IValueConverter bool() { - return new IValueConverter<>() { - @Override - public Boolean toValue(String string, INode node) throws ValueConverterException { - if (!"true".equals(string) && !"false".equals(string)) { - throw new ValueConverterException(string + " is not true or false", node, null); - } - return Boolean.valueOf(string); - } - - @Override - public String toString(Boolean value) { - return value.toString(); - } - }; - } - - /** The text of a quoted scalar without its quotes; a plain scalar unchanged. */ - public static String unquote(String text) { - boolean quoted = text.length() > 1 - && (text.charAt(0) == '"' || text.charAt(0) == '\'') - && text.charAt(text.length() - 1) == text.charAt(0); - return quoted ? text.substring(1, text.length() - 1) : text; - } -} diff --git a/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSourceTest.java b/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSourceTest.java deleted file mode 100644 index 4cf1fd73b..000000000 --- a/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokenSourceTest.java +++ /dev/null @@ -1,288 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.blocks; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.ProjectIntentTokenSource; -import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.internal.InternalProjectIntentParser; -import dev.jorisjonkers.deploykit.emf.syntax.parser.antlr.lexer.InternalProjectIntentLexer; -import java.util.ArrayList; -import java.util.List; -import org.antlr.runtime.ANTLRStringStream; -import org.antlr.runtime.CommonToken; -import org.antlr.runtime.Token; -import org.junit.jupiter.api.Test; - -/** The block structure the grammar reads, as the tokens this source produces for authored YAML. */ -class BlockTokenSourceTest { - - /** Every token of {@code text}, hidden ones included. */ - private static List tokens(String text) { - ProjectIntentTokenSource source = - new ProjectIntentTokenSource(new InternalProjectIntentLexer(new ANTLRStringStream(text))); - List tokens = new ArrayList<>(); - for (Token token = source.nextToken(); token.getType() != Token.EOF; token = source.nextToken()) { - tokens.add(token); - } - return tokens; - } - - /** Every significant token of {@code text}, as "BEGIN", "END" or its own text. */ - private static List blocks(String text) { - ProjectIntentTokenSource source = - new ProjectIntentTokenSource(new InternalProjectIntentLexer(new ANTLRStringStream(text))); - List tokens = new ArrayList<>(); - for (Token token = source.nextToken(); token.getType() != Token.EOF; token = source.nextToken()) { - if (token.getType() == InternalProjectIntentParser.RULE_BEGIN) { - tokens.add("BEGIN"); - } else if (token.getType() == InternalProjectIntentParser.RULE_END) { - tokens.add("END"); - } else if (token.getType() != InternalProjectIntentParser.RULE_WS - && token.getType() != InternalProjectIntentParser.RULE_SL_COMMENT) { - tokens.add(BlockTokenSource.valueOf(token.getText())); - } - } - return tokens; - } - - @Test - void theSourceNameIsTheOneTheLexerGives() { - assertThat(new ProjectIntentTokenSource(new InternalProjectIntentLexer(new ANTLRStringStream("a: 1"))) - .getSourceName()) - .isEqualTo(new InternalProjectIntentLexer(new ANTLRStringStream("a: 1")).getSourceName()); - } - - @Test - void anIndentedLineOpensABlockAndFallingBackClosesIt() { - assertThat(blocks("a:\n b:\n c: 1\nd: 2\n")) - .containsExactly("a", ":", "BEGIN", "b", ":", "BEGIN", "c", ":", "1", "END", "END", "d", ":", "2"); - } - - @Test - void everyBlockStillOpenAtTheEndOfTheFileIsClosed() { - assertThat(blocks("a:\n b:\n c: 1")).endsWith("1", "END", "END"); - } - - @Test - void aDashOpensABlockAroundTheItemThatFollowsIt() { - assertThat(blocks("a:\n - b: 1\n c: 2\n - b: 3\n")) - .containsExactly( - "a", ":", "BEGIN", "-", "BEGIN", "b", ":", "1", "c", ":", "2", "END", "-", "BEGIN", "b", ":", - "3", "END", "END"); - } - - @Test - void aFlowMappingIsABlockOnOneLine() { - assertThat(blocks("a: { b: 1, c: 2 }\n")) - .containsExactly("a", ":", "BEGIN", "b", ":", "1", "c", ":", "2", "END"); - } - - @Test - void aDashFollowedByAFlowMappingOpensOneBlock() { - assertThat(blocks("a:\n - { b: 1 }\n - { b: 2 }\n")) - .containsExactly( - "a", ":", "BEGIN", "-", "BEGIN", "b", ":", "1", "END", "-", "BEGIN", "b", ":", "2", "END", - "END"); - } - - @Test - void aBlockOpenedByAFlowMappingIsClosedWithIt() { - assertThat(blocks("a: { b: 1 }\nc:\n d: 2\n")) - .containsExactly("a", ":", "BEGIN", "b", ":", "1", "END", "c", ":", "BEGIN", "d", ":", "2", "END"); - } - - @Test - void aSyntheticTokenSitsWhereTheTokenThatAskedForItSits() { - ProjectIntentTokenSource source = - new ProjectIntentTokenSource(new InternalProjectIntentLexer(new ANTLRStringStream("a:\n b: 1\n"))); - List tokens = new ArrayList<>(); - for (Token token = source.nextToken(); token.getType() != Token.EOF; token = source.nextToken()) { - tokens.add(token); - } - Token begin = tokens.stream() - .filter(token -> token.getType() == InternalProjectIntentParser.RULE_BEGIN) - .findFirst() - .orElseThrow(); - CommonToken key = (CommonToken) tokens.stream() - .filter(token -> "b".equals(token.getText())) - .findFirst() - .orElseThrow(); - - assertThat(begin.getText()).isEmpty(); - assertThat(begin.getLine()).isEqualTo(key.getLine()); - assertThat(begin.getCharPositionInLine()).isEqualTo(key.getCharPositionInLine()); - assertThat(((CommonToken) begin).getStartIndex()).isEqualTo(key.getStartIndex()); - assertThat(((CommonToken) begin).getStopIndex()).isEqualTo(key.getStartIndex() - 1); - } - - @Test - void indentationInsideAFlowMappingIsNotRead() { - assertThat(blocks("a: { b: 1,\n c: 2 }\nd: 3\n")) - .containsExactly("a", ":", "BEGIN", "b", ":", "1", "c", ":", "2", "END", "d", ":", "3"); - } - - @Test - void aCommentLineOpensNoBlock() { - assertThat(blocks("a: 1\n # a comment, indented\nb: 2\n")).containsExactly("a", ":", "1", "b", ":", "2"); - } - - @Test - void aFoldedScalarIsOneValueWithItsLinesJoinedBySpaces() { - assertThat(blocks("a: >-\n one line\n and another\nb: 2\n")) - .containsExactly("a", ":", "one line and another", "b", ":", "2"); - } - - @Test - void aLiteralScalarKeepsItsLineBreaks() { - assertThat(blocks("a: |-\n one line\n and another\n")).containsExactly("a", ":", "one line\nand another"); - } - - @Test - void aFoldWithoutAChompKeepsTheClosingLineBreak() { - assertThat(blocks("a: >\n one line\n")).containsExactly("a", ":", "one line\n"); - } - - @Test - void aBlankLineInsideAFoldedScalarIsNotRead() { - assertThat(blocks("a: >-\n one\n\n two\n")).containsExactly("a", ":", "one two"); - } - - @Test - void aBlankLineInsideALiteralScalarIsKept() { - assertThat(blocks("a: |-\n one\n\n two\n")).containsExactly("a", ":", "one\n\ntwo"); - } - - @Test - void whatFollowsAFoldedScalarIsReadAsUsual() { - assertThat(blocks("a: >-\n one\n # not a comment, part of the scalar\nb:\n c: 2\n")) - .containsExactly( - "a", ":", "one # not a comment, part of the scalar", "b", ":", "BEGIN", "c", ":", "2", "END"); - } - - @Test - void aFoldedScalarSitsWhereItsMarkerSatAndCoversItsWholeBlock() { - String source = "a: >-\n one line\n and another\nb: 2\n"; - - CommonToken folded = (CommonToken) tokens(source).stream() - .filter(token -> token.getText().startsWith(">")) - .findFirst() - .orElseThrow(); - - assertThat(folded.getLine()).isEqualTo(1); - assertThat(folded.getCharPositionInLine()).isEqualTo(3); - assertThat(folded.getStartIndex()).isEqualTo(source.indexOf('>')); - assertThat(folded.getStopIndex()).isEqualTo(source.indexOf("another") + "another".length() - 1); - } - - @Test - void everyCharacterOfTheFileIsCoveredByExactlyOneToken() { - String source = "a: >-\n one\n two\n\nb:\n c: 2\nd: { e: 1, f: [x, y] }\n"; - int next = 0; - - for (Token token : tokens(source)) { - CommonToken common = (CommonToken) token; - if (!token.getText().isEmpty()) { - assertThat(common.getStartIndex()).as(token.getText()).isEqualTo(next); - next = common.getStopIndex() + 1; - } - } - - assertThat(next).isEqualTo(source.length()); - } - - @Test - void aFoldedScalarsTokenCoversItsSourceSoWhatFollowsSitsWhereItsTextIs() { - String source = "a: >-\n one line\n and another\nb: 2\n"; - - assertThat(tokens(source).stream().map(Token::getText).filter(text -> text.startsWith(">"))) - .containsExactly(">-\n one line\n and another"); - assertThat(BlockTokenSource.valueOf("")).isEmpty(); - assertThat(BlockTokenSource.valueOf("|\n kept")).isEqualTo("kept\n"); - } - - @Test - void aValueOfSeveralWordsIsOnePlainScalarToTheEndOfItsLine() { - assertThat(blocks("a: one two, three # a comment\nb: 2\n")) - .containsExactly("a", ":", "one two, three", "b", ":", "2"); - assertThat(blocks("a: { b: one two, c: [x, y] }\n")) - .containsExactly("a", ":", "BEGIN", "b", ":", "one two", "c", ":", "BEGIN", "x", "y", "END", "END"); - assertThat(blocks("a: { b: one two }\n")).containsExactly("a", ":", "BEGIN", "b", ":", "one two", "END"); - assertThat(blocks("a: one\nb:\n - c\n")) - .containsExactly("a", ":", "one", "b", ":", "BEGIN", "-", "BEGIN", "c", "END", "END"); - } - - @Test - void anItemWhosePartsACommaJoinsIsOnePlainScalarOutsideAFlow() { - assertThat(blocks("a:\n - --r=x,y,z\n - b\n")) - .containsExactly("a", ":", "BEGIN", "-", "BEGIN", "--r=x,y,z", "END", "-", "BEGIN", "b", "END", "END"); - // A comma that ends the scalar, or a comment, a flow or the end of the file after it, ends the value. - assertThat(blocks("- x, y\n")).containsExactly("-", "BEGIN", "x,", "y", "END"); - assertThat(blocks("- x,#c\n")).containsExactly("-", "BEGIN", "x,", "END"); - assertThat(blocks("- x,[y]\n")).containsExactly("-", "BEGIN", "x,", "BEGIN", "y", "END", "END"); - assertThat(blocks("- x,")).containsExactly("-", "BEGIN", "x,", "END"); - // Inside a flow collection the comma still separates. - assertThat(blocks("a: [x,y]\n")).containsExactly("a", ":", "BEGIN", "x", "y", "END"); - } - - @Test - void aColonNoSpaceFollowsIsPartOfThePlainScalarItSitsIn() { - assertThat(blocks("a: [run, --addr=0.0.0.0:80]\n")) - .containsExactly("a", ":", "BEGIN", "run", "--addr=0.0.0.0:80", "END"); - assertThat(blocks("- http://x:8080/y\n")).containsExactly("-", "BEGIN", "http://x:8080/y", "END"); - // A colon a space, a line break or the end of the file follows ends a key, as before. - assertThat(blocks("- b: 1\n")).containsExactly("-", "BEGIN", "b", ":", "1", "END"); - assertThat(blocks("a:\n b:")).containsExactly("a", ":", "BEGIN", "b", ":", "END"); - } - - @Test - void aPlainScalarACommaJoinsSitsWhereItsFirstPartSatAndCoversItsSourceOnce() { - String source = "- --r=x,y # c\n"; - CommonToken scalar = (CommonToken) tokens(source).stream() - .filter(token -> token.getText().equals("--r=x,y")) - .findFirst() - .orElseThrow(); - - assertThat(scalar.getLine()).isEqualTo(1); - assertThat(scalar.getCharPositionInLine()).isEqualTo(2); - assertThat(scalar.getStartIndex()).isEqualTo(2); - assertThat(scalar.getStopIndex()).isEqualTo(8); - } - - @Test - void aFlowSequenceIsAnEmptyBlockRatherThanAnItem() { - assertThat(blocks("a: []\n")).containsExactly("a", ":", "BEGIN", "END"); - } - - @Test - void aValueThatClosesAFlowOrOpensAnItemIsNoPlainScalar() { - assertThat(blocks("a: { b: }\n")).containsExactly("a", ":", "BEGIN", "b", ":", "END"); - assertThat(blocks("a: - b c\n")).containsExactly("a", ":", "-", "BEGIN", "b", "c", "END"); - } - - @Test - void aPlainScalarOfSeveralWordsSitsWhereItsFirstWordSatAndCoversItsSourceOnce() { - String source = "a: one two three # c\n"; - CommonToken scalar = (CommonToken) tokens(source).stream() - .filter(token -> token.getText().equals("one two three")) - .findFirst() - .orElseThrow(); - - assertThat(scalar.getLine()).isEqualTo(1); - assertThat(scalar.getCharPositionInLine()).isEqualTo(3); - assertThat(scalar.getStartIndex()).isEqualTo(3); - assertThat(scalar.getStopIndex()).isEqualTo(16); - int next = 0; - for (Token token : tokens(source)) { - CommonToken common = (CommonToken) token; - if (!token.getText().isEmpty()) { - assertThat(common.getStartIndex()).as(token.getText()).isEqualTo(next); - next = common.getStopIndex() + 1; - } - } - assertThat(next).isEqualTo(source.length()); - } - - @Test - void aMarkerWithNothingUnderItIsOneLineBreak() { - assertThat(BlockTokenSource.valueOf("|")).isEqualTo("\n"); - } -} diff --git a/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokensTest.java b/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokensTest.java deleted file mode 100644 index 63d1ab734..000000000 --- a/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/blocks/BlockTokensTest.java +++ /dev/null @@ -1,43 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.blocks; - -import static org.assertj.core.api.Assertions.assertThat; - -import org.junit.jupiter.api.Test; - -/** Which token types open and close a flow collection. */ -class BlockTokensTest { - - private static final BlockTokens TYPES = new BlockTokens(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); - - @Test - void aBraceAndABracketOpenAndCloseAFlowCollection() { - assertThat(TYPES.opensFlow(TYPES.flowBegin())).isTrue(); - assertThat(TYPES.opensFlow(TYPES.listBegin())).isTrue(); - assertThat(TYPES.closesFlow(TYPES.flowEnd())).isTrue(); - assertThat(TYPES.closesFlow(TYPES.listEnd())).isTrue(); - } - - @Test - void nothingElseOpensOrClosesOne() { - assertThat(TYPES.opensFlow(TYPES.flowEnd())).isFalse(); - assertThat(TYPES.opensFlow(TYPES.dash())).isFalse(); - assertThat(TYPES.closesFlow(TYPES.flowBegin())).isFalse(); - assertThat(TYPES.closesFlow(TYPES.separator())).isFalse(); - } - - @Test - void theTypesAreTheOnesItWasGiven() { - assertThat(TYPES.begin()).isEqualTo(1); - assertThat(TYPES.end()).isEqualTo(2); - assertThat(TYPES.whitespace()).isEqualTo(3); - assertThat(TYPES.comment()).isEqualTo(4); - assertThat(TYPES.dash()).isEqualTo(5); - assertThat(TYPES.flowBegin()).isEqualTo(6); - assertThat(TYPES.flowEnd()).isEqualTo(7); - assertThat(TYPES.listBegin()).isEqualTo(8); - assertThat(TYPES.listEnd()).isEqualTo(9); - assertThat(TYPES.separator()).isEqualTo(10); - assertThat(TYPES.fold()).isEqualTo(11); - assertThat(TYPES.scalar()).isEqualTo(12); - } -} diff --git a/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/linking/LinkingTest.java b/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/linking/LinkingTest.java deleted file mode 100644 index 33223ed80..000000000 --- a/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/linking/LinkingTest.java +++ /dev/null @@ -1,384 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.linking; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Application; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Platform; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Project; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.ProjectIntentPackage; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Route; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Scrape; -import dev.jorisjonkers.deploykit.emf.metamodel.projectintent.Tier; -import dev.jorisjonkers.deploykit.emf.syntax.PlatformIntentStandaloneSetup; -import dev.jorisjonkers.deploykit.emf.syntax.ProjectIntentStandaloneSetup; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.Map; -import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.xtext.EcoreUtil2; -import org.eclipse.xtext.linking.impl.XtextLinkingDiagnostic; -import org.eclipse.xtext.resource.IResourceFactory; -import org.eclipse.xtext.resource.XtextResourceSet; -import org.junit.jupiter.api.Test; - -/** What a route's, a scrape's and a tier's names link to, and what a name that links to nothing becomes. */ -class LinkingTest { - - private static final String DOCUMENT = """ - apiVersion: intent.jorisjonkers.dev/v1 - kind: Project - schemaVersion: 1.0.0 - project: links - owner: joris - applications: - - id: links - observability: - scrape: { process: SCRAPE_PROCESS, surface: SCRAPE_SURFACE, path: /metrics } - exposure: - - name: public - host: links.jorisjonkers.dev - audience: lan - routes: - - { path: /, match: prefix, process: ROUTE_PROCESS, surface: ROUTE_SURFACE } - processes: - - name: links-api - lifecycle: application - image: links-api - runtime: node - provides: { http: 8080, metrics: 9090 } - placement: { memory: 64Mi, cpu: 10m } - cutover: continuous - - id: elsewhere - processes: - - name: elsewhere-api - lifecycle: application - image: elsewhere-api - runtime: node - provides: { http: 8080 } - placement: { memory: 64Mi, cpu: 10m } - cutover: continuous - """; - - private static Resource parse(String routeProcess, String routeSurface, String scrapeProcess, String scrapeSurface) - throws IOException { - EPackage.Registry.INSTANCE.putIfAbsent(ProjectIntentPackage.eNS_URI, ProjectIntentPackage.eINSTANCE); - XtextResourceSet resources = new ProjectIntentStandaloneSetup() - .createInjectorAndDoEMFRegistration() - .getInstance(XtextResourceSet.class); - Resource resource = resources.createResource(URI.createURI("memory:/links.yml")); - String text = DOCUMENT.replace("ROUTE_PROCESS", routeProcess) - .replace("ROUTE_SURFACE", routeSurface) - .replace("SCRAPE_PROCESS", scrapeProcess) - .replace("SCRAPE_SURFACE", scrapeSurface); - resource.load(new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)), Map.of()); - EcoreUtil2.resolveAll(resource); - return resource; - } - - private static List codes(Resource resource) { - return resource.getErrors().stream() - .map(error -> ((XtextLinkingDiagnostic) error).getCode() + " " + error.getMessage()) - .toList(); - } - - private static Application links(Resource resource) { - return ((Project) resource.getContents().get(0)).getApplications().get(0); - } - - @Test - void aRouteAndAScrapeLinkToTheVeryProcessAndSurfaceTheirApplicationHolds() throws IOException { - Resource resource = parse("links-api", "http", "links-api", "metrics"); - Application application = links(resource); - Route route = application.getExposure().get(0).getRoutes().get(0); - Scrape scrape = application.getObservability().getScrape(); - - assertThat(resource.getErrors()).isEmpty(); - assertThat(route.getProcess()).isSameAs(application.getProcesses().get(0)); - assertThat(route.getSurface().getKey()).isEqualTo("http"); - assertThat(scrape.getProcess()).isSameAs(application.getProcesses().get(0)); - assertThat(scrape.getSurface().getKey()).isEqualTo("metrics"); - } - - @Test - void aProcessOfAnotherApplicationIsNotInScope() throws IOException { - assertThat(codes(parse("elsewhere-api", "http", "links-api", "metrics"))) - .containsExactly("E_UNKNOWN_PROCESS no Process of this Application is named elsewhere-api"); - } - - @Test - void aSurfaceTheProcessDoesNotProvideIsUnknown() throws IOException { - assertThat(codes(parse("links-api", "https", "links-api", "metrics"))) - .containsExactly("E_UNKNOWN_SURFACE the Process provides no surface named https"); - } - - @Test - void aSurfaceIsNotReportedWhenItsProcessDidNotLink() throws IOException { - assertThat(codes(parse("links-api", "http", "nothing", "nothing"))) - .containsExactly("E_UNKNOWN_PROCESS no Process of this Application is named nothing"); - } - - private static final String PLATFORM = """ - apiVersion: intent.jorisjonkers.dev/v1 - kind: Platform - schemaVersion: 1.0.0 - owner: joris - metadata: { cluster: production, project: jorisjonkers.dev, nodeContract: "sha256:6f1c" } - substrate: - kubernetesVersion: v1.31.4+k3s1 - datastore: sqlite - serverCount: 1 - secretsEncryption: true - cni: flannel - networkPolicyController: embedded - clusterDns: kube-system - bootstrap: - flux: - sourceRef: flux-system/platform - artifacts: - repository: ghcr.io/o/render - signer: - issuer: "https://token.actions.githubusercontent.com" - subject: "https://github.com/o/estate/.github/workflows/compose.yml@refs/heads/main" - vault: { unsealed: true } - crds: [traefik.io/v1alpha1] - tiers: - - { name: lan, audiences: [lan], listener: plain, certificates: none, traefik: PROXY } - durability: { reconstructible: {} } - engines: {} - monitors: { interval: 30s, timeout: 10s } - hardening: restricted - probes: { period: 10s, timeout: 5s, failures: 3 } - ephemeral: { size: 64Mi } - """; - - /** A Platform document read into the same resource set as {@link #DOCUMENT}, its tier naming {@code proxy}. */ - private static Resource platform(String proxy) throws IOException { - return platform(proxy, ""); - } - - /** The same, with {@code extra} appended to the document: a block the tier tests do not need. */ - private static Resource platform(String proxy, String extra) throws IOException { - Resource project = parse("links-api", "http", "links-api", "metrics"); - Resource platform = new PlatformIntentStandaloneSetup() - .createInjectorAndDoEMFRegistration() - .getInstance(IResourceFactory.class) - .createResource(URI.createURI("memory:/platform.intent.yml")); - project.getResourceSet().getResources().add(platform); - platform.load( - new ByteArrayInputStream((PLATFORM.replace("PROXY", proxy) + extra).getBytes(StandardCharsets.UTF_8)), - Map.of()); - EcoreUtil2.resolveAll(platform); - return platform; - } - - @Test - void aTiersProxyLinksToAnApplicationAnotherDocumentDeclares() throws IOException { - Resource platform = platform("links/elsewhere"); - Tier tier = ((Platform) platform.getContents().get(0)).getTiers().get(0); - - assertThat(platform.getErrors()).isEmpty(); - assertThat(tier.getTraefik().getId()).isEqualTo("elsewhere"); - assertThat(tier.getTraefik().eResource()).isNotSameAs(platform); - } - - @Test - void aPrivilegedRoleNamedUnderAProjectThatDoesNotDeclareItLinksToNothing() throws IOException { - // `links` declares `elsewhere`; no Project called `impostor` is read, so the id alone binds nothing. - assertThat(codes(platform("impostor/elsewhere"))) - .containsExactly("E_UNKNOWN_TIER_PROXY no project file declares the Application impostor/elsewhere"); - assertThat(codes(platform("links/elsewhere", "secretStore: impostor/elsewhere\n"))) - .containsExactly("E_UNKNOWN_SECRET_STORE no project file declares an Application impostor/elsewhere" - + " whose Process provides an `http` surface"); - } - - @Test - void aTiersProxyThatNoDocumentDeclaresIsUnknown() throws IOException { - assertThat(codes(platform("links/traefik-lan"))) - .containsExactly("E_UNKNOWN_TIER_PROXY no project file declares the Application links/traefik-lan"); - } - - @Test - void theTelemetryCollectorLinksOnlyToADeclaredApplicationThatReceivesOnOtlp() throws IOException { - // `elsewhere` is declared, and provides only `http`: it is not a collector, so it is not in scope. - assertThat(codes(platform( - "links/elsewhere", "telemetry: { collector: links/elsewhere, metrics: links/elsewhere }\n"))) - .containsExactly("E_UNKNOWN_TELEMETRY_COLLECTOR no project file declares an Application links/elsewhere" - + " whose Process provides an `otlp` surface"); - assertThat(codes(platform( - "links/elsewhere", "telemetry: { collector: links/gone, metrics: links/elsewhere }\n"))) - .containsExactly("E_UNKNOWN_TELEMETRY_COLLECTOR no project file declares an Application links/gone" - + " whose Process provides an `otlp` surface"); - } - - @Test - void theReleaseGateAndTheMetricsStackLinkOnlyToWhatTheyNeed() throws IOException { - // `elsewhere` provides `http`, so it may be the gate; `gone` is declared nowhere. - String delivery = "delivery: { machinery: [links/elsewhere], gate: links/gone, " - + "analysis: { interval: 30s, iterations: 4, threshold: 3, errorRate: 1%, latency: 500ms } }\n"; - - assertThat(codes(platform( - "links/elsewhere", delivery + "telemetry: { collector: links/gone, metrics: links/gone }\n"))) - .contains( - "E_UNKNOWN_RELEASE_GATE no project file declares an Application links/gone whose Process provides" - + " an `http` surface", - "E_UNKNOWN_METRICS_STACK no project file declares the Application links/gone the metrics stack names"); - } - - @Test - void theReporterLinksOnlyToADeclaredApplicationThatAnswersOnHttp() throws IOException { - // `elsewhere` provides `http` beside the gate, so it may be the Reporter; `gone` is declared nowhere. - String analysis = "analysis: { interval: 30s, iterations: 4, threshold: 3, errorRate: 1%, latency: 500ms } }\n"; - String linked = "delivery: { machinery: [links/elsewhere], gate: links/elsewhere, reporter: links/elsewhere, " - + analysis; - String unlinked = - "delivery: { machinery: [links/elsewhere], gate: links/elsewhere, reporter: links/gone, " + analysis; - - assertThat(codes(platform("links/elsewhere", linked))).isEmpty(); - assertThat(codes(platform("links/elsewhere", unlinked))) - .containsExactly("E_UNKNOWN_REPORTER the project file that declares the Release Gate declares no" - + " Application links/gone whose Process provides an `http` surface"); - } - - @Test - void theReporterLinksToNothingWhereNoProjectFileDeclaresTheGate() throws IOException { - // The Reporter is declared beside the gate, so a gate that links nowhere leaves it nowhere - // to be declared, however many Applications of its name the set holds. - String analysis = "analysis: { interval: 30s, iterations: 4, threshold: 3, errorRate: 1%, latency: 500ms } }\n"; - String refused = "E_UNKNOWN_REPORTER the project file that declares the Release Gate declares no" - + " Application links/elsewhere whose Process provides an `http` surface"; - - assertThat(codes(platform( - "links/elsewhere", - "delivery: { machinery: [links/elsewhere], gate: links/gone, reporter: links/elsewhere, " - + analysis))) - .contains(refused); - // A delivery policy that names no gate at all is the parser's to refuse; the Reporter - // still links to nothing. - assertThat(platform( - "links/elsewhere", - "delivery: { machinery: [links/elsewhere], reporter: links/elsewhere, " + analysis) - .getErrors()) - .filteredOn(XtextLinkingDiagnostic.class::isInstance) - .extracting(error -> ((XtextLinkingDiagnostic) error).getCode() + " " + error.getMessage()) - .contains(refused); - } - - @Test - void theSecretStoreLinksOnlyToADeclaredApplicationThatAnswersOnHttp() throws IOException { - // `elsewhere` provides `http`, so it may be the Secret Store; `gone` is declared nowhere. - Resource platform = platform("links/elsewhere", "secretStore: links/elsewhere\n"); - - assertThat(platform.getErrors()).isEmpty(); - assertThat(((Platform) platform.getContents().get(0)).getSecretStore().getId()) - .isEqualTo("elsewhere"); - assertThat(codes(platform("links/elsewhere", "secretStore: links/gone\n"))) - .containsExactly( - "E_UNKNOWN_SECRET_STORE no project file declares an Application links/gone whose Process" - + " provides an `http` surface"); - } - - @Test - void theDeliveryMachineryLinksToDeclaredApplicationsAndReportsEachOneThatIsNot() throws IOException { - String delivery = "delivery: { machinery: [links/elsewhere, links/gone], gate: links/elsewhere, " - + "analysis: { interval: 30s, iterations: 4, threshold: 3, errorRate: 1%, latency: 500ms } }\n"; - - assertThat(codes(platform("links/elsewhere", delivery))) - .containsExactly( - "E_UNKNOWN_MACHINERY no project file declares the Application links/gone the delivery machinery names"); - } - - @Test - void aHolderOfApiAccessLinksToADeclaredApplicationAndReportsEachOneThatIsNot() throws IOException { - String server = " server:\n - { cidr: 10.43.0.1/32, port: 443 }\n"; - Resource platform = platform("links/elsewhere", "apiAccess:\n holders: [links/elsewhere]\n" + server); - - assertThat(platform.getErrors()).isEmpty(); - assertThat(((Platform) platform.getContents().get(0)) - .getApiAccess() - .getHolders() - .get(0) - .getId()) - .isEqualTo("elsewhere"); - assertThat(codes( - platform("links/elsewhere", "apiAccess:\n holders: [links/elsewhere, links/gone]\n" + server))) - .containsExactly("E_UNKNOWN_API_HOLDER no project file declares the Application links/gone the platform" - + " admits to hold Kubernetes API access"); - } - - /** Each name that links to nothing, by its code, its message and where below its owner it sits. */ - private static List refused(Resource resource) { - return resource.getErrors().stream() - .map(error -> { - XtextLinkingDiagnostic linking = (XtextLinkingDiagnostic) error; - return linking.getCode() + " " + error.getMessage() + " at '" + String.join("", linking.getData()) - + "'"; - }) - .toList(); - } - - @Test - void theSignInProviderIsAnApplicationAProjectFileDeclares() throws IOException { - assertThat( - refused( - platform( - "links/elsewhere", - "signIn: { issuer: \"https://id.jorisjonkers.dev\", provider: links/gone, contract: \"1.2\" }\n"))) - .containsExactly( - "E_UNKNOWN_SIGN_IN_PROVIDER no project file declares the sign-in provider links/gone at ''"); - } - - @Test - void anApiHolderIsAnApplicationAProjectFileDeclares() throws IOException { - assertThat(refused(platform( - "links/elsewhere", - "apiAccess:\n holders: [links/elsewhere]\n namespaceHolders: [links/gone]\n" - + " server:\n - { cidr: 10.43.0.1/32, port: 443 }\n"))) - .containsExactly("E_UNKNOWN_API_HOLDER no project file declares the Application links/gone" - + " the platform admits to hold Kubernetes API access at ''"); - } - - @Test - void aMonitoringApplicationLinksToNothingOnlyUnderAProjectTheSetComposes() throws IOException { - assertThat(refused(platform( - "links/elsewhere", - "monitoring:\n grafana: links/gone\n prometheus: links/elsewhere\n alertmanager: other/gone\n" - + " receivers:\n - name: discord\n discord:\n" - + " webhook: {path: secret/data/platform/discord, key: url}\n" - + " routes:\n - {severity: critical, receiver: discord, repeat: 4h}\n"))) - .containsExactly("E_UNKNOWN_MONITORING_APPLICATION no project file declares the Application links/gone" - + " the monitoring stack's grafana names at '/grafana'"); - } - - @Test - void aCriticalApplicationIsRefusedAtItsPlaceInTheList() throws IOException { - String priority = "priority: { data: { name: platform-data, value: 1000000 }," - + " critical: { name: platform-critical-app, value: 100000 }, criticalApplications: CRITICAL }\n"; - - assertThat(refused(platform("links/elsewhere", priority.replace("CRITICAL", "[links/elsewhere, links/gone]")))) - .containsExactly("E_UNKNOWN_CRITICAL_APPLICATION no project file declares the Application links/gone" - + " the platform names critical at '/criticalApplications/1'"); - assertThat(refused(platform("links/elsewhere", priority.replace("CRITICAL", "[links/gone, links/elsewhere]")))) - .containsExactly("E_UNKNOWN_CRITICAL_APPLICATION no project file declares the Application links/gone" - + " the platform names critical at '/criticalApplications/0'"); - assertThat(refused(platform( - "links/elsewhere", - priority.replace("CRITICAL", "[\"links/elsewhere\", \"links/gone\", \"links/elsewhere\"]")))) - .containsExactly("E_UNKNOWN_CRITICAL_APPLICATION no project file declares the Application links/gone" - + " the platform names critical at '/criticalApplications/2'"); - // A name under no Project at all is under none the set composes. - assertThat(refused(platform("links/elsewhere", priority.replace("CRITICAL", "[gone]")))) - .isEmpty(); - } - - @Test - void aForwardAuthProviderIsRefusedAtItsOwnBlock() throws IOException { - assertThat(refused( - platform("links/elsewhere, forwardAuth: { provider: links/gone, surface: http, path: /gate }"))) - .containsExactly("E_UNKNOWN_FORWARD_AUTH_PROVIDER no project file declares the Application links/gone" - + " that answers the forward-auth surface at ''"); - } -} diff --git a/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/schema/ShapesTest.java b/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/schema/ShapesTest.java deleted file mode 100644 index 1e29c2d42..000000000 --- a/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/schema/ShapesTest.java +++ /dev/null @@ -1,337 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.schema; - -import static org.assertj.core.api.Assertions.assertThat; - -import dev.jorisjonkers.deploykit.emf.syntax.PlatformIntentStandaloneSetup; -import dev.jorisjonkers.deploykit.emf.syntax.ProjectIntentStandaloneSetup; -import dev.jorisjonkers.deploykit.emf.syntax.schema.Shapes.Issue; -import java.util.List; -import org.eclipse.xtext.Grammar; -import org.eclipse.xtext.IGrammarAccess; -import org.junit.jupiter.api.Test; - -/** The shape check: each case is a document in and the refusals it earns out, by JSON pointer. */ -class ShapesTest { - - private static final Grammar PROJECT = new ProjectIntentStandaloneSetup() - .createInjectorAndDoEMFRegistration() - .getInstance(IGrammarAccess.class) - .getGrammar(); - - private static final Grammar PLATFORM = new PlatformIntentStandaloneSetup() - .createInjectorAndDoEMFRegistration() - .getInstance(IGrammarAccess.class) - .getGrammar(); - - private static final String HEAD = - "apiVersion: a\nkind: Project\nschemaVersion: 1\nproject: p\nowner: o\napplications:\n - id: x\n"; - - private static final String PROCESS = - " processes:\n - name: n\n lifecycle: application\n image: i\n runtime: node\n"; - - /** The paths refused in a project whose one process also holds {@code extra}, indented to the process. */ - private static List paths(String extra) { - return check(HEAD + PROCESS + extra).stream().map(Issue::path).toList(); - } - - private static List check(String text) { - return Shapes.check(text, PROJECT); - } - - private static String indented(String lines) { - return lines.lines().map(l -> " " + l + "\n").reduce("", String::concat); - } - - @Test - void aDocumentThatHoldsRefusesNothing() { - assertThat(check(HEAD + PROCESS)).isEmpty(); - } - - @Test - void anUnknownKeyIsRefusedAtItself() { - assertThat(check(HEAD.replace("id: x\n", "id: x\n colour: blue\n size: 3\n") + PROCESS)) - .containsExactlyInAnyOrder( - new Issue("/applications/0/colour", "unknown field `colour`"), - new Issue("/applications/0/size", "unknown field `size`")); - } - - @Test - void aMissingKeyIsRefusedAtTheNodeItBelongsTo() { - assertThat(check(HEAD + PROCESS.replace(" image: i\n", ""))) - .containsExactly(new Issue("/applications/0/processes/0/image", "required field `image` is missing")); - assertThat(check(HEAD.replace("owner: o\n", "") + PROCESS)) - .containsExactly(new Issue("/owner", "required field `owner` is missing")); - } - - @Test - void anOptionalKeyMayBeAbsent() { - assertThat(check(HEAD.replace("id: x\n", "id: x\n description: d\n") + PROCESS)) - .isEmpty(); - } - - @Test - void anEnumValueOutsideItsVocabularyIsRefusedAtTheValue() { - assertThat(check(HEAD + PROCESS.replace("runtime: node", "runtime: cobol"))) - .containsExactly(new Issue( - "/applications/0/processes/0/runtime", "does not match any shape the schema allows here")); - assertThat(paths("")).isEmpty(); - assertThat(check(HEAD + PROCESS.replace("runtime: node", "runtime: \"node\""))) - .hasSize(1); - assertThat(check(HEAD + PROCESS.replace("runtime: node", "runtime: {a: b}"))) - .hasSize(1); - } - - @Test - void aNumberMustBeAnUnquotedInteger() { - String at = "/applications/0/processes/0/provides/http"; - assertThat(paths(indented("provides:\n http: 8080"))).isEmpty(); - assertThat(paths(indented("provides:\n http: \"8080\""))).containsExactly(at); - assertThat(paths(indented("provides:\n http: abc"))).containsExactly(at); - assertThat(paths(indented("provides:\n http: 80a"))).containsExactly(at); - assertThat(paths(indented("provides:\n http: {a: 1}"))).containsExactly(at); - } - - @Test - void aSurfaceNameIsAnyKeyAndEscapedInThePointer() { - assertThat(paths(indented("provides:\n \"a/b\": x\n \"c~d\": y"))) - .containsExactlyInAnyOrder( - "/applications/0/processes/0/provides/a~1b", "/applications/0/processes/0/provides/c~0d"); - assertThat(paths(indented("provides: [a]"))).containsExactly("/applications/0/processes/0/provides"); - } - - @Test - void aBooleanIsTrueOrFalseUnquoted() { - String sidecar = "sidecars:\n - name: s\n image: i\n memory: 1Mi\n cpu: 1m\n init: "; - assertThat(paths(indented(sidecar + "true"))).isEmpty(); - assertThat(paths(indented(sidecar + "false"))).isEmpty(); - assertThat(paths(indented(sidecar + "maybe"))).containsExactly("/applications/0/processes/0/sidecars/0/init"); - assertThat(paths(indented(sidecar + "\"true\""))).hasSize(1); - assertThat(paths(indented(sidecar + "{}"))).hasSize(1); - } - - @Test - void aValueOfNoShapeIsRefusedOnceAtTheValue() { - String at = "/applications/0/processes/0/probes"; - assertThat(paths(indented("probes: none"))).isEmpty(); - assertThat(paths(indented("probes: some"))).containsExactly(at); - assertThat(paths(indented("probes: [a]"))).containsExactly(at); - assertThat(paths(indented("probes:\n readiness: { path: /x, port: 1 }\n liveness: { tcp: 2 }"))) - .isEmpty(); - } - - @Test - void aMappingThatMatchesNoFormIsRefusedByTheClosestOne() { - assertThat(paths(indented("probes:\n readiness: { path: /x }"))) - .containsExactly("/applications/0/processes/0/probes/readiness/port"); - assertThat(paths(indented("probes:\n readiness: { tcp: 1, path: /x }"))) - .containsExactly("/applications/0/processes/0/probes/readiness/path"); - assertThat(paths(indented("probes:\n readiness: { path: /x, port: 1, extra: 1 }"))) - .containsExactly("/applications/0/processes/0/probes/readiness/extra"); - } - - @Test - void ofTwoEquallyCloseFormsTheFirstTheGrammarWritesRefuses() { - assertThat(check(HEAD + PROCESS + indented("assets:\n - from: a"))) - .containsExactly(new Issue( - "/applications/0/processes/0/assets/0/mountAt", "required field `mountAt` is missing")); - } - - @Test - void aSequenceIsExpectedWhereTheGrammarWritesADash() { - assertThat(paths(indented("command: foo"))).containsExactly("/applications/0/processes/0/command"); - assertThat(check(HEAD + PROCESS + indented("command: foo"))) - .containsExactly(new Issue("/applications/0/processes/0/command", "expected a sequence")); - assertThat(paths(indented("command: [a, b]"))).isEmpty(); - assertThat(paths(indented("command:\n - a\n - b"))).isEmpty(); - assertThat(paths(indented("command: [{a: 1}]"))).containsExactly("/applications/0/processes/0/command/0"); - } - - @Test - void aSequenceItemIsRefusedByItsIndex() { - assertThat(paths(indented("sidecars:\n - name: a\n image: i\n memory: 1\n cpu: 1\n - name: b"))) - .containsExactlyInAnyOrder( - "/applications/0/processes/0/sidecars/1/image", - "/applications/0/processes/0/sidecars/1/memory", - "/applications/0/processes/0/sidecars/1/cpu"); - } - - @Test - void aWordMayStandWhereAFormIsOneKeyword() { - String migration = " migration: "; - assertThat(check(HEAD + migration + "self\n" + PROCESS)).isEmpty(); - assertThat(check(HEAD + migration + "none\n" + PROCESS)).isEmpty(); - assertThat(check(HEAD + migration + "\"self\"\n" + PROCESS)).hasSize(1); - assertThat(check(HEAD + migration + "other\n" + PROCESS)) - .containsExactly( - new Issue("/applications/0/migration", "does not match any shape the schema allows here")); - assertThat(check(HEAD + migration + "\n changelog: c.xml\n" + PROCESS)) - .isEmpty(); - } - - @Test - void aPlainScalarMayStandWhereAFormIsOnlyAValue() { - assertThat(paths(indented("writablePaths: [/tmp, {path: /a, memory: 1Mi}]"))) - .isEmpty(); - assertThat(paths(indented("writablePaths: [{path: /a}]"))) - .containsExactly("/applications/0/processes/0/writablePaths/0/memory"); - } - - @Test - void aCrossReferenceIsAScalar() { - String exposure = " l4Exposure:\n - {address: a, port: 1, protocol: tcp, process: p, surface: s}\n"; - assertThat(check(HEAD + exposure + PROCESS)).isEmpty(); - assertThat(check(HEAD + exposure.replace("process: p", "process: [p]") + PROCESS)) - .containsExactly(new Issue( - "/applications/0/l4Exposure/0/process", "does not match any shape the schema allows here")); - } - - @Test - void aGroupNestedInAKeyIsWalked() { - String grant = - "secrets:\n - engine: database\n role: r\n delivery: env\n rotation: {tolerates: restart}"; - assertThat(paths(indented(grant))).isEmpty(); - assertThat(paths(indented(grant.replace("role: r\n ", "")))).hasSize(1); - assertThat(paths(indented(grant.replace("database", "other")))).hasSize(1); - } - - @Test - void aRateLimitAllowsAtLeastOneRequestOverAWholePeriod() { - String route = " exposure:\n - name: e\n host: h\n audience: anonymous\n routes:\n" - + " - {path: /, match: exact, process: p, surface: s, rateLimit: %s}\n"; - String at = "/applications/0/exposure/0/routes/0/rateLimit"; - assertThat(check(HEAD + route.formatted("{requests: 1, per: 1h}") + PROCESS)) - .isEmpty(); - assertThat(check(HEAD + route.formatted("{requests: 10, per: 30s}") + PROCESS)) - .isEmpty(); - assertThat(check(HEAD + route.formatted("{requests: 10, per: 5m}") + PROCESS)) - .isEmpty(); - assertThat(check(HEAD + route.formatted("{requests: 0, per: 1h}") + PROCESS)) - .containsExactly(new Issue(at + "/requests", "`requests` is out of range")); - assertThat(check(HEAD + route.formatted("{requests: 00, per: 1h}") + PROCESS)) - .hasSize(1); - assertThat(check(HEAD + route.formatted("{requests: 10, per: 500ms}") + PROCESS)) - .containsExactly(new Issue(at + "/per", "`per` is out of range")); - assertThat(check(HEAD + route.formatted("{requests: 10, per: 0s}") + PROCESS)) - .hasSize(1); - assertThat(check(HEAD + route.formatted("{requests: 10, per: 1d}") + PROCESS)) - .hasSize(1); - assertThat(check(HEAD + route.formatted("{requests: 10}") + PROCESS)) - .containsExactly(new Issue(at + "/per", "required field `per` is missing")); - assertThat(check(HEAD + route.formatted("{requests: abc, per: 1h}") + PROCESS)) - .containsExactly(new Issue(at + "/requests", "does not match any shape the schema allows here")); - assertThat(check(HEAD + route.formatted("{requests: 10, per: {a: b}}") + PROCESS)) - .containsExactly(new Issue(at + "/per", "does not match any shape the schema allows here")); - } - - @Test - void aConstraintOnlyAppliesToTheKeyItNames() { - String route = " exposure:\n - name: e\n host: h\n audience: anonymous\n routes:\n" - + " - {path: /, match: exact, process: p, surface: s, rateLimit: {requests: 5, per: 1h}}\n"; - assertThat(check(HEAD + route + PROCESS)).isEmpty(); - assertThat(check(HEAD + route.replace("path: /,", "path: 0,") + PROCESS)) - .isEmpty(); - } - - @Test - void aDocumentOutsideTheSubsetIsRefusedOnceAtTheRoot() { - assertThat(check(HEAD + PROCESS.replace("runtime: node", "runtime: !!str node"))) - .containsExactly(new Issue("", "outside the YAML subset: anchor, alias or tag: !!str node")); - assertThat(check("a: 1\n---\nb: 2")) - .containsExactly(new Issue("", "outside the YAML subset: more than one document")); - assertThat(check("")).containsExactly(new Issue("", "outside the YAML subset: no document")); - assertThat(check("")).extracting(Issue::message).containsExactly("outside the YAML subset: no document"); - } - - @Test - void aDocumentTheReaderCannotReadLeavesTheVerdictToTheParser() { - assertThat(check("applications: {a: 1")).isEmpty(); - } - - @Test - void aSequenceAtTheRootIsNoProject() { - assertThat(check("- a\n- b")).containsExactly(new Issue("", "does not match any shape the schema allows here")); - assertThat(check("a")).hasSize(1); - } - - @Test - void aPlatformKeyLiteralIsAnAcceptedValue() { - List issues = Shapes.check( - "l4Addresses:\n a:\n kind: pool\n site: s\n range: r\n b:\n kind: node\n node: n\n" - + " c:\n kind: other\n node: n\n d:\n kind: \"pool\"\n site: s\n range: r\n", - PLATFORM); - assertThat(issues.stream().map(Issue::path)) - .contains("/l4Addresses/c/kind", "/l4Addresses/d/kind") - .doesNotContain("/l4Addresses/a/kind", "/l4Addresses/b/kind", "/l4Addresses/a", "/l4Addresses/b"); - } - - @Test - void aDescriptionIsOneSentenceOfAtMostOneHundredAndSixtyCharactersAndNeverEmpty() { - String at = "/applications/0/processes/0/description"; - assertThat(paths(indented("description: " + "x".repeat(160)))).isEmpty(); - assertThat(paths(indented("description: " + "x".repeat(161)))).containsExactly(at); - assertThat(paths(indented("description: \"\""))).containsExactly(at); - assertThat(paths(indented("description: [a]"))).containsExactly(at); - String application = "/applications/0/description"; - assertThat(check(HEAD.replace("id: x\n", "id: x\n description: " + "x".repeat(160) + "\n") + PROCESS)) - .isEmpty(); - assertThat(check(HEAD.replace("id: x\n", "id: x\n description: " + "x".repeat(161) + "\n") + PROCESS)) - .containsExactly(new Issue(application, "`description` is out of range")); - assertThat(check(HEAD.replace("id: x\n", "id: x\n description: \"\"\n") + PROCESS)) - .extracting(Issue::path) - .containsExactly(application); - } - - @Test - void whatAContainerRunsIsAtLeastOneWordAndACommandWordIsNeverEmpty() { - String process = "/applications/0/processes/0/"; - assertThat(paths(indented("command: [/bin/a]\nargs: [serve, \"\"]"))).isEmpty(); - assertThat(paths(indented("command: []"))).containsExactly(process + "command"); - assertThat(paths(indented("command: [\"\"]"))).containsExactly(process + "command"); - assertThat(paths(indented("command: [a, \"\"]"))).containsExactly(process + "command"); - assertThat(paths(indented("args: []"))).containsExactly(process + "args"); - String sidecar = "sidecars:\n - name: s\n image: i\n memory: 1Mi\n cpu: 1m\n"; - String at = process + "sidecars/0/"; - assertThat(paths(indented(sidecar + " command: [a]\n args: [\"\"]"))) - .isEmpty(); - assertThat(paths(indented(sidecar + " command: []"))).containsExactly(at + "command"); - assertThat(paths(indented(sidecar + " command: [\"\"]"))).containsExactly(at + "command"); - assertThat(paths(indented(sidecar + " args: []"))).containsExactly(at + "args"); - } - - @Test - void anOptionalKeyIsOptionalAndNeverOptionalFalse() { - String grant = - "secrets:\n - path: p\n access: read\n delivery: env\n rotation: {tolerates: restart}\n" - + " keys:\n - name: k\n optional: %s\n"; - String at = "/applications/0/processes/0/secrets/0/keys/0/optional"; - assertThat(paths(indented(grant.formatted("true")))).isEmpty(); - assertThat(paths(indented(grant.formatted("false")))).containsExactly(at); - } - - @Test - void anOffClusterCopyIsEncryptedToAnAgePublicKeyAndNothingElse() { - String recipient = "age1s6v5qrx3mgcgk37gscv8y6z43rssksdct5lx3xk5xrtptjndqvhsnhj7h8"; - String copy = "durability:\n irreplaceable:\n schedule: s\n retain: 1\n offCluster:\n" - + " destination: d\n credential: c\n recipient: %s\n" - + " egress:\n - cidr: 10.0.0.0/8\n port: 443\n"; - String at = "/durability/irreplaceable/offCluster/recipient"; - assertThat(recipientIssues(copy.formatted(recipient))).isEmpty(); - assertThat(recipientIssues(copy.formatted("\"" + recipient + "\""))).isEmpty(); - for (String wrong : List.of( - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI", - recipient.substring(0, recipient.length() - 1), - recipient.replace("age1s", "age1b"), - "x" + recipient, - recipient + "8")) { - assertThat(recipientIssues(copy.formatted(wrong))).as(wrong).containsExactly(at); - } - assertThat(recipientIssues(copy.replace(" recipient: %s\n", ""))).containsExactly(at); - } - - private static List recipientIssues(String text) { - return Shapes.check(text, PLATFORM).stream() - .map(Issue::path) - .filter(path -> path.endsWith("/recipient")) - .toList(); - } -} diff --git a/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/schema/YamlTest.java b/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/schema/YamlTest.java deleted file mode 100644 index 2d382f0ec..000000000 --- a/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/schema/YamlTest.java +++ /dev/null @@ -1,302 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.schema; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import java.util.stream.Collectors; -import org.junit.jupiter.api.Test; - -/** The YAML subset, read into a tree: each case is a document in and the tree it reads as out. */ -class YamlTest { - - /** A node as one line: {@code {k=v}}, {@code [a,b]}, a scalar's text, quoted ones in single quotes. */ - private static String show(Yaml.Node node) { - if (node.isMap()) { - return node.map.entrySet().stream() - .map(e -> e.getKey() + "=" + show(e.getValue())) - .collect(Collectors.joining(",", "{", "}")); - } - if (node.isList()) { - return node.list.stream().map(YamlTest::show).collect(Collectors.joining(",", "[", "]")); - } - return node.quoted ? "'" + node.text + "'" : node.text; - } - - private static String read(String text) { - return show(Yaml.read(text)); - } - - @Test - void aBlockMappingNestsByIndentation() { - assertThat(read("a: 1\nb:\n c: x\n d: y\ne: z")).isEqualTo("{a=1,b={c=x,d=y},e=z}"); - } - - @Test - void aNodeKnowsWhichKindItIs() { - Yaml.Node map = Yaml.read("a: [b]"); - assertThat(map.isMap()).isTrue(); - assertThat(map.isList()).isFalse(); - assertThat(map.isScalar()).isFalse(); - Yaml.Node list = map.map.get("a"); - assertThat(list.isList()).isTrue(); - assertThat(list.isMap()).isFalse(); - Yaml.Node scalar = list.list.get(0); - assertThat(scalar.isScalar()).isTrue(); - assertThat(scalar.isMap()).isFalse(); - assertThat(scalar.isList()).isFalse(); - } - - @Test - void aBlockSequenceHoldsScalarsMappingsAndSequences() { - assertThat(read("a:\n - x\n - k: 1\n l: 2\n - - p\n - q\n -\n m: 3")) - .isEqualTo("{a=[x,{k=1,l=2},[p,q],{m=3}]}"); - } - - @Test - void aSequenceMayShareItsKeysIndentation() { - assertThat(read("a:\n- x\n- y\nb: 1")).isEqualTo("{a=[x,y],b=1}"); - } - - @Test - void aDashAloneOnTheLastLineIsAnEmptyScalar() { - assertThat(read("a:\n -")).isEqualTo("{a=[]}"); - assertThat(read("a:\n - x\n -\nb: 1")).isEqualTo("{a=[x,],b=1}"); - } - - @Test - void aKeyWithNothingAfterItIsAnEmptyScalar() { - assertThat(read("a:\nb: 1")).isEqualTo("{a=,b=1}"); - assertThat(read("a:")).isEqualTo("{a=}"); - } - - @Test - void aSequenceAtTheSameIndentationOnlyBelongsToItsKey() { - assertThat(read("a:\nb:\n- x")).isEqualTo("{a=,b=[x]}"); - } - - @Test - void commentsAreDroppedExceptInsideQuotes() { - assertThat(read("# first\na: 1 # trailing\nb: \"x # y\"\nc: 'p # q'\nd: it's # note\ne: a#b")) - .isEqualTo("{a=1,b='x # y',c='p # q',d=it's,e=a#b}"); - } - - @Test - void aQuoteMidTokenOpensNoString() { - assertThat(read("a: it's\nb: 'x'")).isEqualTo("{a=it's,b='x'}"); - } - - @Test - void aQuoteAfterAnyDelimiterOpensAString() { - assertThat(read("a: [\"x # y\"]\nb: {k: 'p # q'}")).isEqualTo("{a=['x # y'],b={k='p # q'}}"); - } - - @Test - void aQuotedKeyIsUnquoted() { - assertThat(read("\"a b\": 1\n'c': 2")).isEqualTo("{a b=1,c=2}"); - } - - @Test - void anUnclosedQuotedKeyIsNotAMappingEntry() { - assertThatThrownBy(() -> Yaml.read("\"abc: 1")) - .isInstanceOf(Yaml.Unsupported.class) - .hasMessage("not a mapping entry: \"abc: 1"); - } - - @Test - void aColonWithoutASpaceIsNotAKey() { - assertThatThrownBy(() -> Yaml.read("a:b")) - .isInstanceOf(Yaml.Unsupported.class) - .hasMessage("not a mapping entry: a:b"); - assertThatThrownBy(() -> Yaml.read("a")).isInstanceOf(Yaml.Unsupported.class); - } - - @Test - void aKeyMayEndTheLine() { - assertThat(read("a:\n b:")).isEqualTo("{a={b=}}"); - } - - @Test - void aFlowCollectionOpensNoKey() { - assertThat(read("- {a: 1}\n- [b]")).isEqualTo("[{a=1},[b]]"); - } - - @Test - void flowMappingsAndSequencesNestAndQuote() { - assertThat(read("a: { b: 1, c: [x, \"y, z\", 'w'], d: {e: f}, \"g\": h }")) - .isEqualTo("{a={b=1,c=[x,'y, z','w'],d={e=f},g=h}}"); - assertThat(read("a: {}\nb: []")).isEqualTo("{a={},b=[]}"); - assertThat(read("a: {b: 1,}\nc: [x,]")).isEqualTo("{a={b=1},c=[x]}"); - } - - /** - * A colon not followed by a space ends no key and opens no mapping, in a flow sequence as in a - * block one: an item such as {@code --listen=:9100} is one plain scalar, as YAML reads it. - */ - @Test - void aColonInsideASequenceItemIsPartOfItsScalar() { - assertThat(read("a: [--listen=:9100, x:y]")).isEqualTo("{a=[--listen=:9100,x:y]}"); - assertThat(read("a:\n - --listen=:9100")).isEqualTo("{a=[--listen=:9100]}"); - assertThat(read("a: {b: [--l=:1]}")).isEqualTo("{a={b=[--l=:1]}}"); - } - - @Test - void aFlowCollectionMayRunOverSeveralLines() { - assertThat(read("a: {b: 1,\n c: 2}\nd: 3")).isEqualTo("{a={b=1,c=2},d=3}"); - assertThat(read("a: [\"{\", x\n ]\nd: 3")).isEqualTo("{a=['{',x],d=3}"); - assertThat(read("a: ['}'\n]\nd: 3")).isEqualTo("{a=['}'],d=3}"); - } - - @Test - void aFoldedScalarJoinsItsIndentedLines() { - assertThat(read("a: >\n one\n two\nb: |-\n three\nc: >+\n four\nd: 1")) - .isEqualTo("{a=one two,b=three,c=four,d=1}"); - assertThat(read("a: >\nb: 1")).isEqualTo("{a=,b=1}"); - } - - @Test - void aSequenceItemMayBeAFlowCollectionOrScalar() { - assertThat(read("- [a, b]\n- c\n- \"d\"")).isEqualTo("[[a,b],c,'d']"); - } - - @Test - void aLeadingDocumentMarkerIsAllowed() { - assertThat(read("---\na: 1")).isEqualTo("{a=1}"); - assertThat(read("--- \na: 1")).isEqualTo("{a=1}"); - } - - @Test - void aSecondDocumentIsOutsideTheSubset() { - assertThatThrownBy(() -> Yaml.read("a: 1\n---\nb: 2")) - .isInstanceOf(Yaml.Unsupported.class) - .hasMessage("more than one document"); - assertThatThrownBy(() -> Yaml.read("a: 1\n--- x\nb: 2")) - .isInstanceOf(Yaml.Unsupported.class) - .hasMessage("more than one document"); - assertThatThrownBy(() -> Yaml.read("a: 1\n...")) - .isInstanceOf(Yaml.Unsupported.class) - .hasMessage("more than one document"); - } - - @Test - void aFileWithNoContentHoldsNoDocument() { - assertThatThrownBy(() -> Yaml.read("")) - .isInstanceOf(Yaml.Unsupported.class) - .hasMessage("no document"); - assertThatThrownBy(() -> Yaml.read("# only\n\n---\n")) - .isInstanceOf(Yaml.Unsupported.class) - .hasMessage("no document"); - } - - @Test - void anAnchorAnAliasAndATagAreOutsideTheSubset() { - assertThatThrownBy(() -> Yaml.read("a: &x 1")) - .isInstanceOf(Yaml.Unsupported.class) - .hasMessage("anchor, alias or tag: &x 1"); - assertThatThrownBy(() -> Yaml.read("a: *x")) - .isInstanceOf(Yaml.Unsupported.class) - .hasMessage("anchor, alias or tag: *x"); - assertThatThrownBy(() -> Yaml.read("a: !!str x")) - .isInstanceOf(Yaml.Unsupported.class) - .hasMessage("anchor, alias or tag: !!str x"); - assertThatThrownBy(() -> Yaml.read("a: [&x 1]")).isInstanceOf(Yaml.Unsupported.class); - } - - @Test - void contentBelowTheRootIndentationIsUnexpected() { - assertThatThrownBy(() -> Yaml.read("a: 1\n b: 2")) - .isInstanceOf(Yaml.Unsupported.class) - .hasMessage("unexpected content"); - } - - @Test - void trailingSpacesAreDropped() { - assertThat(read("a: x \nb: \n c: y ")).isEqualTo("{a=x,b={c=y}}"); - } - - @Test - void windowsLineEndingsRead() { - assertThat(read("a: 1\r\nb: 2\r\n")).isEqualTo("{a=1,b=2}"); - } - - @Test - void aTextSequenceItemReadsAsTheTextAfterItsDash() { - assertThat(read("- x\n- k: 1\n l: 2")).isEqualTo("[x,{k=1,l=2}]"); - } - - @Test - void aKeyMayStartWithADashThatIsNoSequence() { - assertThat(read("-x: 1\n-y: 2")).isEqualTo("{-x=1,-y=2}"); - } - - @Test - void aQuotedKeyMustBeFollowedByItsColon() { - assertThatThrownBy(() -> Yaml.read("\"abc\"")).isInstanceOf(Yaml.Unsupported.class); - assertThatThrownBy(() -> Yaml.read("\"abc\" x")).isInstanceOf(Yaml.Unsupported.class); - } - - @Test - void aSequenceCannotFollowAMappingAtTheSameIndentationUnlessItBelongsToAKey() { - assertThatThrownBy(() -> Yaml.read("a: 1\n- b")) - .isInstanceOf(Yaml.Unsupported.class) - .hasMessage("unexpected content"); - } - - @Test - void aKeyWithNothingBelowItBeforeALessIndentedLineIsEmpty() { - assertThat(read("a:\n b:\nc: 1")).isEqualTo("{a={b=},c=1}"); - } - - @Test - void aFoldedScalarMayEndTheFile() { - assertThat(read("a: >\n x")).isEqualTo("{a=x}"); - } - - @Test - void aQuoteThatDoesNotMatchLeavesTheTextAsWritten() { - assertThat(read("a: \"abc")).isEqualTo("{a='\"abc'}"); - assertThat(read("a: 'abc")).isEqualTo("{a=''abc'}"); - assertThat(read("a: \"x'")).isEqualTo("{a='\"x''}"); - assertThat(read("a: 'x\"")).isEqualTo("{a=''x\"'}"); - assertThat(read("a: \"")).isEqualTo("{a='\"'}"); - assertThat(read("a: ''")).isEqualTo("{a=''}"); - } - - @Test - void aFlowCollectionMayHoldOnlySpaces() { - assertThat(read("a: { }\nb: [ ]")).isEqualTo("{a={},b=[]}"); - assertThat(Yaml.read("a: [ ]").map.get("a").list).isEmpty(); - } - - @Test - void spacesMayStandBeforeACommaOrAfterATrailingOne() { - assertThat(read("a: {b: [x] , c: d}")).isEqualTo("{a={b=[x],c=d}}"); - assertThat(read("a: {b: c, }\nd: [x, ]")).isEqualTo("{a={b=c},d=[x]}"); - } - - @Test - void aFlowValueEndsItsOwnLine() { - assertThat(read("a: [x]\nb: y")).isEqualTo("{a=[x],b=y}"); - } - - @Test - void aHashGluedToAWordOpensNoComment() { - assertThat(read("a: b# c")).isEqualTo("{a=b# c}"); - assertThat(read("a: b #c")).isEqualTo("{a=b}"); - } - - @Test - void anEmptyDashBeforeASiblingIsAnEmptyItem() { - assertThat(read("-\n- b")).isEqualTo("[,b]"); - } - - @Test - void aKeyMayBeEmpty() { - assertThat(read(": x\na: 1")).isEqualTo("{=x,a=1}"); - assertThat(read("- : x")).isEqualTo("[{=x}]"); - } - - @Test - void aFlowCollectionCannotStandForAKey() { - assertThatThrownBy(() -> Yaml.read("a: 1\n{b: 2}")).isInstanceOf(Yaml.Unsupported.class); - } -} diff --git a/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/values/ProjectIntentValueConvertersTest.java b/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/values/ProjectIntentValueConvertersTest.java deleted file mode 100644 index ac90461af..000000000 --- a/emf/bundles/syntax/src/test/java/dev/jorisjonkers/deploykit/emf/syntax/values/ProjectIntentValueConvertersTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.syntax.values; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -import org.eclipse.xtext.conversion.ValueConverterException; -import org.junit.jupiter.api.Test; - -/** What the authored text of a scalar means. */ -class ProjectIntentValueConvertersTest { - - private static final ProjectIntentValueConverters CONVERTERS = new ProjectIntentValueConverters(); - - @Test - void aQuotedScalarLosesItsQuotesAndAPlainOneIsUnchanged() { - assertThat(CONVERTERS.text().toValue("\"0400\"", null)).isEqualTo("0400"); - assertThat(CONVERTERS.text().toValue("'0400'", null)).isEqualTo("0400"); - assertThat(CONVERTERS.text().toValue("0400", null)).isEqualTo("0400"); - assertThat(CONVERTERS.text().toValue("\"", null)).isEqualTo("\""); - assertThat(CONVERTERS.text().toValue("\"unbalanced", null)).isEqualTo("\"unbalanced"); - assertThat(CONVERTERS.text().toValue("'mixed\"", null)).isEqualTo("'mixed\""); - } - - @Test - void theTextOfAScalarIsTheValueItself() { - assertThat(CONVERTERS.text().toString("0400")).isEqualTo("0400"); - } - - @Test - void aBooleanIsABoolean() { - assertThat(CONVERTERS.bool().toValue("true", null)).isTrue(); - assertThat(CONVERTERS.bool().toValue("false", null)).isFalse(); - assertThat(CONVERTERS.bool().toString(true)).isEqualTo("true"); - } - - @Test - void anythingElseIsNotABoolean() { - assertThatThrownBy(() -> CONVERTERS.bool().toValue("yes", null)) - .isInstanceOf(ValueConverterException.class) - .hasMessageContaining("yes is not true or false"); - } -} diff --git a/emf/docs/adr/README.md b/emf/docs/adr/README.md deleted file mode 100644 index f3d273d44..000000000 --- a/emf/docs/adr/README.md +++ /dev/null @@ -1,50 +0,0 @@ -# Decision register: the model-driven implementation - -The decisions that shape the EMF implementation under `emf/`. Every one is -deleted with this directory -([0071](emf/0071-emf-is-coursework-scoped-and-self-contained.md)), and none of -them can change what the model means: the model's decisions are in -[`docs/adr/`](../../../docs/adr/README.md), and the contract this -implementation shares with the production implementation is -[0068](../../../docs/adr/architecture/0068-two-implementations-meet-at-the-parity-table.md). - -The contract every record here satisfies is the root register's, unchanged: one -record per decision, frontmatter schema, one falsifiable claim per premise, -`rests-on` naming premises only, the Alternatives table and the citation rule. -`normative:` pointers name sections of [`emf/docs/architecture.md`](../architecture.md). -`node scripts/lint-adrs.ts emf` enforces all of it. - -Numbers come from the one estate-wide sequence shared with `docs/adr/`. - -## Domains - -| directory | holds | `normative:` pointers resolve against | linted | -|---|---|---|---| -| [`emf/`](emf/) | the EMF implementation: toolchain, metamodels, constraints, grammar, transformation, templates, witnesses | `emf/docs/architecture.md` | yes | - -## Premises - -| # | title | claim | normative | -|---|---|---|---| -| [0070](emf/0070-the-model-is-expressible-in-the-emf-toolchain.md) | The v1 model is expressible in the EMF toolchain without changing the model | open | architecture.md#scope-and-sunset | - -## Decisions - -| # | title | claim | -|---|---|---| -| [0071](emf/0071-emf-is-coursework-scoped-and-self-contained.md) | The EMF implementation is coursework-scoped, lives entirely under `emf/`, and is deleted when two conditions hold | open | -| [0072](emf/0072-maven-and-tycho-against-a-pinned-target-platform.md) | Maven builds `emf/`, with Tycho resolving p2-only bundles against a pinned target platform, on JDK 21, with no Eclipse IDE | settled | -| [0073](emf/0073-source-and-target-metamodels-are-hand-written.md) | The source and target metamodels are hand-written in Ecore, and their Java is generated at build time | open | -| [0074](emf/0074-constraints-are-complete-ocl-named-by-code.md) | Constraints are Complete OCL invariants named by the diagnostic code they emit | open | -| [0075](emf/0075-xtext-parses-the-authored-yaml-into-the-metamodel.md) | The Xtext grammar parses the authored YAML files themselves, into the imported metamodel | open | -| [0076](emf/0076-qvto-derives-the-resolved-deployment.md) | QVT-Operational derives the Resolved Deployment | open | -| [0077](emf/0077-acceleo-4-renders-the-deliverable-set.md) | Acceleo 4 renders the Deliverable Set, byte for byte against the committed tree | open | -| [0078](emf/0078-model-behaviours-have-a-junit-witness.md) | Every model behaviour in the behaviour ledger has a JUnit witness, listed inside `emf/` | open | -| [0079](emf/0079-the-emf-gates-are-estate-shaped.md) | The model-driven build carries the gates the estate's JVM repositories enforce, plus Java-shaped equivalents, and measures its thresholds | open | -| [0080](emf/0080-parity-crosses-the-cli-file-interface.md) | The parity suite reaches the pipeline through its file interface, and holds no EMF type | open | -| [0081](emf/0081-bundles-and-tests-are-separate-tiers.md) | The tree splits into an Eclipse bundle tier and a test tier, and only the bundle tier is Java | open | -| [0082](emf/0082-the-env-files-are-read-not-parsed-by-xtext.md) | The env files are read by a hand-written reader, not by a second Xtext grammar | settled | -| [0098](emf/0098-cross-file-invariants-navigate-an-estate-root.md) | Cross-file invariants navigate an Estate root that contains every document of a set, instead of reading the resource set through `allInstances()` | open | -| [0143](emf/0143-a-refusal-is-decided-in-ocl-unless-the-model-cannot-hold-what-it-asks.md) | A refusal is decided in Complete OCL, unless the model cannot hold what it asks | settled | -| [0151](emf/0151-a-rule-group-file-is-read-as-data-into-a-generic-tree.md) | A rule-group file is read as data into a generic tree, not into typed alert-rule classes | settled | -| [0152](emf/0152-emf-compare-decides-and-explains-every-model-comparison.md) | EMF Compare decides and explains every comparison of two models in the tests, pairing objects by natural key | settled | diff --git a/emf/docs/adr/emf/0070-the-model-is-expressible-in-the-emf-toolchain.md b/emf/docs/adr/emf/0070-the-model-is-expressible-in-the-emf-toolchain.md deleted file mode 100644 index edfc14c47..000000000 --- a/emf/docs/adr/emf/0070-the-model-is-expressible-in-the-emf-toolchain.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -tier: premise -status: proposed -claim: open -owner: joris -date: 2026-09-14 -normative: docs/architecture.md#scope-and-sunset ---- - -# The v1 model is expressible in the EMF toolchain without changing the model - -## Rests on -Every structure, constraint, derivation and rendered byte `spec/v1` defines can -be carried by Ecore, Complete OCL, an Xtext grammar, a QVT-Operational -transformation and Acceleo templates, so the second implementation needs no -change to `spec/v1` and no field the TypeScript compiler lacks. False if: a -parity case can only be made green by editing a chapter, an oracle file, or -the parity contract to suit a tool. Settled by: the `emf` job green on every -parity case under `spec/v1/examples/` with `git diff --stat spec/v1 -docs/architecture.md` over the whole `emf/` history touching only oracle files -both implementations were already failing. - -## Why -Every decision in this domain assumes the course's toolchain can carry the -model as it stands. If it cannot, the choice is between bending the model to a -tool that will be deleted and failing a parity case on purpose, and that choice -has to be visible rather than made quietly in a template. The claim is open -because nothing has been built: the likeliest counterexamples are the YAML -subset Xtext has to parse, byte-exact output from Acceleo, and derivations over -the whole composed union in QVTo. - -## Alternatives -| option | cost if taken | why rejected | -|---|---|---| -| Assume it and say nothing | No premise to maintain | A model change made to suit a coursework tool would look like a model decision | -| Allow the EMF side a documented subset of the model | Less work in October | The course project is graded on the whole pipeline, and a subset makes parity a claim about part of the model | - -## Reversibility -Undo cost today: deleting this file. Becomes irreversible once: never; the -premise describes a test, and a counterexample is recorded as a gap, not built -around. - -## Consequences -- A counterexample is written into this file as evidence and raised as a model - question in its own pull request, never absorbed into `emf/`. Paid by whoever - finds it, in one issue. -- The model stays tool-neutral: nothing in `spec/v1` depends on Ecore, Eclipse - OCL, Xtext, QVTo or Acceleo. The Essential OCL statements in the chapters' - rule tables are OMG notation, not tool input, and the Complete OCL invariants - under `emf/` are held to them. Paid by nobody while this holds. diff --git a/emf/docs/adr/emf/0071-emf-is-coursework-scoped-and-self-contained.md b/emf/docs/adr/emf/0071-emf-is-coursework-scoped-and-self-contained.md deleted file mode 100644 index a5596ef37..000000000 --- a/emf/docs/adr/emf/0071-emf-is-coursework-scoped-and-self-contained.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -tier: decision -status: proposed -claim: open -owner: joris -date: 2026-09-14 -normative: docs/architecture.md#scope-and-sunset -rests-on: ["0070"] ---- - -# The EMF implementation is coursework-scoped, lives entirely under `emf/`, and is deleted when two conditions hold - -## Rests on -The premise here is -[0070](0070-the-model-is-expressible-in-the-emf-toolchain.md): the toolchain -can carry the model unchanged. False if: deleting `emf/` and the root lines the -architecture lists as naming it leaves anything in the repository broken or -changes any behaviour of `src/`. Settled by: the sunset pull request's CI green -with exactly those removals and no other change outside `spec/v1/examples/`. - -## Why -The course requires the EMF toolchain; the estate does not. The TypeScript -compiler is the implementation the estate will run, and the proposal -(`docs/mde/task-0-proposal/Sections/07-tooling.tex`) already argued that a JVM -and Eclipse toolchain buys nothing for the deployment workflow. The Java tree is -therefore built to be removed. - -Removal is cheap only if nothing outside `emf/` knows it exists. So the Maven -build, its modules, its checks, its ledgers and its decisions live under -`emf/`, and the root names it only where it must: CI, the ADR lint's domain -list and its test, and the parity contract's pointer. - -"Temporary" alone names no moment, so the sunset is two conditions. The grade -alone is not enough: if the TypeScript compiler still lags when the grade is -recorded, deleting `emf/` would delete the only complete implementation. - -## Alternatives -| option | cost if taken | why rejected | -|---|---|---| -| Remove after the course ends, by date | Simplest to state | A date says nothing about whether the TypeScript compiler can stand alone yet | -| Keep it permanently as a second implementation | No sunset work | Every model change in two languages, forever, for a toolchain the estate does not use | -| EMF decisions and checks in the root `docs/` and `scripts/` | One register, one place to look | Sunset becomes picking files out of shared directories, and the root stops being TypeScript | - -## Reversibility -Undo cost today: moving files out of `emf/`, an hour. Becomes irreversible -once: never; the point of the layout is that deleting it is always one pull -request. - -## Consequences -- The root gains a CI job, a lint step, a lint domain entry with its test, and - one architecture section, and loses all but the section at sunset. Paid in - that pull request. -- EMF ADR numbers come from the estate-wide sequence, so a number used under - `emf/docs/adr/` is never reused under `docs/adr/`, and the reverse. Paid by - whoever picks the next number, by checking both registers. -- `emf/` cannot import TypeScript tooling: its own checks are JUnit through - Maven. Paid in duplicated check code, deleted with it. diff --git a/emf/docs/adr/emf/0072-maven-and-tycho-against-a-pinned-target-platform.md b/emf/docs/adr/emf/0072-maven-and-tycho-against-a-pinned-target-platform.md deleted file mode 100644 index d4175b433..000000000 --- a/emf/docs/adr/emf/0072-maven-and-tycho-against-a-pinned-target-platform.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -tier: decision -status: accepted -claim: settled -owner: joris -date: 2026-09-14 -normative: docs/architecture.md#toolchain -rests-on: ["0070"] ---- - -# Maven builds `emf/`, with Tycho resolving p2-only bundles against a pinned target platform, on JDK 21, with no Eclipse IDE - -The walking skeleton (#81) proved it: `mvnw verify` -runs all five tools headless, each through its standalone API: an `.ecore` -loaded and an instance validated, a Complete OCL invariant fired, a generated -Xtext parser read a three-line document, a QVT-Operational identity -transformation ran, and an Acceleo 4 template wrote a file. Three facts follow: - -- Every bundle, EMF and Xtext included, resolves from one p2 repository: the - 2026-06 simultaneous release at its dated build, with each unit pinned to - an exact version in `emf/emf.target`. Maven Central carries a newer Xtext - than the release the OCL and QVT-Operational bundles were built against, so - taking EMF and Xtext from Central would have mixed two releases. The one - Central artifact left is the ANTLR 3 generator the Xtext generator calls, - which is not published to p2. -- A module that needs a p2 bundle is an Eclipse bundle (`eclipse-plugin`, - with a manifest), because Tycho resolves p2 dependencies only for bundles. - Its tests still run on a plain classpath through Maven Surefire, outside - OSGi, so the standalone APIs CI checks are the ones a command-line user - gets. -- The Xtext generator runs as an MWE2 workflow in `generate-sources`, writing - every Java file, stubs included, under `target/`. - -No Eclipse IDE is needed to build, and CI never -uses one. The projects must still be loadable in Eclipse Modeling Tools for -the course's examiners, as the Task 0 proposal promises: they import as -existing Maven projects, the metamodels open, the Xtext-generated editor -reports OCL constraint violations while editing, and committed launch -configurations run the -QVT-Operational transformation and the Acceleo generator. Keeping that -working is part of this decision; the Maven build stays the only path CI -checks. - -## Rests on -Resting on [0070](0070-the-model-is-expressible-in-the-emf-toolchain.md), the -claim here is that every tool the course requires runs headless from one Maven -build: EMF, Xtext, Eclipse OCL, QVT-Operational and Acceleo 4 all resolve from -Maven Central or a pinned p2 site and run without an OSGi workspace. False if: -any of them needs the Eclipse IDE, a launch configuration or a manual step to -produce what CI checks. Settled by: the walking skeleton's `mvn verify` green -in CI from a clean runner cache. - -## Why -The course teaches these tools inside the Eclipse IDE. The estate works in -IntelliJ and CI, and a build a grader cannot reproduce with one command is a -build nobody can check. So the IDE is out, and the question is which build tool -reaches the tools. - -Gradle was the preference and was dropped: the EMF-family tools that publish -only to p2 have no maintained Gradle route, and the Eclipse projects themselves -build with Maven and Tycho. Tycho exists to resolve p2 repositories from Maven, -with the target platform as one file pinned to exact versions, which is the -same pinning discipline the rest of the repository applies to CI binaries. -JDK 21 is the current LTS the Eclipse releases target. - -## Alternatives -| option | cost if taken | why rejected | -|---|---|---| -| Gradle | The estate's preferred build tool, existing templates | p2-only bundles need unmaintained plugins or hand-vendored jars, and every tool's documented headless route is Maven | -| Plain Maven with vendored jars | No Tycho conventions | Transitive bundles resolved by hand and upgraded by hand | -| The Eclipse IDE, as taught | Matches the lectures | Not reproducible in CI, not the estate's editor | - -## Reversibility -Undo cost today: nothing exists. Becomes irreversible once: never; the build is -deleted with `emf/`. - -## Consequences -- CI gains a JDK and a Maven cache for one job. Paid in pipeline minutes. -- Modules that consume p2 bundles follow Tycho's packaging conventions. Paid - once per module. -- A tool that turns out not to run headless stops Task 1 early rather than in - October. Paid by the skeleton, in a day. diff --git a/emf/docs/adr/emf/0073-source-and-target-metamodels-are-hand-written.md b/emf/docs/adr/emf/0073-source-and-target-metamodels-are-hand-written.md deleted file mode 100644 index 66fa5aaaf..000000000 --- a/emf/docs/adr/emf/0073-source-and-target-metamodels-are-hand-written.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -tier: decision -status: proposed -claim: open -owner: joris -date: 2026-09-14 -normative: docs/architecture.md#metamodels -rests-on: ["0070"] ---- - -# The source and target metamodels are hand-written in Ecore, and their Java is generated at build time - -There are two packages, as the project proposal defines -([#102](https://github.com/JorisJonkers-dev/deploy-kit/pull/102)): a source -metamodel holding Project Intent and the Platform document, and a target -metamodel holding the Resolved Deployment with its typed Kubernetes and -extension resources. A third holds the pinned inputs the resolution reads beside -the source: the node contract, the images lock, the ClusterState snapshot, the -migration proofs and the text of the Asset files. -The descriptor covers the source metamodel only. - -## Rests on -Resting on [0070](0070-the-model-is-expressible-in-the-emf-toolchain.md), the -claim is that the source metamodel (Project Intent, with the Platform document -it is resolved against) fits one Ecore package whose structure, exported as the -parity descriptor, equals the structure the Zod schemas in `src/` declare, and -that the target metamodel (the Resolved Deployment with its typed resources) -fits a second package the templates can walk. -False if: the descriptor exported from Ecore cannot equal the committed -descriptor without a type, multiplicity or vocabulary that the TypeScript side -does not have. Settled by: the descriptor parity suite green in both -implementations. - -## Why -The course grades metamodelling as its first task, and the metamodel is what -every later tool reads: the grammar imports it, the constraints annotate it, -the transformation maps between its packages, and the templates walk it. It is -written by hand because the course grades authored metamodels and because -generating it from Zod would make its structure unfalsifiable against Zod. - -The proposal defines two metamodels, a source and a target, and the course -grades them as such. The three layers of the three-model pipeline -([0003](../../../../docs/adr/model/0003-three-model-pipeline.md)) still hold: -the Deliverable Set is the generated files, so it has no metamodel, and the -target metamodel carries layer 2 together with the typed resources the files -are written from, because an Acceleo template reads one model. The Platform -document is part of the source package because the transformation resolves a -Project against it. The pinned inputs are not: nobody authors them as intent, -each is a document another process publishes and resolution pins by digest, and -neither the descriptor nor the TypeScript schemas the descriptor is compared -with hold them, so a package of their own keeps the descriptor what it was and -nothing in the target refers to them. -Cross-document references are Ecore references, so the transformation navigates -them rather than joining strings. - -Java is generated from the `.genmodel` during the build rather than committed: -the tools work on typed models most smoothly, and committed generated code is a -second copy that goes stale. - -## Alternatives -| option | cost if taken | why rejected | -|---|---|---| -| Dynamic EMF, no generated Java | No code generation step | Every test and helper works through reflection, and the course's material assumes generated model code | -| Commit the generated Java | Navigable without a build | Large diffs on every metamodel change and a stale copy the moment someone forgets to regenerate | -| OCLinEcore or Xcore as the source | One textual file per layer | The `.ecore` is what every tool and the grader reads, so a second source format adds a translation | - -## Reversibility -Undo cost today: nothing exists. Becomes irreversible once: never; deleted with -`emf/`. - -## Consequences -- A model change is an `.ecore` edit and a Zod edit, and the descriptor suite - fails until both match. Paid by whoever changes the model. -- Class diagrams for the course report are drawn from the `.ecore` files, not - maintained separately. Paid by nobody. diff --git a/emf/docs/adr/emf/0074-constraints-are-complete-ocl-named-by-code.md b/emf/docs/adr/emf/0074-constraints-are-complete-ocl-named-by-code.md deleted file mode 100644 index 42391ea2b..000000000 --- a/emf/docs/adr/emf/0074-constraints-are-complete-ocl-named-by-code.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -tier: decision -status: proposed -claim: open -owner: joris -date: 2026-09-14 -normative: docs/architecture.md#constraints -rests-on: ["0070"] ---- - -# Constraints are Complete OCL invariants named by the diagnostic code they emit - -The same Complete OCL constraints also run in the Xtext-generated editor, -which marks each violation while a source file is edited. Diagnostics in the -build keep the code and JSON Pointer contract; the editor shows the code as -the message. - -## Rests on -Resting on [0070](0070-the-model-is-expressible-in-the-emf-toolchain.md), the -claim is that every constraint the specification defines is expressible as an -OCL invariant evaluated standalone, and that each refused case yields the same -set of `(code, path)` pairs from OCL as from Zod. False if: a constraint -needs Java code outside OCL, or the containment chain cannot produce the JSON -Pointer the TypeScript side reports. Settled by: every refused case's -diagnostics parity green in `emf/tests/parity`, and the constraint parity test -finding an invariant for every code a TypeScript check emits -([0068](../../../../docs/adr/architecture/0068-two-implementations-meet-at-the-parity-table.md)). - -## Why -OCL is the course's constraint language, and the TypeScript side's constraints -are checks named by the same codes. The two are held together by that naming -and by committed diagnostics, not by translation. - -Complete OCL files sit beside the metamodel rather than inside it, which keeps -structure and rules apart the way the wire schemas and the domain invariants -are apart in `src/`. Naming each invariant by its code makes the mapping from a -failed invariant to a diagnostic a name read, not a table to keep in step. - -The path is part of the contract, so it is computed, not described: the -containment chain gives each containing feature and index, which is what a -JSON Pointer into the canonical intent document is. - -## Alternatives -| option | cost if taken | why rejected | -|---|---|---| -| OCLinEcore annotations inside the `.ecore` | One file per layer | Mixes structure and rules in the file the descriptor exporter reads | -| Java validators via EMF's validation framework | No OCL learning curve | The course grades OCL, and Java validators duplicate the TypeScript code in a third form | -| Compare codes only, not paths | No path computation | A diagnostic at the wrong object would pass | - -## Reversibility -Undo cost today: nothing exists. Becomes irreversible once: never; deleted with -`emf/`. - -## Consequences -- Every new constraint is a ledger row, a Zod check, an OCL invariant and a - refused fixture in one pull request. Paid by its author. -- OCL evaluation order is unspecified, so diagnostics compare as a set, never a - list. Paid by nobody; it is the contract. diff --git a/emf/docs/adr/emf/0075-xtext-parses-the-authored-yaml-into-the-metamodel.md b/emf/docs/adr/emf/0075-xtext-parses-the-authored-yaml-into-the-metamodel.md deleted file mode 100644 index 0792f02d8..000000000 --- a/emf/docs/adr/emf/0075-xtext-parses-the-authored-yaml-into-the-metamodel.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -tier: decision -status: proposed -claim: open -owner: joris -date: 2026-09-14 -normative: docs/architecture.md#concrete-syntax -rests-on: ["0070"] ---- - -# The Xtext grammar parses the authored YAML files themselves, into the imported metamodel - -Xtext also generates the editor that examiners use in Eclipse, configured to -run the OCL validators and report constraint violations during editing. The -grammar imports the one source metamodel, which holds the Platform document -as well. The pinned inputs resolution reads, the node contract, the images lock, -the ClusterState snapshot and a project's migration proof, are YAML in the same subset, so each is read by a -grammar of its own that inherits the project grammar's terminals, block tokens -and scalars and imports the pinned-inputs metamodel; which grammar reads a file -is the file's name to say, as it is for the Platform document. - -## Rests on -Resting on [0070](0070-the-model-is-expressible-in-the-emf-toolchain.md), the -claim is that the YAML subset every authored example uses can be parsed by an -Xtext grammar with synthetic indentation tokens, producing instances of the -hand-written source metamodel. False if: an -authored example needs YAML the grammar cannot parse without ambiguity, or the -parsed model serialises to an `intent.json` different from the committed one. -Settled by: the parsed-intent parity suite green for every authored file under -`spec/v1/examples/`. - -## Why -Parse parity is only direct when both implementations read the same bytes. A -new textual syntax for the Java side would double every fixture and add a -third failure mode, drift between a YAML file and its twin. - -Importing the metamodel instead of letting Xtext infer one keeps a single -layer-1 metamodel: the parser's output is what OCL validates and QVTo reads. -The price is that the grammar has to fit the metamodel's shape, so YAML keys -become keywords, and YAML the examples do not use is refused rather than -supported. - -## Alternatives -| option | cost if taken | why rejected | -|---|---|---| -| A new DSL with paired YAML and DSL fixtures | A cleaner grammar to present | Every fixture written twice, and pairs drift | -| An inferred metamodel mapped to the hand-written one | The grammar is free of the metamodel's shape | A third metamodel and an extra transformation to keep in parity | -| A plain YAML loader instead of Xtext | Full YAML support | The course requires Xtext | - -## Reversibility -Undo cost today: nothing exists. Becomes irreversible once: never; deleted with -`emf/`. - -## Consequences -- A YAML construct new to the examples needs a grammar change before the Java - side can read it. Paid by whoever introduces it, and visible as a failing - parse parity case. -- The grammar refuses flow sequences, anchors and multi-document files unless - an example needs them. Paid by nobody while examples avoid them. diff --git a/emf/docs/adr/emf/0076-qvto-derives-the-resolved-deployment.md b/emf/docs/adr/emf/0076-qvto-derives-the-resolved-deployment.md deleted file mode 100644 index d4946328c..000000000 --- a/emf/docs/adr/emf/0076-qvto-derives-the-resolved-deployment.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -tier: decision -status: proposed -claim: open -owner: joris -date: 2026-09-14 -normative: docs/architecture.md#transformation -rests-on: ["0070"] ---- - -# QVT-Operational derives the Resolved Deployment - -The transformation targets the model-driven Resolved Deployment metamodel, -which holds typed resources, so its output is not compared with -`resolved.json`. The two implementations are compared on the resolved -dependency edges and on the generated files instead, as the project proposal names -them ([#102](https://github.com/JorisJonkers-dev/deploy-kit/pull/102)). - -## Rests on -Resting on [0070](0070-the-model-is-expressible-in-the-emf-toolchain.md), the -claim is that every derivation and assignment chapter 20 defines, including the -ones over the whole composed union, is expressible as QVTo mappings and helpers -run by the standalone executor. False if: a derivation needs Java black-box -code for anything but hashing, or the transformation's output yields dependency -edges or generated files different from the committed ones. Settled by: the -dependency-edge and rendered parity suites green for every case under -`spec/v1/examples/`. - -## Why -The course teaches ATL and QVT-Operational for model-to-model transformation. -The Resolved Deployment is derived mostly by computation over the whole input, -not by matching one element to one element: the path plan, collision detection, -the Reconcile Unit graph and the release gate inputs all read the composed -union. QVTo is imperative, which fits that; ATL's rule matching fits a -structural mapping and pushes the global derivations into helpers anyway. - -## Alternatives -| option | cost if taken | why rejected | -|---|---|---| -| ATL | The most course examples | Global derivations end up as helper code outside the rule model | -| ATL for mapping, QVTo for derivations | Shows both taught tools | Two transformation runtimes to build and keep in parity | -| Java over the generated model | Fastest to write | The course grades a transformation language | - -## Reversibility -Undo cost today: nothing exists. Becomes irreversible once: never; deleted with -`emf/`. - -## Consequences -- Hashing for `renderHash` and content-hashed Assets is a black-box Java helper, - the one allowed. Paid once. -- A derivation the transformation lacks shows up as a dependency-edge or - rendered parity failure, not a silent default. Paid by the author of the derivation. -- The resolution resolves one project per run, and everything that project - delivers is planned in that run, its Vault policy job and its rollout events - among them, so there are two transformations and no pass over several - Resolved Deployments. While the estate is handed over, a legacy datastore's - catalog is planned by each project that reads it, as estate-scoped output - beside its own model. Paid in that output being planned once per reader. diff --git a/emf/docs/adr/emf/0077-acceleo-4-renders-the-deliverable-set.md b/emf/docs/adr/emf/0077-acceleo-4-renders-the-deliverable-set.md deleted file mode 100644 index d49b917a4..000000000 --- a/emf/docs/adr/emf/0077-acceleo-4-renders-the-deliverable-set.md +++ /dev/null @@ -1,50 +0,0 @@ ---- -tier: decision -status: proposed -claim: open -owner: joris -date: 2026-09-14 -normative: docs/architecture.md#text-generation -rests-on: ["0070"] ---- - -# Acceleo 4 renders the Deliverable Set, byte for byte against the committed tree - -The templates read a Resolved Deployment model of the target metamodel, -which already holds the typed resources; the Deliverable Set itself has no -metamodel. - -## Rests on -Resting on [0070](0070-the-model-is-expressible-in-the-emf-toolchain.md), the -claim is that Acceleo 4 templates run standalone can reproduce every committed -`rendered/` file exactly, whitespace and key order included. False if: a -rendered file cannot be matched without post-processing the template output -outside Acceleo. Settled by: the rendered parity suite green for every case -under `spec/v1/examples/`, with no formatter between the templates and the -comparison. - -## Why -The course requires Acceleo for model-to-text, and code generation carries the -largest share of the project grade. Acceleo 4 is the maintained line, with AQL -queries and a standalone API; Acceleo 3 is in maintenance. - -Byte equality is strict for a template language, and it is the contract the -TypeScript serializer already meets. Relaxing it for one implementation would -make the rendered oracle mean two things. - -## Alternatives -| option | cost if taken | why rejected | -|---|---|---| -| Acceleo 3 | Most tutorials | Maintenance mode, and its standalone launch goes through generated launchers | -| Compare parsed YAML, not bytes | Whitespace stops mattering | The TypeScript side is held to bytes, and determinism is part of the model | -| Templates plus a YAML formatter pass | Easy whitespace | The formatter, not the templates, would be doing the generation being graded | - -## Reversibility -Undo cost today: nothing exists. Becomes irreversible once: never; deleted with -`emf/`. - -## Consequences -- Whitespace control is a template concern throughout. Paid in template - complexity. -- A rendered file changed in `spec/v1/examples/` fails here until the template - matches. Paid by whoever changes it. diff --git a/emf/docs/adr/emf/0078-model-behaviours-have-a-junit-witness.md b/emf/docs/adr/emf/0078-model-behaviours-have-a-junit-witness.md deleted file mode 100644 index 55575d1bb..000000000 --- a/emf/docs/adr/emf/0078-model-behaviours-have-a-junit-witness.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -tier: decision -status: proposed -claim: open -owner: joris -date: 2026-09-14 -normative: docs/architecture.md#witnesses -rests-on: ["0070"] ---- - -# Every model behaviour in the behaviour ledger has a JUnit witness, listed inside `emf/` - - -The list has a **pending** state, for a model behaviour row this implementation -cannot prove yet. `REQ-033`, `REQ-034` and `REQ-035` are layer-2 -and node-contract behaviours whose Ecore half lands with -[#87](https://github.com/JorisJonkers-dev/deploy-kit/issues/87), and until it -does there is no target metamodel here to validate against. The alternatives -were to drop the rows from the gate, which loses them, or to witness them -against a test that proves something else, which is the gate reporting an -agreement nobody established. A pending row names its ticket, still has to -name a real model row, may not also be witnessed, and is counted separately, -so what is owed stays visible. It is the state the -[rule ledger](../../rules.md) already carries for a rule not enforced yet -([0066](../../../../docs/adr/architecture/0066-every-enforced-rule-has-an-id-a-row-and-a-fixture.md)). - -## Rests on -Resting on [0070](0070-the-model-is-expressible-in-the-emf-toolchain.md), the -claim is that the behaviours a unit test proves in `src/` about parsing, -validation, resolution and rendering can each be proved by a JUnit test here, -and that a list inside `emf/` can be checked against the root ledger without -the root knowing about it. False if: a model behaviour row can only be proved -in one implementation, or keeping the list requires a column in the root -ledger. Settled by: the witness check in `emf/tests/parity` green, and failing on a -fixture that removes one witness. - -## Why -The oracle files prove agreement on what the examples exercise. A unit test -proves a behaviour the examples may not reach, such as an error raised for an -input no worked example contains. Without a rule, one implementation tests it -and the other never does, and the parity contract says nothing. - -The list lives in `emf/` so the root ledger stays the TypeScript ledger it is, -and the sunset deletes the list with nothing to edit in the root. - -## Alternatives -| option | cost if taken | why rejected | -|---|---|---| -| A witness column in the root ledger | One table | The root gains an EMF dependency, and the sunset edits every row | -| Parity only through the examples | No list to maintain | Unit-level behaviour can diverge wherever no example reaches | -| A separate EMF requirements ledger with its own ids | Clean separation | Two ledgers can disagree about which behaviours exist | - -## Reversibility -Undo cost today: nothing exists. Becomes irreversible once: never; deleted with -`emf/`. - -## Consequences -- A model behaviour row lands with a JUnit witness or the `emf` job fails. Paid - by its author, in the same pull request. -- A witness is a JUnit test in whichever language its module is written: Kotlin - functions of `tests/parity` and Java methods of a bundle alike - ([0081](0081-bundles-and-tests-are-separate-tiers.md)), and a witness row names - the function as it is written, backticks and spaces included. -- The check needs to know which rows are model behaviours; the TypeScript tests - that prove them live under `test/model/`, and that path is the marker. Paid - once, when the first model test lands. diff --git a/emf/docs/adr/emf/0079-the-emf-gates-are-estate-shaped.md b/emf/docs/adr/emf/0079-the-emf-gates-are-estate-shaped.md deleted file mode 100644 index f239d3871..000000000 --- a/emf/docs/adr/emf/0079-the-emf-gates-are-estate-shaped.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -tier: decision -status: proposed -claim: open -owner: joris -date: 2026-09-14 -normative: docs/architecture.md#gates -rests-on: ["0070"] ---- - -# The model-driven build carries the gates the estate's JVM repositories enforce, plus Java-shaped equivalents, and measures its thresholds - -Every gate holds with Tycho in the build. Two are carried differently in -Eclipse bundles, and generated sources are left out of measurement: - -- Tycho compiles bundles with the Eclipse JDT compiler, not `javac`, so - `-Xlint:all -Werror` reaches plain jar modules only. Bundles get the JDT - equivalent: its default warnings, with any warning failing the build. -- Dependency convergence is not checked in bundles. Their dependencies are - p2 bundles at the versions the target platform pins, so Maven has no - version choice to converge. -- Coverage and mutation are bound in the parent and run in every module. A - module with no main classes has nothing to measure and both skip it; the - syntax module excludes the classes the Xtext generator writes from both, - and allows an empty mutation set until it holds code written by hand. - -## Rests on -Resting on [0070](0070-the-model-is-expressible-in-the-emf-toolchain.md), the -claim is that the gates the estate's Gradle repositories run for JVM code have -Maven equivalents that hold over this build, including once Tycho and generated -EMF sources arrive. False if: a gate has to be switched off, or its threshold -lowered, beyond the two bundle carve-outs above, to let a stage land. Settled by: the -`emf` job green with every gate in `emf/docs/rules.md` enforced after the Task 3 -code generation work merges. - -## Why -The estate's JVM repositories share one set of Gradle convention plugins. An -audit of fourteen of them found what they actually enforce: JDK 21 toolchains, -compiler warnings as errors, JaCoCo with a line-coverage floor wired into -`check`, JUnit with AssertJ and ArchUnit, Renovate, pinned CI actions and one -aggregating `Pipeline Complete` check. Their formatting and static analysis -(ktlint, detekt) are Kotlin-only. - -This build ports the first group one for one: the enforcer for JDK and Maven -versions, `-Xlint:all -Werror`, JaCoCo bound to `verify`, JUnit 6 with AssertJ -and ArchUnit. It gives Java the equivalent the estate gives Kotlin, Spotless -with palantir-java-format, because Java would otherwise be the one language in -the estate nobody formats. It adds PIT mutation testing, which the root already -plans for the TypeScript gates and no estate JVM repository runs yet, because -the parity code here decides what counts as agreement between two -implementations and a line that runs is not a line that is checked. - -The thresholds are set from the first measurement, not from a convention: the -first `mvn verify` over the canonical JSON writer and the ledger checks reached -100% line coverage, 100% branch coverage and 87 of 87 mutants killed, so those -are the floors, and they only rise. Equivalent mutants were removed by -restructuring the code, not by lowering the score. - -## Alternatives -| option | cost if taken | why rejected | -|---|---|---| -| SpotBugs, Error Prone and NullAway | Stronger static analysis | No estate JVM repository runs any of them; Error Prone only reaches plain jar modules under Tycho, and CodeQL `security-and-quality` already scans the Java | -| An 80% line floor, the estate's default | Matches the Gradle conventions | The first measurement is 100%, and a floor below what the suite reaches is a floor that lets coverage fall | -| No mutation testing for a deprecated tree | Faster builds | Parity code that passes by accident makes two implementations look equal when they are not | -| SBOM and artifact signing | Supply-chain evidence | Nothing is published, and no estate JVM artifact carries either | - -## Reversibility -Undo cost today: deleting plugin blocks and ledger rows, an hour. Becomes -irreversible once: never; deleted with `emf/`. - -## Consequences -- Every generated source directory Tycho, Xtext or genmodel adds must be excluded - from formatting, coverage and mutation in the pull request that adds it. Paid - by the walking skeleton first. -- If PIT cannot run inside an OSGi test runtime, it is scoped to the plain jar - modules and the scoping is recorded here. Paid by whichever stage meets it. -- Every build runs mutation testing, so `mvn verify` grows with the code. Paid in - CI minutes, and revisited if the job passes ten minutes. -- A threshold change is a line in `emf/pom.xml` that has to be argued in review. - Paid by whoever wants to lower one. diff --git a/emf/docs/adr/emf/0080-parity-crosses-the-cli-file-interface.md b/emf/docs/adr/emf/0080-parity-crosses-the-cli-file-interface.md deleted file mode 100644 index 5a6fe6167..000000000 --- a/emf/docs/adr/emf/0080-parity-crosses-the-cli-file-interface.md +++ /dev/null @@ -1,118 +0,0 @@ ---- -tier: decision -status: proposed -claim: open -owner: joris -date: 2026-09-16 -normative: docs/architecture.md#parity -rests-on: ["0070"] ---- - -# The parity suite reaches the pipeline through its file interface, and holds no EMF type - -## Rests on -Resting on [0070](0070-the-model-is-expressible-in-the-emf-toolchain.md), the -claim is that everything the parity contract compares is already a file, so a -suite that calls no EMF type can still prove every case under -`spec/v1/examples/`. False if: a parity case exists that cannot be decided from -the pipeline's own output files and its exit code, and can only be decided by -reading an in-memory model. Settled by: the parity module building as a plain -jar with no dependency on the target platform, green on every case the three -course tasks land. - -## Why -Today `parity/` imports `Pipeline`, `Parsed`, `Diagnostic` from the `cli` -module and `Descriptor`, `ProjectIntentPackage` from `metamodel`. Those are EMF -types, resolved from p2, so the test module has to be an Eclipse bundle to see -them. It is one: `parity/pom.xml` declares `eclipse-plugin` packaging, while -[the architecture](../../architecture.md#toolchain) says modules that need no p2 -bundle, like `parity/`, stay plain jars. The drift is not a typo. One suite -reaching past the pipeline's own interface pulled the whole Eclipse toolchain -into the module whose job is to be independent of it. - -The pipeline's real interface is narrower than its Java types: input files and -arguments in; an exit code, diagnostics and a rendered tree out. That is the -interface [0068](../../../../docs/adr/architecture/0068-two-implementations-meet-at-the-parity-table.md) -already compares the two implementations across, because an oracle file is a -file and nothing else. Two things are compared today through Java instead: the -metamodel descriptor and the parsed intent. Both are values the pipeline can -write, so both can cross the same interface as everything else. - -Moving the suite onto that interface pays three times. The test module loses -every p2 dependency and becomes a plain jar. A parity failure then names an -output a person can open, not a Java field a person has to reconstruct. And the -suite exercises what a run of the pipeline leaves behind, which is what a grader -sees from `mvn verify` and what an examiner sees from a launch configuration, so -a case that passes in CI is a case either of them can reproduce. - -Losing every p2 dependency is also what lets the module be written in a language -the target platform does not carry, which is -[0081](0081-bundles-and-tests-are-separate-tiers.md)'s subject. This decision -stands on its own (the drift it closes is live today), but that is the order the -two are taken in. - -The module keeps `Ledgers` in its `src/main`: it is a helper the suites call, -not a test, and it touches no EMF. `CanonicalJson` does not stay: the pipeline -now writes what the suite used to serialise, so the writer moves down to -`metamodel/`, the lowest module that writes a canonical file, and the suites -compare bytes instead of serialising anything. - -It costs the ability to assert on anything the pipeline does not write. That is -the point: a value worth asserting on is a value worth emitting, and one that -is not emitted is not evidence of parity. - -## Alternatives -| option | cost if taken | why rejected | -|---|---|---| -| Leave `parity/` an Eclipse bundle and fix the architecture's sentence instead | Nothing to build; the drift closes by rewriting the doc | Keeps the toolchain inside the module that exists to be free of it, and keeps the widest interface in the tree as the test surface | -| Keep the Java calls, but add a second, file-level suite beside them | Both surfaces proven | Two suites decide the same cases, and the narrow one is never trusted while the wide one exists | -| Make the pipeline a separate process the suite runs | The strictest seam, exit code included | Costs a packaged, runnable artifact and process plumbing for no case the in-process file interface cannot decide; revisit if one appears | -| Export only the descriptor, keep `Parsed` in Java | One less thing to serialise | The parsed intent is the Task 1 evidence, so it is exactly the thing that must be readable as a file | - -## Reversibility -Undo cost today: restoring the Java calls and the `eclipse-plugin` packaging, -half a day, and the serialisers stay useful either way. Becomes irreversible -once: never; deleted with `emf/`. - -## Consequences -- The pipeline writes the parsed intent and the diagnostics as canonical JSON, - and the metamodel writes its descriptor as a build artifact. Paid by the - pull request that moves the suite. -- `parity/pom.xml` becomes `jar` packaging and loses its `META-INF/MANIFEST.MF` - and its `build.properties`, the two PDE artifacts, so it builds without the - target platform. Paid in the same pull request. -- **The module rules stop enforcing unless they are given their classes and a - non-empty guard.** `ArchitectureTest` is `@AnalyzeClasses(packages = - "dev.jorisjonkers.deploykit.emf")`, so it sees the other modules only because - `parity/META-INF/MANIFEST.MF` requires them. Dropping that dependency, which - this decision mandates, leaves the importer with parity's own classes; every - other layer is then empty, `withOptionalLayers(true)` excuses it, and - `EMF-010` and `EMF-011` pass while proving nothing. The suite reads the - class directories the build wrote, by path, **and** asserts every module whose - classes the build wrote is in the import, so an empty import fails loudly - instead of passing. A module with no class of its own yet, which `resolve/` - and `render/` are until their stage lands, is empty in the tree rather than - missing from the import, and is not reported. Paid in the same pull request, - as `EMF-017`, and shown by a fixture that empties the import. -- A module that declares no dependency is ordered by its position in the - reactor alone, so `-T`, `-pl` or an IDE can run the suite before the bundles - wrote their classes and output files. Each case asserts its expected output - file exists before comparing it, and a missing one fails as a missing file - rather than as a skipped case. That is a different absence from a case with no - committed oracle, which is still listed as not yet a parity case: one is the - pipeline failing to write what it owes, the other is a case nobody has pinned - yet. Paid in the same pull request. -- `EMF-010` and `EMF-011` keep their rows but gain the fixture - [0066](../../../../docs/adr/architecture/0066-every-enforced-rule-has-an-id-a-row-and-a-fixture.md) - requires, since a rule that has only ever run clean is untested and these two - would be the first to pass vacuously. Paid in the same pull request. -- The module table's dependency rule changes shape: the parity module depends on - no module, only on the files the build writes. That is a row in - [the architecture](../../architecture.md#modules), a row in - [the rule ledger](../../rules.md) for `EMF-010`, **and** the rule's own - enforcement: `MODULES_DEPEND_ONLY_ON_MODULES_ABOVE_THEM` in - `ArchitectureTest` currently names `parity` in five `mayOnlyBeAccessedByLayers` - chains, so it would keep permitting exactly what this decision forbids. The - layer and those five entries go together with the imports. -- A stage that wants a new parity assertion must first make the pipeline emit - the value. Paid by Task 2 and Task 3. diff --git a/emf/docs/adr/emf/0081-bundles-and-tests-are-separate-tiers.md b/emf/docs/adr/emf/0081-bundles-and-tests-are-separate-tiers.md deleted file mode 100644 index 2dd475da7..000000000 --- a/emf/docs/adr/emf/0081-bundles-and-tests-are-separate-tiers.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -tier: decision -status: proposed -claim: open -owner: joris -date: 2026-09-16 -normative: docs/architecture.md#modules -rests-on: ["0070"] ---- - -# The tree splits into an Eclipse bundle tier and a test tier, and only the bundle tier is Java - -## Rests on -Resting on [0070](0070-the-model-is-expressible-in-the-emf-toolchain.md), the -claim is that the modules an examiner opens in Eclipse and the modules that -only ever run from Maven are two disjoint sets, and that the second set needs -nothing from the Eclipse toolchain. False if: a module has to be both, or a -test tier written outside Java cannot hold a gate this build already enforces. -Settled by: `./mvnw -B -ntp verify` green with `bundles/` built by Tycho, the -test tier built as a plain Kotlin jar, and every rule in -[the rule ledger](../../rules.md) still enforced. - -## Why -Every module under `emf/` is an Eclipse bundle today, and the directory listing -says nothing about which of them a course examiner ever opens. Five of them are -the graded artefacts: the metamodels, the grammar, the transformation, the -templates and the pipeline that runs them. One, `parity/`, is this -repository's own evidence, built and run only by Maven, and by -[0080](0080-parity-crosses-the-cli-file-interface.md) it holds no EMF type at -all. Two audiences, two toolchains, one flat list. - -The split names them: `bundles/` for what Tycho builds against `emf.target` -and Eclipse imports, `tests/` for what Maven builds as a plain jar. The boundary -answers a question every reader currently has to work out from a `pom.xml`: is -this file graded, and will a teacher open it. It says nothing about the -documents: `emf/docs/` keeps its architecture, its rule ledger, its witness list -and its register where they are, and a reader who finds them spread out is -finding a different problem than this one. - -The boundary is also a language boundary. Ecore generates Java, Xtext's runtime -hooks are Java, and a bundle compiles through Tycho's JDT compiler against a -target platform that carries no Kotlin: putting Kotlin in a bundle means a -`kotlin-stdlib` unit in `emf.target`, a second compiler ahead of JDT, and an -examiner who needs the Kotlin Eclipse plugin to read the source. So `bundles/` -is Java, without exception. - -The `cli` module is the one worth naming, because it looks like the exception. -It is not run from Eclipse the way the metamodels are read there, so it reads -like a candidate for Kotlin. It is not one: it calls the EMF, OCL, QVTo and -Acceleo standalone APIs, every one of them resolved from p2, so it is a bundle -by its dependencies whatever language it is written in, and it carries the -launch configurations an examiner runs. Kotlin reaches it only as a launcher -wrapping a Java pipeline, which buys argument parsing and pays a module for it. -The part with no teacher, no Eclipse and no p2 dependency is the test tier, and -that is the part this decision moves. `tests/` has none of those constraints and every -other JVM repository in the estate is Kotlin with a mature suite, so it is -Kotlin, and the estate's test idiom applies here rather than being reinvented -in Java. - -The graded modules keep their short directory names. Tycho's convention is a -directory named for the bundle's symbolic name, but Eclipse names an imported -Maven project from its `artifactId` regardless, so the long names buy nothing -an import already gives and cost every path in the tree. - -## Alternatives -| option | cost if taken | why rejected | -|---|---|---| -| Keep the flat module list, document the split in prose | No moves, no path updates | The listing is what a reader sees first; a convention only a document knows is a convention that gets broken | -| Split by course task (`task1/`, `task2/`, `task3/`) instead | Matches the grading schedule exactly | The `cli` and the metamodels span every task, so the split would have to cut them; the deadline is a property of a row in the module table, not of a directory | -| Directories named for bundle symbolic names | Tycho and PDE convention, directory equals Eclipse project | Eclipse takes the project name from the `artifactId` anyway, so it buys a naming match nobody reads and costs 40-character paths | -| Kotlin in the bundles too, one language for the tree | One toolchain to learn | A p2 target platform with no Kotlin, a second compiler before JDT, and generated EMF Java that stays Java regardless | -| Kotlin for `cli` alone, the module no teacher runs as a project | The pipeline entry in the estate's language | `cli` calls four standalone APIs resolved from p2, so it is a bundle by its dependencies; Kotlin would reach only a launcher around the Java pipeline | -| Keep the test tier in Java | No second language in the build | Every other JVM repository in the estate is Kotlin, so a Java suite here is the one suite nobody has a pattern for | - -## Reversibility -Undo cost today: moving six directories back and updating the paths that name -them. `grep -rIl -E 'emf/(metamodel|syntax|cli|resolve|render|parity)'` over the -tracked tree finds them; an afternoon. Becomes -irreversible once: never; deleted with `emf/`. - -## Consequences -- The reactor's `` entries become `bundles/…` and `tests/…`, and the - root's `test/emf-wiring.test.ts` keeps holding them, since it reads the - entries rather than assuming a depth. Paid by the moving pull request. -- The `bundle` profile in `emf/pom.xml`, which activates on a module's - `META-INF/MANIFEST.MF`, now agrees with the directory it sits in. The file - test stays: the directory is documentation, the manifest is the fact. -- Spotless with palantir-java-format covers `bundles/`; the test tier needs - the formatter the estate's Kotlin repositories run. Paid by the pull request - that ports the suite. -- PIT reports many equivalent mutants on Kotlin, so the mutation threshold of - [0079](0079-the-emf-gates-are-estate-shaped.md) may not hold over the test - tier at the number it holds over Java. Lowering it is a decision of its own, - with its own record, and until one exists the threshold stands. -- `emf/README.md` gains the one table that says which artefact lives where and - which task grades it, so the layout answers the navigation question without - a search. Paid by the moving pull request. -- A witness is a JUnit test in whichever language its module is written - ([0078](0078-model-behaviours-have-a-junit-witness.md)); the ported suite's - witnesses are Kotlin functions. -- Every document that names a module by its current path moves with it, in the - same commit, `emf/docs/architecture.md` and `emf/README.md` included: [the rule ledger](../../rules.md), whose `EMF-010`, `EMF-011`, - `EMF-013`, `EMF-014` and `EMF-016` rows each name a file under `parity/` and - whose `EMF-014` check fails the build the moment a named file is not where its - row says; [the witness list](../../witnesses.md); - [the root architecture](../../../../docs/architecture.md); the refusal - examples' README; and the two root tests that name a parity path in a comment - and in a fixture string. The ledger is the one that breaks the build if it is - forgotten. diff --git a/emf/docs/adr/emf/0082-the-env-files-are-read-not-parsed-by-xtext.md b/emf/docs/adr/emf/0082-the-env-files-are-read-not-parsed-by-xtext.md deleted file mode 100644 index 92670877b..000000000 --- a/emf/docs/adr/emf/0082-the-env-files-are-read-not-parsed-by-xtext.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -tier: decision -status: accepted -claim: settled -date: 2026-09-21 -normative: docs/architecture.md#concrete-syntax -rests-on: ["0070"] ---- - -# The env files are read by a hand-written reader, not by a second Xtext grammar - -[0075](0075-xtext-parses-the-authored-yaml-into-the-metamodel.md) settles how -the authored YAML reaches the metamodel. The other authored artefact, the -dotenv env files -([chapter 10](../../../../spec/v1/10-project-intent.md#the-dotenv-subset-that-is-read)), -reaches it through a reader written by hand in each implementation instead, and -produces the same `EnvFile`, `EnvEntry`, `EnvLiteral` and `Placeholder` -instances the rest of the model is made of. - -## Rests on - -The model is expressible in the EMF toolchain -([0070](0070-the-model-is-expressible-in-the-emf-toolchain.md)), and this -decision narrows where one tool of it is used rather than reaching outside the -set: nothing here is parsed by something the course does not name, because a -reader is not a parser generator, it is the code the Java side would write -around any parser anyway. - -## Why - -**An ANTLR lexer cannot separate a dotenv key from its value.** A value runs to -the end of its line and may contain `=`: a connection string and a base64 -secret both do. So the greedy value terminal matches `NAME=value` whole, from -the first column, and wins the longest match against the name terminal. Xtext -exposes no lexer mode and no syntactic predicate to break the tie. - -**The technique that fixes it makes the grammar a fiction.** This repository -already answers an unlexable syntax with a token source: `BlockTokenSource` -turns YAML indentation into the synthetic `BEGIN` and `END` tokens the project -grammar reads, and that works because what the token source computes -(indentation) is not what the grammar decides (structure). For dotenv the split -at `=` *is* the structure, and telling a literal from a placeholder is the only -other decision in the language. A token source doing both leaves a grammar with -two rules and nothing to decide, which is a parser with a grammar-shaped -comment on it. - -**One reader, two implementations, one oracle.** The reader is about forty -lines on each side and both are held to the same committed `intent.json`, which -is the same evidence every other stage offers. Parse parity is unaffected: both -implementations read the same bytes, which is what -[0075](0075-xtext-parses-the-authored-yaml-into-the-metamodel.md) asked for. - -## Alternatives - -| option | cost if taken | why rejected | -|---|---|---| -| A third Xtext language with a token source that splits at `=` and classifies the value | the token source decides the whole language, and the grammar it feeds says only "entries are entries"; two generated lexers, a runtime module and a standalone setup exist to host it | the grammar would document nothing and enforce nothing, at the price of the largest scaffolding in the bundle | -| Restrict a literal to carry no `=` | a connection string, a base64 secret and a query string stop being expressible, and the model gains a rule about ANTLR rather than about deployment | the model may not be shaped by the parser generator's lexer | -| Author env as YAML so the existing grammar reads it | every env file in the estate is rewritten, and dotenv stops being what a process reads; `0013` chose dotenv because that is the format the thing being configured already consumes | the authored format is the model's, not the toolchain's | -| Leave env unparsed, and let layer 2 read the files | the placeholder and the grant it byte-matches sit in different worlds, so the unauthorised-reference check has no model to run over | the check is the reason the files are in the model at all | - -## Reversibility - -Undo cost today: the reader is one file per implementation with one entry -point, so replacing it with a generated parser is deleting it and binding the -new one where it was called, plus the scaffolding that parser needs: a day. -Becomes irreversible once: nothing, because the reader's output is model -instances and every consumer downstream sees only those. - -## Consequences - -- One authored artefact of two is parsed by a grammar and the other by a reader, so "what parses the authored files" has two answers, paid by a reader of the architecture, who is told both in one section. -- The dotenv subset is enforced by the reader rather than by a grammar, so the subset lives in prose and in two implementations instead of in one file, paid by the chapter, which states it exhaustively, and by the parity oracle, which is what holds the two readers to it. -- An examiner's Eclipse editor validates the project and Platform documents and not the env files, paid by the course, which asked for a grammar and gets one for the language that has one. diff --git a/emf/docs/adr/emf/0098-cross-file-invariants-navigate-an-estate-root.md b/emf/docs/adr/emf/0098-cross-file-invariants-navigate-an-estate-root.md deleted file mode 100644 index 5b4aa3076..000000000 --- a/emf/docs/adr/emf/0098-cross-file-invariants-navigate-an-estate-root.md +++ /dev/null @@ -1,75 +0,0 @@ ---- -tier: decision -status: accepted -claim: open -owner: joris -date: 2026-10-09 -normative: docs/architecture.md#constraints -rests-on: ["0070"] ---- - -# Cross-file invariants navigate an Estate root that contains every document of a set, instead of reading the resource set through `allInstances()` - -The documents of a set are read into one **Estate** root object that contains -every Project, the Platform document and the Infrastructure document. An -invariant over more than one document is written in the context of `Estate` -and navigates containment; no invariant calls `allInstances()`. An invariant -over one document stays on that document's own classes. The section that -states it is [the constraints chapter](../../architecture.md#constraints). - -## Rests on - -The v1 model is expressible in the EMF toolchain without changing the model -([0070](0070-the-model-is-expressible-in-the-emf-toolchain.md)), and the -specification already composes every document into one union before checking -what they break together -([chapter 40](../../../../spec/v1/40-composition.md#the-estate-wide-invariants)), -so a root that holds the union is the model's own shape, not an artefact of -OCL. - -**False if:** an invariant over the composed documents cannot be written by -navigation from an `Estate`, or the refusals the cross-file invariants produce -change when they move onto it. **Settled by:** every invariant that reads -`allInstances()` today rewritten in the context of `Estate`, with the refused -fixtures' diagnostics byte-identical before and after, tracked on -[#324](https://github.com/JorisJonkers-dev/deploy-kit/issues/324). - -## Why - -**The course review named the cost.** The Task 1 feedback recorded that -cross-file constraints "require EMF allInstances() scans with explicit safety -guards, introducing performance and evaluation complexity when files are -loaded individually". The guards exist because `allInstances()` ranges over -whatever resource set a document happened to be read into: an invariant over -the set holds trivially over a document read alone, so the pipeline reads each -file alone first and the set together second, and an invariant's meaning -depends on which reading is running. - -**A root makes the scope a value, not a circumstance.** Navigating from -`Estate` reaches exactly the documents the set contains, read once; there is no -second reading, no trivially true pass, and nothing whose extent depends on the -resource set. It is also how chapter 40 already describes the check: the -estate-wide invariants hold over the composed union, which is an object. - -## Alternatives - -| option | cost if taken | why rejected | -|---|---|---| -| Keep `allInstances()` with its guards and document the cost | nothing to change | the two readings and the trivially true pass stay, and an invariant's meaning still depends on its resource set | -| Move cross-file checks out of OCL into Java or QVT | full control over evaluation | the constraints stop being Complete OCL named by code ([0074](0074-constraints-are-complete-ocl-named-by-code.md)) | -| Cross-document references resolved as EReferences, still evaluated per document | no root class | a reference does not bound the scope of a quantifier over every Project | - -## Reversibility - -Undo cost today: nothing implements it yet; this record. Becomes irreversible -once: the invariants are written against `Estate` and the two-reading pipeline -is removed. - -## Consequences - -- The metamodel gains one root class, and every cross-file invariant moves - onto it, paid once in [#324](https://github.com/JorisJonkers-dev/deploy-kit/issues/324). -- The pipeline reads a set once, so a refusal over a single document and one - over the set come from the same pass. -- Until #324 lands, the invariants read the set through `allInstances()` as - the constraints chapter records. diff --git a/emf/docs/adr/emf/0143-a-refusal-is-decided-in-ocl-unless-the-model-cannot-hold-what-it-asks.md b/emf/docs/adr/emf/0143-a-refusal-is-decided-in-ocl-unless-the-model-cannot-hold-what-it-asks.md deleted file mode 100644 index cf1335076..000000000 --- a/emf/docs/adr/emf/0143-a-refusal-is-decided-in-ocl-unless-the-model-cannot-hold-what-it-asks.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -tier: decision -status: accepted -claim: settled -date: 2026-10-30 -normative: docs/architecture.md#constraints -rests-on: ["0070"] ---- - -# A refusal is decided in Complete OCL, unless the model cannot hold what it asks - -Most of the refusals the specification names are invariants of the Complete OCL -file beside the source metamodel. A few are decided in Java, in the `cli` -bundle's pipeline, beside the parse. This record says which go where, and why -the line is drawn by what the model holds rather than by what is convenient to -write. - -## Rests on - -The model is expressible in the EMF toolchain -([0070](0070-the-model-is-expressible-in-the-emf-toolchain.md)). OCL is the -toolchain's language for a rule over a model, so a rule over the model is -written in it. A rule over something the model does not hold is outside what -OCL can see, and the toolchain gives it no other home than the code that reads -the files. - -## Why - -**OCL decides what one parsed model holds.** An invariant reads the objects of -the documents a set was read into, and nothing else. A rule over a Process's -cutover, its volumes, its grants, its routes or the Platform document's tiers -is a rule over that model, and its name is the code it emits, so `Constraints` maps a -failure to its diagnostic with no table. - -**Three kinds of question are not about that model, and Java answers them:** - -- **A file beside the project file.** The model names a dashboard or a rule file - by path and holds none of its content: whether it is there, holds a uid, or - lists rule groups is a fact of the file system. `ShippedFiles` reads it, as the - Asset check already did. -- **A pinned input.** The images lock is a separate document of a separate - metamodel that a set's check does not read as intent. Whether an image a pod - runs as its own user is locked as root is decided where the lock is read. -- **A refusal placed at a position the invariant's path cannot write.** An - invariant reports at its object, plus at most one feature named after `__`. - An entry of a list of strings, such as one Project the mesh enrols, or a port - a tier derives rather than one a project file writes, has no object of its - own. `L4Checks`, `OperatedChecks` and `Pipeline.check` place these. - -**What a Process holds across the union is asked only of a document that -holds.** Self delivery without a Vault client, and a secret placeholder on a -Client without one, read the env files beside the project, which are attached -before the document is checked. A tier's proxy under a Platform document with -no `apiAccess` is asked of the union by composition. The production -implementation asks these after each document's own checks pass, so a document -refused for its own shape is not refused for them as well. `Pipeline.refusals` -keeps that order with one named set of such codes. - -## Alternatives - -| option | cost if taken | why rejected | -|---|---|---| -| Every refusal in OCL, with the files' contents and the lock loaded into the model first | a dashboard's JSON and a rule file's YAML become model objects only to be asked whether they parse; the lock joins the intent extent it is pinned against | the model would hold content it never resolves, to let a rule look at it | -| A second Complete OCL file for the pinned inputs | Eclipse OCL binds one Complete OCL document per package and thread, and a second file for a package already bound is never evaluated ([0098](0098-cross-file-invariants-navigate-an-estate-root.md)) | the file would be silently skipped | -| Widen the invariant's path convention to carry an index | `Constraints` would parse a position out of the invariant's name or its message | a path built from a name is the lookup table the convention exists to avoid | -| Every union-level code asked unconditionally | a document refused for its shape is refused again for a grant it holds, where the production implementation reports one refusal | parity is per diagnostic, so the extra one is a difference | - -## Reversibility - -Undo cost today: each Java check is one class or one method, called from one -place in `Pipeline.check`, and held by its own unit tests and by the refusal -oracles. Moving a check into OCL means bringing what it reads into the model -first: a day per kind. Becomes irreversible once: nothing, since every refusal -is compared by code, document and path, wherever it is decided. - -## Consequences - -- "Where is a refusal decided" has two answers, paid by a reader of the architecture, who finds both, and the reason for each group, in its constraints section. -- Four Java classes carry rules an examiner would look for in the `.ocl` file, paid by the course report, which defends the split rather than hiding it. -- The union-level codes are listed twice, as invariants and as the set `Pipeline.refusals` defers them by, paid by whoever adds such a code, who adds it to both. diff --git a/emf/docs/adr/emf/0151-a-rule-group-file-is-read-as-data-into-a-generic-tree.md b/emf/docs/adr/emf/0151-a-rule-group-file-is-read-as-data-into-a-generic-tree.md deleted file mode 100644 index deb040ba6..000000000 --- a/emf/docs/adr/emf/0151-a-rule-group-file-is-read-as-data-into-a-generic-tree.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -tier: decision -status: accepted -claim: settled -date: 2026-11-01 -normative: docs/architecture.md#concrete-syntax -rests-on: ["0070"] ---- - -# A rule-group file is read as data into a generic tree, not into typed alert-rule classes - -An Application's alert rules arrive as a file beside its project file -([chapter 10](../../../../spec/v1/10-project-intent.md#alert-rules)), and the -monitoring stack's `PrometheusRule` carries that file's groups as the file writes -them. The model-driven implementation reads such a file with a hand-written -reader, `DataFile` in the `cli` bundle, into a generic tree of `Datum` -instances (`DatumMap`, `DatumEntry`, `DatumList` and `DatumScalar`, a scalar -typed as YAML's core schema types it) in both the pinned-inputs and the -Resolved Deployment metamodels. The typed `AlertRuleGroup` and `AlertRule` -classes it replaces are gone. - -## Rests on - -The model is expressible in the EMF toolchain -([0070](0070-the-model-is-expressible-in-the-emf-toolchain.md)). A reader is -not a parser generator, so reading a file by hand stays inside that set, as -the env files' reader does -([0082](0082-the-env-files-are-read-not-parsed-by-xtext.md)). - -## Why - -**What the rules hold is Prometheus's, not the model's.** A rule group may carry -recording rules, an evaluation interval, a limit, labels and annotations of any -shape, and fields a later Prometheus adds. The model decides where the rules go -and which `PrometheusRule` holds them, never what a rule says, just as it -decides where an Asset mounts and never what the Asset holds. - -**Typed classes lost what they did not name.** `AlertRuleGroup` and `AlertRule` -named an alert's name, expression, duration, labels and annotations. The real -estate's vendored kube-prometheus rules carry recording rules and group -intervals, and the typed classes dropped them, so the rendered `PrometheusRule` -stopped equalling the oracle the first time a real Project's rules were rendered. - -**Key for key needs the order and the types kept.** The oracle writes each group -with its keys in the file's order and each scalar as the type YAML gives it, so -`for: 5m` stays a string and `limit: 10` stays an integer. A generic tree that -keeps entries in order and records each scalar's kind is the smallest model -that renders the file byte for byte, and a template walks it with one recursive -rule. - -**The file may be YAML or JSON.** Vendored rule sets ship as JSON and authored -ones as YAML. One reader of the YAML subset, of which JSON's syntax is a part, -reads both into the same tree. - -## Alternatives - -| option | cost if taken | why rejected | -|---|---|---| -| Typed classes covering the whole Prometheus rule schema | the model tracks another project's schema field by field, and lags it on every Prometheus release | the model would own a schema it does not decide | -| An Xtext grammar for rule files | a third grammar for a format the model only carries through, and its typed output has the same gaps as the classes | [0082](0082-the-env-files-are-read-not-parsed-by-xtext.md) already reserves grammars for the languages the model owns | -| Carry the file as text and paste it into the template | a JSON file cannot be pasted into YAML, and the groups must be re-indented under `spec`; both are a parse in disguise | the template would hide a reader | - -## Reversibility - -Undo cost today: one reader, and five classes and an enum in each of two metamodels, plus -the one recursive template that writes them, so moving back to typed classes is -a day. Becomes irreversible once: nothing, since every consumer reads the tree -through the template alone. - -## Consequences - -- Two kinds of authored file are now read by a hand-written reader rather than a grammar, env files and rule files, paid by the architecture's "Concrete syntax" section, which names both. -- A rule file's content is not validated by the model: a malformed rule reaches the `PrometheusRule` as written, paid by the cluster's own admission and by the oracle comparison, which holds the rendered tree byte for byte. -- An examiner's Eclipse editor shows a rule file's groups as a generic tree in the reflective model editor, not as named alert-rule objects, paid by the metamodel diagrams, which show the `Datum` classes as the carrier they are. diff --git a/emf/docs/adr/emf/0152-emf-compare-decides-and-explains-every-model-comparison.md b/emf/docs/adr/emf/0152-emf-compare-decides-and-explains-every-model-comparison.md deleted file mode 100644 index 1176a525e..000000000 --- a/emf/docs/adr/emf/0152-emf-compare-decides-and-explains-every-model-comparison.md +++ /dev/null @@ -1,86 +0,0 @@ ---- -tier: decision -status: accepted -claim: settled -date: 2026-11-02 -normative: docs/architecture.md#stage-tests -rests-on: ["0070"] ---- - -# EMF Compare decides and explains every comparison of two models in the tests, pairing objects by natural key - -Every test that compares two models, an XMI golden of the stage harness, an -oracle distance, or a resolution held against a hand-written model, asks EMF -Compare. Two models are equal only when it reports no difference, and each -difference it reports is one line at the object's keyed path, in the stage -harness's own format. The rules for the key and the report are in -[Stage tests](../../architecture.md#stage-tests). - -## Rests on - -The model is expressible in the EMF toolchain -([0070](0070-the-model-is-expressible-in-the-emf-toolchain.md)), and EMF Compare -is part of that toolchain's simultaneous release: the 2026-06 build the target -already pins ([0072](0072-maven-and-tycho-against-a-pinned-target-platform.md)) -carries EMF Compare 3.3.28, whose core needs only EMF and Guava, both already -resolved there. - -## Why - -**An index walk reports where a list shifted, not what changed.** The resolved -model links by index fragment and the walk it replaces paired list items by -index, so an insertion, a deletion or a reordering moved every item after it -and every reference into it. Breaking the largest resolve golden on purpose, -the walk reported 130 lines for two Applications swapped, 60 for a removed -process, 12 for a moved environment entry and 9 for an inserted one; EMF Compare -keyed by natural key reported 1, 10 (the process and each reference to it), 1 -and 1. - -**A whole-model dump says nothing.** `ResolutionTest`'s checks failed by -printing the resolved model's whole XMI, up to 250 lines with no word of where -it differed. The same failure through EMF Compare is two lines: the input digest -that moved and the hash that follows it. - -**One tool should decide and explain.** Keeping `EcoreUtil.EqualityHelper` as -the verdict and EMF Compare as the explanation would leave two definitions of -equal, and a failure whose explanation is empty. With EMF Compare deciding, a -difference is reported exactly when it fails a test. The one thing it does not -tell apart on its own, an unsettable feature unset beside one set to its default, -the comparison adds, because an XMI file does. - -**The key is the model's own, not the metamodel's IDs.** Only three classes -declare an `iD` attribute, and EMF Compare's default matcher, keyed by those and -by similarity elsewhere, still paired keyless objects across Deliverables when -two Applications swapped, because similarity weighs a reference by its target's -index fragment. Keying each list item by the attribute that names it, a pair of -them where one is not unique, or a reference to a keyed object, pairs what a -reader would pair, and leaves similarity to the items that have no name. - -**It is fast and stays test-only.** A resolve golden compares in 0 to 4 ms and -reports the same lines every run. The bundle is on the `cli` bundle's -classpath through `additional.bundles`, never in a manifest, so nothing a module -ships can need it, and the coverage and mutation gates, which measure shipped -classes, see nothing new. - -## Alternatives - -| option | cost if taken | why rejected | -|---|---|---| -| Keep `EcoreUtil.EqualityHelper` and the index walk | nothing to add | the reports above; a reordering reads as every later item changed | -| `EqualityHelper` decides, EMF Compare explains a failure | two notions of equal, kept in agreement by hand | a failure whose explanation is empty is possible, and nothing says which of the two is right | -| Key the walk by name as the YAML half already does | a hand-written move detection and no answer for items without a name | EMF Compare already pairs by similarity, detects moves and moves across containers | -| EMF Compare with its default matcher | no key function to keep | similarity weighs index fragments, so a swap pairs unrelated objects elsewhere in the model | - -## Reversibility - -Undo cost today: one test class, `ModelDiff`, and the two call sites that use it, -plus one target unit and two `build.properties` lines; going back to an equality -check is an hour. Becomes irreversible once: nothing, since no shipped class may -depend on it (`EMF-021`). - -## Consequences - -- A line names a list item by its key, `[name="api"]`, where it named it by index, paid by the comparison's own tests, which hold every kind of line, and by each golden that fails, whose report changes shape. -- A key that changes reads as one item removed and one added, or as one item changed where similarity pairs them, paid by the line's path, which names both. -- An item with no key is paired by similarity, which may pair it with a different item than a reader would, paid by the marker on every such line and by `ModelDiffTest`, which asserts that no real difference compares equal however the items are paired. -- The target carries a unit the course does not require, paid by its version moving with the rest of the release in one change, as every unit does. diff --git a/emf/docs/architecture.md b/emf/docs/architecture.md deleted file mode 100644 index c74109a26..000000000 --- a/emf/docs/architecture.md +++ /dev/null @@ -1,658 +0,0 @@ -# The model-driven implementation's structure - -Normative for the code under `emf/`, the way -[`docs/architecture.md`](../../docs/architecture.md) is normative for `src/`. -Decisions in [`docs/adr/emf/`](adr/README.md) point their `normative:` field at -sections of this document, and the ADR lint checks that the anchor exists. - -This implementation answers to the model in [`spec/v1`](../../spec/v1/00-overview.md) -and to the [parity contract](../../docs/architecture.md#the-parity-contract), -and to nothing in `src/`. Where this document and either of those disagree, -they win and this document is what gets fixed. - -## Scope and sunset - -This tree implements the whole compiler: parse, validate, resolve and render, -for every case under `spec/v1/examples/`. It is built in the order the course -grades it. - -| course task | due | lands here | -|---|---|---| -| Task 1: metamodelling | 2026-09-25 | the two Ecore metamodels, the Xtext grammar and its editor, the OCL constraints; parity on the parsed intent, the descriptor and refused cases | -| Task 2: transformations | 2026-10-16 | the QVT-Operational transformation into the Resolved Deployment; parity on the resolved dependency edges | -| Task 3: code generation | 2026-10-30 | the Acceleo templates rendering the Deliverable Set; parity on `rendered/` | - -The tree is deleted in one pull request when both of these hold: - -1. the final grade for the course project is recorded; -2. the TypeScript suite is green on every parity case with the `emf` CI job - removed from `Pipeline Complete`. - -What that pull request keeps: every oracle file under `spec/v1/examples/`, the -constraint parity test without its OCL column, and the descriptor check. What it -deletes: this directory; the `emf` CI job and the `ADR contract (emf)` step in -`.github/workflows/ci.yml`; the `java-kotlin` entry in -`.github/workflows/codeql.yml`; `test/emf-wiring.test.ts`, with `RULE-061` and -`RULE-062` in `docs/architecture-rules/gates.md` and `REQ-015` in -`docs/requirements/repository.md`; the `emf` domain entry in `scripts/lint-adrs.ts` and -the two `emf/` cases in `test/adr-contract.test.ts`; the `emf` exclusion in -`release-please-config.json`, the `emf maven` rule in `renovate.json`, the -`/emf/` line in `.github/CODEOWNERS`, the `mvnw` line in `.gitattributes` and -the stage goldens' line in `.prettierignore`; -and the `emf/` mentions in `docs/architecture.md`, `docs/requirements.md`, -`docs/requirements/repository.md`, -`docs/adr/README.md`, `README.md`, `CONTEXT.md` and `CLAUDE.md`. - -## Toolchain - -Maven, with Eclipse Tycho resolving every EMF-family bundle from one p2 -repository: the Eclipse simultaneous release at a dated build, named in -`emf.target` with each unit at an exact version, so EMF, Xtext, OCL, -QVT-Operational and Acceleo arrive at versions released together. The one -Maven Central artifact outside the test libraries is the ANTLR 3 generator the -Xtext generator calls. The units the tests alone use come from the same -release: EMF Compare's core ([Stage tests](#stage-tests)), and ATL's EMFTVM -runtime and compiler, which run the benchmark's ATL port of the lowering and -nothing else ([the benchmark](benchmarks.md)). JDK 21. -No Eclipse IDE, workspace or launch configuration is part of the build: every -step CI runs is `mvn verify` from `emf/`. `.mvn/maven.config` turns on Maven -Resolver's file-lock sync context, so several builds on one machine, such as -parallel worktrees, can share one local repository (`-Dmaven.repo.local=`, -outside `~/.m2`) without corrupting it. The projects are nonetheless kept -loadable in Eclipse Modeling Tools for the course's examiners: they import as -existing Maven projects, the metamodels open, the Xtext-generated editor reports -OCL constraint violations while a source file is edited, and committed launch -configurations run the transformation and the generator. - -A module that needs a p2 bundle is an Eclipse bundle: a `META-INF/MANIFEST.MF` -naming the bundles it requires, and `eclipse-plugin` packaging. A manifest -switches on the parent's `bundle` profile, which runs the module's tests -through Maven Surefire on a plain classpath, outside OSGi, so every tool is -exercised through the standalone API a command-line run uses. A module that -needs no p2 bundle stays a plain jar, declaring its own test libraries because -the `bundle` profile does not activate for it. `tests/parity` is the one such -module, for the reason [Parity](#parity) records. The profile activates on a -module's `META-INF/MANIFEST.MF` rather than on the tier it sits in, and stays -that way: the directory is documentation, the manifest is the fact. - -The first change to this tree is the **EMF scaffold**: the Maven reactor, the -wrapper, the gates and the `emf` CI job, with no EMF dependency and one module, -`parity`, holding the canonical JSON writer and the ledger checks. The second is -the **walking skeleton**, which proves each tool runs headless in CI before any -model work depends on it: an `.ecore` loads, an OCL -invariant fires, the Xtext parser reads a three-line document, a QVTo identity -transformation runs, and an Acceleo template writes one file. Its smoke tests -sat in the module each tool belongs to (the QVTo and Acceleo ones are gone, -deleted by the resolution and rendering tracers), and each is deleted by the -stage ticket whose suite covers that tool. - -## Modules - -Two tiers, under one parent `pom.xml` that owns the Tycho configuration and the -target platform. `bundles/` holds one Maven module per pipeline stage: what -Tycho builds against `emf.target`, and what an examiner imports into Eclipse. -`tests/` holds what Maven alone builds and runs, and what no examiner opens -([0081](adr/emf/0081-bundles-and-tests-are-separate-tiers.md)). The boundary -answers the question a flat list left every reader to work out from a -`pom.xml`: is this file graded, and will a teacher open it. - -The directories keep their short names. Tycho's convention is a directory named -for the bundle's symbolic name, but Eclipse names an imported Maven project from -its `artifactId` regardless, so the long names would buy a match nobody reads -and cost every path in the tree. - -| module | holds | graded in | -|---|---|---| -| `bundles/metamodel` | the source, target and pinned-inputs `.ecore` and `.genmodel`, Complete OCL `.ocl` for the source metamodel, the descriptor exporter, and the canonical JSON writer both it and `cli` write through | Task 1 | -| `bundles/syntax` | the Xtext grammars for the authored YAML subset and the pinned inputs written in it, and the generated editor bundles that run the OCL validators | Task 1 | -| `bundles/resolve` | the QVTo transformations: the two transformations, the lowering onto the Process, then Project Intent with Platform Intent and the pinned inputs to one Project's Resolved Deployment; and the one Java black box, hashing | Task 2 | -| `bundles/render` | the Acceleo 4 templates from a Resolved Deployment model to the Deliverable Set's files | Task 3 | -| `bundles/cli` | the pipeline entry point: files in, the parsed intent, diagnostics and rendered files out | Task 1 onward | -| `tests/parity` | JUnit suites asserting each stage against the committed oracles, and the witness ledger check | no task grades it | - -Beside the two tiers sits `models/`, which is neither: hand-written example -models, in the target metamodel's own XMI. They belong to no module because -two use them from opposite ends. `minimal.resolveddeployment` is what the -Acceleo templates are first run against, and what the QVT-Operational -transformation produces for `minimal`: the pipeline's resolution test holds the -two equal, so a change to either is a change to both. -`secrets.resolveddeployment` is the complete expected model of `secrets`, whose -dependencies oracle holds no edge and which has no production `resolved.json`: -the same test holds the transformation's output equal to it, so it is the one -check on the rest of that case's resolution. Neither is a **parity oracle**: -`resolved.json` binds the production implementation only, for the reason -[Metamodels](#metamodels) gives, and nothing outside `emf/` reads them. - -A module may depend on the modules above it in this table and on nothing -below. `tests/parity` depends on no module at all: it reads the files a run -leaves behind, which is what [Parity](#parity) records. - -Every module of `bundles/` is Java, without exception. Ecore generates Java, -Xtext's runtime hooks are Java, and a bundle compiles through Tycho's JDT -compiler against a target platform holding no Kotlin unit, so a language other -than Java is a bundle's problem before it is anything else. `tests/` carries -none of those constraints and is Kotlin, the estate's JVM language, with the -test idiom its other repositories run: JUnit 6, AssertJ, ArchUnit, and a test -function named as a sentence in backticks. - -## Metamodels - -Two hand-written Ecore metamodels, as the project proposal defines them, and a -third the resolution reads beside the source. All three -are committed `.ecore` XMI, with names taken unchanged from -[`CONTEXT.md`](../../CONTEXT.md). - -| metamodel | role | holds | -|---|---|---| -| Project Intent | source | the authored Project, Application and Process with everything layer 1 declares, the lowered pair the Effective Intent is written in, and the Platform document the source is resolved against | -| Resolved Deployment | target | every derived value of layer 2 together with the typed Kubernetes and extension resources, identities and output paths the templates write | -| Pinned Inputs | read beside the source | the node contract, the images lock and the ClusterState snapshot, which another process publishes and resolution pins by digest; the migration proof an Application's CI writes beside its project file; and the text of each Asset's file ([0073](adr/emf/0073-source-and-target-metamodels-are-hand-written.md)) | - -The pinned inputs are a package of their own because they are no part of the -authored intent: the descriptor, which fixes the source metamodel's structure -against the TypeScript schemas, would otherwise list three documents those -schemas do not hold. Nothing in the target refers to them; the Resolved -Deployment carries their digests and the values it read out of them. - -The Deliverable Set is not a metamodel: it is the files Acceleo generates from -a Resolved Deployment model. The target metamodel is deliberately not the shape -of the production implementation's Resolved Deployment, which keeps layer 2 in -model words and builds typed objects separately; a model-to-text template reads -one model, so here the two are one package. This is why the parity contract -compares the two implementations through dependency edges and generated files -rather than through `resolved.json`. - -Cross-document references, including those from a Project into the Platform -document, are Ecore references, not strings, with the two exceptions -[Concrete syntax](#concrete-syntax) names: a dependency edge's names and a -library mount's library. - -Typed Java for each metamodel is generated from its `.genmodel` during the -Maven build into `target/`, and never committed: an MWE2 workflow runs EMF's -`EcoreGenerator` in `generate-sources`, and the generated packages are left out -of formatting, coverage and mutation. - -The target metamodel holds the two halves in one package: every decision -layer 2 takes, and one class per resource family of the project proposal's -generated-resources table, each carrying the path it is written to. A template -walks the second half and decides nothing, so no name in it appears in the -first: a `WorkloadFile` carries the controller kind and the strategy that spell -a Process's `cutover`, a `SwitchoverFile` is the Canary that switches a -`blue-green` one, and the `cutover` itself stays on the Process. - -The descriptor exporter walks the source `EPackage` reflectively and writes the -descriptor the parity contract fixes. It is the only place the Ecore structure -is compared with anything. Three shapes it normalises: an abstract class is a -union, so it is not listed and a feature that points at one names its concrete -classes; a map entry is not a class, so the feature that holds the entries -is a map; and a class annotated `authored=no` is no part of the authored shape, -so it is not listed either. The last is what keeps `EffectiveProject` and -`EffectiveApplication` out of the descriptor: they are what the lowering writes, -and no document holds one. - -## Constraints - -Every constraint over the parsed model lives in a Complete OCL file beside the source metamodel, -evaluated by Eclipse OCL standalone in the build and by the Xtext-generated -editor while a file is edited. An -invariant's name is the diagnostic code it emits, so a failed invariant maps to -a diagnostic without a lookup table. - -An invariant failure becomes a diagnostic whose path is the JSON Pointer of the -offending object, computed from its containment chain: each containing feature's -name, and the index for a many-valued feature. Validation reports every failed -invariant, never only the first. - -The constraints a Platform document and the project files beside it answer -together are invariants in the same file. Eclipse OCL binds one Complete OCL -document to a package for the thread that first loads it, so a second file for -the same package is never evaluated. Such an invariant is written in the -context of an **Estate** root that contains every document of the set, and -navigates containment from it; no invariant calls `allInstances()` -([0098](adr/emf/0098-cross-file-invariants-navigate-an-estate-root.md)). A set is -read once, into its Estate, so an invariant's scope is the set it was handed -rather than whatever resource set a document happened to be read into. A -diagnostic names the file its path points into. - -Until [#324](https://github.com/JorisJonkers-dev/deploy-kit/issues/324) lands -the Estate root, the cross-file invariants still read the other documents -through `allInstances()`, whose extent is the resource set, and hold trivially -over a document read alone; the pipeline therefore reads each file of a set -alone first, and the set together only once every file holds. - -Three consequences of evaluating OCL over Ecore, all recorded here because they -shaped the metamodel. The constraints import the metamodel by its `nsURI`, not -by file, so they bind to the classes the parser instantiates rather than to a -second copy. And EMF reads an unset enumeration as its first literal, so a -vocabulary an invariant tests for absence carries a literal with no spelling: -`Engine::absent` is what an unset `engine` reads as, and `Audience::absent` -what a route's unset `audience` does; a document cannot write either, and the -descriptor leaves them out because a literal the language cannot write is not -part of the vocabulary. And the Platform classes live in the Project Intent -package, because a tier's proxy is an Application a project file declares, and -one package is what lets that be an Ecore reference. - -A few refusals are decided in Java instead, beside the parse in the `cli` -bundle, because each asks something the parsed model does not hold -([0143](adr/emf/0143-a-refusal-is-decided-in-ocl-unless-the-model-cannot-hold-what-it-asks.md)): - -- `ShippedFiles`: whether a dashboard or a rule file a project names is beside - it, keyed by a uid or holding rule groups, and whether two dashboards of the - set share a uid. The model holds the path, never the file. -- `L4Checks`: a tier's proxy that answers no listener, a pool with fewer - addresses than Processes, a node's port two owners dial. A tier derives ports - no project file writes, and a refusal there is placed at the tier's address, - which no invariant's path can name. -- `OperatedChecks`: an argument of the monitoring stack's Prometheus or - Alertmanager that is no flag, or sets what the Prometheus operator sets - itself, placed at its entry of the Process's list of arguments. -- `Pipeline.check`: a Project the mesh enrols that no file declares, placed at - its entry of a list of strings, and an image the images lock holds as root, - which the pinned inputs decide and the intent's constraints never read. - -A Process is checked with the env files beside its project attached, since -what it reads through them is part of what is checked of it. The codes that -ask that, self delivery without a Vault client and a secret placeholder on a -Client that holds none, are kept by `Pipeline.refusals` until a document holds -on its own, as the production implementation asks them of the union only after -each document's own checks pass. A tier's proxy under a Platform document that -says nowhere where the Kubernetes API answers is kept the same way, since -composition asks it of the union too. - -Constraint parity is checked by code: every OCL invariant is named by the -diagnostic code it emits, and the root's parity test compares those names with -the TypeScript checks and the refused fixtures -([0068](../../docs/adr/architecture/0068-two-implementations-meet-at-the-parity-table.md)). - -## Concrete syntax - -The Xtext grammar parses the same authored `.project.yml` and -`platform.intent.yml` files the TypeScript compiler reads. Four more grammars -read the pinned inputs: `node-contract.yml`, `images.lock.yml` and -`cluster-state.yml` beside the Platform document, and `migration-proof.yml` -beside a project file. An Asset's file is read as text, never parsed: what is in -it is the Application's, not the model's. A rule-group file is the one exception, -read by `DataFile` in the `cli` bundle as the YAML or JSON it is into a generic -tree in the pinned extent, because its groups are written into the monitoring -stack's PrometheusRule as the file writes them, keys and types and all -([0151](adr/emf/0151-a-rule-group-file-is-read-as-data-into-a-generic-tree.md)). Each grammar inherits the project grammar's -terminals, block tokens and scalars as the Platform grammar does, imports the -pinned-inputs metamodel, and adds only its own rules -([0075](adr/emf/0075-xtext-parses-the-authored-yaml-into-the-metamodel.md)). It covers the YAML -subset those files use, with indentation handled by synthetic block tokens, and -refuses anything outside the subset with a diagnostic rather than a guess. - -The grammar imports the hand-written source metamodel, so the parser produces -instances of the graded metamodel directly. A union in the model is a union in -the grammar: a probe is HTTP or TCP, a probe policy is a block or the word -`none`, and a grant is keyed by its engine, which a grant that has one writes -first. Both languages bind the `.yml` extension, because EMF resolves a resource -factory by the last extension alone, so which document a file holds is the -file name's to say: the pipeline creates a `platform.intent.yml` through the -Platform language's resource factory and a `*.project.yml` through the project -language's, into one resource set. The Platform grammar inherits the project -grammar, its terminals, block tokens and scalars included, and adds only its -own rules. There is no inferred syntax metamodel and no mapping step between -parsing and validation. - -A schema refusal is decided by a shape check, not by the parser's error. The -check reads the grammar's own rules as data, which keys a mapping may hold, which -it must, and what each value may be, over a plain reading of the YAML subset into -a tree, and it runs on every authored document beside the Xtext parse. Where it -finds a fault, its diagnostics replace the parser's; where it finds none, what -the parser said stands. Xtext stops at its first error and recovers into more -that point nowhere, while the production implementation names every offending -key by its JSON pointer, so only a check that reads the whole file can report -the same set of paths. The grammar stays the one statement of the schema: the -check holds nothing the grammar says, only the two scalar limits it cannot, a -rate limit's request count and period. - -The lexer's scalar terminal holds no colon and no comma, because it cannot tell -`sha256:6f1c` from a key, or a flow's separator from content, without looking -past them. The block token source looks instead: a colon no space follows, and -a comma outside any flow collection, join the parts on either side into one -plain scalar, as YAML reads them, so `0.0.0.0:12345` in a flow sequence and -`--resources=pods,nodes` in a block one are each one value. A colon a space -follows still ends a key. - -A route's and a scrape's `process` and `surface` are cross-references, linked by -a scope provider that offers the Processes of the Application holding them and the -surfaces the linked Process provides. A name that links to nothing becomes the -specification's code, `E_UNKNOWN_PROCESS` or `E_UNKNOWN_SURFACE`, at the pointer -of the route or scrape; a surface whose Process did not link is not reported as -well. A tier's `traefik` is the one name that reaches another document: it links to -an Application any project file of the set declares, and one that links to -nothing is `E_UNKNOWN_TIER_PROXY` at the tier. A Platform document read alone -leaves it unlinked, and its intent writes the name as authored. A dependency -edge's names reach other documents and stay names until the composed union -links them. A library mount's `library` names a library of the Platform -document and stays a name as well: the lowering writes a project file read -alone, where a link into the Platform document has no target and so no name to -write back. The invariants `E_UNKNOWN_LIBRARY` and `E_LIBRARY_NOT_GRANTED` -check it once the documents are read together. - -Indentation is not the grammar's concern: a token source turns the block -structure into the synthetic `BEGIN` and `END` tokens the rules read, and folds -a scalar written over several lines into one token. A line -indented further than the one before it opens a block, a dash opens one around -the item that follows it, and a flow collection opens and closes one on a single -line, so `{ path: /, match: prefix }` and the same keys written as an indented -block parse through one rule. The rules themselves are unordered groups, because -the order of keys in a mapping is not meaning. - -The generated editor is configured to run the OCL validators and to mark each -constraint violation on the source line it concerns, with the diagnostic code as -its message. It is built by the same Maven and Tycho build as an Eclipse plugin; -CI builds it but never runs it. - -## Transformation - -Two QVT-Operational transformations, both run through the standalone -transformation executor. - -**The lowering** comes first and stays inside layer 1: Shared Intent declared at -the Project or an Application is merged onto the Processes that hold it, and what -comes out is the Effective Intent, in which `EffectiveProject` and -`EffectiveApplication` carry no Shared Intent at all and the Process carries all -of it ([0012](../../docs/adr/model/0012-shared-intent-descends-and-is-lowered.md)). -Source and target are the same metamodel, because the shapes differ by two -classes and a Process is a Process in both. It runs after the constraints and -before composition, and it has no error path: a duplicate is refused before it, -so the mapping is total. Lists extend each other keyed by the family's own -identity, the lowest declaration of one thing holds, and a quantity comes from -the Process, which is the whole of what it does. - -**The resolution** derives a Resolved Deployment model from the lowered Project -Intent model. It reads the Effective Intent and never the authored shape, which -is what keeps a derivation from having to union three levels for itself. Every derivation `spec/v1/20-resolved-deployment.md` names is a mapping -or a helper in it; a derived value with no mapping is a gap a parity case -exposes, through the dependency edges or the generated files. The resolved -dependency edges are exported from the target model as canonical JSON and -compared with `expected/dependencies.json`. - -**Two transformations, then the templates.** The pipeline is lower, then -resolve, then render, and nothing runs over the Resolved Deployments of several -projects together. Every object a project delivers is planned by that -project's own resolution, in its own Resolved Deployment -([0116](../../docs/adr/model/0116-a-project-owns-every-object-it-delivers.md)): -its Vault policy job, whose documents' content the resolution writes as -canonical JSON and digests through the black box -([chapter 30](../../spec/v1/30-deliverables.md#vault-configuration-is-rendered-not-applied)), -its catalog where it runs the datastore, and the route Flux's events about its -unit take. While the estate is handed over, the catalog of a datastore the old -path still runs, and the estate-scoped job that writes its documents, are -planned by the resolution of each project that reads that catalog, as -estate-scoped output beside its own model. Every reader plans the same files, -and the templates write each file once, so a render of several readers writes -the same bytes as a render of one. - -It reads two extents and writes one. The **intent** extent holds every project -of the union, authored and lowered, and the Platform document: the authored -Projects stay in it because the Platform document's links point into them, -while every derivation reads the lowering. The **pinned** extent holds the node -contract, the images lock and the snapshot. Two configuration properties name -what is not derived: the project of the union to resolve, and the schema -package's integrity the provenance records. - -**Hashing is the one black box.** A revision and an input digest are digests of -canonical bytes, which OCL has no way to produce, so they are a Java library, -`Hashing`, imported as a unit and called on an `EObject`: the digest of a model's -canonical JSON, walked reflectively, and the digest of the bytes the -transformation writes for an Application's element -([0076](adr/emf/0076-qvto-derives-the-resolved-deployment.md)). Everything else -is a mapping or a query, including that element: the transformation writes it as -the production implementation's canonical JSON, so the revision is the -production implementation's, which the rendered tree carries in every Canary. -The provenance's digests are over this implementation's own model, and bind this -implementation only, as `resolved.json` binds the other. - -**What the transformation cannot derive stops the run.** It resolves every case -the production implementation resolves, and an input it cannot derive is a -fatal assertion naming what is missing, never a model with a gap or a default in -it: an image the lock does not hold, an edge no provider answers, a placeholder -that names nothing, a Runtime Profile key written in an env file, an Asset whose -file is not beside its project or holds a placeholder, a backed-up volume with -no schedule, retention or engine to back it up with. - -**One place the model is one level coarser than the production -implementation's.** A Reconcile Unit is the project's, so what it must follow is -the union over the project's Applications: Flux orders units, and one unit -cannot follow two lists. - -**The path plan holds every family the production implementation renders.** An -Application's directory holds one file per family, each naming every Process it -applies to, and a file that would hold no object is not written: the workloads, -the Canaries of the blue-green Processes and the Services of the others, the -identities, the claims, the Asset ConfigMaps, the backups, the monitor, what the -operator syncs, and one network policy per Process. A project's directory holds -the operator's connection to the Secret Store wherever an Application syncs from -it, and the estate-scoped Vault directory holds one policy and one role per -identity that holds a grant. Each index lists what its directory applies, so the -policy files and the Vault documents, which nothing applies, are listed nowhere. -The families the production implementation does not render either, the -disruption budgets and the migration Jobs that `auth`'s and `knowledge`'s -goal-state trees hold, are not modelled yet. - -## Text generation - -Acceleo 4 templates generate the Deliverable Set's YAML and JSON files from a -Resolved Deployment model, run through Acceleo's standalone API. They render the -transformation's output: the pipeline's one entry, `Pipeline.render`, parses and -checks every document, lowers and resolves each project, and runs the templates -over the Resolved Deployments in one pass, and no test feeds them a hand-written -model. Output is compared byte for byte with the committed `rendered/` trees, so -whitespace, key order and the `GENERATED` header are template decisions made to -match the oracle, not presentation. - -`bundles/render/model/render.mtl` is one module. Its main template walks the -Deployment's `deliverables` and opens one file per Deliverable at the path the -path plan assigned it, and each Deliverable kind has one template that spells -its target format: YAML under the one header line, or for a Vault document JSON, -which carries no comment. A YAML kind's template is chosen by the Deliverable's -type, so a kind with no template fails the rendering rather than writing a file -that holds only the header. An Asset's content is a block scalar, kept as -written, its last line break chomped the way the production serializer chooses. - -The templates decide nothing: every value they write is a feature of the model, -and the only arithmetic they do is spelling, a duration as whole seconds and a -precedence as a Traefik priority. What a template once chose is derived by the -resolution instead: the name and namespace of the Middleware a route names -(`MiddlewareStep.name`, `.namespace`), the Deployment that serves between -releases and the label its pods are selected by (`ResolvedProcess.serving`, -`.servingLabel`), and what a Vault policy allows at each path -(`VaultPolicyFile.paths`, `ResolvedCatalogJob.policy`). A query in the module -only selects or reaches what the model holds. - -Acceleo 4 strips two spaces of margin from every line of a block's body, and a -call written at a column repeats that column's text before every line the call -writes. The templates lean on the second rule: a fragment that appears in more -than one object (the metadata, the label set, a policy peer, a probe target) is -one template written unindented, and each caller places it at its own depth. -A list item is a fragment that opens on its own `- `, because the repeated text -is copied literally and a `- ` before the call would open every line as an item. - -A string value is written plain unless a YAML 1.1 reader would read it as null, -a boolean, an integer, a float or a timestamp, in which case it is -double-quoted, as the production implementation's serializer, which writes YAML -1.1, quotes it: the Kubernetes API reads YAML through `sigs.k8s.io/yaml`, a YAML -1.1 reader, where `on`, `yes` and `0755` are not strings. That serializer also -quotes a string for an indicator character or an embedded `: `, which no value -the examples render carries yet, so the templates do not spell that case. The Java -side, `Rendering`, only loads the module and runs it. It writes beside the root -and moves the files under it once every one is written, and fails the run with -Acceleo's own diagnostic when a template does not parse or does not evaluate, -leaving the root as it was, so a half-written tree is never read as a whole one. - -## Stage tests - -Each stage also runs on its own, in-process, file in and file out, so a wrong -label costs one stage and names its path rather than a full build and a byte -diff of a whole file. The cases sit under -`bundles/cli/src/test/resources/stages///`, in `cli` because it -is the one bundle that reaches every stage, and `StageTest` reads them from the -working copy. Only `parse` holds an `input/`, the authored documents of a -union; `lower`, `resolve` and `render` each read the `expected/` of the stage -before, the same files, so one golden serves in two roles and two stages cannot -drift apart. `parse` writes the authored extent with its env files, -`intent.xmi`, the pinned extent, `pinned.xmi`, and each document's intent; -`lower` writes `effective.xmi` and each project's Effective Intent; `resolve` -writes `.resolveddeployment` and its edges for each project its -`projects` file names; `render` writes the tree. The goldens are this -implementation's own: `estate` reads main's worked documents, every project -of the estate together, beside a `coverage` project and a Platform document -that write what the worked documents leave out. A `resolve` or `render` case -names the projects it resolves in its `projects` file. - -A `resolve` case with no `lower` case of its name is *given*: its Resolved -Deployment is written by hand, because no resolution writes that shape yet, and -it drives the `render` case of the same name alone. A given model must validate -against the metamodel, and its stage never rewrites it. A `render` case whose -expected files are copies of the production implementation's oracles names -each in an `oracles` file, one ` ` pair a line, and -each copy must equal its oracle byte for byte, so the copies cannot drift; a -golden update leaves such a case alone. - -`Comparison` compares by content first and bytes last: JSON as a Jackson tree, -YAML as every document of the stream through SnakeYAML's YAML 1.1 reader on both -sides, and XMI loaded into EMF and compared by EMF Compare. It reports every -difference as a path, a list of named items by name, and a file whose content -matches but whose bytes do not as one "formatting only" difference at the first -line that parts. Jackson and SnakeYAML reach the bundles in test scope only, -beside JUnit and AssertJ. - -Every comparison of two models in the tests goes through `ModelDiff`, the XMI -branch of `Comparison` and `ResolutionTest`'s whole-model checks alike -([0152](adr/emf/0152-emf-compare-decides-and-explains-every-model-comparison.md)): -EMF Compare decides, and two models are equal only when it reports no -difference. It pairs objects by natural key, a path from the root naming each -list item by the first of `name`, `id`, `path`, `alias`, `key`, `project` and -`from` unique among its siblings, else by one of those with another of them or -an enumeration-typed attribute (an input digest's `input` and `name`), else by -a single-valued reference to a keyed object (a gate member by its process). A -root is keyed among its resource's roots, by position when it has no key. Two -objects pair by key only when both sides key them alike; the rest, and every -item with no key, are paired by similarity, and a line about an item with no -key names it by index and says so. Each difference is one line at its keyed -path: a changed attribute, a set feature beside an unset one, an added or -removed subtree with its size, a move with both indexes, and a reference by its -target's keyed path rather than its index fragment. `ModelDiffTest` holds each -kind to its line, and changes, unsets, removes, reorders and retargets every -feature of every class the stage goldens hold, one at a time, asserting none -compares equal. - -EMF Compare is the one unit of `emf.target` the course does not name, and the -tests alone use it: it reaches the `cli` bundle through `additional.bundles` in -its `build.properties`, never through a manifest, and `EMF-021` fails a class a -module ships that depends on it. - -Two more suites ride on the same cases. `FieldCoverageTest` lists, per stage, -every feature of every concrete class a stage's documents can hold that no case -sets, every enum literal none uses, the same of what `lower` and `resolve` -write, every intent schema path no `parse` input carries, and every type -`render.mtl` dispatches on that no `render` input instantiates; the stage's -`gaps.txt` must equal that list, so a new gap fails and a covered one must be -removed. `OracleDistanceTest` compares this implementation with every oracle -under `spec/v1/examples/` through the same comparator: the cases in `PASSING` -must match, a case that matches must be listed, and every other case prints how -many differences it is from passing. - -The loop, from `emf/`, after one full build: - -```bash -./mvnw verify -Dtest=StageTest -Dsurefire.failIfNoSpecifiedTests=false \ - -Djacoco.skip=true -Dspotless.check.skip=true -DskipPitest=true -``` - -That runs the reactor and the stage cases alone, about 25 seconds warm against -35 for `OutputsTest` and `ParityTest`; one case takes well under two seconds of -it. Adding `-Dgolden.update=true` rewrites every `expected/` from what the -stages wrote, in stage order, and removes the covered entries of each -`gaps.txt`; review it in `git diff`. It never writes under `spec/v1/examples/`. -Run `verify`, not `test`: the constraints load from the packaged metamodel -bundle, and add `clean` when a test compile reads a stale class. - -## Parity - -`tests/parity` holds this repository's own evidence: the suites that assert each stage -against the committed oracles, the ledger checks, and the module rules. It is -built and run by Maven only, and no examiner opens it. - -It reaches the pipeline through the pipeline's own interface, and through nothing -else ([0080](adr/emf/0080-parity-crosses-the-cli-file-interface.md)): arguments -and input files in; an exit code, diagnostics, the parsed intent, the descriptor -and the rendered tree out. A run of the build leaves those files under the build -output of the module that wrote them, one directory per case, mirroring -`spec/v1/examples/` so a written file and its oracle are obviously a pair: -`bundles/cli/target/parity//` holds `intent.json` or `diagnostics.json` beside the -`exit` the run ended on, and, where the case carries an `expected/effective.json`, -the `effective.json` the lowering wrote from the document and the env files beside -it. A case the resolution reaches also holds the `dependencies.json` exported from -its Resolved Deployment, the model itself as `.resolveddeployment`, and the -two extents it was resolved from, `resolution.intent.xmi` and -`resolution.pinned.xmi`, which the launch configuration in Eclipse runs the -transformation on. `bundles/cli/target/parity/rendered/` holds the tree the -composed union of `minimal` and `data` renders to, which is the committed -`minimal/rendered/` and `data/rendered/` together, file for file, or the -diagnostics that refused the union in its place. -`bundles/metamodel/target/parity/` holds `descriptor.json`. -Every case also leaves each document it reads as an XMI instance of the source -metamodel, named after its authored file (`notes.project.yml` leaves -`notes.project.xmi`), for a reader who opens it in Eclipse without the grammar. A -refused case leaves its model too, and a set's models link to each other, so the -refusal reproduces there by validating it. No oracle compares them, because the -parity contract is JSON. None of them is committed. - -So the module holds no EMF type, needs no p2 bundle, and builds as a plain jar -with no `META-INF/MANIFEST.MF` and no `build.properties`. Its `src/main` holds -`Ledgers`; the canonical JSON writer sits in `bundles/metamodel`, the lowest module that -writes a canonical file, because the pipeline writes what the suite used to -serialise. A value a parity case asserts on is a value the pipeline writes, and a -derivation with no output file is not evidence. - -Two things follow from depending on no module, and both are enforced rather than -remembered. A case asserts its file exists before comparing it, so a file the run -owes and did not write fails as a missing file rather than as a skipped case, -which is a different absence from a case with no committed oracle, and that one -is listed as not yet a parity case. And nothing puts the other modules' classes on this module's -classpath, so `ArchitectureTest` reads their class directories by path and -`EMF-017` fails an import that holds no module: `withOptionalLayers` would -otherwise excuse every empty layer and let `EMF-010` and `EMF-011` pass while -proving nothing. - -## Witnesses - -A behaviour ledger row whose behaviour is the model's own is proved in both -implementations. `emf/docs/witnesses.md` lists, for each such `REQ-NNN` id, the -JUnit test that proves it here, in whichever language its module is written. -`tests/parity` fails when a model row in any of the behaviour ledger's area -files under `docs/requirements/` has no witness in that file, or a witness names a test -that does not exist or an id that no row carries. - -## Gates - -One CI job, `emf`, runs `./mvnw -B -ntp verify` in `emf/` on the JDK named by -`emf/.java-version` and is required by `Pipeline Complete`. The wrapper -downloads the Maven distribution pinned by checksum; no wrapper jar is -committed. The job writes one line to its summary: tests, line coverage and -mutation score, from `scripts/summary.sh`. The ADR lint for `emf/docs/adr/` runs -in the existing `contracts` job, as `node scripts/lint-adrs.ts emf`. - -`verify` runs these gates, in this order, and fails on the first that does not -hold ([0079](adr/emf/0079-the-emf-gates-are-estate-shaped.md)): - -| gate | plugin | fails when | -|---|---|---| -| toolchain | `maven-enforcer-plugin` | the JDK is not 21, Maven is not 3.9, a plugin version is unpinned, dependency versions do not converge outside a bundle, or anything declares a distribution target | -| compile | `maven-compiler-plugin`, `tycho-compiler-plugin` in a bundle, or `kotlin-maven-plugin` in the test tier | any `-Xlint:all` warning, in a bundle any warning the JDT compiler reports, and in the test tier any warning `kotlinc` reports | -| tests | `maven-surefire-plugin` | a JUnit test fails, including the ArchUnit module rules and the ledger checks | -| format | `spotless-maven-plugin` | Java source differs from palantir-java-format, or Kotlin source from ktlint; `./mvnw spotless:apply` fixes either | -| coverage | `jacoco-maven-plugin` | line or branch coverage of a module's hand-written classes falls below the floor in `emf/pom.xml` | -| mutation | `pitest-maven` | the mutation score of a module's hand-written classes falls below the threshold in `emf/pom.xml` | - -Every rule these gates enforce is listed in [the rule ledger](rules.md), and -every model behaviour's JUnit proof in [the witness list](witnesses.md), in -whichever language its module is written. - -CodeQL analyses the Java under `emf/` as `java-kotlin` with no build, ignoring -build output and generated sources; `test/emf-wiring.test.ts` at the root holds -that configuration and the `emf` job to the tree they describe. diff --git a/emf/docs/benchmarks.md b/emf/docs/benchmarks.md deleted file mode 100644 index ea005ca91..000000000 --- a/emf/docs/benchmarks.md +++ /dev/null @@ -1,472 +0,0 @@ -# Benchmarks - -How long each stage of the model-driven pipeline takes, how that grows with -the number of Projects, and how the QVT-Operational lowering compares with an -ATL port of it on the same inputs -([JorisJonkers-dev/deploy-kit#809](https://github.com/JorisJonkers-dev/deploy-kit/issues/809)). -The numbers are evidence, not a gate: nothing in the default build reads them. - -## What was asked, and what is measured - -The Task 2 report preferred QVT-Operational to ATL -([`02-alternatives.tex`](../../docs/mde/task-2-transformations/Sections/02-alternatives.tex), -section "The Transformation Language") for two reasons, and neither is a -claim about speed: - -- the resolution reads its own output in the same operation: the - `Revision` hashes the completed `Application`, and ATL's target models are - write-only; -- explicit mapping calls make the construction order visible, which the - resolution needs. - -The grader asked for those execution arguments to be backed by measurement. -What can be measured is time, so this document measures two things: - -1. every stage of the pipeline as it ships, so the share of time each - transformation takes is known; -2. one transformation written in both languages and held equal: the - **lowering**, `lower.qvto` (474 lines, 54 mappings), ported to ATL on - EMFTVM. The resolution (`resolution.qvto`, 4,212 lines) is where the - report's two reasons apply, and it was not ported; see - [What the numbers do not support](#what-the-numbers-do-not-support). - -## Method - -- **Harness.** JUnit suites in the `cli` bundle's tests, skipped unless - `emf.benchmark=true`: - [`PipelineBenchmarkTest`](../bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/PipelineBenchmarkTest.java), - [`LoweringBenchmarkTest`](../bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/LoweringBenchmarkTest.java) - and - [`LoweringEquivalenceTest`](../bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/LoweringEquivalenceTest.java). - The `benchmark` profile in [`pom.xml`](../pom.xml) sets that property, runs - only those suites, and turns off what would distort a timing: JaCoCo's agent - and the JVM's assertions. No gate runs. To reproduce, from `emf/`: - - ```sh - ./mvnw -B verify -Pbenchmark - ``` - - The tables land in `bundles/cli/target/benchmark/*.md`. The counts are - system properties: `-Demf.benchmark.warmup=5 -Demf.benchmark.runs=10 - -Demf.benchmark.forks=5` are the defaults this document used. -- **A warm series** runs its task 5 times unmeasured, collects the garbage, - then times 10 runs one by one with `System.nanoTime()`. A cell reads - `median [p25–p75]` in milliseconds: the median, and the interquartile range - as the spread. The lowerings take well under a millisecond each, so before - any lowering series both engines first run 40 times over every Project. -- **A cold sample** is one run in a JVM started for it alone - ([`ColdRun`](../bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ColdRun.java)), - with the JVM's defaults: class loading, transformation compilation and - interpretation before the JIT are all inside the timing. Five JVMs per - series; the cell is the same `median [p25–p75]` over the five. -- **Stages.** Each stage is timed on the output of the stage before it, built - once outside the timing: - - *read*: every document of the union parsed by its Xtext language and - linked (`Pipeline.read`); - - *check*: the documents read again, checked against the OCL constraints, - the names and the pinned inputs, and joined to their env files - (`Pipeline.authored`, what the pipeline does before lowering); - - *lower*: every Project of the union lowered by `Lowering.lower`, as - shipped. When the tables of the next two sections were measured it loaded - `lower.qvto` on each call; it now loads it once per JVM, and - [Loading each transformation once](#loading-each-transformation-once) - measures the change; - - *resolve*: one Project resolved against the union by `resolution.qvto` - **loaded once and reused**, as `Resolution.resolve` now loads it. The load - is timed apart ([Loading](#loading-a-transformation)). When these tables - were measured, `Resolution.resolve` loaded it on every call and every load - stayed reachable for the life of the JVM, so a series of hundreds of - shipped calls exhausted a 16 GiB heap. The suite checks, per example, that - the reused resolution writes what the shipped one writes; - - *render*: the Resolved Deployments rendered to files by - `Rendering.render`, which parses the Acceleo templates on every call, as - shipped. -- **Inputs.** The 16 worked examples this implementation resolves - (`Outputs.RESOLVED`), each read with the union it names, and the real - estate's union of 24 Projects under `spec/v1/examples/estate/`. For scaling, - the estate is cut to its first *n* Projects in a fixed order: the first 12 - are the smallest union the checks accept (the Platform document names an - Application of each, or another of the twelve depends on one), and every - prefix from 12 to 24 is accepted. A prefix of 1, 4 or 8 is read and lowered - but never checked or resolved. -- **The lowering head to head** runs on the 36 Project files the resolved - examples read (the 12 worked ones and the estate's 24), each lowered with - its env files attached, as the pipeline lowers it. `knowledge` is left out: - no union resolves it, because no lock holds its images. "Loaded once" is a - QVTo `TransformationExecutor` loaded once and an EMFTVM `ExecEnvPool` whose - module was compiled once; "per call" is `lower.qvto` loaded for each - Project, and the ATL source compiled for each Project. - -## The machine - -| | | -|---|---| -| CPU | Apple M4 Max, 16 cores (12 performance, 4 efficiency) | -| memory | 64 GiB | -| OS | macOS 27.0.1, arm64 | -| JVM | Amazon Corretto 21.0.10 (OpenJDK 64-Bit Server VM 21.0.10+7-LTS), G1, the default maximum heap of 16 GiB, no JVM arguments | -| build | Maven 3.9 wrapper, Tycho 5.0.4, `emf.target` (Eclipse 2026-06): QVTo 3.11, Acceleo 4.2, Xtext 2.43, ATL/EMFTVM 4.12.0 | - -A developer laptop on mains power, with the usual background processes -running, among them an endpoint antivirus that scans every file written: the -spread columns show how much that cost. Absolute numbers will -differ on another machine; the ratios and the shapes are what to read. - -## The pipeline, per worked example - -Warm, in milliseconds, `median [p25–p75]` of 10 runs. *lower* is every -Project of the union, as shipped; *resolve* and *render* are the example's -own Project. - -| example | documents | Projects | read ms | check ms | lower ms (all Projects) | resolve ms (one Project, loaded once) | render ms (one Project) | -|---|---|---|---|---|---|---|---| -| agents | 13 | 9 | 42.7 [41.2–43.9] | 410 [405–413] | 67.8 [67.1–68.5] | 7.95 [7.81–8.16] | 54.7 [53.9–56.2] | -| auth | 15 | 10 | 48.2 [47.7–50.8] | 443 [436–452] | 76.3 [75.0–78.2] | 8.40 [7.95–8.72] | 42.6 [41.9–42.8] | -| data | 13 | 9 | 42.6 [41.7–43.3] | 424 [414–430] | 74.2 [73.4–75.0] | 11.1 [11.0–11.3] | 89.2 [85.4–96.5] | -| delivery | 13 | 9 | 42.7 [42.4–43.1] | 413 [408–418] | 69.6 [68.6–71.3] | 6.09 [5.99–6.16] | 47.2 [44.2–58.7] | -| edge | 13 | 9 | 42.6 [41.4–43.8] | 446 [439–454] | 70.3 [68.8–71.2] | 5.40 [5.36–5.59] | 44.3 [43.1–47.8] | -| estate/hindsight | 28 | 24 | 54.7 [54.5–55.5] | 1060 [1043–1091] | 200 [198–205] | 22.6 [22.4–23.1] | 470 [377–590] | -| estate/immich | 28 | 24 | 54.1 [53.0–56.0] | 1038 [1037–1045] | 183 [179–189] | 14.7 [14.5–14.8] | 495 [301–686] | -| estate/observability | 28 | 24 | 52.5 [51.8–54.4] | 1008 [1005–1016] | 189 [188–192] | 248 [247–249] | 227 [223–241] | -| identity | 13 | 9 | 43.9 [43.4–44.5] | 416 [413–427] | 71.4 [70.9–72.2] | 7.04 [6.85–7.13] | 57.1 [51.7–64.1] | -| knowledge-platform | 14 | 10 | 44.4 [43.7–45.2] | 490 [475–502] | 78.8 [78.7–79.1] | 15.1 [14.9–15.3] | 82.9 [75.8–87.1] | -| mail | 13 | 9 | 43.5 [42.8–43.7] | 418 [416–424] | 71.8 [70.9–74.7] | 3.28 [3.10–3.48] | 29.9 [28.6–33.1] | -| minimal | 14 | 10 | 43.8 [43.1–45.0] | 448 [445–449] | 78.4 [77.3–79.3] | 3.32 [3.22–3.43] | 31.7 [30.6–37.8] | -| node | 13 | 9 | 43.0 [42.8–43.8] | 429 [422–434] | 71.9 [70.7–72.5] | 1.60 [1.55–1.77] | 37.5 [36.3–38.1] | -| observability | 14 | 10 | 43.1 [42.6–43.3] | 463 [455–474] | 78.5 [77.6–80.6] | 15.6 [15.3–15.8] | 91.8 [88.2–94.2] | -| secrets | 13 | 9 | 41.6 [41.0–41.7] | 421 [416–422] | 70.9 [69.9–72.6] | 3.74 [3.64–3.99] | 40.3 [39.1–44.5] | -| utility | 13 | 9 | 42.6 [41.9–43.5] | 426 [421–432] | 70.3 [69.3–71.0] | 4.57 [4.50–4.88] | 40.8 [37.0–50.0] | - -`check` dominates every example: parsing again, the Complete OCL -constraints, the cross-file names and the pinned inputs take 55–63% of a -warm run, counting the resolution's load as shipped. The lowering of a whole -union (9 to 24 Projects) takes 68–200 ms, -and almost all of it is loading `lower.qvto` again for every Project (next -table). The resolution's execution is 2–23 ms for every example but -`estate/observability`, whose metrics stack scrapes every Process of the -estate. *render* is the noisiest column: it writes a few dozen files a run, -and this laptop's endpoint antivirus scans each one (see -[The machine](#the-machine)), so its spread is wide and its value moved by up -to an order of magnitude between runs. - -### Loading a transformation - -Warm, parse and compile only, as `Lowering.lower` and `Resolution.resolve` -each did on every call when these tables were measured, and now do once per -JVM. - -| transformation | lines | load ms (parse, compile) | -|---|---|---| -| lower.qvto | 473 | 15.1 [14.1–15.5] | -| resolution.qvto | 4212 | 109 [108–111] | - -So loading on every call cost a resolution about 110 ms on top of the -execution above, and a lowering about 15 ms on top of well under a -millisecond of execution. Every load of `resolution.qvto` also stays -reachable for the life of the JVM, about 8 MiB each; one reused executor does -not grow. `lower.qvto`, which imports no blackbox, does not keep its loads. -Both now load once per JVM: -[Loading each transformation once](#loading-each-transformation-once). - -## The pipeline over the estate, growing - -Warm, milliseconds. The estate's Platform document and pinned inputs, plus -its first *n* Projects. Below 12 the checks refuse the union, so only *read* -and *lower* run. *resolve* and *render* here cover **every** Project of the -union: what `Pipeline.render` does for the whole estate. - -| Projects | documents | read ms | check ms | lower ms (all Projects) | resolve ms (every Project, loaded once) | render ms (every Project) | -|---|---|---|---|---|---|---| -| 1 | 5 | 40.1 [38.7–41.9] | – | 9.90 [9.62–10.2] | – | – | -| 4 | 8 | 46.2 [45.6–46.7] | – | 38.9 [37.2–40.7] | – | – | -| 8 | 12 | 48.4 [47.4–49.5] | – | 71.6 [66.2–73.4] | – | – | -| 12 | 16 | 47.4 [46.8–49.6] | 583 [572–589] | 96.9 [93.6–97.9] | 314 [312–317] | 940 [815–1475] | -| 16 | 20 | 53.0 [49.5–54.2] | 737 [733–740] | 132 [131–134] | 360 [359–361] | 893 [843–947] | -| 20 | 24 | 54.9 [54.3–55.9] | 822 [805–842] | 162 [161–163] | 438 [436–439] | 750 [710–856] | -| 24 | 28 | 54.6 [52.7–57.2] | 1038 [1031–1049] | 191 [189–191] | 521 [520–524] | 1182 [1092–1275] | - -Every stage but *render* grows roughly linearly with the union between 12 -and 24 Projects: doubling the Projects multiplies *check* by about 1.8, -*lower* by 2.0 and *resolve* (every Project) by 1.7. *read* is nearly flat: -one Xtext setup per language dominates it, not the documents. Resolving one -Project does not get dearer as the union grows (about 22 ms a Project at 24 -against 26 ms at 12), even though each resolution reads the whole union. -*render* stays between 0.75 and 1.2 s with no clear trend; its file writes -are what the antivirus scans, so it is not to be read finely. - -### Cold - -One fresh JVM per sample, five samples, every stage once in pipeline order, -with the shipped `Lowering.lower` and `Resolution.resolve`. - -| example | read ms | check ms | lower ms | resolve ms | render ms | -|---|---|---|---|---|---| -| minimal | 951 [939–958] | 1703 [1660–1703] | 510 [502–545] | 356 [334–366] | 233 [225–246] | -| estate/hindsight | 906 [898–919] | 2030 [2026–2238] | 593 [581–621] | 349 [340–364] | 255 [246–257] | - -A cold run of `minimal` takes about 3.8 s, of which 2.7 s are *read* and -*check*: class loading and the first Xtext and OCL setups. The transformations -together (lower, resolve, render) are about 1.1 s cold. - -## Loading each transformation once - -`Lowering.lower` and `Resolution.resolve` now load their transformation once -per JVM and reuse it, each call with an execution context and model extents -of its own -([JorisJonkers-dev/deploy-kit#826](https://github.com/JorisJonkers-dev/deploy-kit/issues/826)). -Every stage golden, rendered tree and oracle comparison is unchanged. Both -measures come from `-Pbenchmark` runs on one machine in one session, first -on `main`, then on the change: - -| measure | before | after | -|---|---|---| -| lowering, the estate's 24 Projects, as shipped (ms) | 174 [172–177] | 7.82 [7.63–7.99] | -| lowering, per Project, as shipped (ms) | 7.25 | 0.33 | -| lowering, a worked example's union (9 to 24 Projects), as shipped (ms) | 64.7–179 | 3.17–13.7 | -| heap kept per shipped resolution, over 40 in one JVM (MiB) | 8.24 | 0.00 | - -The lowering rows are the *lower* column of the two pipeline suites: warm, -`median [p25–p75]` of 10 runs, the per-Project row being the 24-Project -median divided by 24. The heap row is `PipelineBenchmarkTest`'s series of 40 -shipped resolutions of `minimal`'s `notes`, the heap still in use after full -collections read before and after it and the difference divided by 40. -Lowering now costs about what its execution costs -([Execution, growing](#execution-growing): 7.62 ms loaded once). - -The columns the change does not touch moved between the two runs too: *read* -was up to a quarter faster after, and *resolve* and *render* of the largest -examples up to a third slower (`estate/observability` resolved in 232 ms -before and 310 ms after, with the resolution loaded once in both). The cause -was not isolated. The suite's JVM held about 14 GiB still reachable in both -runs, close to its 16 GiB maximum, and this laptop's run-to-run noise is wide -([The machine](#the-machine)). So those columns are not re-tabulated here. - -## QVTo against ATL - -### Equivalence - -[`LoweringEquivalenceTest`](../bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/LoweringEquivalenceTest.java) -lowers each of the 36 Projects with the shipped QVTo lowering and with the -ATL port, and compares the two Effective Intents with -[`ModelDiff`](../bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/ModelDiff.java), -EMF Compare under the tests' natural keys -([0152](adr/emf/0152-emf-compare-decides-and-explains-every-model-comparison.md)). -It also holds the loaded-once QVTo lowering equal to the shipped one, and each -source unchanged by both. - -**Result: no difference on any of the 36 Projects (2,564 input objects).** -ModelDiff tells a set unsettable feature from an unset one, so "equal" covers -what an author did not write too: the port's first runs differed exactly -there, and the [hard parts](#what-atl-made-hard) below are what closed them. - -Equivalence covers only the rules the inputs reach: 51 of the port's 54. -`NoMigration`, `NoProbes` and `DatabaseGrantCopy` match no object in any -example, so for those three the port is unproven. The port copies -exactly what `lower.qvto` copies, including what it leaves out: neither copies -`Generate.adopt`. - -### Execution, per Project - -Warm, transformation loaded once, milliseconds. - -
-All 36 Projects - -| Project | objects | QVTo ms | ATL ms | ATL / QVTo | -|---|---|---|---|---| -| delivery/delivery.project.yml | 53 | 0.39 [0.38–0.40] | 0.39 [0.37–0.43] | 1.00× | -| edge/edge.project.yml | 31 | 0.21 [0.21–0.22] | 0.22 [0.22–0.23] | 1.07× | -| observability/observability.project.yml | 137 | 0.99 [0.94–1.00] | 1.00 [1.00–1.04] | 1.01× | -| secrets/secrets.project.yml | 27 | 0.21 [0.21–0.23] | 0.20 [0.19–0.22] | 0.98× | -| identity/identity.project.yml | 30 | 0.23 [0.23–0.27] | 0.28 [0.28–0.30] | 1.24× | -| mail/mail.project.yml | 19 | 0.14 [0.14–0.16] | 0.17 [0.17–0.19] | 1.17× | -| utility/utility.project.yml | 26 | 0.20 [0.20–0.21] | 0.23 [0.22–0.23] | 1.13× | -| agents/agents.project.yml | 107 | 0.57 [0.56–0.60] | 0.57 [0.55–0.61] | 1.01× | -| data/data.project.yml | 92 | 0.60 [0.56–0.61] | 0.62 [0.61–0.64] | 1.04× | -| auth/auth.project.yml | 77 | 0.33 [0.33–0.34] | 0.40 [0.37–0.41] | 1.21× | -| estate/arr/arr.project.yml | 43 | 0.32 [0.31–0.34] | 0.30 [0.30–0.32] | 0.94× | -| estate/auth/auth.project.yml | 149 | 0.50 [0.49–0.51] | 0.64 [0.62–0.65] | 1.28× | -| estate/data/data.project.yml | 59 | 0.35 [0.34–0.36] | 0.34 [0.34–0.35] | 0.98× | -| estate/delivery/delivery.project.yml | 95 | 0.54 [0.53–0.56] | 0.51 [0.50–0.53] | 0.95× | -| estate/edge/edge.project.yml | 21 | 0.19 [0.17–0.23] | 0.18 [0.17–0.20] | 0.99× | -| estate/estate-dashboard/estate-dashboard.project.yml | 62 | 0.27 [0.26–0.29] | 0.30 [0.29–0.33] | 1.11× | -| estate/findability-explorer/findability-explorer.project.yml | 56 | 0.26 [0.26–0.28] | 0.32 [0.31–0.33] | 1.20× | -| estate/grimoire/grimoire.project.yml | 70 | 0.31 [0.30–0.33] | 0.35 [0.34–0.36] | 1.13× | -| estate/hindsight/hindsight.project.yml | 163 | 0.82 [0.81–0.83] | 1.05 [1.01–1.15] | 1.28× | -| estate/home-portal/home-portal.project.yml | 11 | 0.11 [0.11–0.12] | 0.12 [0.11–0.14] | 1.06× | -| estate/immich/immich.project.yml | 74 | 0.35 [0.34–0.36] | 0.46 [0.43–0.47] | 1.33× | -| estate/jellyfin/jellyfin.project.yml | 18 | 0.14 [0.13–0.15] | 0.14 [0.13–0.15] | 1.01× | -| estate/jellyseerr/jellyseerr.project.yml | 17 | 0.11 [0.11–0.12] | 0.16 [0.16–0.18] | 1.46× | -| estate/karakeep/karakeep.project.yml | 97 | 0.48 [0.47–0.50] | 0.53 [0.51–0.56] | 1.11× | -| estate/mail/mail.project.yml | 71 | 0.34 [0.31–0.40] | 0.37 [0.36–0.41] | 1.09× | -| estate/n8n/n8n.project.yml | 75 | 0.26 [0.25–0.27] | 0.32 [0.31–0.35] | 1.26× | -| estate/observability/observability.project.yml | 264 | 1.33 [1.32–1.39] | 1.48 [1.46–1.50] | 1.12× | -| estate/outline/outline.project.yml | 104 | 0.36 [0.34–0.46] | 0.41 [0.40–0.45] | 1.15× | -| estate/overleaf/overleaf.project.yml | 103 | 0.36 [0.36–0.38] | 0.43 [0.42–0.43] | 1.18× | -| estate/prowlarr/prowlarr.project.yml | 18 | 0.14 [0.14–0.17] | 0.17 [0.17–0.18] | 1.18× | -| estate/qbittorrent/qbittorrent.project.yml | 16 | 0.12 [0.12–0.14] | 0.13 [0.13–0.14] | 1.06× | -| estate/secrets/secrets.project.yml | 8 | 0.08 [0.07–0.08] | 0.09 [0.09–0.11] | 1.25× | -| estate/tribelt/tribelt.project.yml | 62 | 0.28 [0.28–0.30] | 0.33 [0.33–0.35] | 1.18× | -| estate/utility/utility.project.yml | 47 | 0.28 [0.27–0.29] | 0.30 [0.27–0.34] | 1.07× | -| knowledge-platform/knowledge-platform.project.yml | 243 | 0.96 [0.95–0.97] | 1.14 [1.10–1.25] | 1.19× | -| minimal/notes.project.yml | 19 | 0.14 [0.13–0.18] | 0.15 [0.14–0.17] | 1.05× | -| **sum of medians** | | 13.3 | 14.8 | 1.12× | - -
- -ATL takes 0.94× to 1.46× QVTo's time per Project (median 1.12×), and -1.12× over all 36 together (14.8 ms against 13.3 ms). - -### Execution, growing - -The estate's first *n* Projects, all lowered, milliseconds. Left: each -transformation loaded once (QVTo `TransformationExecutor`, EMFTVM -`ExecEnvPool`). Right: `lower.qvto` loaded for every Project, which is how -`Lowering.lower` shipped when this was measured, against the ATL source -compiled for every Project. - -| Projects | objects | QVTo ms (loaded once) | ATL ms (compiled once) | ATL / QVTo | QVTo ms (loaded per Project) | ATL ms (compiled per Project) | ATL / QVTo | -|---|---|---|---|---|---|---|---| -| 1 | 43 | 0.28 [0.27–0.29] | 0.31 [0.30–0.32] | 1.11× | 12.8 [12.5–13.1] | 179 [175–179] | 13.94× | -| 4 | 346 | 1.56 [1.53–1.64] | 1.73 [1.71–1.79] | 1.11× | 36.9 [36.2–37.5] | 783 [749–847] | 21.24× | -| 8 | 764 | 3.38 [3.32–3.57] | 3.93 [3.81–4.08] | 1.16× | 88.7 [87.2–89.4] | 1599 [1536–1627] | 18.03× | -| 12 | 853 | 4.00 [3.90–4.37] | 4.62 [4.55–4.73] | 1.16× | 273 [209–288] | 2298 [2220–2412] | 8.41× | -| 16 | 1153 | 5.23 [5.20–5.34] | 6.20 [6.17–6.21] | 1.19× | 267 [167–289] | 3344 [3200–3566] | 12.50× | -| 20 | 1359 | 6.25 [6.23–6.30] | 7.43 [7.37–7.51] | 1.19× | 187 [181–204] | 4813 [4669–5155] | 25.78× | -| 24 | 1703 | 7.62 [7.53–7.84] | 8.91 [8.84–9.16] | 1.17× | 336 [263–611] | 7843 [7448–7892] | 23.37× | - -Both execute in time linear in the input: about 4.5 µs an input object for -QVTo and 5.2 µs for ATL at 24 Projects, with ATL 1.11× to 1.19× slower at -every size. Loaded per call, ATL is 8× to 26× slower (the QVTo side of that -column is noisy), because compiling ATL costs far more than loading QVTo: - -### Loading, and cold - -| what is timed | QVTo ms | ATL ms | ATL / QVTo | -|---|---|---|---| -| load, warm JVM (parse, compile, load the transformation) | 22.7 [22.4–24.8] | 280 [270–283] | 12.37× | -| cold JVM: load | 335 [285–338] | 850 [832–873] | 2.53× | -| cold JVM: load and lower the first estate Project | 382 [323–384] | 858 [840–882] | 2.25× | -| cold JVM: load and lower all 24 estate Projects | 487 [399–487] | 911 [888–937] | 1.87× | - -Compiling the ATL source runs the ATL parser and then the ATL-to-EMFTVM -compiler, which is itself an ATL transformation, before the module is loaded: -about 280 ms warm, against 15–23 ms to parse and compile `lower.qvto` (the -two QVTo figures come from two suites, run at different points of the JVM's -warm-up). Cold, ATL adds about 0.4 s to a run: 911 ms against 487 ms to load -the transformation and lower all 24 estate Projects. - -### The sources - -| | lower.qvto | lower.atl | -|---|---|---| -| lines | 474 | 625 | -| lines of code (not blank, not a comment) | 366 | 489 | -| mappings / rules | 54 | 33 matched, 21 lazy | -| of which only dispatch to a subtype (`disjuncts`) | 8 | – | -| queries / helpers | 9 | 35 | - -The port is a third longer in lines of code. QVTo's eight `disjuncts` mappings -become helpers on each subtype (ATL dispatches a helper on the runtime type); -QVTo's `init` variables become attribute helpers on `Process`, which ATL -caches per object; and 42 conditional writes move into imperative `do` -blocks. - -### What ATL made hard - -Each of these was met while porting, and each is visible in -[`lower.atl`](../bundles/cli/src/test/resources/benchmark/lower.atl): - -1. **One image per source.** A matched rule creates one target per source - object. The lowering copies a Grant, an edge, an asset, a path or an env - entry declared on the Project or an Application once **per Process below - it**, so those copies cannot be matched rules: they are 21 lazy rules, - each called explicitly by the rule that holds the copy, the ATL counterpart of QVTo's - `copyFor(owner)` keyed mappings. Only what has exactly one image (33 - rules) is matched. -2. **A binding is unconditional.** An unsettable feature must be written - only where the source states it, or the Effective Intent states what no - author wrote. EMFTVM writes a null it is given, which marks the feature - set, and a binding has no `if`. So 42 conditional writes sit in imperative - `do` blocks: the rule shape QVTo writes declaratively with - `if … then x := … endif`. -3. **A lazy rule with a `do` block answers the block, not its target.** The - first runs failed with `Cannot add OclUndefined to multi-valued field - SharedIntent::dependsOn`: a lazy rule whose `do` block ends in an `if` - returns that statement's value, null. Each such rule ends with `t;`. -4. **`#absent` matches nothing.** EMFTVM reads an enumerator by its literal, - and every `absent` literal in the metamodel is the empty string, so the - value reads as `#` and never equals `#absent`. The comparison is with the - text (`toString() = '#'`). Without it, nine Processes lost their inherited - `cutover` and three generated keys gained an `encoding`. -5. **Optional children need guards.** QVTo's `map` on a null answers null; - an ATL lazy rule called on `OclUndefined` fails. Every optional child is - `if x.present then thisModule.R(x) else OclUndefined endif`. -6. **Keyword-named features** (`from`, `to`, `init`, `class`, `library`) are - quoted, as QVTo prefixes them with `_`. -7. **Headless needs two steps.** The ATL resource factory parses to an ATL - syntax tree, not a module; running headless means compiling with - `AtlToEmftvmCompiler` to EMFTVM bytecode, loading that as a module, and - running it through an `ExecEnvPool` - ([`AtlLowering`](../bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/AtlLowering.java)). - -### What ATL made easier - -- **No construction order.** A reference to a lowered `Process` or `Surface` - (a route's, a scrape's, an L4 port's) is written with the authored object, - and EMFTVM resolves it through the default trace after every matched rule - has run. QVTo's `resolveone` finds a copy only once it exists, so - `Application::lower` has to assign `processes` before anything that refers - to them; the port has no such constraint. -- **Dispatch.** A helper redeclared on each subtype dispatches on the runtime - type, where `lower.qvto` needs `disjuncts` mappings and a single `sameGrant` - query, because a QVTo query redeclared on subclasses binds statically. - -## Conclusion - -What the numbers support: - -- **The lowering's language does not decide the pipeline's speed.** Warm, - the ATL port executes the lowering in about 1.1× to 1.2× the QVTo time, - both linear in the input, and the whole lowering of the estate is under - 10 ms either way, against about 1 s for *check* alone. Cold, ATL costs - about 0.4 s more, mostly compiling its source, against a cold run of - nearly 4 s. -- **Where time goes:** parsing and checking dominate both warm (55–63%) and - cold (about 70%). Of the transformations, the measurable waste was - loading: the lowering spent more than 95% of its time loading `lower.qvto` - once per Project, and every resolution loaded `resolution.qvto` (about - 110 ms) and kept it. Both now load once per JVM: lowering the estate's 24 - Projects takes 7.8 ms instead of 174 ms, and a series of resolutions keeps - no heap per call instead of about 8 MiB. - -What they do not support: - -- **That QVTo was chosen for speed, or that ATL would be slow.** The report - did not claim it, and on the lowering the two are close. -- **Anything about the resolution in ATL.** The report's two reasons, reading - the completed target to hash the `Revision` and an explicit construction - order, are about the resolution, which was not ported. The lowering needs - neither: it never reads its own output, and its one ordering constraint - (Processes before what refers to them) disappeared in ATL rather than got - harder. So the port is evidence that ATL can express the lowering at a - similar speed, and no evidence either way on the resolution; there, reading - the target would need a second ATL pass over the output or a - recomputation from the source, and neither was built or timed. -- **Larger models.** The largest input is the estate's 24 Projects, 1,703 - objects to lower. The measured growth is linear up to there; nothing - beyond it was run. -- **Another machine, or a finer ratio.** One laptop, not isolated, one JVM. - The first full run warmed each series only five times, and put QVTo behind - ATL from 8 Projects on (0.3×); a probe then showed QVTo's reused executor - still settling after some hundreds of lowerings, which is why every - lowering series now warms both engines 40 times over every Project first. - The per-Project sums of the three full runs agree (1.11×, 1.15× and - 1.12×). The absolute numbers moved by 20–30% between runs, and *render* by - far more; the tables here are the last run, with the pipeline tables - rerun once more on a quieter machine. - -The ATL port stays benchmark-only: it is test code in the `cli` bundle, its -runtime reaches that bundle's tests alone through `additional.bundles`, and -the pipeline ships the QVTo lowering. No decision changes, so no ADR records -one. diff --git a/emf/docs/rules.md b/emf/docs/rules.md deleted file mode 100644 index 63babb2f2..000000000 --- a/emf/docs/rules.md +++ /dev/null @@ -1,39 +0,0 @@ -# Rule ledger - -The rules the model-driven build enforces on itself. The root -[rule ledger](../../docs/architecture-rules.md) holds the rules the root -enforces, including the two that watch this build from outside; the rules -here are enforced by Maven inside `emf/` and deleted with it -([0079](adr/emf/0079-the-emf-gates-are-estate-shaped.md)). - -A row names the file that enforces the rule, relative to `emf/`, and the -literal in that file that does the enforcing. `Ledgers.checkRules` in -`tests/parity` fails the build when a file no longer exists or no longer contains -its literal, so a gate cannot be removed while its row stays. That the rule -fires is shown once, by breaking it, in the pull request that adds it. - -This ledger holds **21** rules. - -| id | rule | enforcer | witness | -|---|---|---|---| -| EMF-001 | The build runs on JDK 21 and no other major version | `pom.xml` | `[21,22)` | -| EMF-002 | The build runs on Maven 3.9, the line Tycho 5 requires | `pom.xml` | `[3.9,4)` | -| EMF-003 | Every plugin version is pinned | `pom.xml` | `` | -| EMF-004 | Dependency versions converge | `pom.xml` | `` | -| EMF-005 | Nothing is ever published | `pom.xml` | `` | -| EMF-006 | Every compiler warning is enabled and fails the build | `pom.xml` | `-Werror` | -| EMF-007 | Java source is formatted with palantir-java-format, checked in `verify` | `pom.xml` | `` | -| EMF-008 | Line and branch coverage stay at or above the measured floor, in every module | `pom.xml` | `BRANCH` | -| EMF-009 | The mutation score stays at or above the measured threshold, in every module | `pom.xml` | `${emf.mutation.threshold}` | -| EMF-010 | A module depends only on the modules above it in the architecture's module table | `tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ArchitectureTest.kt` | `MODULES_DEPEND_ONLY_ON_MODULES_ABOVE_THEM` | -| EMF-011 | No dependency cycle between modules | `tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ArchitectureTest.kt` | `MODULES_HAVE_NO_CYCLES` | -| EMF-012 | The Maven distribution the wrapper downloads is pinned by checksum | `.mvn/wrapper/maven-wrapper.properties` | `distributionSha256Sum=` | -| EMF-013 | Every model behaviour has a JUnit witness, in whichever language its module is written, or is listed as pending with the ticket that lands it | `tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/LedgersTest.kt` | `Ledgers.checkWitnesses(repository)` | -| EMF-014 | Every rule in this ledger is still enforced by its named file | `tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/LedgersTest.kt` | `Ledgers.checkRules(repository)` | -| EMF-015 | Every warning the JDT compiler reports in a Tycho bundle fails the build | `pom.xml` | `true` | -| EMF-016 | The target platform resolves from one dated release build and names every unit at an exact version | `tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/TargetPlatformTest.kt` | `EVERY_UNIT_IS_PINNED` | -| EMF-017 | The module rules run over the classes the build wrote, never over an import that holds no module | `tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ArchitectureTest.kt` | `ModuleRules.modulesMissingFrom(classes)` | -| EMF-018 | Kotlin source is formatted with ktlint, checked in `verify` | `pom.xml` | `${ktlint.version}` | -| EMF-019 | A stage's field coverage gaps are exactly its committed baseline, which only shrinks | `bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/FieldCoverageTest.java` | `aStagesGapsAreExactlyItsBaseline` | -| EMF-020 | Every oracle comparison listed as passing matches the production implementation's oracle, and every one that matches is listed | `bundles/cli/src/test/java/dev/jorisjonkers/deploykit/emf/cli/OracleDistanceTest.java` | `passing, and not listed` | -| EMF-021 | No class a module ships depends on EMF Compare, which the tests alone use | `tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ArchitectureTest.kt` | `NO_MODULE_DEPENDS_ON_EMF_COMPARE` | diff --git a/emf/docs/witnesses.md b/emf/docs/witnesses.md deleted file mode 100644 index 3eb8211fc..000000000 --- a/emf/docs/witnesses.md +++ /dev/null @@ -1,122 +0,0 @@ -# Witnesses - -A row of the root [behaviour ledger](../../docs/requirements.md), in any of -its area files under [`docs/requirements/`](../../docs/requirements/), whose -behaviour is the model's own is proved in both implementations. The root row -names the production implementation's test, under `test/model/`; this list -names the JUnit test that proves the same behaviour here -([0078](adr/emf/0078-model-behaviours-have-a-junit-witness.md)). A witness is a -JUnit test in whichever language its module is written, so a row here names a -Kotlin function of the test tier or a Java method of a bundle, and the check -reads both. - -`Ledgers.checkWitnesses` in `tests/parity` fails the `emf` build when a model row -has no witness here, when a witness names an id that is not a model row, or -when it names a test method that does not exist. - -A model behaviour this implementation cannot prove **yet** is listed as pending -below, with the ticket that lands it. It is the same state the -[rule ledger](rules.md) already carries for a rule not enforced yet: a row that -is visibly owed, rather than one quietly dropped. A pending row still has to -name a real model row, it may not also be witnessed, and its count is stated -beside the witness count, so the gate keeps its teeth while the work is -outstanding. - -This list holds **88** witnesses, and **1** pending. - -| id | JUnit test | -|---|---| -| REQ-021 | `ParityTest#the parsed intent equals the committed oracle` | -| REQ-023 | `ParityTest#the metamodels structure equals the committed descriptor` | -| REQ-024 | `ParityTest#a refused document equals its committed diagnostics` | -| REQ-029 | `LinkingTest#aRouteAndAScrapeLinkToTheVeryProcessAndSurfaceTheirApplicationHolds` | -| REQ-030 | `PlatformIntentTest#aPlatformDocumentParsesAndATierWithoutItsEndpointIsRefused` | -| REQ-031 | `IntentSetTest#everyEnvAndFileGrantIsRefusedWhereSecretsAreNotEncryptedAtRest` | -| REQ-033 | `ResolvedDeploymentTest#theResolvedModelNamesNoKubernetesOrTraefikField` | -| REQ-034 | `PinnedInputsTest#theNodeContractPublishesTheSevenNodesTheirCapabilitiesAndAMediumNoProcessMayAskFor` | -| REQ-036 | `LoweringTest#everyProcessHoldsTheGrantsOfEveryLevelAboveItExtendedByItsOwn` | -| REQ-037 | `EnvFilesTest#readsALiteralAPlaceholderCommentsAndBlankLines` | -| REQ-038 | `ResolutionTest#theRevisionIsTheOneEveryCommittedProjectionRecordsAndMovesOnlyWithADecision` | -| REQ-039 | `ParityTest#the resolved dependency edges equal the committed oracle` | -| REQ-040 | `RenderedTreeTest#aProjectsShareIsItsCommittedTreeByteForByte` | -| REQ-049 | `RenderedTreeTest#aProjectsShareIsItsCommittedTreeByteForByte` | -| REQ-052 | `RenderedTreeTest#authsShareAndTheEstateShareItDerivesAreItsCommittedTreeByteForByte` | -| REQ-053 | `RenderedTreeTest#theKnowledgePlatformsShareAndTheEstateShareItDerivesAreItsCommittedTreeByteForByte` | -| REQ-054 | `ParityTest#a negative fixture equals its committed diagnostics in either order` | -| REQ-057 | `RenderedTreeTest#authsShareAndTheEstateShareItDerivesAreItsCommittedTreeByteForByte` | -| REQ-058 | `LinkingTest#theReporterLinksOnlyToADeclaredApplicationThatAnswersOnHttp` | -| REQ-061 | `RenderedTreeTest#theKnowledgePlatformsShareAndTheEstateShareItDerivesAreItsCommittedTreeByteForByte` | -| REQ-062 | `RenderedTreeTest#theKnowledgePlatformsShareAndTheEstateShareItDerivesAreItsCommittedTreeByteForByte` | -| REQ-065 | `RenderedTreeTest#aProjectsShareIsItsCommittedTreeByteForByte` | -| REQ-066 | `RenderedTreeTest#theKnowledgePlatformsShareAndTheEstateShareItDerivesAreItsCommittedTreeByteForByte` | -| REQ-067 | `RenderedTreeTest#theKnowledgePlatformsShareAndTheEstateShareItDerivesAreItsCommittedTreeByteForByte` | -| REQ-068 | `RenderedTreeTest#aProjectsShareIsItsCommittedTreeByteForByte` | -| REQ-069 | `RenderedTreeTest#theKnowledgePlatformsShareAndTheEstateShareItDerivesAreItsCommittedTreeByteForByte` | -| REQ-070 | `RenderedTreeTest#aProjectsShareIsItsCommittedTreeByteForByte` | -| REQ-071 | `RenderedTreeTest#theKnowledgePlatformsShareAndTheEstateShareItDerivesAreItsCommittedTreeByteForByte` | -| REQ-072 | `RenderedTreeTest#authsShareAndTheEstateShareItDerivesAreItsCommittedTreeByteForByte` | -| REQ-075 | `ModelWitnessesTest#aLowPortKeepsNetBindServiceAloneAndAHighPortAddsNothing` | -| REQ-076 | `ModelWitnessesTest#aTransitGrantThatReadsCoversTheKeyAndUpdatesEachOtherOperationsOnePath` | -| REQ-077 | `ModelWitnessesTest#aMongoIsDumpedByThePlatformsMethodOwnsNoDatabaseAndIsRefusedWithoutADurableVolume` | -| REQ-078 | `ModelWitnessesTest#aScheduledProcessIsACronJobThatNeverRunsTwiceAndSkipsALateRun` | -| REQ-079 | `PipelineRefusalsTest#anImageTheLockHoldsAsRootIsRefusedAtTheLock` | -| REQ-080 | `ModelWitnessesTest#eachHumanGrantIsOneClusterRoleBindingInEveryCompositionAndADuplicateIsRefused` | -| REQ-081 | `ModelWitnessesTest#aProcessExposedOnAPoolIsHeldToThePoolsSiteAndAPlacementThatContradictsItIsRefused` | -| REQ-082 | `ModelWitnessesTest#everyMonitorCarriesThePlatformsSelectorLabelsBesideItsOwnAndTheMonitorsOwnValueWins` | -| REQ-084 | `ModelWitnessesTest#theSameHostOnOneTierIsRefusedAndOnTwoTiersRendersOneRoutePerProxy` | -| REQ-085 | `ModelWitnessesTest#everyRouteCarriesItsTiersIngressClassAndATierThatNamesNoneIsRefused` | -| REQ-087 | `ModelWitnessesTest#theProjectThatDeclaresAProxyRendersTheSharedMiddlewaresOncePerNamespace` | -| REQ-089 | `ModelWitnessesTest#replicasSpreadAcrossNodesRepelEachOtherWithinOneRevisionAndNeedANodeEach` | -| REQ-090 | `ModelWitnessesTest#aForwardAuthNamesAProviderSurfaceAndPathAndAnUnknownProviderIsRefused` | -| REQ-091 | `ModelWitnessesTest#aTiersProxyIsConfiguredByItsSurfacesAndTheCrdProviderFilteredOnItsClass` | -| REQ-092 | `ModelWitnessesTest#eachDashboardFileIsOneGrafanaDashboardInItsFolderAndAnUnusableOneIsRefused` | -| REQ-093 | `ModelWitnessesTest#theMetricsStackRendersRuleGroupsAndRoutesEachSeverityToItsReceiverAndNoRuleGroupsRenderElsewhere` | -| REQ-094 | `ModelWitnessesTest#aRouteOnATierThatDeclaresDnsCarriesTheExternalDnsAnnotationsAndOneOnATierWithoutCarriesNone` | -| REQ-095 | `ModelWitnessesTest#aParkedProcessKeepsWhatItOwnsRunsNoPodAndAParkedScheduleStartsNoRun` | -| REQ-096 | `ModelWitnessesTest#aDatastoreRunsAtTheDataClassACriticalApplicationAtTheCriticalClassAndAnyOtherAtNone` | -| REQ-097 | `ModelWitnessesTest#aNodeAddressExposureIsAHostPortOnTheProcessHoldsItToTheNodeAndRendersNoLoadBalancer` | -| REQ-098 | `ModelWitnessesTest#theNodeAgentsAreDerivedAndACatalogThatNamesNoImageForOneIsRefusedAtTheEntry` | -| REQ-099 | `ModelWitnessesTest#aTiersAddressExposesItsProxyOnTheListenersPortsAndAnAcmeTierGetsAResolverWithItsOwnState` | -| REQ-100 | `ModelWitnessesTest#aRoutesTlsFollowsItsTierAnAcmeTierNamesItsResolverAPlainTierRendersNoneAndATlsTierThatIssuesNoneAnEmptyBlock` | -| REQ-101 | `ModelWitnessesTest#theLogCollectorReadsEveryPodsLogThroughTheApiAsOneCopyAndNoTreeHoldsAWebhookHookOrAggregatedRole` | -| REQ-102 | `PipelineRefusalsTest#aProcessIsCheckedWithTheEnvFilesBesideItsProjectFile` | -| REQ-104 | `ModelWitnessesTest#anOffClusterCopyNamesAnAgePublicKeyAndOneThatIsNoneIsRefusedWithThePlatformDocument` | -| REQ-105 | `ModelWitnessesTest#aProcessAnsweringOnPort53ResolvesThroughThePlatformsUpstreamNameserversAndIsRefusedWithoutThem` | -| REQ-107 | `ModelWitnessesTest#aProcessThatSpawnsCreatesPodsFromItsTemplateAlone` | -| REQ-108 | `ModelWitnessesTest#anAdmittedApiBlockWithNoRulesRendersNoRoleAndNoBindingBesideItsMountedToken` | -| REQ-109 | `ModelWitnessesTest#anEdgeIntoAnObjectStoreThatNamesBucketsDerivesItsCatalogAndHandsTheConsumerItsKey` | -| REQ-111 | `ModelWitnessesTest#everyStableAddressIsOneExternalNameKeptCurrentByFluxAndAConsumersAliasNamesItAlone` | -| REQ-117 | `ModelWitnessesTest#everyCanaryAsksTheReleaseGateAFourthQuestionRollback` | -| REQ-118 | `ModelWitnessesTest#theMetricsStackScrapesFluxsControllersWhereThePlatformRecordsTheirMetricsAndNowhereElse` | -| REQ-119 | `ModelWitnessesTest#aProcessAndASidecarCarryTheCommandAndArgumentsTheyNameAsWrittenAndNamingNoneCarriesNone` | -| REQ-120 | `ModelWitnessesTest#aWritablePathsSizeIsAddedToTheProcessesMemoryAndAPathNoNodeCanHoldBesideItIsRefused` | -| REQ-121 | `ModelWitnessesTest#aDescriptionRendersNothingAndOneOverOneHundredAndSixtyCharactersOrEmptyIsASchemaRefusal` | -| REQ-123 | `ModelWitnessesTest#anOptionalKeyMakesEveryReferenceToItOptionalAndOptionalFalseIsRefused` | -| REQ-124 | `ModelWitnessesTest#aSeededAssetIsRefusedWhereThePlatformNamesNoSeederAndWhereItLandsBelowNoVolumeOrWritablePath` | -| REQ-125 | `ModelWitnessesTest#aSeededAssetIsTheFirstInitContainerThatWritesItAtMode0600AndTheProcessNeverMountsIt` | -| REQ-127 | `ModelWitnessesTest#anUnproxiedHostPointsAtTheTiersDirectAddressAndItsRoutesCountAClientByItsConnection` | -| REQ-130 | `ModelWitnessesTest#aSetWithoutTheNodeContractDerivesNoAgentAndAPoolOnASiteWithNoNodeDerivesNoAnnouncer` | -| REQ-140 | `ModelWitnessesTest#aSidecarMountsOnlyAnAssetItsProcessHoldsAndAnotherIsRefused` | -| REQ-151 | `ModelWitnessesTest#aClientTakesTheFieldsItsSignInModeTakesAndRequiresWhatItNeedsAndTheLogoutPathIsANativeClientsAlone` | -| REQ-152 | `ModelWitnessesTest#aContainerThatMountsAWritableTmpGetsHomeAfterItsOwnVariablesAndOneWithoutGetsNone` | -| REQ-153 | `ModelWitnessesTest#everyNamespaceTheRenderWritesIsNeverPruned` | -| REQ-155 | `ModelWitnessesTest#theL4SpeakerStartsOnMetalLbZeroFifteenThreeReadingSecretsInItsOwnNamespaceAlone` | -| REQ-156 | `ModelWitnessesTest#theGpuDeviceHandsOutEachCardByItsIndex` | -| REQ-157 | `ModelWitnessesTest#theL4SpeakerRunsMemberlistKeyedByTheNodeProjectsOwnGeneratedKeyAndWithoutAPolicyJobNone` | -| REQ-158 | `ModelWitnessesTest#aMongoResolvesItsOwnServiceNameToItselfAndAProcessOfAnyOtherEngineToNothing` | -| REQ-159 | `ModelWitnessesTest#anHourlyPolicyOrCatalogRunGivesUpWithinTheHourAndTheOneShotJobRetriesUntilItSucceeds` | -| REQ-160 | `ModelWitnessesTest#theMonitoringStacksPrometheusAndAlertmanagerRenderAsTheOperatorsObjectsAndAProcessItCannotRunIsRefused` | -| REQ-161 | `ModelWitnessesTest#everyProcessThatAnswersATierHoldsTheApiAccessItsProxyReadsRoutesWithAndNoApiAccessBlockIsRefused` | -| REQ-162 | `ModelWitnessesTest#aTlsTierThatIssuesNoCertificateServesTheOneItReadsFromTheSecretStoreAndElsewhereItIsRefused` | -| REQ-163 | `ModelWitnessesTest#theMonitoringStacksGrafanaRendersItsInstanceReadsOneGeneratedAdminAndDerivesItsDataSources` | -| REQ-164 | `ModelWitnessesTest#theMetricsStackScrapesK3sWhereTheBootstrapSetRecordsItAndAComponentItDoesNotRecordIsNotScraped` | -| REQ-166 | `RenderedTreeTest#aRealEstateProjectIsItsCommittedOraclesByteForByte` | -| REQ-168 | `ModelWitnessesTest#anAcmeTiersClaimIsNamedForItsProxysProcessAndAVolumeUnderItIsRefused` | -| REQ-169 | `ModelWitnessesTest#anAcmeProxysPodReownsItsVolumeOnlyWhileItsRootDoesNotMatchAndNoOtherPodSaysSo` | -| REQ-170 | `ModelWitnessesTest#aGeneratedKeyThatAdoptsAValueHandsTheVaultPolicyJobTheLocationItAdoptsFrom` | - -## Pending - -| id | why no witness yet | ticket | -|---|---|---| -| REQ-035 | `resolved.json` binds the production implementation only, so the shared claim is the rendered tree, which REQ-040's witness holds; the row's own last clause, knowledge's resolved edges, is resolved by neither implementation, and leaves with the example when knowledge-system retires ([the parity contract](../../docs/architecture.md#the-parity-contract)) | #272 | diff --git a/emf/emf.target b/emf/emf.target deleted file mode 100644 index 7bcc0fb73..000000000 --- a/emf/emf.target +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/emf/models/minimal.resolveddeployment b/emf/models/minimal.resolveddeployment deleted file mode 100644 index 2b902e828..000000000 --- a/emf/models/minimal.resolveddeployment +++ /dev/null @@ -1,144 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - error-rate - latency - - - - - - - - - - - - - - - - - - - - - - - - - enschede-t1000-1 - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - libraries.yaml - namespace.yaml - notes - rollout-events - - - - - canary.yaml - configmap.yaml - podmonitor.yaml - route-public.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/models/secrets.resolveddeployment b/emf/models/secrets.resolveddeployment deleted file mode 100644 index f09509792..000000000 --- a/emf/models/secrets.resolveddeployment +++ /dev/null @@ -1,269 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - tokenreviews - create - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - - - - - - server - -config=/vault/config/vault.hcl - vault - - - - - - - vaultstaticsecrets - vaultstaticsecrets/status - vaultdynamicsecrets - vaultdynamicsecrets/status - vaultauths - vaultauths/status - vaultconnections - vaultconnections/status - get - list - watch - create - update - patch - delete - - - secrets - get - list - watch - create - update - patch - delete - - - serviceaccounts/token - create - - - deployments - statefulsets - daemonsets - get - list - watch - patch - - - events - create - patch - - - - - - - - - - - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - enschede-pi-1 - enschede-pi-2 - enschede-pi-3 - frankfurt-contabo-1 - - - - - - enschede-t1000-1 - enschede-rx7900xtx-1 - enschede-gtx-960m-1 - frankfurt-contabo-1 - - - - - - - namespace.yaml - rollout-events - vault - vault-policy - vault-secrets-operator - vaultconnection.yaml - - - - - backup.yaml - configmap.yaml - pvc.yaml - rbac.yaml - service.yaml - serviceaccount.yaml - vso.yaml - workload.yaml - - - - - - - - - - - - - - - - - - - rbac.yaml - service.yaml - serviceaccount.yaml - workload.yaml - - - - - - - - - - - - - - - read - - - read - - - - - - - - - priorityclasses.yaml - - - - - - clusterrolebindings.yaml - - - - - - - - - - - - - - - - - - - - - - - configmap.yaml - cronjob.yaml - job.yaml - serviceaccount.yaml - - - - - alert.yaml - provider.yaml - - diff --git a/emf/mvnw b/emf/mvnw deleted file mode 100755 index bd8896bf2..000000000 --- a/emf/mvnw +++ /dev/null @@ -1,295 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Apache Maven Wrapper startup batch script, version 3.3.4 -# -# Optional ENV vars -# ----------------- -# JAVA_HOME - location of a JDK home dir, required when download maven via java source -# MVNW_REPOURL - repo url base for downloading maven distribution -# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output -# ---------------------------------------------------------------------------- - -set -euf -[ "${MVNW_VERBOSE-}" != debug ] || set -x - -# OS specific support. -native_path() { printf %s\\n "$1"; } -case "$(uname)" in -CYGWIN* | MINGW*) - [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" - native_path() { cygpath --path --windows "$1"; } - ;; -esac - -# set JAVACMD and JAVACCMD -set_java_home() { - # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched - if [ -n "${JAVA_HOME-}" ]; then - if [ -x "$JAVA_HOME/jre/sh/java" ]; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - JAVACCMD="$JAVA_HOME/jre/sh/javac" - else - JAVACMD="$JAVA_HOME/bin/java" - JAVACCMD="$JAVA_HOME/bin/javac" - - if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then - echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 - echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 - return 1 - fi - fi - else - JAVACMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v java - )" || : - JAVACCMD="$( - 'set' +e - 'unset' -f command 2>/dev/null - 'command' -v javac - )" || : - - if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then - echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 - return 1 - fi - fi -} - -# hash string like Java String::hashCode -hash_string() { - str="${1:-}" h=0 - while [ -n "$str" ]; do - char="${str%"${str#?}"}" - h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) - str="${str#?}" - done - printf %x\\n $h -} - -verbose() { :; } -[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } - -die() { - printf %s\\n "$1" >&2 - exit 1 -} - -trim() { - # MWRAPPER-139: - # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. - # Needed for removing poorly interpreted newline sequences when running in more - # exotic environments such as mingw bash on Windows. - printf "%s" "${1}" | tr -d '[:space:]' -} - -scriptDir="$(dirname "$0")" -scriptName="$(basename "$0")" - -# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties -while IFS="=" read -r key value; do - case "${key-}" in - distributionUrl) distributionUrl=$(trim "${value-}") ;; - distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; - esac -done <"$scriptDir/.mvn/wrapper/maven-wrapper.properties" -[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" - -case "${distributionUrl##*/}" in -maven-mvnd-*bin.*) - MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ - case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in - *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; - :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; - :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; - :Linux*x86_64*) distributionPlatform=linux-amd64 ;; - *) - echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 - distributionPlatform=linux-amd64 - ;; - esac - distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" - ;; -maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; -*) MVN_CMD="mvn${scriptName#mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; -esac - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" -distributionUrlName="${distributionUrl##*/}" -distributionUrlNameMain="${distributionUrlName%.*}" -distributionUrlNameMain="${distributionUrlNameMain%-bin}" -MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" -MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" - -exec_maven() { - unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : - exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" -} - -if [ -d "$MAVEN_HOME" ]; then - verbose "found existing MAVEN_HOME at $MAVEN_HOME" - exec_maven "$@" -fi - -case "${distributionUrl-}" in -*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; -*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; -esac - -# prepare tmp dir -if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then - clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } - trap clean HUP INT TERM EXIT -else - die "cannot create temp dir" -fi - -mkdir -p -- "${MAVEN_HOME%/*}" - -# Download and Install Apache Maven -verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -verbose "Downloading from: $distributionUrl" -verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -# select .zip or .tar.gz -if ! command -v unzip >/dev/null; then - distributionUrl="${distributionUrl%.zip}.tar.gz" - distributionUrlName="${distributionUrl##*/}" -fi - -# verbose opt -__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' -[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v - -# normalize http auth -case "${MVNW_PASSWORD:+has-password}" in -'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; -has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; -esac - -if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then - verbose "Found wget ... using wget" - wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" -elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then - verbose "Found curl ... using curl" - curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" -elif set_java_home; then - verbose "Falling back to use Java to download" - javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" - targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" - cat >"$javaSource" <<-END - public class Downloader extends java.net.Authenticator - { - protected java.net.PasswordAuthentication getPasswordAuthentication() - { - return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); - } - public static void main( String[] args ) throws Exception - { - setDefault( new Downloader() ); - java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); - } - } - END - # For Cygwin/MinGW, switch paths to Windows format before running javac and java - verbose " - Compiling Downloader.java ..." - "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" - verbose " - Running Downloader.java ..." - "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" -fi - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -if [ -n "${distributionSha256Sum-}" ]; then - distributionSha256Result=false - if [ "$MVN_CMD" = mvnd.sh ]; then - echo "Checksum validation is not supported for maven-mvnd." >&2 - echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - elif command -v sha256sum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c - >/dev/null 2>&1; then - distributionSha256Result=true - fi - elif command -v shasum >/dev/null; then - if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then - distributionSha256Result=true - fi - else - echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 - echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 - exit 1 - fi - if [ $distributionSha256Result = false ]; then - echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 - echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 - exit 1 - fi -fi - -# unzip and move -if command -v unzip >/dev/null; then - unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" -else - tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" -fi - -# Find the actual extracted directory name (handles snapshots where filename != directory name) -actualDistributionDir="" - -# First try the expected directory name (for regular distributions) -if [ -d "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" ]; then - if [ -f "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/bin/$MVN_CMD" ]; then - actualDistributionDir="$distributionUrlNameMain" - fi -fi - -# If not found, search for any directory with the Maven executable (for snapshots) -if [ -z "$actualDistributionDir" ]; then - # enable globbing to iterate over items - set +f - for dir in "$TMP_DOWNLOAD_DIR"/*; do - if [ -d "$dir" ]; then - if [ -f "$dir/bin/$MVN_CMD" ]; then - actualDistributionDir="$(basename "$dir")" - break - fi - fi - done - set -f -fi - -if [ -z "$actualDistributionDir" ]; then - verbose "Contents of $TMP_DOWNLOAD_DIR:" - verbose "$(ls -la "$TMP_DOWNLOAD_DIR")" - die "Could not find Maven distribution directory in extracted archive" -fi - -verbose "Found extracted Maven distribution directory: $actualDistributionDir" -printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$actualDistributionDir/mvnw.url" -mv -- "$TMP_DOWNLOAD_DIR/$actualDistributionDir" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" - -clean || : -exec_maven "$@" diff --git a/emf/mvnw.cmd b/emf/mvnw.cmd deleted file mode 100644 index 92450f932..000000000 --- a/emf/mvnw.cmd +++ /dev/null @@ -1,189 +0,0 @@ -<# : batch portion -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM http://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Apache Maven Wrapper startup batch script, version 3.3.4 -@REM -@REM Optional ENV vars -@REM MVNW_REPOURL - repo url base for downloading maven distribution -@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven -@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output -@REM ---------------------------------------------------------------------------- - -@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) -@SET __MVNW_CMD__= -@SET __MVNW_ERROR__= -@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% -@SET PSModulePath= -@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( - IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) -) -@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% -@SET __MVNW_PSMODULEP_SAVE= -@SET __MVNW_ARG0_NAME__= -@SET MVNW_USERNAME= -@SET MVNW_PASSWORD= -@IF NOT "%__MVNW_CMD__%"=="" ("%__MVNW_CMD__%" %*) -@echo Cannot start maven from wrapper >&2 && exit /b 1 -@GOTO :EOF -: end batch / begin powershell #> - -$ErrorActionPreference = "Stop" -if ($env:MVNW_VERBOSE -eq "true") { - $VerbosePreference = "Continue" -} - -# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties -$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl -if (!$distributionUrl) { - Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" -} - -switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { - "maven-mvnd-*" { - $USE_MVND = $true - $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" - $MVN_CMD = "mvnd.cmd" - break - } - default { - $USE_MVND = $false - $MVN_CMD = $script -replace '^mvnw','mvn' - break - } -} - -# apply MVNW_REPOURL and calculate MAVEN_HOME -# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ -if ($env:MVNW_REPOURL) { - $MVNW_REPO_PATTERN = if ($USE_MVND -eq $False) { "/org/apache/maven/" } else { "/maven/mvnd/" } - $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace "^.*$MVNW_REPO_PATTERN",'')" -} -$distributionUrlName = $distributionUrl -replace '^.*/','' -$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' - -$MAVEN_M2_PATH = "$HOME/.m2" -if ($env:MAVEN_USER_HOME) { - $MAVEN_M2_PATH = "$env:MAVEN_USER_HOME" -} - -if (-not (Test-Path -Path $MAVEN_M2_PATH)) { - New-Item -Path $MAVEN_M2_PATH -ItemType Directory | Out-Null -} - -$MAVEN_WRAPPER_DISTS = $null -if ((Get-Item $MAVEN_M2_PATH).Target[0] -eq $null) { - $MAVEN_WRAPPER_DISTS = "$MAVEN_M2_PATH/wrapper/dists" -} else { - $MAVEN_WRAPPER_DISTS = (Get-Item $MAVEN_M2_PATH).Target[0] + "/wrapper/dists" -} - -$MAVEN_HOME_PARENT = "$MAVEN_WRAPPER_DISTS/$distributionUrlNameMain" -$MAVEN_HOME_NAME = ([System.Security.Cryptography.SHA256]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' -$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" - -if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { - Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" - Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" - exit $? -} - -if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { - Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" -} - -# prepare tmp dir -$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile -$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" -$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null -trap { - if ($TMP_DOWNLOAD_DIR.Exists) { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } - } -} - -New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null - -# Download and Install Apache Maven -Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." -Write-Verbose "Downloading from: $distributionUrl" -Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" - -$webclient = New-Object System.Net.WebClient -if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { - $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) -} -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 -$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null - -# If specified, validate the SHA-256 sum of the Maven distribution zip file -$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum -if ($distributionSha256Sum) { - if ($USE_MVND) { - Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." - } - Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash - if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { - Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." - } -} - -# unzip and move -Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null - -# Find the actual extracted directory name (handles snapshots where filename != directory name) -$actualDistributionDir = "" - -# First try the expected directory name (for regular distributions) -$expectedPath = Join-Path "$TMP_DOWNLOAD_DIR" "$distributionUrlNameMain" -$expectedMvnPath = Join-Path "$expectedPath" "bin/$MVN_CMD" -if ((Test-Path -Path $expectedPath -PathType Container) -and (Test-Path -Path $expectedMvnPath -PathType Leaf)) { - $actualDistributionDir = $distributionUrlNameMain -} - -# If not found, search for any directory with the Maven executable (for snapshots) -if (!$actualDistributionDir) { - Get-ChildItem -Path "$TMP_DOWNLOAD_DIR" -Directory | ForEach-Object { - $testPath = Join-Path $_.FullName "bin/$MVN_CMD" - if (Test-Path -Path $testPath -PathType Leaf) { - $actualDistributionDir = $_.Name - } - } -} - -if (!$actualDistributionDir) { - Write-Error "Could not find Maven distribution directory in extracted archive" -} - -Write-Verbose "Found extracted Maven distribution directory: $actualDistributionDir" -Rename-Item -Path "$TMP_DOWNLOAD_DIR/$actualDistributionDir" -NewName $MAVEN_HOME_NAME | Out-Null -try { - Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null -} catch { - if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { - Write-Error "fail to move MAVEN_HOME" - } -} finally { - try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } - catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } -} - -Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/emf/pom.xml b/emf/pom.xml deleted file mode 100644 index 8403e14fd..000000000 --- a/emf/pom.xml +++ /dev/null @@ -1,438 +0,0 @@ - - - - 4.0.0 - - dev.jorisjonkers.deploykit.emf - emf-parent - 0.1.0-SNAPSHOT - pom - deploy-kit model-driven implementation - - - bundles/metamodel - bundles/syntax - bundles/cli - bundles/resolve - bundles/render - tests/parity - - - - 21 - UTF-8 - UTF-8 - 2026-09-14T00:00:00Z - - - 1.00 - 1.00 - 100 - - 4 - - 6.1.3 - 3.27.7 - 1.5.1 - - 2.22.4 - 2.7 - - 2.4.21 - - 2.98.0 - 1.7.1 - 0.8.16 - 1.30.1 - 1.2.3 - 5.0.4 - - - - - - org.junit - junit-bom - ${junit.version} - pom - import - - - org.assertj - assertj-core - ${assertj.version} - - - com.tngtech.archunit - archunit-junit5 - ${archunit.version} - - - com.fasterxml.jackson.core - jackson-databind - ${jackson.version} - - - org.yaml - snakeyaml - ${snakeyaml.version} - - - org.jetbrains.kotlin - kotlin-stdlib - ${kotlin.version} - - - - - - - - org.apache.maven.pluginsmaven-clean-plugin3.5.0 - org.apache.maven.pluginsmaven-resources-plugin3.5.0 - org.apache.maven.pluginsmaven-compiler-plugin3.16.0 - org.apache.maven.pluginsmaven-surefire-plugin3.6.1 - org.apache.maven.pluginsmaven-jar-plugin3.5.1 - org.apache.maven.pluginsmaven-install-plugin3.2.0 - org.apache.maven.pluginsmaven-deploy-plugin3.2.0 - org.apache.maven.pluginsmaven-site-plugin3.22.0 - org.apache.maven.pluginsmaven-enforcer-plugin3.7.0 - com.diffplug.spotlessspotless-maven-plugin3.10.4 - org.jacocojacoco-maven-plugin${jacoco.version} - org.pitestpitest-maven${pitest.version} - org.eclipse.tychotycho-compiler-plugin${tycho.version} - org.eclipse.tychotycho-packaging-plugin${tycho.version} - org.eclipse.tychotycho-surefire-plugin${tycho.version} - org.eclipse.tychotycho-p2-plugin${tycho.version} - org.eclipse.tychotycho-ds-plugin${tycho.version} - org.eclipse.tychotycho-bnd-plugin${tycho.version} - org.eclipse.tychotycho-source-plugin${tycho.version} - org.codehaus.mojoexec-maven-plugin3.6.4 - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.codehaus.mojo - exec-maven-plugin - [3.0.0,) - java - - - - - - - - - - org.jetbrains.kotlinkotlin-maven-plugin${kotlin.version} - - - - - - - org.eclipse.tycho - tycho-maven-plugin - ${tycho.version} - true - - - org.eclipse.tycho - target-platform-configuration - ${tycho.version} - - - ${maven.multiModuleProjectDirectory}/emf.target - - consider - - linuxgtkx86_64 - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - - - enforce - enforce - - - [21,22) - [3.9,4) - - - - - - - - converge - enforce - - - - - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - - - -Xlint:all - -Werror - - - - - - com.diffplug.spotless - spotless-maven-plugin - - - src/*/java/**/*.java - ${palantir-java-format.version} - - - - - src/*/kotlin/**/*.kt - ${ktlint.version} - - - - - format-check - check - - - - - - org.jacoco - jacoco-maven-plugin - - - prepare-agent - prepare-agent - - - false - - - - report - verify - report - - - coverage-floor - verify - check - - - - BUNDLE - - - LINE - COVEREDRATIO - ${emf.coverage.line.minimum} - - - BRANCH - COVEREDRATIO - ${emf.coverage.branch.minimum} - - - - - - - - - - - org.pitest - pitest-maven - - - org.pitest - pitest-junit5-plugin - ${pitest-junit5.version} - - - - dev.jorisjonkers.deploykit.emf.* - dev.jorisjonkers.deploykit.emf.* - ${emf.mutation.threshold} - ${emf.mutation.threads} - - -Demf.mutation=true - XMLHTML - false - true - - - - mutation-threshold - verify - mutationCoverage - - - - - - - - - - benchmark - - true - true - LoweringEquivalenceTest,LoweringBenchmarkTest,PipelineBenchmarkTest - false - - - - - org.apache.maven.plugins - maven-surefire-plugin - - false - - true - - - - - - - - - quick - - true - true - true - - - - - bundle - - ${basedir}/META-INF/MANIFEST.MF - - - - org.junit.jupiter - junit-jupiter - test - - - org.assertj - assertj-core - test - - - - com.fasterxml.jackson.core - jackson-databind - test - - - org.yaml - snakeyaml - test - - - - - - org.apache.maven.plugins - maven-enforcer-plugin - - - converge - true - - - - - - org.eclipse.tycho - tycho-compiler-plugin - - true - true - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - standalone-test - test - test - - - - - - - - diff --git a/emf/scripts/summary.sh b/emf/scripts/summary.sh deleted file mode 100755 index bb0aeff5b..000000000 --- a/emf/scripts/summary.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash -# Prints one Markdown line for the CI job summary: tests, line coverage and -# mutation score of the model-driven build, read from the reports `mvnw verify` -# leaves behind. Missing reports print as "n/a" rather than failing, because the -# summary runs after a failed build too. So no `pipefail`: each read ends in an -# awk that prints "n/a" for no input, and a `cat` or `grep` that finds nothing -# upstream of it is no failure of the script. -set -eu -cd "$(dirname "$0")/.." - -tests=$(cat ./*/*/target/surefire-reports/TEST-*.xml 2>/dev/null \ - | grep -o ']*' | grep -o ' tests="[0-9]*"' | grep -o '[0-9]*' \ - | awk '{s+=$1} END {print (NR ? s : "n/a")}') - -coverage=$(cat ./*/*/target/site/jacoco/jacoco.csv 2>/dev/null | awk -F, ' - NR > 1 && $1 != "GROUP" {missed += $8; covered += $9} - END {if (missed + covered) printf "%.1f%%", 100 * covered / (missed + covered); else print "n/a"}') - -mutation=$(cat ./*/*/target/pit-reports/mutations.xml 2>/dev/null | awk ' - {total += gsub(/ - - 4.0.0 - - - dev.jorisjonkers.deploykit.emf - emf-parent - 0.1.0-SNAPSHOT - ../../pom.xml - - - dev.jorisjonkers.deploykit.emf.parity - - jar - deploy-kit model-driven parity - - - - org.jetbrains.kotlin - kotlin-stdlib - - - org.junit.jupiter - junit-jupiter - test - - - org.assertj - assertj-core - test - - - com.tngtech.archunit - archunit-junit5 - test - - - - - src/main/kotlin - src/test/kotlin - - - org.jetbrains.kotlin - kotlin-maven-plugin - - ${maven.compiler.release} - - -Werror - - - - compile - compile - compile - - - test-compile - test-compile - test-compile - - - - - - org.pitest - pitest-maven - - - - kotlin.jvm.internal.Intrinsics - kotlin.jdk7.AutoCloseableKt - - - - - - diff --git a/emf/tests/parity/src/main/kotlin/dev/jorisjonkers/deploykit/emf/parity/Ledgers.kt b/emf/tests/parity/src/main/kotlin/dev/jorisjonkers/deploykit/emf/parity/Ledgers.kt deleted file mode 100644 index 40941d719..000000000 --- a/emf/tests/parity/src/main/kotlin/dev/jorisjonkers/deploykit/emf/parity/Ledgers.kt +++ /dev/null @@ -1,189 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.parity - -import java.io.IOException -import java.io.UncheckedIOException -import java.nio.file.Files -import java.nio.file.Path -import kotlin.streams.asSequence - -/** - * The two ledgers the model-driven build holds itself to, checked against the repository they - * describe. Each check returns every violation it finds, never only the first. - */ -object Ledgers { - private val REQUIREMENT_ROW = Regex("""^\|\s*(REQ-\d{3})\s*\|.*\[[^]]*]\(\.\./\.\./([^)]+)\)\s*\|\s*$""") - private val WITNESS_ROW = Regex("""^\|\s*(REQ-\d{3})\s*\|\s*`([A-Za-z0-9_]+)#([^`]+)`\s*\|\s*$""") - private val PENDING_ROW = Regex("""^\|\s*(REQ-\d{3})\s*\|\s*([^|]+?)\s*\|\s*(#\d+)\s*\|\s*$""") - private val RULE_ROW = Regex("""^\|\s*(EMF-\d{3})\s*\|\s*[^|]+\|\s*`([^`]+)`\s*\|\s*`([^`]+)`\s*\|\s*$""") - private val STATED = Regex("""holds \*\*(\d+)\*\*""") - private val STATED_PENDING = Regex("""\*\*(\d+)\*\* pending""") - - /** - * The witness list: every behaviour ledger row proved by a test under `test/model/` names a JUnit - * test here, and every witness names a real model row and a real test method. The ledger's rows - * live one file per area under `docs/requirements/`, each linking its test from two levels down, - * and every area file is read. - * - * A model row this implementation cannot prove yet is listed as **pending** with the ticket that - * lands it, the same state the rule ledger already carries for a rule not enforced yet - * (docs/adr/emf/0114). A pending row satisfies the witness check and nothing else: it still has - * to name a real model row, it may not also be witnessed, and its count is stated separately, so - * a behaviour cannot leave the gate quietly. - */ - fun checkWitnesses(repository: Path): List { - val errors = mutableListOf() - val modelRows = - areas(repository.resolve("docs/requirements")) - .flatMap { lines(it) } - .mapNotNull { REQUIREMENT_ROW.matchEntire(it) } - .filter { it.groupValues[2].startsWith("test/model/") } - .map { it.groupValues[1] } - .toSet() - val text = lines(repository.resolve("emf/docs/witnesses.md")) - val listed = linkedMapOf() - for (line in text) { - val row = WITNESS_ROW.matchEntire(line) ?: continue - val (id, type, method) = row.destructured - if (listed.put(id, "$type#$method") != null) { - errors.add("$id: listed twice") - } - if (id !in modelRows) { - errors.add("$id: names no model behaviour row in docs/requirements/") - } - if (!testMethodExists(repository.resolve("emf"), type, method)) { - errors.add("$id: names $type#$method, which is not a test in emf/") - } - } - val pending = linkedMapOf() - for (line in text) { - val row = PENDING_ROW.matchEntire(line) ?: continue - val (id, _, ticket) = row.destructured - if (pending.put(id, ticket) != null) { - errors.add("$id: pending twice") - } - if (id !in modelRows) { - errors.add("$id: is pending and names no model behaviour row in docs/requirements/") - } - if (id in listed) { - errors.add("$id: is both witnessed and pending") - } - } - for (id in modelRows) { - if (id !in listed && id !in pending) { - errors.add("$id: is a model behaviour with no witness in emf/docs/witnesses.md") - } - } - checkStatedCount(text, listed.size, "emf/docs/witnesses.md", errors) - checkStatedPending(text, pending.size, errors) - return errors - } - - /** - * The rule ledger: every row names a file under `emf/` that exists and still contains the witness - * literal that enforces the rule. - */ - fun checkRules(repository: Path): List { - val errors = mutableListOf() - val emf = repository.resolve("emf") - val text = lines(emf.resolve("docs/rules.md")) - val ids = mutableSetOf() - var rows = 0 - for (line in text) { - val row = RULE_ROW.matchEntire(line) ?: continue - rows++ - val (id, named, literal) = row.destructured - if (!ids.add(id)) { - errors.add("$id: listed twice") - } - val enforcer = emf.resolve(named).normalize() - if (!enforcer.startsWith(emf) || !Files.isRegularFile(enforcer)) { - errors.add("$id: names enforcer $named, which is not a file in emf/") - } else if (!read(enforcer).contains(literal)) { - errors.add("$id: $named no longer contains `$literal`") - } - } - checkStatedCount(text, rows, "emf/docs/rules.md", errors) - return errors - } - - /** The pending count is stated beside the witness count, so neither can drift unnoticed. */ - private fun checkStatedPending( - text: List, - rows: Int, - errors: MutableList, - ) { - val stated = STATED_PENDING.find(text.joinToString("\n")) - if (stated == null) { - if (rows != 0) { - errors.add("emf/docs/witnesses.md: states no pending count but holds $rows") - } - } else if (stated.groupValues[1] != rows.toString()) { - errors.add("emf/docs/witnesses.md: states ${stated.groupValues[1]} pending but holds $rows") - } - } - - private fun checkStatedCount( - text: List, - rows: Int, - file: String, - errors: MutableList, - ) { - val stated = STATED.find(text.joinToString("\n")) - if (stated == null) { - errors.add("$file: states no row count") - } else if (stated.groupValues[1] != rows.toString()) { - errors.add("$file: states ${stated.groupValues[1]} rows but holds $rows") - } - } - - /** - * Whether `className` declares `method` as a test somewhere under `emf/`. A witness is a JUnit - * test in whichever language its module is written, so both tiers are searched and both - * declarations are read (docs/adr/emf/0114). - */ - private fun testMethodExists( - emf: Path, - className: String, - method: String, - ): Boolean = - Files.walk(emf).use { files -> - files - .asSequence() - .filter { it.toString().contains("src/test/") } - .filter { it.fileName.toString() in setOf("$className.java", "$className.kt") } - .any { declaresTest(read(it), method) } - } - - private fun declaresTest( - source: String, - method: String, - ): Boolean { - val name = Regex.escape(method) - return Regex("""\bvoid $name\s*\(""").containsMatchIn(source) || - Regex("""\bfun `$name`\s*\(""").containsMatchIn(source) - } - - /** The behaviour ledger's area files, in name order so a report reads the same every run. */ - private fun areas(directory: Path): List = - try { - Files.list(directory).use { files -> - files - .asSequence() - .filter { it.fileName.toString().endsWith(".md") } - .sorted() - .toList() - } - } catch (e: IOException) { - throw UncheckedIOException(e) - } - - private fun lines(file: Path): List = read(file).lines() - - /** A read whose failure is a broken repository, reported rather than declared. */ - private fun read(file: Path): String = - try { - Files.readString(file) - } catch (e: IOException) { - throw UncheckedIOException(e) - } -} diff --git a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/cli/fixture/ComparingInMain.kt b/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/cli/fixture/ComparingInMain.kt deleted file mode 100644 index 6f484415f..000000000 --- a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/cli/fixture/ComparingInMain.kt +++ /dev/null @@ -1,12 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli.fixture - -import org.eclipse.emf.compare.fixture.StandIn - -/** - * The fixture EMF-021 is shown firing on: a class in a module's package reaching into EMF Compare's, - * as a class the bundle tier ships would if it compared models itself. It is never called; it exists - * to be imported. - */ -object ComparingInMain { - fun compare(): String = StandIn.name() -} diff --git a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/cli/fixture/UpperReachingDown.kt b/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/cli/fixture/UpperReachingDown.kt deleted file mode 100644 index 320882db3..000000000 --- a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/cli/fixture/UpperReachingDown.kt +++ /dev/null @@ -1,14 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.cli.fixture - -import dev.jorisjonkers.deploykit.emf.metamodel.fixture.LowerReachingUp - -/** - * The other half of the fixture EMF-010 and EMF-011 are shown firing on: a class in the highest - * module of the table reaching down, which the direction allows, and which closes the cycle the - * upward reach in [LowerReachingUp] opens. It is never called; it exists to be imported. - */ -object UpperReachingDown { - fun name(): String = "fixture" - - fun down(): String = LowerReachingUp.up() -} diff --git a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/metamodel/fixture/LowerReachingUp.kt b/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/metamodel/fixture/LowerReachingUp.kt deleted file mode 100644 index 975119160..000000000 --- a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/metamodel/fixture/LowerReachingUp.kt +++ /dev/null @@ -1,14 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.metamodel.fixture - -import dev.jorisjonkers.deploykit.emf.cli.fixture.UpperReachingDown - -/** - * The fixture EMF-010 and EMF-011 are shown firing on: a class in the lowest module of the table - * reaching up into the highest, which the module direction forbids and which closes a cycle with - * [UpperReachingDown] - * (docs/adr/architecture/0066-every-enforced-rule-has-an-id-a-row-and-a-fixture.md). It is never - * called; it exists to be imported. - */ -object LowerReachingUp { - fun up(): String = UpperReachingDown.name() -} diff --git a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ArchitectureTest.kt b/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ArchitectureTest.kt deleted file mode 100644 index 25899b791..000000000 --- a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ArchitectureTest.kt +++ /dev/null @@ -1,84 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.parity - -import com.tngtech.archunit.core.domain.JavaClasses -import com.tngtech.archunit.core.importer.ClassFileImporter -import com.tngtech.archunit.core.importer.ImportOption -import com.tngtech.archunit.junit.AnalyzeClasses -import com.tngtech.archunit.junit.ArchTest -import com.tngtech.archunit.lang.ArchRule -import dev.jorisjonkers.deploykit.emf.cli.fixture.ComparingInMain -import dev.jorisjonkers.deploykit.emf.cli.fixture.UpperReachingDown -import dev.jorisjonkers.deploykit.emf.metamodel.fixture.LowerReachingUp -import org.assertj.core.api.Assertions.assertThat -import org.assertj.core.api.Assertions.assertThatThrownBy -import org.junit.jupiter.api.Test - -/** - * The module direction docs/architecture.md#modules states: a module may depend on the modules above - * it in that table and on nothing below. A layer with no classes yet is allowed to be empty; the rule - * holds for it the moment its first class lands. - * - * This suite depends on no module, so it reads the class directories the build wrote by path and - * asserts every module the build wrote arrived: an empty import would leave every layer optional and - * let both rules pass while proving nothing - * (docs/adr/emf/0080-parity-crosses-the-cli-file-interface.md). Each rule is shown firing on a - * fixture that breaks it, beside the run that holds the tree to it. - */ -@AnalyzeClasses( - locations = [ModuleRules.BuiltModules::class], - importOptions = [ImportOption.DoNotIncludeTests::class], -) -class ArchitectureTest { - @ArchTest - fun `every module the build wrote is imported`(classes: JavaClasses) { - assertThat(ModuleRules.modulesMissingFrom(classes)).isEmpty() - } - - @Test - fun `the direction fails on a module reaching up`() { - assertThatThrownBy { ModuleRules.layered().check(REACHING_UP) } - .isInstanceOf(AssertionError::class.java) - .hasMessageContaining("metamodel") - } - - @Test - fun `the cycle rule fails on two modules reaching each other`() { - assertThatThrownBy { ModuleRules.acyclic().check(REACHING_UP) } - .isInstanceOf(AssertionError::class.java) - .hasMessageContaining("Cycle") - } - - @Test - fun `the comparison rule fails on a module class reaching EMF Compare`() { - assertThatThrownBy { ModuleRules.testsAloneCompare().check(COMPARING) } - .isInstanceOf(AssertionError::class.java) - .hasMessageContaining("org.eclipse.emf.compare") - } - - @Test - fun `the import guard fails on an import holding no module`() { - assertThat(ModuleRules.modulesMissingFrom(ClassFileImporter().importClasses())) - .contains("metamodel", "syntax", "cli") - } - - companion object { - @ArchTest - @JvmField - val MODULES_DEPEND_ONLY_ON_MODULES_ABOVE_THEM: ArchRule = ModuleRules.layered() - - @ArchTest - @JvmField - val MODULES_HAVE_NO_CYCLES: ArchRule = ModuleRules.acyclic() - - @ArchTest - @JvmField - val NO_MODULE_DEPENDS_ON_EMF_COMPARE: ArchRule = ModuleRules.testsAloneCompare() - - /** A metamodel class reaching up into cli, and the cli class reaching back down into it. */ - private val REACHING_UP: JavaClasses = - ClassFileImporter().importClasses(LowerReachingUp::class.java, UpperReachingDown::class.java) - - /** A cli class reaching into EMF Compare's package. */ - private val COMPARING: JavaClasses = ClassFileImporter().importClasses(ComparingInMain::class.java) - } -} diff --git a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/LedgersTest.kt b/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/LedgersTest.kt deleted file mode 100644 index fb6431e7c..000000000 --- a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/LedgersTest.kt +++ /dev/null @@ -1,302 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.parity - -import org.assertj.core.api.Assertions.assertThat -import org.assertj.core.api.Assertions.assertThatThrownBy -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.io.TempDir -import java.io.UncheckedIOException -import java.nio.file.Files -import java.nio.file.Path - -class LedgersTest { - /** The committed ledgers, checked against this repository. */ - @Test - fun `the committed ledgers hold`() { - val repository = repository() - - assertThat(Ledgers.checkWitnesses(repository)).isEmpty() - assertThat(Ledgers.checkRules(repository)).isEmpty() - } - - @Test - fun `a model behaviour without a witness fails`( - @TempDir root: Path, - ) { - write(root, AREA, "$MODEL_ROW\n$GATE_ROW") - write(root, "emf/docs/witnesses.md", "This list holds **0** witnesses.\n") - - assertThat(Ledgers.checkWitnesses(root)) - .containsExactly("$MODEL: is a model behaviour with no witness in emf/docs/witnesses.md") - } - - @Test - fun `a witness must name a model row and a real test once`( - @TempDir root: Path, - ) { - write(root, AREA, "$MODEL_ROW\n$GATE_ROW") - write(root, "emf/tests/parity/src/test/kotlin/x/ParseTest.kt", "class ParseTest { fun `parses`() {} }") - write(root, "emf/tests/parity/src/main/kotlin/x/ParseTest.kt", "class ParseTest { fun `missing`() {} }") - write( - root, - "emf/docs/witnesses.md", - listOf( - "This list holds **4** witnesses.", - "| $MODEL | `ParseTest#parses` |", - "| $MODEL | `ParseTest#parses` |", - "| $GATE | `ParseTest#parses` |", - "| $UNKNOWN | `ParseTest#missing` |", - ).joinToString("\n"), - ) - - assertThat(Ledgers.checkWitnesses(root)) - .containsExactly( - "$MODEL: listed twice", - "$GATE: names no model behaviour row in docs/requirements/", - "$UNKNOWN: names no model behaviour row in docs/requirements/", - "$UNKNOWN: names ParseTest#missing, which is not a test in emf/", - "emf/docs/witnesses.md: states 4 rows but holds 3", - ) - } - - @Test - fun `a model behaviour listed as pending needs no witness`( - @TempDir root: Path, - ) { - write(root, AREA, "$MODEL_ROW\n$GATE_ROW") - write( - root, - "emf/docs/witnesses.md", - listOf( - "This list holds **0** witnesses, and **1** pending.", - "| $MODEL | nothing here reads it yet | #87 |", - ).joinToString("\n"), - ) - - assertThat(Ledgers.checkWitnesses(root)).isEmpty() - } - - @Test - fun `a row that is both witnessed and pending fails`( - @TempDir root: Path, - ) { - write(root, AREA, MODEL_ROW) - write(root, "emf/tests/parity/src/test/kotlin/x/ParseTest.kt", "class ParseTest { fun `parses`() {} }") - write( - root, - "emf/docs/witnesses.md", - listOf( - "This list holds **1** witnesses, and **1** pending.", - "| $MODEL | `ParseTest#parses` |", - "| $MODEL | also pending | #87 |", - ).joinToString("\n"), - ) - - assertThat(Ledgers.checkWitnesses(root)).containsExactly("$MODEL: is both witnessed and pending") - } - - @Test - fun `a row pending twice fails`( - @TempDir root: Path, - ) { - write(root, AREA, MODEL_ROW) - write( - root, - "emf/docs/witnesses.md", - listOf( - // One pending id, listed twice: the count is of ids, the way the - // witness count is, so the duplicate is the only complaint. - "This list holds **0** witnesses, and **1** pending.", - "| $MODEL | not yet | #87 |", - "| $MODEL | still not yet | #87 |", - ).joinToString("\n"), - ) - - assertThat(Ledgers.checkWitnesses(root)).containsExactly("$MODEL: pending twice") - } - - @Test - fun `a pending row naming no model row fails, and the real row stays owed`( - @TempDir root: Path, - ) { - write(root, AREA, MODEL_ROW) - write( - root, - "emf/docs/witnesses.md", - listOf( - "This list holds **0** witnesses, and **1** pending.", - "| $UNKNOWN | not a model row | #87 |", - ).joinToString("\n"), - ) - - assertThat(Ledgers.checkWitnesses(root)) - .containsExactly( - "$UNKNOWN: is pending and names no model behaviour row in docs/requirements/", - "$MODEL: is a model behaviour with no witness in emf/docs/witnesses.md", - ) - } - - @Test - fun `a pending count that drifts fails`( - @TempDir root: Path, - ) { - write(root, AREA, MODEL_ROW) - write( - root, - "emf/docs/witnesses.md", - listOf( - "This list holds **0** witnesses, and **2** pending.", - "| $MODEL | not yet | #87 |", - ).joinToString("\n"), - ) - - assertThat(Ledgers.checkWitnesses(root)) - .containsExactly("emf/docs/witnesses.md: states 2 pending but holds 1") - } - - @Test - fun `a pending row with no stated pending count fails`( - @TempDir root: Path, - ) { - write(root, AREA, MODEL_ROW) - write( - root, - "emf/docs/witnesses.md", - "This list holds **0** witnesses.\n| $MODEL | not yet | #87 |", - ) - - assertThat(Ledgers.checkWitnesses(root)) - .containsExactly("emf/docs/witnesses.md: states no pending count but holds 1") - } - - /** A Java witness is read the same way, so the rule is the module's language and not the suite's. */ - @Test - fun `a witness naming a java test in a bundle is found`( - @TempDir root: Path, - ) { - write(root, AREA, MODEL_ROW) - write(root, "emf/bundles/cli/src/test/java/x/ParseTest.java", "class ParseTest { void parses() {} }") - write( - root, - "emf/docs/witnesses.md", - "This list holds **1** witnesses.\n| $MODEL | `ParseTest#parses` |", - ) - - assertThat(Ledgers.checkWitnesses(root)).isEmpty() - } - - /** - * The ledger is one file per area, so a model row in any of them is owed a witness, and the - * index page, which holds no rows, is not read as one. - */ - @Test - fun `a model row in every area file is read and the index page is not`( - @TempDir root: Path, - ) { - val second = "REQ-" + "021" - write(root, AREA, GATE_ROW) - write( - root, - "docs/requirements/processes.md", - "| $second | runs a pod | [test/model/pod.test.ts](../../test/model/pod.test.ts) |", - ) - write(root, "docs/requirements/notes.txt", MODEL_ROW) - write(root, "docs/requirements.md", "| $UNKNOWN | old | [test/model/x.test.ts](../test/model/x.test.ts) |") - write(root, "emf/docs/witnesses.md", "This list holds **0** witnesses.\n") - - assertThat(Ledgers.checkWitnesses(root)) - .containsExactly("$second: is a model behaviour with no witness in emf/docs/witnesses.md") - } - - @Test - fun `a witness list stating no count fails`( - @TempDir root: Path, - ) { - write(root, AREA, GATE_ROW) - write(root, "emf/docs/witnesses.md", "No count here.\n") - - assertThat(Ledgers.checkWitnesses(root)).containsExactly("emf/docs/witnesses.md: states no row count") - } - - @Test - fun `a rule whose enforcer no longer holds its witness fails`( - @TempDir root: Path, - ) { - write(root, "emf/pom.xml", "-Werror") - write( - root, - "emf/docs/rules.md", - listOf( - "This ledger holds **4** rules.", - "| EMF-001 | warnings fail | `pom.xml` | `-Werror` |", - "| EMF-001 | lint all | `pom.xml` | `-Xlint:all` |", - "| EMF-003 | outside | `../docs/rules.md` | `rules` |", - "| EMF-004 | missing | `gone.xml` | `x` |", - ).joinToString("\n"), - ) - - assertThat(Ledgers.checkRules(root)) - .containsExactly( - "EMF-001: listed twice", - "EMF-001: pom.xml no longer contains `-Xlint:all`", - "EMF-003: names enforcer ../docs/rules.md, which is not a file in emf/", - "EMF-004: names enforcer gone.xml, which is not a file in emf/", - ) - } - - @Test - fun `a rule ledger whose count drifts fails`( - @TempDir root: Path, - ) { - write(root, "emf/pom.xml", "-Werror") - write( - root, - "emf/docs/rules.md", - "This ledger holds **2** rules.\n| EMF-001 | warnings fail | `pom.xml` | `-Werror` |", - ) - - assertThat(Ledgers.checkRules(root)).containsExactly("emf/docs/rules.md: states 2 rows but holds 1") - } - - @Test - fun `a stated count too large for an int is reported not thrown`( - @TempDir root: Path, - ) { - write(root, AREA, GATE_ROW) - write(root, "emf/docs/witnesses.md", "This list holds **99999999999** witnesses.\n") - - assertThat(Ledgers.checkWitnesses(root)) - .containsExactly("emf/docs/witnesses.md: states 99999999999 rows but holds 0") - } - - @Test - fun `a ledger that cannot be read fails loudly`( - @TempDir root: Path, - ) { - assertThatThrownBy { Ledgers.checkRules(root) }.isInstanceOf(UncheckedIOException::class.java) - assertThatThrownBy { Ledgers.checkWitnesses(root) }.isInstanceOf(UncheckedIOException::class.java) - } - - companion object { - // Fixture ids are assembled so the root requirements lint, which reads every tracked file for - // behaviour ledger citations, does not mistake them for citations of rows that do not exist. - private const val MODEL = "REQ-" + "020" - private const val GATE = "REQ-" + "001" - private const val UNKNOWN = "REQ-" + "099" - - private const val MODEL_ROW = - "| $MODEL | parses a project | [test/model/parse.test.ts](../../test/model/parse.test.ts) |" - private const val GATE_ROW = - "| $GATE | lints ADRs | [test/adr-contract.test.ts](../../test/adr-contract.test.ts) |" - private const val AREA = "docs/requirements/intent.md" - - private fun write( - root: Path, - relative: String, - content: String, - ) { - val file = root.resolve(relative) - Files.createDirectories(file.parent) - Files.writeString(file, content) - } - } -} diff --git a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ModuleRules.kt b/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ModuleRules.kt deleted file mode 100644 index bfa096c1a..000000000 --- a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ModuleRules.kt +++ /dev/null @@ -1,102 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.parity - -import com.tngtech.archunit.core.domain.JavaClasses -import com.tngtech.archunit.core.importer.Location -import com.tngtech.archunit.junit.LocationProvider -import com.tngtech.archunit.lang.ArchRule -import com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses -import com.tngtech.archunit.library.Architectures.layeredArchitecture -import com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices -import java.nio.file.Files -import java.nio.file.Path -import kotlin.streams.asSequence - -/** - * The module rules of docs/architecture.md#modules, and the classes they are held over, kept apart - * from the suite that runs them so the same rule can be run over a fixture that breaks it - * (docs/adr/architecture/0066-every-enforced-rule-has-an-id-a-row-and-a-fixture.md). - */ -object ModuleRules { - const val ROOT = "dev.jorisjonkers.deploykit.emf." - - /** The bundle tier, lowest first: a module may depend on the modules above it and on nothing below. */ - val MODULES = listOf("metamodel", "syntax", "resolve", "render", "cli") - - /** EMF-010: a module depends only on the modules above it in the architecture's module table. */ - fun layered(): ArchRule = - layeredArchitecture() - .consideringOnlyDependenciesInLayers() - .withOptionalLayers(true) - .layer("metamodel") - .definedBy(ROOT + "metamodel..") - .layer("syntax") - .definedBy(ROOT + "syntax..") - .layer("resolve") - .definedBy(ROOT + "resolve..") - .layer("render") - .definedBy(ROOT + "render..") - .layer("cli") - .definedBy(ROOT + "cli..") - .whereLayer("cli") - .mayNotBeAccessedByAnyLayer() - .whereLayer("render") - .mayOnlyBeAccessedByLayers("cli") - .whereLayer("resolve") - .mayOnlyBeAccessedByLayers("render", "cli") - .whereLayer("syntax") - .mayOnlyBeAccessedByLayers("resolve", "render", "cli") - .whereLayer("metamodel") - .mayOnlyBeAccessedByLayers("syntax", "resolve", "render", "cli") - - /** EMF-011: no dependency cycle between modules. */ - fun acyclic(): ArchRule = slices().matching(ROOT + "(*)..").should().beFreeOfCycles() - - /** - * EMF-021: no class a module ships depends on EMF Compare. It is the tests' model comparison - * (docs/adr/emf/0152-emf-compare-decides-and-explains-every-model-comparison.md), on the cli - * bundle's classpath through `additional.bundles` and never named in a manifest, so a shipped - * class could reach it at compile time and fail only where the bundle runs without it. - */ - fun testsAloneCompare(): ArchRule = - noClasses() - .that() - .resideInAPackage(ROOT.removeSuffix(".") + "..") - .should() - .dependOnClassesThat() - .resideInAPackage("org.eclipse.emf.compare..") - - /** - * EMF-017: the modules the build wrote classes for that are not in `classes`. The two rules above - * hold over optional layers, so an import that reached no module would excuse every layer and let - * both pass while proving nothing. This suite depends on no module, which is exactly how an empty - * import happens, so the emptiness is the thing that has to fail. A module with no class of its - * own yet is not missing: its layer is empty in the tree, not in the import. - */ - fun modulesMissingFrom(classes: JavaClasses): List = - modulesTheBuildWrote().filter { module -> - classes.none { it.packageName.startsWith(ROOT + module) } - } - - /** The modules whose class directory holds a class: what an import of those directories carries. */ - fun modulesTheBuildWrote(): List = MODULES.filter { holdsAClass(classesOf(it)) } - - private fun holdsAClass(directory: Path): Boolean = - Files.isDirectory(directory) && - Files.walk(directory).use { tree -> - tree.asSequence().any { it.fileName.toString().endsWith(".class") } - } - - /** Where the build left a module's compiled classes. */ - fun classesOf(module: String): Path = bundles().resolve(module).resolve("target").resolve("classes") - - /** Where the bundle tier's modules sit. */ - fun bundles(): Path = repository().resolve("emf").resolve("bundles") - - /** - * The class directories the build wrote, by path. The suite requires no module, so nothing puts - * their classes on its classpath; the reactor's own output is what it reads instead. - */ - class BuiltModules : LocationProvider { - override fun get(testClass: Class<*>): Set = MODULES.map { Location.of(classesOf(it)) }.toSet() - } -} diff --git a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ParityTest.kt b/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ParityTest.kt deleted file mode 100644 index 4fdebbac8..000000000 --- a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/ParityTest.kt +++ /dev/null @@ -1,214 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.parity - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import org.junit.jupiter.params.ParameterizedTest -import org.junit.jupiter.params.provider.MethodSource -import java.nio.file.Files -import java.nio.file.Path -import kotlin.streams.asSequence - -/** - * Every case under `spec/v1/examples/` that carries an oracle, decided from what a run of the - * pipeline left behind and compared with the committed file byte for byte - * (docs/architecture.md#the-parity-contract). - * - * The suite calls nothing and holds no EMF type - * (docs/adr/emf/0080-parity-crosses-the-cli-file-interface.md): the pipeline's interface here is - * arguments and input files in, an exit code and output files out. A file a case needs and the run - * did not write fails as a missing file, never as a skipped case. - */ -class ParityTest { - @ParameterizedTest(name = "{0}") - @MethodSource("casesWithAnIntentOracle") - fun `the parsed intent equals the committed oracle`(directory: Path) { - val written = output(PIPELINE_OUTPUT, directory) - - assertThat(left(written, EXIT)).isEqualTo("0") - assertThat(left(written, INTENT)).isEqualTo(read(directory.resolve("expected").resolve(INTENT))) - } - - @ParameterizedTest(name = "{0}") - @MethodSource("casesWithAnEffectiveOracle") - fun `the lowered intent equals the committed effective oracle`(directory: Path) { - val written = output(PIPELINE_OUTPUT, directory) - - assertThat(left(written, EFFECTIVE)).isEqualTo(read(directory.resolve("expected").resolve(EFFECTIVE))) - } - - @ParameterizedTest(name = "{0}") - @MethodSource("refusalsWithADiagnosticsOracle") - fun `a refused document equals its committed diagnostics`(oracle: Path) { - val stem = oracle.fileName.toString().removeSuffix(".$DIAGNOSTICS") - val written = output(PIPELINE_OUTPUT, oracle.resolveSibling(stem)) - - assertThat(left(written, EXIT)).isEqualTo("1") - assertThat(left(written, DIAGNOSTICS)).isEqualTo(read(oracle)) - } - - @ParameterizedTest(name = "{0}") - @MethodSource("negativeFixtures") - fun `a negative fixture equals its committed diagnostics in either order`(oracle: Path) { - val stem = oracle.fileName.toString().removeSuffix(".$DIAGNOSTICS") - val written = output(PIPELINE_OUTPUT, oracle.resolveSibling(stem)) - - assertThat(left(written, EXIT)).isEqualTo("1") - assertThat(left(written, DIAGNOSTICS)).isEqualTo(read(oracle)) - assertThat(left(written, REVERSED)).isEqualTo(read(oracle)) - } - - @ParameterizedTest(name = "{0}") - @MethodSource("casesTheResolutionReaches") - fun `the resolved dependency edges equal the committed oracle`(directory: Path) { - val written = output(PIPELINE_OUTPUT, directory) - - assertThat(left(written, DEPENDENCIES)).isEqualTo(read(directory.resolve("expected").resolve(DEPENDENCIES))) - } - - @Test - fun `the composed union renders to the committed trees byte for byte`() { - val written = repository().resolve(PIPELINE_OUTPUT).resolve(RENDERED) - val committed = RENDERED_CASES.map { examples().resolve(it).resolve(RENDERED) } - val expected = committed.flatMap { tree -> filesUnder(tree).map { it to tree.resolve(it) } }.toMap() - - assertThat(filesUnder(written)).containsExactlyElementsOf(expected.keys.sorted()) - expected.forEach { (file, oracle) -> - assertThat(left(written, file)).`as`(file).isEqualTo(read(oracle)) - } - } - - @Test - fun `every case the resolution reaches carries a dependencies oracle`() { - assertThat(casesTheResolutionReaches()).allSatisfy { directory -> - assertThat(directory.resolve("expected").resolve(DEPENDENCIES)).exists() - } - } - - @Test - fun `the metamodels structure equals the committed descriptor`() { - val written = repository().resolve(METAMODEL_OUTPUT) - - assertThat(left(written, DESCRIPTOR)).isEqualTo(read(examples().resolve("expected").resolve(DESCRIPTOR))) - } - - @Test - fun `one changed field no longer matches the oracle`() { - val directory = casesWithAnIntentOracle().first() - val written = left(output(PIPELINE_OUTPUT, directory), INTENT) - val changed = written.replace("\"owner\":\"joris\"", "\"owner\":\"someone-else\"") - - assertThat(changed).isNotEqualTo(written) - assertThat(changed).isNotEqualTo(read(directory.resolve("expected").resolve(INTENT))) - } - - companion object { - /** Where a run of the pipeline leaves the parsed intent and the diagnostics, under `emf/`. */ - private const val PIPELINE_OUTPUT = "emf/bundles/cli/target/parity" - - /** Where a run of the build leaves the source metamodel's descriptor, under `emf/`. */ - private const val METAMODEL_OUTPUT = "emf/bundles/metamodel/target/parity" - - private const val INTENT = "intent.json" - private const val EFFECTIVE = "effective.json" - private const val DIAGNOSTICS = "diagnostics.json" - private const val REVERSED = "diagnostics.reversed.json" - private const val DESCRIPTOR = "descriptor.json" - private const val DEPENDENCIES = "dependencies.json" - - /** - * The cases the QVT-Operational resolution reaches: every case the pipeline resolves. `knowledge` - * carries a dependencies oracle but is resolved by neither implementation, and retires with the - * project it models (JorisJonkers-dev/deploy-kit#272). - */ - private val RESOLVED = - listOf("auth", "data", "delivery", "edge", "knowledge-platform", "minimal", "observability", "secrets") - private const val EXIT = "exit" - private const val RENDERED = "rendered" - - /** - * The cases whose committed rendered trees the composed union writes between them: minimal's - * and data's own, and the platform's estate-scoped share every render holds. - */ - private val RENDERED_CASES = listOf("minimal", "data", "platform") - - /** Every file under `root`, by its path below it, sorted; a tree's README is no rendered file. */ - private fun filesUnder(root: Path): List = - Files.walk(root).use { tree -> - tree - .asSequence() - .filter { Files.isRegularFile(it) && it.fileName.toString() != "README.md" } - .map { root.relativize(it).toString() } - .sorted() - .toList() - } - - @JvmStatic - fun casesWithAnIntentOracle(): List = - Files.walk(examples()).use { tree -> - tree - .asSequence() - .filter { it.endsWith("expected/$INTENT") } - .map { it.parent.parent } - .sorted() - .toList() - } - - @JvmStatic - fun casesTheResolutionReaches(): List = RESOLVED.map { examples().resolve(it) } - - @JvmStatic - fun casesWithAnEffectiveOracle(): List = - Files.walk(examples()).use { tree -> - tree - .asSequence() - .filter { it.endsWith("expected/$EFFECTIVE") } - .map { it.parent.parent } - .sorted() - .toList() - } - - @JvmStatic - fun negativeFixtures(): List = - Files.list(examples().resolve("negative")).use { files -> - files - .asSequence() - .filter { it.fileName.toString().endsWith(".$DIAGNOSTICS") } - .sorted() - .toList() - } - - @JvmStatic - fun refusalsWithADiagnosticsOracle(): List = - Files.list(examples().resolve("refusals")).use { files -> - files - .asSequence() - .filter { it.fileName.toString().endsWith(".$DIAGNOSTICS") } - .sorted() - .toList() - } - - /** Where the run left a case's files: the output tree mirrors the example tree, case for case. */ - private fun output( - root: String, - directory: Path, - ): Path = repository().resolve(root).resolve(examples().relativize(directory)) - - /** - * A file the run owes, read. Its absence is the pipeline failing to write what it owes, which - * is a different thing from a case with no committed oracle, and is reported as the missing - * file. - */ - private fun left( - directory: Path, - name: String, - ): String { - val file = directory.resolve(name) - assertThat(file).`as`("%s: a run of the pipeline leaves this file behind, and did not", file).exists() - return read(file) - } - - private fun read(path: Path): String = Files.readString(path, Charsets.UTF_8) - - private fun examples(): Path = repository().resolve("spec/v1/examples") - } -} diff --git a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/Repository.kt b/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/Repository.kt deleted file mode 100644 index 4a7e06f19..000000000 --- a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/Repository.kt +++ /dev/null @@ -1,13 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.parity - -import java.nio.file.Files -import java.nio.file.Path - -/** The repository this suite runs inside, found from its own working directory. */ -fun repository(): Path { - var dir = Path.of("").toAbsolutePath() - while (!Files.isRegularFile(dir.resolve("emf/pom.xml"))) { - dir = dir.parent - } - return dir -} diff --git a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/TargetPlatformTest.kt b/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/TargetPlatformTest.kt deleted file mode 100644 index 68ee133ba..000000000 --- a/emf/tests/parity/src/test/kotlin/dev/jorisjonkers/deploykit/emf/parity/TargetPlatformTest.kt +++ /dev/null @@ -1,76 +0,0 @@ -package dev.jorisjonkers.deploykit.emf.parity - -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test -import org.w3c.dom.Element -import java.nio.file.Files -import java.nio.file.Path -import javax.xml.parsers.DocumentBuilderFactory - -/** - * The target platform resolves from one dated build of a simultaneous release, and names every unit - * at an exact version, so a clean runner cache resolves the same bundles as the last green build - * (docs/adr/emf/0108). - */ -class TargetPlatformTest { - @Test - fun `every unit is pinned`() { - assertThat(problems(repository().resolve("emf/emf.target"))).`as`(EVERY_UNIT_IS_PINNED).isEmpty() - } - - @Test - fun `an unpinned unit or an undated repository is a problem`() { - val target = Files.createTempFile("emf", ".target") - Files.writeString( - target, - """ - - - - - - - """.trimIndent(), - ) - - assertThat(problems(target)) - .containsExactly( - "repository https://download.eclipse.org/releases/latest/ is not a dated release build", - "unit b is not pinned: 0.0.0", - "unit c is not pinned: [1.0.0,2.0.0)", - ) - } - - companion object { - const val EVERY_UNIT_IS_PINNED = "every unit names an exact version from one dated repository" - - private val DATED_RELEASE = Regex("""https://download\.eclipse\.org/releases/\d{4}-\d{2}/\d{12}/""") - private val EXACT_VERSION = Regex("""\d+\.\d+\.\d+(\.[\w-]+)?""") - - private fun problems(target: Path): List { - val root = - DocumentBuilderFactory - .newInstance() - .newDocumentBuilder() - .parse(target.toFile()) - .documentElement - val problems = mutableListOf() - val repositories = root.getElementsByTagName("repository") - for (i in 0 until repositories.length) { - val location = (repositories.item(i) as Element).getAttribute("location") - if (!DATED_RELEASE.matches(location)) { - problems.add("repository $location is not a dated release build") - } - } - val units = root.getElementsByTagName("unit") - for (i in 0 until units.length) { - val unit = units.item(i) as Element - val version = unit.getAttribute("version") - if (!EXACT_VERSION.matches(version) || version == "0.0.0") { - problems.add("unit ${unit.getAttribute("id")} is not pinned: $version") - } - } - return problems - } - } -} diff --git a/emf/tests/parity/src/test/kotlin/org/eclipse/emf/compare/fixture/StandIn.kt b/emf/tests/parity/src/test/kotlin/org/eclipse/emf/compare/fixture/StandIn.kt deleted file mode 100644 index ddaff3147..000000000 --- a/emf/tests/parity/src/test/kotlin/org/eclipse/emf/compare/fixture/StandIn.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.eclipse.emf.compare.fixture - -/** - * A stand-in for a class of EMF Compare, which this suite has no classpath entry for: it sits in EMF - * Compare's package so the fixture EMF-021 is shown firing on can depend on it. It is never called; - * it exists to be imported. - */ -object StandIn { - fun name(): String = "stand-in" -} diff --git a/eslint.config.js b/eslint.config.js index 78f11cb8f..98875f4f1 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -19,8 +19,6 @@ export default defineConfig( "node_modules/**", "reports/**", ".stryker-tmp/**", - // Maven build output from the model-driven implementation under emf/. - "**/target/**", // What `deploy-kit generate identity` writes for a worked example, in an // application's language: an oracle, not this repository's source. "spec/v1/examples/**/generated/**", diff --git a/release-please-config.json b/release-please-config.json index 83969b8fe..6af214aca 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -6,7 +6,6 @@ "changelog-path": "CHANGELOG.md", "extra-files": ["src/cli/main.ts"], "include-component-in-tag": false, - "exclude-paths": ["emf"], "bump-minor-pre-major": true, "draft": false, "prerelease": false diff --git a/renovate.json b/renovate.json index a20b563bd..f70c12668 100644 --- a/renovate.json +++ b/renovate.json @@ -1,19 +1,4 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["github>JorisJonkers-dev/renovate-config"], - "packageRules": [ - { - "description": "The model-driven build under emf/ is deleted at its sunset (emf/docs/adr/emf/0107); its Maven and wrapper updates travel together.", - "matchManagers": ["maven", "maven-wrapper"], - "matchFileNames": ["emf/**"], - "groupName": "emf maven" - }, - { - "description": "Tycho 5.0.4 cannot collect its p2 dependencies under Maven 3.10.0 (Invalid Collect Request: null), so the wrapper under emf/ stays on 3.9.", - "matchManagers": ["maven-wrapper"], - "matchFileNames": ["emf/**"], - "matchPackageNames": ["org.apache.maven:apache-maven"], - "allowedVersions": "<3.10" - } - ] + "extends": ["github>JorisJonkers-dev/renovate-config"] } diff --git a/scripts/lib/change-buckets.ts b/scripts/lib/change-buckets.ts index e5b05b1cd..3f8586f56 100644 --- a/scripts/lib/change-buckets.ts +++ b/scripts/lib/change-buckets.ts @@ -63,44 +63,12 @@ const ROOT_TOOLING_FILES = new Set([ "renovate.json", ]); -// emf/ (docs/adr/emf/0107) is the coursework's own Java build: its own -// decision register, docs, source, tests and Maven/Tycho plumbing, deleted -// with the directory at the course's sunset. It gets the same nine buckets -// as the rest of the tree, checked in the same specific-before-general -// order, rather than a tenth bucket of its own. -const EMF_PRODUCTION_EXTENSIONS = [ - ".java", - ".xtext", - ".mwe2", - ".ecore", - ".ocl", - ".genmodel", - ".xmi", - ".mtl", - ".qvto", -]; - -function bucketOfEmfPath(rest: string): Bucket { - if (rest.startsWith("docs/adr/")) return "decision records"; - if (rest.startsWith("docs/") || rest === "README.md") return "documentation"; - if (rest.startsWith("scripts/")) return "tooling"; - if (rest.includes("/src/test/") || rest.endsWith("Test.java")) return "tests"; - if (EMF_PRODUCTION_EXTENSIONS.some((extension) => rest.endsWith(extension))) - return "production code"; - // Everything else is Maven/Tycho/PDE plumbing: pom.xml, mvnw, .mvn/, - // .java-version, plugin.xml, plugin.properties, build.properties, - // META-INF/MANIFEST.MF, the target platform, a launch configuration. - return "tooling"; -} - /** * The bucket `path` (relative to the repository root, forward-slashed) * belongs to, or `null` when no rule claims it. */ export function bucketOf(path: string): Bucket | null { if (path.startsWith(".github/")) return "CI"; - if (path.startsWith("emf/")) - return bucketOfEmfPath(path.slice("emf/".length)); // No generator exists yet (docs/adr/README.md, issue #21): nothing in the // tracked tree matches this today, and the rule is here so the first diff --git a/scripts/lint-adrs.ts b/scripts/lint-adrs.ts index d0fe63106..ce0a90393 100644 --- a/scripts/lint-adrs.ts +++ b/scripts/lint-adrs.ts @@ -38,9 +38,6 @@ const DOMAINS = [ domain: "architecture", normativeRoots: ["docs/architecture.md", "docs/architecture-rules.md"], }, - // The coursework implementation's register, linted with `emf` as the root, - // so its pointers name emf/docs/architecture.md. Deleted with emf/ (0107). - { domain: "emf", normativeRoots: ["docs/architecture.md"] }, ] as const; const SECTIONS = [ diff --git a/scripts/lint-codes.ts b/scripts/lint-codes.ts index a9c4cbdd5..94c9cf080 100644 --- a/scripts/lint-codes.ts +++ b/scripts/lint-codes.ts @@ -28,10 +28,9 @@ const CHAPTER = /^spec\/v1\/\d\d-[^/]+\.md$/; // typechecked: it holds every code a chapter defines, and no other. export const CLOSED = "src/model/diagnostic.ts"; const EXERCISING = [/^test\//, /\.diagnostics\.json$/]; -// Model changes land in TypeScript first and emf/ catches up later, so its -// codes neither exercise nor are checked. +// Docs and working notes name codes as history or as plans, not as code the +// compiler defines. const OUT_OF_SCOPE = [ - /^emf\//, /^docs\/mde\//, /^docs\/adr\/deferred\//, /^review\//, diff --git a/scripts/lint-links.ts b/scripts/lint-links.ts index 017548d0b..ce9e3be50 100644 --- a/scripts/lint-links.ts +++ b/scripts/lint-links.ts @@ -40,9 +40,7 @@ export function lintLinks(root: string): LinkLintResult { }, ) .split("\0") - // emf/ catches up with the TypeScript side after it, so its links into - // that side may trail; they are not checked. Links into it are. - .filter((file) => file !== "" && !file.startsWith("emf/")); + .filter((file) => file !== ""); const anchorCache = new Map>(); const anchorsOf = (path: string, text: string): Set => { diff --git a/scripts/lint-meaning.ts b/scripts/lint-meaning.ts index 79698d617..728c2d753 100644 --- a/scripts/lint-meaning.ts +++ b/scripts/lint-meaning.ts @@ -34,10 +34,8 @@ const REPOSITORY = join(import.meta.dirname, ".."); // Never scanned, the same exclusions the em-dash ban uses: docs/mde holds // third-party coursework kept verbatim, and CHANGELOG.md is release-please's. -// emf/ catches up with model changes after TypeScript does, so its prose may -// trail a rename and is not scanned. const EXCLUDE = new Set(["CHANGELOG.md"]); -const EXCLUDE_PREFIXES = ["docs/mde/", "emf/"]; +const EXCLUDE_PREFIXES = ["docs/mde/"]; function inScope(rel: string): boolean { return ( diff --git a/spec/v1/examples/refusals/README.md b/spec/v1/examples/refusals/README.md index c978fb71c..20a61faa3 100644 --- a/spec/v1/examples/refusals/README.md +++ b/spec/v1/examples/refusals/README.md @@ -100,8 +100,8 @@ one defect so the refusal has a single cause. Every refused fixture carries a committed `.diagnostics.json` beside it: the set of `(code, path)` pairs the model emits, where the path is the RFC 6901 -JSON Pointer of the object refused. Both implementations are held to that file -([the parity contract](../../../../docs/architecture.md#the-parity-contract)), +JSON Pointer of the object refused. The compiler is held to that file +([the oracles](../../../../docs/architecture.md#the-oracles)), and it replaces the `expect:` header these fixtures used to carry. A value outside a closed vocabulary, and every other defect the schema or the diff --git a/spec/v1/examples/schema-refusals/README.md b/spec/v1/examples/schema-refusals/README.md index aa62c4c2b..15a84ea9c 100644 --- a/spec/v1/examples/schema-refusals/README.md +++ b/spec/v1/examples/schema-refusals/README.md @@ -34,8 +34,9 @@ the chapter's table says the refusal lands at. | [`human-grant-role-outside-vocabulary/`](human-grant-role-outside-vocabulary/) | a Human Grant of a role outside the built-in four | the value | | [`human-grant-without-reason/`](human-grant-without-reason/) | a Human Grant with no `reason` | where the field would be | -These oracles bind the production implementation only -([the parity contract](../../../../docs/architecture.md#the-parity-contract)): -the model-driven implementation reads a file through a grammar, which refuses -the token rather than naming the field. `test/schema-refusals.test.ts` -runs each case. +A file the reader refuses, outside the YAML subset or against the schema, is +refused with the code `schema` at the place +[chapter 10](../../../../spec/v1/10-project-intent.md#what-a-schema-refusal-reports) +fixes +([the oracles](../../../../docs/architecture.md#the-oracles)). +`test/schema-refusals.test.ts` runs each case. diff --git a/src/check/project.ts b/src/check/project.ts index d160fb076..aeb76b8d4 100644 --- a/src/check/project.ts +++ b/src/check/project.ts @@ -1,11 +1,8 @@ -// The rules one authored document answers on its own: the counterpart of the -// Complete OCL invariants the model-driven implementation evaluates, and the -// same refusals at the same places. Each carries the code the specification -// gives it and the JSON Pointer of the object it refuses -// (docs/architecture.md#the-parity-contract), which is the object an invariant -// takes as its context. A rule that needs more than one document belongs to -// composition.ts, not here. The env files beside a project file are checked -// here too, because they are part of what one project authors. +// The rules one authored document answers on its own. Each carries the code +// the specification gives it and the JSON Pointer of the object it refuses +// (docs/architecture.md#the-oracles). A rule that needs more than one document +// belongs to composition.ts, not here. The env files beside a project file are +// checked here too, because they are part of what one project authors. import type { Diagnostic, RefusalCode } from "../model/diagnostic.ts"; import type { EnvScope, ScopedEnv } from "../model/env.ts"; import type { diff --git a/src/model/descriptor.ts b/src/model/descriptor.ts index fa33ddb41..11585d3e8 100644 --- a/src/model/descriptor.ts +++ b/src/model/descriptor.ts @@ -1,6 +1,6 @@ -// The descriptor the parity contract fixes: every class of the source +// The descriptor the oracle contract fixes: every class of the source // metamodel with its features, and every closed vocabulary with its literals -// (docs/architecture.md#the-parity-contract). It is built from the Zod schemas +// (docs/architecture.md#the-oracles). It is built from the Zod schemas // through Zod's own JSON Schema, and normalised into the contract's shape, // which is neither format's. import { z } from "zod"; diff --git a/src/model/effective-intent.ts b/src/model/effective-intent.ts index 8bc5e025a..bd14d67ed 100644 --- a/src/model/effective-intent.ts +++ b/src/model/effective-intent.ts @@ -2,8 +2,8 @@ // onto the Processes that hold it, and the only layer-1 shape anything // downstream reads (spec/v1/10-project-intent.md#the-effective-intent, // docs/adr/model/0012-shared-intent-descends-and-is-lowered.md). It keeps the -// authored vocabulary, so its canonical JSON is the `effective.json` oracle both -// implementations meet at (docs/architecture.md#the-parity-contract). +// authored vocabulary, so its canonical JSON is the `effective.json` oracle +// (docs/architecture.md#the-oracles). // // A key no level declares is absent here, as it is in the authored file, and a // route or a scrape names its Process and surface as the author wrote them: the diff --git a/src/read/env.ts b/src/read/env.ts index d9b31df4e..8ed89e9a2 100644 --- a/src/read/env.ts +++ b/src/read/env.ts @@ -1,7 +1,7 @@ // The dotenv subset chapter 10 fixes, read into the model // (spec/v1/10-project-intent.md#the-dotenv-subset-that-is-read). A reader -// rather than a grammar, for the reason -// emf/docs/adr/emf/0082-the-env-files-are-read-not-parsed-by-xtext.md records. +// rather than a grammar: the file is data the pipeline reads, not syntax the +// grammar owns, so an env file cannot make a document fail to parse. import type { Diagnostic, Result } from "../model/diagnostic.ts"; import type { EnvVariable, diff --git a/src/resolve/union.ts b/src/resolve/union.ts index 5a7e54c73..c7b2ad4c2 100644 --- a/src/resolve/union.ts +++ b/src/resolve/union.ts @@ -1,8 +1,8 @@ // The composed union to every project's projections // (spec/v1/20-resolved-deployment.md): each Application's element, published // with the provenance every render from these inputs shares, and each -// project's resolved dependency edges, the part of resolution both -// implementations meet at (docs/architecture.md#the-parity-contract). +// project's resolved dependency edges, resolution's committed contract +// (docs/architecture.md#the-oracles). import type { Hasher } from "../model/hasher.ts"; import type { InputDigest, diff --git a/test/adr-contract.test.ts b/test/adr-contract.test.ts index c5c9efb23..8340a35ea 100644 --- a/test/adr-contract.test.ts +++ b/test/adr-contract.test.ts @@ -32,29 +32,6 @@ test("the ADR lint, run as a command, passes over the committed decision set", ( expect(out).toMatch(/^ADR lint: \d+ files clean$/m); }); -test("the coursework register under emf/, linted as its own root, passes", () => { - const out = execFileSync( - process.execPath, - [join(REPOSITORY, "scripts", "lint-adrs.ts"), join(REPOSITORY, "emf")], - { encoding: "utf8" }, - ); - expect(out).toMatch(/^ADR lint: \d+ files clean$/m); -}); - -test("no number is used in both the root register and the coursework register", () => { - const emfDir = join(REPOSITORY, "emf", "docs", "adr", "emf"); - const numbers = (dir: string): string[] => - (existsSync(dir) ? readdirSync(dir) : []) - .filter((file) => /^\d{4}-.+\.md$/.test(file)) - .map((file) => file.slice(0, 4)); - const root = new Set( - ["model", "architecture", "deferred"].flatMap((domain) => - numbers(join(ADR_DIR, domain)), - ), - ); - expect(numbers(emfDir).filter((n) => root.has(n))).toEqual([]); -}); - test("the decision set is non-empty, and one number is used once", () => { expect(adrFiles.length).toBeGreaterThanOrEqual(40); const numbers = adrFiles.map((file) => Number(basename(file).slice(0, 4))); diff --git a/test/canonical-json.test.ts b/test/canonical-json.test.ts index 3f97d2783..0c84004dd 100644 --- a/test/canonical-json.test.ts +++ b/test/canonical-json.test.ts @@ -1,4 +1,4 @@ -// REQ-020 (docs/requirements.md). The same cases as emf/bundles/metamodel CanonicalJsonTest. +// REQ-020 (docs/requirements.md). import { describe, expect, it } from "vitest"; import { canonicalJson } from "../src/index.ts"; diff --git a/test/codes-lint.test.ts b/test/codes-lint.test.ts index cf1f5288c..eb4cd6909 100644 --- a/test/codes-lint.test.ts +++ b/test/codes-lint.test.ts @@ -84,26 +84,6 @@ describe("codeErrors", () => { }); }); - it("neither counts nor checks the emf/ tree", () => { - const result = codeErrors( - { - "spec/v1/10-intent.md": chapter(ALPHA), - "emf/tests/parity/src/test/java/X.java": ALPHA, - "emf/bundles/metamodel/model/x.ocl": BETA, - }, - [], - ); - - expect(result).toStrictEqual({ - defined: 1, - exercised: 0, - pending: 0, - errors: [ - `${ALPHA}: defined by the specification, exercised by no test, and not pending`, - ], - }); - }); - it("fails a pending code once a test exercises it, naming the file", () => { const result = codeErrors( { "spec/v1/10-intent.md": chapter(ALPHA), "test/a.test.ts": ALPHA }, diff --git a/test/emf-wiring.test.ts b/test/emf-wiring.test.ts deleted file mode 100644 index 39e9cba2e..000000000 --- a/test/emf-wiring.test.ts +++ /dev/null @@ -1,271 +0,0 @@ -// The model-driven build under emf/ has no npm script, so the pipeline wiring -// test cannot see it: a workflow step running the Maven wrapper against a -// directory with no build, or a reactor naming a module that is not on disk, -// would pass every other check and fail only in CI, or not at all. This test -// holds the Maven side to the same rule 0064 states for npm: the job CI runs is -// the build the tree contains. It also holds CodeQL to scanning that build. -// -// Deleted with emf/ at its sunset (emf/docs/adr/emf/0107). The build runs on -// every change to emf/ or the workflow, and gates nothing. -// -// REQ-015 (docs/requirements.md): the model-driven build CI runs is the build -// in the tree. -import { - existsSync, - mkdirSync, - readFileSync, - readdirSync, - writeFileSync, -} from "node:fs"; -import { join } from "node:path"; -import { describe, expect, it } from "vitest"; -import { temporary } from "./setup.ts"; - -const REPOSITORY = join(import.meta.dirname, ".."); - -interface Workflow { - readonly name: string; - readonly text: string; -} - -function workflows(): Workflow[] { - const dir = join(REPOSITORY, ".github", "workflows"); - return readdirSync(dir) - .filter((name) => name.endsWith(".yml")) - .map((name) => ({ name, text: readFileSync(join(dir, name), "utf8") })); -} - -/** - * Every workflow step that runs the Maven wrapper, as the directory it runs - * in. A step is the text between two list markers at the same indent, and the - * directory is its `working-directory`, or the repository root without one. - */ -function mavenSteps(files: readonly Workflow[]): string[] { - return files.flatMap((file) => - file.text - .split(/\n(?= {6}- )/) - .filter((step) => /\bmvnw\b/.test(step)) - .map((step) => /'working-directory':\s*'([^']+)'/.exec(step)?.[1] ?? "."), - ); -} - -/** A command line that passes the `quick` profile: `-Pquick`, `-P quick`, a list naming it, or `--activate-profiles`. */ -const QUICK_PROFILE = /(?:-P\s*|--activate-profiles[=\s]+)(?:[\w-]+,)*quick\b/; - -/** - * Every place CI could pass the model-driven build's `quick` profile: a - * workflow that names it anywhere (a step's command, its `env:`, a - * `MAVEN_ARGS`), or the committed `emf/.mvn/maven.config`, which every build - * reads. The profile skips the coverage floor, PIT and the Spotless check for - * a local edit (emf/pom.xml), so CI passing it would skip the gates it exists - * to run. - */ -function quickProfileErrors( - files: readonly Workflow[], - root: string, -): string[] { - const errors = files - .filter((file) => QUICK_PROFILE.test(file.text)) - .map( - (file) => - `${file.name} passes the quick profile to the model-driven build, which skips the gates CI runs`, - ); - const config = join(root, "emf", ".mvn", "maven.config"); - if (existsSync(config) && QUICK_PROFILE.test(readFileSync(config, "utf8"))) - errors.push( - "emf/.mvn/maven.config passes the quick profile to every model-driven build, which skips the gates CI runs", - ); - return errors; -} - -/** Every problem with the Maven steps and the reactor under `root`. */ -function mavenWiringErrors(files: readonly Workflow[], root: string): string[] { - const errors: string[] = []; - for (const dir of mavenSteps(files)) { - if (!existsSync(join(root, dir, "pom.xml"))) - errors.push( - `a step runs the Maven wrapper in ${dir}, which names a POM that does not exist`, - ); - if (!existsSync(join(root, dir, "mvnw"))) - errors.push( - `a step runs the Maven wrapper in ${dir}, which holds no mvnw`, - ); - } - const reactor = join(root, "emf", "pom.xml"); - const modules = existsSync(reactor) - ? [ - ...readFileSync(reactor, "utf8").matchAll(/([^<]+)<\/module>/g), - ].map((match) => match[1] ?? "") - : []; - for (const module of modules) - if (!existsSync(join(root, "emf", module, "pom.xml"))) - errors.push(`emf/pom.xml names module ${module}, which is not on disk`); - return errors; -} - -function workflow(name: string, text: string): Workflow { - return { name, text }; -} - -const MAVEN_STEP = [ - " 'steps':", - " - 'uses': 'actions/checkout@abc' # v7", - " - 'name': 'Verify'", - " 'working-directory': 'emf'", - " 'run': './mvnw -B -ntp verify'", -].join("\n"); - -describe("the model-driven build CI runs is the build in the tree", () => { - it("passes over this repository's workflows and reactor", () => { - const files = workflows(); - - expect(mavenSteps(files)).toContain("emf"); - expect(mavenWiringErrors(files, REPOSITORY)).toEqual([]); - }); - - it("fails a step whose directory names a POM that does not exist", () => { - const moved = workflow("ci.yml", MAVEN_STEP.replace("'emf'", "'java'")); - - expect(mavenWiringErrors([moved], REPOSITORY)).toEqual([ - "a step runs the Maven wrapper in java, which names a POM that does not exist", - "a step runs the Maven wrapper in java, which holds no mvnw", - ]); - }); - - it("fails a step with no working directory, since the root holds no build", () => { - const rooted = workflow( - "ci.yml", - MAVEN_STEP.replace(" 'working-directory': 'emf'\n", ""), - ); - - expect(mavenWiringErrors([rooted], REPOSITORY)).toEqual([ - "a step runs the Maven wrapper in ., which names a POM that does not exist", - "a step runs the Maven wrapper in ., which holds no mvnw", - ]); - }); - - it("fails a reactor that names a module which is not on disk", () => { - const root = temporary(); - mkdirSync(join(root, "emf", "parity"), { recursive: true }); - writeFileSync(join(root, "emf", "parity", "pom.xml"), ""); - writeFileSync( - join(root, "emf", "pom.xml"), - "paritygone", - ); - - expect(mavenWiringErrors([], root)).toEqual([ - "emf/pom.xml names module gone, which is not on disk", - ]); - }); -}); - -describe("CI never passes the model-driven build's quick profile", () => { - it("passes over this repository's workflows and Maven configuration", () => { - expect(quickProfileErrors(workflows(), REPOSITORY)).toEqual([]); - }); - - it.each([ - ["-Pquick", "./mvnw -B -ntp verify -Pquick"], - ["-P quick", "./mvnw -B -ntp -P quick verify"], - ["a list of profiles", "./mvnw -B -ntp verify -Pbenchmark,quick"], - ["--activate-profiles", "./mvnw -B -ntp verify --activate-profiles=quick"], - ])("fails a step that passes it with %s", (_, run) => { - const quick = workflow( - "ci.yml", - MAVEN_STEP.replace("./mvnw -B -ntp verify", run), - ); - - expect(quickProfileErrors([quick], temporary())).toEqual([ - "ci.yml passes the quick profile to the model-driven build, which skips the gates CI runs", - ]); - }); - - it("fails a step that passes it through MAVEN_ARGS", () => { - const quick = workflow( - "ci.yml", - MAVEN_STEP.replace( - " 'run':", - " 'env':\n 'MAVEN_ARGS': '-Pquick'\n 'run':", - ), - ); - - expect(quickProfileErrors([quick], temporary())).toEqual([ - "ci.yml passes the quick profile to the model-driven build, which skips the gates CI runs", - ]); - }); - - it("fails a committed Maven configuration that passes it", () => { - const root = temporary(); - mkdirSync(join(root, "emf", ".mvn"), { recursive: true }); - writeFileSync(join(root, "emf", ".mvn", "maven.config"), "-Pquick\n"); - - expect(quickProfileErrors([], root)).toEqual([ - "emf/.mvn/maven.config passes the quick profile to every model-driven build, which skips the gates CI runs", - ]); - }); - - it("passes a step that names another profile", () => { - const benchmark = workflow( - "ci.yml", - MAVEN_STEP.replace( - "./mvnw -B -ntp verify", - "./mvnw -B -ntp verify -Pbenchmark -Dquickly=true", - ), - ); - - expect(quickProfileErrors([benchmark], temporary())).toEqual([]); - }); -}); - -describe("the model-driven build runs where a change reaches it, and gates nothing", () => { - const ci = readFileSync( - join(REPOSITORY, ".github", "workflows", "ci.yml"), - "utf8", - ); - const job = /\n {2}'emf':\n([\s\S]*?)\n {4}'steps':/.exec(ci)?.[1] ?? ""; - const needs = - /'pipeline-complete':[\s\S]*?'needs':\n((?:\s+- '[\w-]+'\n)+)/.exec( - ci, - )?.[1] ?? ""; - - it("runs on every change to emf/ or the workflow, and on dispatch", () => { - expect(ci).toContain("grep -qE '^(emf/|\\.github/workflows/ci\\.yml$)'"); - expect(job).not.toContain("github.event_name == 'workflow_dispatch'"); - }); - - it("runs mutation testing only on the nightly run and a dispatch", () => { - expect(ci).toContain("./mvnw -B -ntp verify -DskipPitest=true"); - expect(ci).toContain( - `if [ "\${EVENT}" = 'workflow_dispatch' ] || [ "\${EVENT}" = 'schedule' ]; then`, - ); - }); - - it("is not a job Pipeline Complete needs", () => { - expect(needs).toContain("- 'tests'\n"); - expect(needs).not.toContain("- 'emf'"); - }); -}); - -describe("CodeQL scans the model-driven build", () => { - const codeql = readFileSync( - join(REPOSITORY, ".github", "workflows", "codeql.yml"), - "utf8", - ); - const config = readFileSync( - join(REPOSITORY, ".github", "codeql", "codeql-config.yml"), - "utf8", - ); - - it("analyses java-kotlin without a build, with the shared configuration", () => { - expect(codeql).toContain("'language': 'java-kotlin'"); - expect(codeql).toContain("'build-mode': 'none'"); - expect(codeql).toContain( - "'config-file': './.github/codeql/codeql-config.yml'", - ); - }); - - it("ignores build output and generated sources", () => { - expect(config).toContain("- '**/target/**'"); - expect(config).toContain("- '**/src-gen/**'"); - }); -}); diff --git a/test/link-contract.test.ts b/test/link-contract.test.ts index f3eafa2a3..4d148af33 100644 --- a/test/link-contract.test.ts +++ b/test/link-contract.test.ts @@ -129,18 +129,6 @@ describe("the link lint", () => { ); expect(lintLinks(root)).toStrictEqual({ files: 1, errors: [] }); }); - - it("skips the emf/ tree as a source, and still checks links into it", () => { - const root = repository({ - "README.md": "# Root\n\nSee [it](emf/README.md#gone).\n", - "emf/README.md": "# Emf\n\nSee [it](../spec/ch.md#the-old-name).\n", - "spec/ch.md": "# Chapter\n", - }); - expect(lintLinks(root)).toStrictEqual({ - files: 2, - errors: ["README.md: anchor #gone not found in emf/README.md"], - }); - }); }); describe("the command", () => { diff --git a/test/meaning-lint-negative.test.ts b/test/meaning-lint-negative.test.ts index e9b63174d..d567a5e5c 100644 --- a/test/meaning-lint-negative.test.ts +++ b/test/meaning-lint-negative.test.ts @@ -149,10 +149,9 @@ describe("lintMeaning", () => { }); }); - it("ignores docs/mde, CHANGELOG.md and the emf/ tree", () => { + it("ignores docs/mde and CHANGELOG.md", () => { const root = fixture({ "docs/mde/paper.md": "Service Intent, verbatim coursework text.\n", - "emf/docs/rules.md": "Service Intent, frozen at mde-task-3.\n", "CHANGELOG.md": "* mentions Service Intent, release-please owns this\n", }); expect(lintMeaning(root).errors).toStrictEqual([]); diff --git a/test/mutation-scope.test.ts b/test/mutation-scope.test.ts index 2c4e2b5ac..11873c5b9 100644 --- a/test/mutation-scope.test.ts +++ b/test/mutation-scope.test.ts @@ -52,7 +52,6 @@ describe("whether a change reaches the mutation gate", () => { ".release-please-manifest.json", "docs/adr/architecture/0063-coverage-and-mutation-are-ratchets.md", "spec/v1/10-project-intent.md", - "emf/pom.xml", "scripts/lint-adrs.ts", "scripts/lib/pr-comment.ts", ".github/workflows/release.yml", diff --git a/test/schema-refusals.test.ts b/test/schema-refusals.test.ts index bf71eb450..abaa46c63 100644 --- a/test/schema-refusals.test.ts +++ b/test/schema-refusals.test.ts @@ -3,10 +3,10 @@ // Pointers its committed diagnostics oracle names // (spec/v1/10-project-intent.md#reading-a-file). // -// These oracles bind the production implementation only -// (docs/architecture.md#the-parity-contract): the model-driven implementation's -// front end is a grammar, which refuses a token rather than naming the field. -// So the test sits outside test/model/, whose rows each need a witness there. +// A file the reader refuses, outside the YAML subset or against the schema, +// is refused with the code `schema` at the JSON Pointers its committed +// diagnostics oracle names (docs/architecture.md#the-oracles). The test sits +// outside test/model/, whose rows take the model's own behaviour. import { readFileSync, readdirSync, statSync } from "node:fs"; import { join, sep } from "node:path"; import { describe, expect, it } from "vitest";