From 6346a3603c7e9ac4565102fcbc2500675377d72d Mon Sep 17 00:00:00 2001 From: Agustin Celentano <12614595+agustincelentano@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:47:12 -0300 Subject: [PATCH 1/2] chore: remove migrated postgres-k8s and endpoint-exposer services Both services were migrated to their own repositories: - postgres-k8s -> nullplatform/services-postgresql-k-8-s - endpoint-exposer -> nullplatform/services-endpoint-exposer Update README service catalog to point to the new repos and drop the endpoint-exposer test block from the pre-commit hook. --- .DS_Store | Bin 0 -> 6148 bytes .githooks/pre-commit | 16 - README.md | 18 +- databases/.DS_Store | Bin 0 -> 8196 bytes databases/postgres/k8s/README.md | 242 ----------- databases/postgres/k8s/entrypoint/entrypoint | 4 - databases/postgres/k8s/handle-service-agent | 14 - .../postgres/k8s/postgres-db/ensure_psql.sh | 6 - .../k8s/postgres-db/link/create-database-user | 39 -- .../k8s/postgres-db/link/delete-database-user | 40 -- .../k8s/postgres-db/link/update-database-user | 70 --- .../k8s/postgres-db/run_query_in_pod.sh | 148 ------- .../postgres-db/service/create-postgres-db | 46 -- .../postgres-db/service/delete-postgres-db | 30 -- .../postgres-db/service/ensure_helm_deps.sh | 47 -- .../k8s/postgres-db/service/handle-helm.sh | 39 -- .../k8s/postgres-db/service/project.sh | 2 - .../k8s/postgres-db/service/run-ddl-query | 35 -- .../k8s/postgres-db/service/run-dml-query | 47 -- .../postgres-db/service/update-postgres-db | 10 - .../k8s/postgres-db/service/values.yaml.tpl | 49 --- .../k8s/specs/actions/run-ddl-query.json | 48 --- .../k8s/specs/actions/run-dml-query.json | 54 --- .../k8s/specs/links/database-user.json | 66 --- .../postgres/k8s/specs/service-spec.json | 90 ---- endpoint-exposer/README.md | 190 -------- .../deployment/sync_exposer | 172 -------- .../deployment/workflows/blue_green.yaml | 5 - .../deployment/workflows/delete.yaml | 5 - .../deployment/workflows/finalize.yaml | 5 - .../deployment/workflows/initial.yaml | 5 - .../deployment/workflows/rollback.yaml | 5 - .../deployment/workflows/switch_traffic.yaml | 5 - .../container-scope-override/values.yaml | 3 - endpoint-exposer/entrypoint/entrypoint | 66 --- endpoint-exposer/entrypoint/link | 34 -- endpoint-exposer/entrypoint/service | 39 -- endpoint-exposer/github/setup-hooks.sh | 11 - endpoint-exposer/install/installation.md | 101 ----- endpoint-exposer/install/prerequisites.md | 66 --- .../install/specs/actions/read.json.tpl | 25 -- .../specs/notification-channel.json.tpl | 34 -- .../install/specs/service-spec.json.tpl | 216 ---------- .../install/tofu/.terraform.lock.hcl | 66 --- endpoint-exposer/install/tofu/backend.tf | 5 - endpoint-exposer/install/tofu/main.tf | 54 --- endpoint-exposer/install/tofu/provider.tf | 20 - .../install/tofu/terraform.tfvars.example | 40 -- endpoint-exposer/install/tofu/variables.tf | 98 ----- endpoint-exposer/scripts/common/apply | 90 ---- endpoint-exposer/scripts/istio/build_context | 46 -- .../scripts/istio/build_httproute | 111 ----- endpoint-exposer/scripts/istio/build_ingress | 28 -- .../scripts/istio/build_ingress_with_rule | 406 ------------------ endpoint-exposer/scripts/istio/build_rule | 182 -------- endpoint-exposer/scripts/istio/config | 13 - .../scripts/istio/fetch_provider_data | 20 - endpoint-exposer/scripts/istio/process_routes | 116 ----- endpoint-exposer/scripts/istio/read_ingress | 8 - .../scripts/istio/update_httproute_hostname | 37 -- .../templates/istio/httproute.yaml.tpl | 26 -- endpoint-exposer/test/.gitignore | 11 - endpoint-exposer/test/CONTRIBUTING.md | 302 ------------- endpoint-exposer/test/README.md | 103 ----- .../test/fixtures/authorization-disabled.json | 83 ---- .../test/fixtures/no-public-routes.json | 71 --- .../fixtures/public-and-private-routes.json | 95 ---- .../test/fixtures/simple-public-routes.json | 83 ---- endpoint-exposer/test/helpers.bash | 298 ------------- endpoint-exposer/test/run-tests.sh | 83 ---- endpoint-exposer/test/test_apply_cleanup.bats | 139 ------ endpoint-exposer/test/test_build_context.bats | 98 ----- .../test/test_build_httproute.bats | 179 -------- endpoint-exposer/test/test_integration.bats | 229 ---------- endpoint-exposer/values.yaml | 2 - endpoint-exposer/workflows/istio/create.yaml | 53 --- endpoint-exposer/workflows/istio/delete.yaml | 6 - endpoint-exposer/workflows/istio/read.yaml | 30 -- endpoint-exposer/workflows/istio/update.yaml | 7 - 79 files changed, 15 insertions(+), 5370 deletions(-) create mode 100644 .DS_Store create mode 100644 databases/.DS_Store delete mode 100644 databases/postgres/k8s/README.md delete mode 100755 databases/postgres/k8s/entrypoint/entrypoint delete mode 100755 databases/postgres/k8s/handle-service-agent delete mode 100755 databases/postgres/k8s/postgres-db/ensure_psql.sh delete mode 100755 databases/postgres/k8s/postgres-db/link/create-database-user delete mode 100755 databases/postgres/k8s/postgres-db/link/delete-database-user delete mode 100755 databases/postgres/k8s/postgres-db/link/update-database-user delete mode 100755 databases/postgres/k8s/postgres-db/run_query_in_pod.sh delete mode 100755 databases/postgres/k8s/postgres-db/service/create-postgres-db delete mode 100755 databases/postgres/k8s/postgres-db/service/delete-postgres-db delete mode 100644 databases/postgres/k8s/postgres-db/service/ensure_helm_deps.sh delete mode 100755 databases/postgres/k8s/postgres-db/service/handle-helm.sh delete mode 100755 databases/postgres/k8s/postgres-db/service/project.sh delete mode 100755 databases/postgres/k8s/postgres-db/service/run-ddl-query delete mode 100755 databases/postgres/k8s/postgres-db/service/run-dml-query delete mode 100755 databases/postgres/k8s/postgres-db/service/update-postgres-db delete mode 100755 databases/postgres/k8s/postgres-db/service/values.yaml.tpl delete mode 100644 databases/postgres/k8s/specs/actions/run-ddl-query.json delete mode 100644 databases/postgres/k8s/specs/actions/run-dml-query.json delete mode 100644 databases/postgres/k8s/specs/links/database-user.json delete mode 100644 databases/postgres/k8s/specs/service-spec.json delete mode 100644 endpoint-exposer/README.md delete mode 100755 endpoint-exposer/container-scope-override/deployment/sync_exposer delete mode 100644 endpoint-exposer/container-scope-override/deployment/workflows/blue_green.yaml delete mode 100644 endpoint-exposer/container-scope-override/deployment/workflows/delete.yaml delete mode 100644 endpoint-exposer/container-scope-override/deployment/workflows/finalize.yaml delete mode 100644 endpoint-exposer/container-scope-override/deployment/workflows/initial.yaml delete mode 100644 endpoint-exposer/container-scope-override/deployment/workflows/rollback.yaml delete mode 100644 endpoint-exposer/container-scope-override/deployment/workflows/switch_traffic.yaml delete mode 100644 endpoint-exposer/container-scope-override/values.yaml delete mode 100755 endpoint-exposer/entrypoint/entrypoint delete mode 100755 endpoint-exposer/entrypoint/link delete mode 100755 endpoint-exposer/entrypoint/service delete mode 100755 endpoint-exposer/github/setup-hooks.sh delete mode 100644 endpoint-exposer/install/installation.md delete mode 100644 endpoint-exposer/install/prerequisites.md delete mode 100644 endpoint-exposer/install/specs/actions/read.json.tpl delete mode 100644 endpoint-exposer/install/specs/notification-channel.json.tpl delete mode 100644 endpoint-exposer/install/specs/service-spec.json.tpl delete mode 100644 endpoint-exposer/install/tofu/.terraform.lock.hcl delete mode 100644 endpoint-exposer/install/tofu/backend.tf delete mode 100644 endpoint-exposer/install/tofu/main.tf delete mode 100644 endpoint-exposer/install/tofu/provider.tf delete mode 100644 endpoint-exposer/install/tofu/terraform.tfvars.example delete mode 100644 endpoint-exposer/install/tofu/variables.tf delete mode 100644 endpoint-exposer/scripts/common/apply delete mode 100644 endpoint-exposer/scripts/istio/build_context delete mode 100755 endpoint-exposer/scripts/istio/build_httproute delete mode 100644 endpoint-exposer/scripts/istio/build_ingress delete mode 100755 endpoint-exposer/scripts/istio/build_ingress_with_rule delete mode 100644 endpoint-exposer/scripts/istio/build_rule delete mode 100755 endpoint-exposer/scripts/istio/config delete mode 100755 endpoint-exposer/scripts/istio/fetch_provider_data delete mode 100755 endpoint-exposer/scripts/istio/process_routes delete mode 100644 endpoint-exposer/scripts/istio/read_ingress delete mode 100755 endpoint-exposer/scripts/istio/update_httproute_hostname delete mode 100644 endpoint-exposer/templates/istio/httproute.yaml.tpl delete mode 100644 endpoint-exposer/test/.gitignore delete mode 100644 endpoint-exposer/test/CONTRIBUTING.md delete mode 100644 endpoint-exposer/test/README.md delete mode 100644 endpoint-exposer/test/fixtures/authorization-disabled.json delete mode 100644 endpoint-exposer/test/fixtures/no-public-routes.json delete mode 100644 endpoint-exposer/test/fixtures/public-and-private-routes.json delete mode 100644 endpoint-exposer/test/fixtures/simple-public-routes.json delete mode 100644 endpoint-exposer/test/helpers.bash delete mode 100755 endpoint-exposer/test/run-tests.sh delete mode 100644 endpoint-exposer/test/test_apply_cleanup.bats delete mode 100644 endpoint-exposer/test/test_build_context.bats delete mode 100644 endpoint-exposer/test/test_build_httproute.bats delete mode 100644 endpoint-exposer/test/test_integration.bats delete mode 100644 endpoint-exposer/values.yaml delete mode 100644 endpoint-exposer/workflows/istio/create.yaml delete mode 100644 endpoint-exposer/workflows/istio/delete.yaml delete mode 100644 endpoint-exposer/workflows/istio/read.yaml delete mode 100644 endpoint-exposer/workflows/istio/update.yaml diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..cda7ef07dc37d702abc0622fd147d693f1e4a42c GIT binary patch literal 6148 zcmeHKy-veG4ED8=NCiVA76yhqL8VHpNTCWFTVH_wsZ?r}N^J%thP(m10K5Xc1uG*f z8ygGkd_G^pRSAdzA%twn_g#E;?0h-JIU+LMeAFR|h$w_IHd+{Jgx6Us(r}g?pt1MJ zX+-1Mq|+N_6>l~CMF#lYZBd(sG^0Lw?{B_v<=#|1=2@B!X4wEM;qBu~>-qBjsLpHj z4X?!+@0N8o-iH*Ro(WB9B|Ayhnr{bB{+eII_3q(*{$Oh;W9QjN_PTXHZxG&b-WGOm zpH|QTbV*}c`V~a^$wj@FU(58hyRN0?etuP7d;0Z7=T}^xiZY-KC<8ym0D3k{xGkuo zGN24710@6eeTboqiNiwBemXGNBLFaf*$U?N9}XC^0hl-}1Yv;~2?a{1aYqaz;jqWf zFL781N;nyt8TWCSjXR+jn;rJpx|2x+byNnFflUUQav5>|KmPpuzZs-g%78NPuNW{v z+Dp55B-dLj568VWhMq!M*sl;QLol(e7{1(!_n=l_k9h)292SDGK=enz(x8Jf@T&~G E13$=cWB>pF literal 0 HcmV?d00001 diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 925520b..0f91f47 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -7,19 +7,3 @@ echo "Running tests before commit..." # Change to the repository root REPO_ROOT="$(git rev-parse --show-toplevel)" cd "$REPO_ROOT" - -# Check if endpoint-exposer tests need to be run (if any endpoint-exposer files changed) -if git diff --cached --name-only | grep -q "^endpoint-exposer/"; then - echo "Endpoint-exposer files changed, running tests..." - - if command -v bats &> /dev/null; then - cd endpoint-exposer - bats test/ - else - echo "⚠️ BATS not installed, skipping tests" - echo "Install BATS: brew install bats-core (macOS) or see https://bats-core.readthedocs.io" - exit 0 - fi - - echo "✅ All endpoint-exposer tests passed!" -fi diff --git a/README.md b/README.md index bccec21..06968a6 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,24 @@ This repository contains a collection of service definitions for the null platfo ## Table of Contents -- Service Catalog - - Databases - - [PostgreSQL Database](./databases/postgres/k8s/README.md) +- [Service Catalog](#service-catalog) - [Usage](#usage) - [Contributing](#contributing) +## Service Catalog + +### Services in this repository + +- Databases + - [Azure Cosmos DB](./databases/azure-cosmos-db) + - [RDS PostgreSQL Database](./databases/rds-postgres-db/README.md) + - [RDS PostgreSQL Server](./databases/rds-postgres-server/README.md) + +### Services in other repositories + +- PostgreSQL (Kubernetes) → [nullplatform/services-postgresql-k-8-s](https://github.com/nullplatform/services-postgresql-k-8-s) +- Endpoint Exposer → [nullplatform/services-endpoint-exposer](https://github.com/nullplatform/services-endpoint-exposer) + ## Usage Each service is defined by its specification files and includes: diff --git a/databases/.DS_Store b/databases/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..44fdf2e3ca8238ac9148a5e0e4ac73019fee49fd GIT binary patch literal 8196 zcmeHMJxc>Y5S@({0l^OxjNKKs0sRAVhS&=MYfVm6$Z^pa3qd$6?EM2`Wh2-r2sTzW z`V#~z3rnp9-|Q}C&r9OPLJZEp?o0OOWoO=9ZZa1lQl(ZfPgEeHJO<G*C_?HUs{lUXv z^ex5)^{oSwZUKP9Sk{Ku=mRvzv*=rl4QeVr({vBYQk88nl%eCe$L>JiVrAEoNZ_KVUUB-RMrS4elfj{S0E4Hgrx+Hv^)>hfY3j%oo>3 z)1wDE=G13}Q9H_Ber{Z(mN~95L=$LLzr>f;ndtuPdxjhH@yc6U=brnx8DwWA^2zCZ zCVS-5#I>|TdpsxAKY2u68JTW=x7&>ydmUwFx6f4n>_oom2|?3D*L?Y#vW0I^n9Ox% zAsfrh^ZfGjJZ9L>J(vA46ZzR9%Sk%MrPjk>^ex5)d5PC`6$VQEXFK)iz ` -- Verify service configuration in nullplatform dashboard -- Review Helm release status: `helm status ` - -## License - -This service definition is part of the nullplatform services repository. \ No newline at end of file diff --git a/databases/postgres/k8s/entrypoint/entrypoint b/databases/postgres/k8s/entrypoint/entrypoint deleted file mode 100755 index 3deab82..0000000 --- a/databases/postgres/k8s/entrypoint/entrypoint +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash -set -e -SCRIPT_DIR="$(dirname "$(realpath "$0")")" -exec "$SCRIPT_DIR/../handle-service-agent" "$@" diff --git a/databases/postgres/k8s/handle-service-agent b/databases/postgres/k8s/handle-service-agent deleted file mode 100755 index 6b011a9..0000000 --- a/databases/postgres/k8s/handle-service-agent +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -x - -WORKING_DIRECTORY="$(dirname "$(realpath "$0")")" -cd "$WORKING_DIRECTORY" || exit 1 - -# Bridge: np-agent exposes NP_API_KEY, but np CLI expects NULLPLATFORM_API_KEY -if [ -n "${NP_API_KEY:-}" ] && [ -z "${NULLPLATFORM_API_KEY:-}" ]; then - export NULLPLATFORM_API_KEY="$NP_API_KEY" -fi - -echo "Starting handle agent service" - -np service-action exec --live-output --live-report --debug -exit $? \ No newline at end of file diff --git a/databases/postgres/k8s/postgres-db/ensure_psql.sh b/databases/postgres/k8s/postgres-db/ensure_psql.sh deleted file mode 100755 index e5fd879..0000000 --- a/databases/postgres/k8s/postgres-db/ensure_psql.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash - -CLI=$(which uuidgen) -if [[ "$CLI" == "" ]]; then - apk add uuidgen -fi \ No newline at end of file diff --git a/databases/postgres/k8s/postgres-db/link/create-database-user b/databases/postgres/k8s/postgres-db/link/create-database-user deleted file mode 100755 index 7655b83..0000000 --- a/databases/postgres/k8s/postgres-db/link/create-database-user +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -set -e -export WORKING_DIRECTORY_ORIGINAL="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $WORKING_DIRECTORY_ORIGINAL -../ensure_psql.sh - -# Get service connection details -SERVICE_HOSTNAME=$ACTION_SERVICE_ATTRIBUTES_HOSTNAME -SERVICE_PORT=$ACTION_SERVICE_ATTRIBUTES_PORT -SERVICE_DBNAME=$ACTION_SERVICE_ATTRIBUTES_DBNAME -SECRET_NAME=$ACTION_SERVICE_ATTRIBUTES_K_8_S_SECRET_NAME - -# Get link parameters -export DB_USERNAME="usr$(uuidgen | tr -d "-")" -USER_TYPE=$ACTION_PARAMETERS_USER_TYPE -GENERATED_PASSWORD=pwd"$(uuidgen)" - -# Get admin credentials from K8s secret -ADMIN_PASSWORD=$(kubectl get secret $SECRET_NAME -n postgres-db -o json | jq -r '.data["postgres-password"]' | base64 -d) - -# Prepare user creation query -USER_CREATION_QUERY=" --- Create user -CREATE USER "$DB_USERNAME" WITH PASSWORD '$GENERATED_PASSWORD'; -" - -# Execute user creation using PostgreSQL client pod -../run_query_in_pod.sh "$SERVICE_HOSTNAME" "$SERVICE_PORT" "$SERVICE_DBNAME" "postgres" "$ADMIN_PASSWORD" "$USER_CREATION_QUERY" "ddl" - -# After create we run edit to set permissions -./update-database-user -# Update link results with connection details -JSON_RESPONSE=$(echo $NP_ACTION_CONTEXT | jq ".notification.parameters + { - username: \"$DB_USERNAME\", - password: \"$GENERATED_PASSWORD\" -}") - -np link action update --results "$JSON_RESPONSE" \ No newline at end of file diff --git a/databases/postgres/k8s/postgres-db/link/delete-database-user b/databases/postgres/k8s/postgres-db/link/delete-database-user deleted file mode 100755 index 80b9d86..0000000 --- a/databases/postgres/k8s/postgres-db/link/delete-database-user +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - -set -e -export WORKING_DIRECTORY_ORIGINAL="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $WORKING_DIRECTORY_ORIGINAL - -# Get service connection details -SERVICE_HOSTNAME=$ACTION_SERVICE_ATTRIBUTES_HOSTNAME -SERVICE_PORT=$ACTION_SERVICE_ATTRIBUTES_PORT -SERVICE_DBNAME=$ACTION_SERVICE_ATTRIBUTES_DBNAME -SECRET_NAME=$ACTION_SERVICE_ATTRIBUTES_K_8_S_SECRET_NAME - -# Get link parameters -USERNAME=$ACTION_LINK_ATTRIBUTES_USERNAME - -# Get admin credentials from K8s secret -ADMIN_PASSWORD=$(kubectl get secret $SECRET_NAME -n postgres-db -o json | jq -r '.data["postgres-password"]' | base64 -d) - -# Connect to PostgreSQL and delete user -QUERY=$(cat << EOF --- Revoke all privileges first -REVOKE ALL PRIVILEGES ON DATABASE "$SERVICE_DBNAME" FROM "$USERNAME"; -REVOKE ALL PRIVILEGES ON SCHEMA public FROM "$USERNAME"; -REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM "$USERNAME"; -REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM "$USERNAME"; -ALTER USER "$USERNAME" WITH NOSUPERUSER; - --- Reassign or drop owned objects -REASSIGN OWNED BY "$USERNAME" TO postgres; -DROP OWNED BY "$USERNAME"; - --- Now drop the user -DROP USER IF EXISTS "$USERNAME"; -EOF -) - -../run_query_in_pod.sh "$SERVICE_HOSTNAME" "$SERVICE_PORT" "$SERVICE_DBNAME" "postgres" "$ADMIN_PASSWORD" "$QUERY" "ddl" - - -echo "User $USERNAME deleted successfully" \ No newline at end of file diff --git a/databases/postgres/k8s/postgres-db/link/update-database-user b/databases/postgres/k8s/postgres-db/link/update-database-user deleted file mode 100755 index 0d549da..0000000 --- a/databases/postgres/k8s/postgres-db/link/update-database-user +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash - -set -e -export WORKING_DIRECTORY_ORIGINAL="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $WORKING_DIRECTORY_ORIGINAL -../ensure_psql.sh - -# Get service connection details -SERVICE_HOSTNAME=$ACTION_SERVICE_ATTRIBUTES_HOSTNAME -SERVICE_PORT=$ACTION_SERVICE_ATTRIBUTES_PORT -SERVICE_DBNAME=$ACTION_SERVICE_ATTRIBUTES_DBNAME -SECRET_NAME=$ACTION_SERVICE_ATTRIBUTES_K_8_S_SECRET_NAME - -if [[ $DB_USERNAME == "" ]]; then - DB_USERNAME=$ACTION_LINK_ATTRIBUTES_USERNAME -fi - - -# Get admin credentials from K8s secret -ADMIN_PASSWORD=$(kubectl get secret $SECRET_NAME -n postgres-db -o json | jq -r '.data["postgres-password"]' | base64 -d) - -# Prepare user update query -USER_UPDATE_QUERY=" - --- Revoke all existing privileges -REVOKE ALL PRIVILEGES ON DATABASE "$SERVICE_DBNAME" FROM "$DB_USERNAME"; -REVOKE ALL PRIVILEGES ON SCHEMA public FROM "$DB_USERNAME"; -REVOKE ALL PRIVILEGES ON ALL TABLES IN SCHEMA public FROM "$DB_USERNAME"; -REVOKE ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public FROM "$DB_USERNAME"; -ALTER USER "$DB_USERNAME" WITH NOSUPERUSER; -" - -if [[ "$ACTION_PARAMETERS_PERMISIONS_READ" == "true" ]]; then - USER_UPDATE_QUERY+=" -GRANT CONNECT ON DATABASE \"$SERVICE_DBNAME\" TO \"$DB_USERNAME\"; -GRANT USAGE ON SCHEMA public TO \"$DB_USERNAME\"; -GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"$DB_USERNAME\"; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO \"$DB_USERNAME\"; -" -fi -if [[ "$ACTION_PARAMETERS_PERMISIONS_WRITE" == "true" ]]; then - USER_UPDATE_QUERY+=" -GRANT CONNECT ON DATABASE \"$SERVICE_DBNAME\" TO \"$DB_USERNAME\"; -GRANT USAGE, CREATE ON SCHEMA public TO \"$DB_USERNAME\"; -GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO \"$DB_USERNAME\"; -GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO \"$DB_USERNAME\"; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO \"$DB_USERNAME\"; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT ON SEQUENCES TO \"$DB_USERNAME\"; -" -fi - -if [[ "$ACTION_PARAMETERS_PERMISIONS_ADMIN" == "true" ]]; then - USER_UPDATE_QUERY+=" -ALTER USER \"$DB_USERNAME\" WITH SUPERUSER; -" -fi - -# Execute user update using PostgreSQL client pod -../run_query_in_pod.sh "$SERVICE_HOSTNAME" "$SERVICE_PORT" "$SERVICE_DBNAME" "postgres" "$ADMIN_PASSWORD" "$USER_UPDATE_QUERY" "ddl" - -# Update link results with connection details -JSON_RESPONSE=$(echo $NP_ACTION_CONTEXT | jq ".notification.parameters + { - permisions: { - read: $ACTION_PARAMETERS_PERMISIONS_READ, - write: $ACTION_PARAMETERS_PERMISIONS_WRITE, - admin: $ACTION_PARAMETERS_PERMISIONS_ADMIN - } -}") - -np link action update --results "$JSON_RESPONSE" \ No newline at end of file diff --git a/databases/postgres/k8s/postgres-db/run_query_in_pod.sh b/databases/postgres/k8s/postgres-db/run_query_in_pod.sh deleted file mode 100755 index 0328c3e..0000000 --- a/databases/postgres/k8s/postgres-db/run_query_in_pod.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/bin/bash - -# Function to run PostgreSQL queries using Bitnami PostgreSQL client pod -# Usage: run_query_in_pod [query_type] -# query_type: "ddl" or "dml" (default: "dml") - -set -e -HOSTNAME=$1 -PORT=$2 -DBNAME=$3 -USERNAME=$4 -PASSWORD=$5 -QUERY=$6 -QUERY_TYPE=${7:-"dml"} -QUERY_OUTPUT_FILE=$8 -if [ -z "$HOSTNAME" ] || [ -z "$PORT" ] || [ -z "$DBNAME" ] || [ -z "$USERNAME" ] || [ -z "$PASSWORD" ] || [ -z "$QUERY" ]; then - echo "Usage: run_query_in_pod [query_type]" - exit 1 -fi - -# Generate unique names -TIMESTAMP=$(date +%s) -RANDOM_ID=$(uuidgen | tr '[:upper:]' '[:lower:]' | tr -d '-' | cut -c1-8) -POD_NAME="psql-client-${TIMESTAMP}-${RANDOM_ID}" -SECRET_NAME="psql-client-secret-${TIMESTAMP}-${RANDOM_ID}" -CONFIGMAP_NAME="psql-client-query-${TIMESTAMP}-${RANDOM_ID}" - -# Clean up function (only deletes secret and configmap, leaves pod for debugging on failure) -cleanup() { - kubectl delete pod $POD_NAME -n postgres-db --ignore-not-found=true 2>/dev/null || true - kubectl delete secret $SECRET_NAME -n postgres-db --ignore-not-found=true 2>/dev/null || true - kubectl delete configmap $CONFIGMAP_NAME -n postgres-db --ignore-not-found=true 2>/dev/null || true - rm -f /tmp/${POD_NAME}-pod.yaml 2>/dev/null || true - rm -f /tmp/${POD_NAME}-query.sql 2>/dev/null || true -} -trap cleanup EXIT - -# Create temporary SQL file -SQL_FILE="/tmp/${POD_NAME}-query.sql" -echo "$QUERY" > "$SQL_FILE" - -# Create ConfigMap with the SQL query -echo "Creating ConfigMap with SQL query..." -kubectl create configmap $CONFIGMAP_NAME -n postgres-db --from-file=query.sql="$SQL_FILE" - -# Create secret with database credentials -echo "Creating Secret with database credentials..." -kubectl create secret generic $SECRET_NAME -n postgres-db \ - --from-literal=hostname="$HOSTNAME" \ - --from-literal=port="$PORT" \ - --from-literal=dbname="$DBNAME" \ - --from-literal=username="$USERNAME" \ - --from-literal=password="$PASSWORD" - -# Prepare psql command flags based on query type -if [ "$QUERY_TYPE" = "dml" ]; then - PSQL_FLAGS="-t -A -F','" -else - PSQL_FLAGS="" -fi - -# Create pod YAML manifest -cat > /tmp/${POD_NAME}-pod.yaml << EOF -apiVersion: v1 -kind: Pod -metadata: - name: $POD_NAME - namespace: postgres-db -spec: - restartPolicy: Never - containers: - - name: psql-client - image: bitnami/postgresql:latest - command: ["/bin/bash", "-c"] - args: - - | - PGPASSWORD="\$DB_PASSWORD" psql -h "\$DB_HOSTNAME" -p "\$DB_PORT" -U "\$DB_USERNAME" -d "\$DB_DBNAME" $PSQL_FLAGS -f /sql/query.sql - env: - - name: DB_HOSTNAME - valueFrom: - secretKeyRef: - name: $SECRET_NAME - key: hostname - - name: DB_PORT - valueFrom: - secretKeyRef: - name: $SECRET_NAME - key: port - - name: DB_DBNAME - valueFrom: - secretKeyRef: - name: $SECRET_NAME - key: dbname - - name: DB_USERNAME - valueFrom: - secretKeyRef: - name: $SECRET_NAME - key: username - - name: DB_PASSWORD - valueFrom: - secretKeyRef: - name: $SECRET_NAME - key: password - volumeMounts: - - name: sql-query - mountPath: /sql - readOnly: true - volumes: - - name: sql-query - configMap: - name: $CONFIGMAP_NAME -EOF - -# Apply the pod manifest -echo "Creating pod $POD_NAME..." -kubectl apply -f /tmp/${POD_NAME}-pod.yaml - -POD_STATUS=$(kubectl get pod $POD_NAME -n postgres-db -o jsonpath='{.status.phase}' 2>/dev/null || echo "NotFound") -MAX_RETRIES=30 -RETRY_COUNT=0 -while [[ "$POD_STATUS" == "Pending" || "$POD_STATUS" == "ContainerCreating" || "$POD_STATUS" == "Running" ]] && [[ $RETRY_COUNT -lt $MAX_RETRIES ]]; do - echo "Pod is still pending or creating, waiting..." - sleep 5 - POD_STATUS=$(kubectl get pod $POD_NAME -n postgres-db -o jsonpath='{.status.phase}' 2>/dev/null || echo "NotFound") - ((++RETRY_COUNT)) || true -done -echo "Pod status: $POD_STATUS" - -# Show logs -echo "Pod logs:" -export QUERY_LOGS=$(kubectl logs $POD_NAME -n postgres-db --follow || true) - -# Check final status - - -if [[ "$QUERY_OUTPUT_FILE" != "" ]]; then - echo $QUERY_LOGS > $QUERY_OUTPUT_FILE -fi - - - - -if [ "$POD_STATUS" = "Succeeded" ]; then - exit 0 -else - echo "Query execution failed or pod did not complete successfully." - exit 1; -fi \ No newline at end of file diff --git a/databases/postgres/k8s/postgres-db/service/create-postgres-db b/databases/postgres/k8s/postgres-db/service/create-postgres-db deleted file mode 100755 index 87c2ec2..0000000 --- a/databases/postgres/k8s/postgres-db/service/create-postgres-db +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash -set -e -export WORKING_DIRECTORY_ORIGINAL="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $WORKING_DIRECTORY_ORIGINAL - -source ./handle-helm.sh - -# Wait for PostgreSQL service to be ready -SERVICE_IP="" -MAX_RETRIES=60 -RETRY_COUNT=0 - -echo "Waiting for PostgreSQL service to be ready..." -while [[ -z "$SERVICE_IP" && $RETRY_COUNT -lt $MAX_RETRIES ]]; do - SERVICE_IP=$(kubectl get svc $PROJECT-postgres -n postgres-db -o json 2>/dev/null | jq ".spec.clusterIP" -r 2>/dev/null || true) - if [[ -z "$SERVICE_IP" || "$SERVICE_IP" == "null" ]]; then - echo "Waiting for service IP... (attempt $((RETRY_COUNT + 1))/$MAX_RETRIES)" - sleep 10 - ((RETRY_COUNT++)) - fi -done - -if [[ -z "$SERVICE_IP" || "$SERVICE_IP" == "null" ]]; then - echo "Failed to get PostgreSQL service IP after $MAX_RETRIES attempts" - exit 1 -fi - -# Wait for PostgreSQL pod to be ready -echo "Waiting for PostgreSQL pod to be ready..." -kubectl wait --for=condition=ready pod -l app.kubernetes.io/instance=$PROJECT-postgres -n postgres-db --timeout=300s || true - -# Get database name and generate secret name -DB_NAME="${ACTION_PARAMETERS_USAGE_TYPE:-app}_db" -SECRET_NAME="$PROJECT-postgres-credentials" -HELM_RELEASE_NAME="$PROJECT-postgres" - -# Construct response with connection details -JSON_RESPONSE=$(echo $NP_ACTION_CONTEXT | jq "{ - hostname: \"$SERVICE_IP\", - port: 5432, - dbname: \"$DB_NAME\", - helm_release_name: \"$HELM_RELEASE_NAME\", - k8s_secret_name: \"$SECRET_NAME\" -}") - -np service action update --results "$JSON_RESPONSE" \ No newline at end of file diff --git a/databases/postgres/k8s/postgres-db/service/delete-postgres-db b/databases/postgres/k8s/postgres-db/service/delete-postgres-db deleted file mode 100755 index 0d01b58..0000000 --- a/databases/postgres/k8s/postgres-db/service/delete-postgres-db +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -set -e -export WORKING_DIRECTORY_ORIGINAL="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $WORKING_DIRECTORY_ORIGINAL - -source ./project.sh -source ./ensure_helm_deps.sh - -echo "Deleting PostgreSQL service..." - -# Uninstall Helm chart -helm uninstall $PROJECT-postgres -n postgres-db || true - -# Delete specific persistent volume claims for this PostgreSQL instance -echo "Deleting persistent volume claims for $PROJECT-postgres..." -kubectl delete pvc data-$PROJECT-postgres-0 -n postgres-db --ignore-not-found=true - -# Get the specific PV that was bound to our PVC and delete it -echo "Cleaning up associated persistent volume..." -PV_NAME=$(kubectl get pv -o json | jq -r '.items[] | select(.spec.claimRef.name == "data-'$PROJECT'-postgres-0" and .spec.claimRef.namespace == "postgres-db") | .metadata.name' 2>/dev/null || true) -if [ -n "$PV_NAME" ]; then - echo "Deleting persistent volume: $PV_NAME" - kubectl delete pv $PV_NAME --ignore-not-found=true || true -fi - -# Delete the secret -kubectl delete secret $PROJECT-postgres-credentials -n postgres-db --ignore-not-found=true - -echo "PostgreSQL service and volumes deleted successfully" \ No newline at end of file diff --git a/databases/postgres/k8s/postgres-db/service/ensure_helm_deps.sh b/databases/postgres/k8s/postgres-db/service/ensure_helm_deps.sh deleted file mode 100644 index b249f93..0000000 --- a/databases/postgres/k8s/postgres-db/service/ensure_helm_deps.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -# Ensure curl is available (needed for binary downloads) -if ! command -v curl &>/dev/null; then - apk add --no-cache curl -fi - -# Ensure openssl is installed (used for password generation) -if ! command -v openssl &>/dev/null; then - apk add --no-cache openssl -fi - -# Ensure jq is installed (used for JSON processing) -if ! command -v jq &>/dev/null; then - apk add --no-cache jq -fi - -# Ensure kubectl is installed -if ! command -v kubectl &>/dev/null; then - apk add --no-cache kubectl 2>/dev/null || { - KUBECTL_VERSION=$(curl -fsSL https://dl.k8s.io/release/stable.txt) - curl -fsSL -o /usr/local/bin/kubectl \ - "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl" - chmod +x /usr/local/bin/kubectl - } -fi - -# Ensure helm is installed -if ! command -v helm &>/dev/null; then - apk add --no-cache helm 2>/dev/null || { - HELM_VERSION="v3.17.3" - curl -fsSL -o /tmp/helm.tar.gz \ - "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz" - tar -xzf /tmp/helm.tar.gz -C /tmp - mv /tmp/linux-amd64/helm /usr/local/bin/helm - chmod +x /usr/local/bin/helm - rm -rf /tmp/helm.tar.gz /tmp/linux-amd64 - } -fi - -# Ensure gomplate is installed (not available in apk repos) -if ! command -v gomplate &>/dev/null; then - GOMPLATE_VERSION="v3.11.7" - curl -fsSL -o /usr/local/bin/gomplate \ - "https://github.com/hairyhenderson/gomplate/releases/download/${GOMPLATE_VERSION}/gomplate_linux-amd64" - chmod +x /usr/local/bin/gomplate -fi diff --git a/databases/postgres/k8s/postgres-db/service/handle-helm.sh b/databases/postgres/k8s/postgres-db/service/handle-helm.sh deleted file mode 100755 index 740f7b4..0000000 --- a/databases/postgres/k8s/postgres-db/service/handle-helm.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -export WORKING_DIRECTORY_ORIGINAL="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $WORKING_DIRECTORY_ORIGINAL - -source ./project.sh -source ./ensure_helm_deps.sh - -# Add Bitnami Helm repo if not already added -helm repo add bitnami https://charts.bitnami.com/bitnami || true -helm repo update - -# Get parameters -USAGE_TYPE=$ACTION_PARAMETERS_USAGE_TYPE -PII_ENABLED=${ACTION_PARAMETERS_PII:-false} -DB_NAME="${USAGE_TYPE:-app}_db" - -# Generate random password for PostgreSQL superuser -POSTGRES_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25) - -# Create Kubernetes secret for PostgreSQL credentials -kubectl create namespace postgres-db --dry-run=client -o yaml | kubectl apply -f - - -# Create secret with database credentials -kubectl create secret generic $PROJECT-postgres-credentials \ - --from-literal=postgres-password="$POSTGRES_PASSWORD" \ - --from-literal=username=postgres \ - --from-literal=password="$POSTGRES_PASSWORD" \ - --from-literal=database="$DB_NAME" \ - -n postgres-db \ - --dry-run=client -o yaml | kubectl apply -f - - -echo '{"projectName":"'"$PROJECT"'","usageType":"'"$USAGE_TYPE"'","piiEnabled":'"$PII_ENABLED"',"dbName":"'"$DB_NAME"'","postgresPassword":"'"$POSTGRES_PASSWORD"'"}' > /tmp/context-$PROJECT.json - -gomplate \ - --context .=/tmp/context-$PROJECT.json \ - -f values.yaml.tpl > /tmp/values-$PROJECT.yaml - -# Install using Bitnami PostgreSQL chart -helm upgrade --install -n postgres-db $PROJECT-postgres bitnami/postgresql -f /tmp/values-$PROJECT.yaml --create-namespace > /dev/null \ No newline at end of file diff --git a/databases/postgres/k8s/postgres-db/service/project.sh b/databases/postgres/k8s/postgres-db/service/project.sh deleted file mode 100755 index 8bc20a6..0000000 --- a/databases/postgres/k8s/postgres-db/service/project.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -export PROJECT=$ACTION_SERVICE_SLUG-$ACTION_TAGS_APPLICATION_ID diff --git a/databases/postgres/k8s/postgres-db/service/run-ddl-query b/databases/postgres/k8s/postgres-db/service/run-ddl-query deleted file mode 100755 index 8b3541d..0000000 --- a/databases/postgres/k8s/postgres-db/service/run-ddl-query +++ /dev/null @@ -1,35 +0,0 @@ -#!/bin/bash - -set -e -export WORKING_DIRECTORY_ORIGINAL="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $WORKING_DIRECTORY_ORIGINAL - -# Get service connection details -SERVICE_HOSTNAME=$ACTION_SERVICE_ATTRIBUTES_HOSTNAME -SERVICE_PORT=$ACTION_SERVICE_ATTRIBUTES_PORT -SERVICE_DBNAME=$ACTION_SERVICE_ATTRIBUTES_DBNAME -SECRET_NAME=$ACTION_SERVICE_ATTRIBUTES_K_8_S_SECRET_NAME - -# Re export due encoding -eval "echo $(np service-action export-action-data --format bash --bash-prefix ACTION)" -# Get query parameter -QUERY="$ACTION_PARAMETERS_QUERY" -# Validate that this is a DDL query -if ! echo "$QUERY" | grep -iE "^\s*(CREATE|ALTER|DROP|TRUNCATE)" > /dev/null; then - ERROR_MSG="Only DDL queries (CREATE, ALTER, DROP, TRUNCATE) are allowed in this action. Use run-dml-query for SELECT, INSERT, UPDATE, DELETE." - JSON_RESPONSE='{"error": "'$ERROR_MSG'", "results": ""}' - np service action update --results "$JSON_RESPONSE" - exit 1 -fi - -# Get admin credentials from K8s secret -ADMIN_PASSWORD=$(kubectl get secret $SECRET_NAME -n postgres-db -o json | jq -r '.data["postgres-password"]' | base64 -d) - -# Execute the DDL query using PostgreSQL client pod -ERROR_MSG="" -RESULT_MSG="" -OUTPUT_FILE="/tmp/ddl_query_output-$ACTION_ID.txt" -../run_query_in_pod.sh "$SERVICE_HOSTNAME" "$SERVICE_PORT" "$SERVICE_DBNAME" "postgres" "$ADMIN_PASSWORD" "$QUERY" "ddl" "$OUTPUT_FILE" -ENCODED_OUTPUT=$(printf '%s' "$(cat $OUTPUT_FILE)" | jq -Rs .) -JSON_RESPONSE="{\"results\": $ENCODED_OUTPUT}" -np service action update --results "$JSON_RESPONSE" \ No newline at end of file diff --git a/databases/postgres/k8s/postgres-db/service/run-dml-query b/databases/postgres/k8s/postgres-db/service/run-dml-query deleted file mode 100755 index d1bedb8..0000000 --- a/databases/postgres/k8s/postgres-db/service/run-dml-query +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -set -e -export WORKING_DIRECTORY_ORIGINAL="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $WORKING_DIRECTORY_ORIGINAL - -# Get service connection details -SERVICE_HOSTNAME=$ACTION_SERVICE_ATTRIBUTES_HOSTNAME -SERVICE_PORT=$ACTION_SERVICE_ATTRIBUTES_PORT -SERVICE_DBNAME=$ACTION_SERVICE_ATTRIBUTES_DBNAME -SECRET_NAME=$ACTION_SERVICE_ATTRIBUTES_K_8_S_SECRET_NAME - -# Re export due encoding -eval "echo $(np service-action export-action-data --format bash --bash-prefix ACTION)" -# Get query parameter -QUERY="$ACTION_PARAMETERS_QUERY" - -# Validate that this is a DML query (not DDL) -if echo "$QUERY" | grep -iE "^\s*(CREATE|ALTER|DROP|TRUNCATE)" > /dev/null; then - ERROR_MSG="DDL queries are not allowed in DML action. Use run-ddl-query instead." - JSON_RESPONSE='{"error": "'$ERROR_MSG'"}' - np service action update --results "$JSON_RESPONSE" - exit 1 -fi - -# validate if query is a select to wrap it as json -if echo "$QUERY" | grep -iE "^\s*SELECT" > /dev/null; then - QUERY="SELECT json_agg(row_to_json(t)) FROM ($QUERY) t;" - export is_select_query=true -fi - -# Get admin credentials from K8s secret -ADMIN_PASSWORD=$(kubectl get secret $SECRET_NAME -n postgres-db -o json | jq -r '.data["postgres-password"]' | base64 -d) - -# Execute the DDL query using PostgreSQL client pod -ERROR_MSG="" -RESULT_MSG="" -OUTPUT_FILE="/tmp/ddl_query_output-$ACTION_ID.txt" -../run_query_in_pod.sh "$SERVICE_HOSTNAME" "$SERVICE_PORT" "$SERVICE_DBNAME" "postgres" "$ADMIN_PASSWORD" "$QUERY" "dml" "$OUTPUT_FILE" -if [[ "$is_select_query" == "true" ]]; then - JSON=$(cat $OUTPUT_FILE | jq -r) - JSON_RESPONSE="{\"results\": $JSON}" -else - ENCODED_OUTPUT=$(printf '%s' "$(cat $OUTPUT_FILE)" | jq -Rs .) - JSON_RESPONSE="{\"textresult\": $ENCODED_OUTPUT}" -fi -np service action update --results "$JSON_RESPONSE" \ No newline at end of file diff --git a/databases/postgres/k8s/postgres-db/service/update-postgres-db b/databases/postgres/k8s/postgres-db/service/update-postgres-db deleted file mode 100755 index fe14840..0000000 --- a/databases/postgres/k8s/postgres-db/service/update-postgres-db +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -set -e -export WORKING_DIRECTORY_ORIGINAL="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -cd $WORKING_DIRECTORY_ORIGINAL - -# For updates, we just re-run the Helm deployment with new values -source ./handle-helm.sh - -echo "PostgreSQL service updated successfully" \ No newline at end of file diff --git a/databases/postgres/k8s/postgres-db/service/values.yaml.tpl b/databases/postgres/k8s/postgres-db/service/values.yaml.tpl deleted file mode 100755 index d569f10..0000000 --- a/databases/postgres/k8s/postgres-db/service/values.yaml.tpl +++ /dev/null @@ -1,49 +0,0 @@ -# Bitnami PostgreSQL Helm chart values -nameOverride: "{{ .projectName }}-postgres" -fullnameOverride: "{{ .projectName }}-postgres" - -# Use existing secret for authentication -auth: - existingSecret: "{{ .projectName }}-postgres-credentials" - secretKeys: - adminPasswordKey: "postgres-password" - userPasswordKey: "password" - database: "{{ .dbName }}" - username: "postgres" - -# Persistence configuration -primary: - persistence: - enabled: true - size: 10Gi - - resources: - limits: - cpu: 500m - memory: 512Mi - requests: - cpu: 100m - memory: 256Mi - -{{- if .piiEnabled }} - securityContext: - enabled: true - runAsNonRoot: true - runAsUser: 1001 - fsGroup: 1001 -{{- end }} - -# Service configuration -service: - type: ClusterIP - ports: - postgresql: 5432 - -# Common labels -commonLabels: - usage-type: "{{ .usageType }}" - pii-enabled: "{{ .piiEnabled }}" - -# Metrics (optional) -metrics: - enabled: false \ No newline at end of file diff --git a/databases/postgres/k8s/specs/actions/run-ddl-query.json b/databases/postgres/k8s/specs/actions/run-ddl-query.json deleted file mode 100644 index a5a2c78..0000000 --- a/databases/postgres/k8s/specs/actions/run-ddl-query.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "Run DDL Query", - "slug": "run-ddl-query", - "type": "custom", - "annotations": {}, - "retryable": false, - "parameters": { - "schema": { - "type": "object", - "required": [ - "query" - ], - "uiSchema": { - "type": "VerticalLayout", - "elements": [ - { - "type": "Control", - "scope": "#/properties/query", - "options": { - "multi": true - } - } - ] - }, - "properties": { - "query": { - "type": "string" - } - } - }, - "values": {} - }, - "results": { - "schema": { - "type": "object", - "required": [], - "properties": { - "error": { - "type": "string" - }, - "results": { - "type": "string" - } - } - }, - "values": {} - } -} \ No newline at end of file diff --git a/databases/postgres/k8s/specs/actions/run-dml-query.json b/databases/postgres/k8s/specs/actions/run-dml-query.json deleted file mode 100644 index 90225f2..0000000 --- a/databases/postgres/k8s/specs/actions/run-dml-query.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "name": "Run DML Query", - "slug": "run-dml-query", - "type": "custom", - "annotations": {}, - "retryable": false, - "parameters": { - "schema": { - "type": "object", - "required": [ - "query" - ], - "uiSchema": { - "type": "VerticalLayout", - "elements": [ - { - "type": "Control", - "scope": "#/properties/query", - "options": { - "multi": true - } - } - ] - }, - "properties": { - "query": { - "type": "string" - } - } - }, - "values": {} - }, - "results": { - "schema": { - "type": "object", - "required": [], - "properties": { - "error": { - "type": "string" - }, - "results": { - "type": "array", - "items": { - "type": "object" - } - }, - "textresult": { - "type": "string" - } - } - }, - "values": {} - } -} \ No newline at end of file diff --git a/databases/postgres/k8s/specs/links/database-user.json b/databases/postgres/k8s/specs/links/database-user.json deleted file mode 100644 index cbb8595..0000000 --- a/databases/postgres/k8s/specs/links/database-user.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name": "database-user", - "slug": "database-user", - "visible_to": [], - "unique": false, - "dimensions": {}, - "assignable_to": "any", - "use_default_actions": true, - "attributes": { - "schema": { - "type": "object", - "required": [ - "permisions" - ], - "properties": { - "password": { - "type": "string", - "export": { - "type": "environment_variable", - "secret": true - }, - "secret": true, - "visibleOn": [ - "read" - ], - "editableOn": [] - }, - "username": { - "type": "string", - "export": true, - "visibleOn": [ - "read" - ], - "editableOn": [] - }, - "permisions": { - "type": "object", - "properties": { - "read": { - "type": "boolean", - "default": true, - "description": "User will have read permisions" - }, - "admin": { - "type": "boolean", - "default": false, - "description": "User will have DDL permisions" - }, - "write": { - "type": "boolean", - "default": false, - "description": "User will have write permisions" - } - } - } - } - }, - "values": {} - }, - "selectors": { - "category": "any", - "imported": false, - "provider": "any", - "sub_category": "any" - } -} \ No newline at end of file diff --git a/databases/postgres/k8s/specs/service-spec.json b/databases/postgres/k8s/specs/service-spec.json deleted file mode 100644 index 1894f50..0000000 --- a/databases/postgres/k8s/specs/service-spec.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "name": "Postgres DB", - "slug": "postgres-db", - "type": "dependency", - "use_default_actions": true, - "available_actions": [ - "run-ddl-query", - "run-dml-query" - ], - "available_links": [ - "database-user" - ], - "agent_command":{ - "data": { - "cmdline": "nullplatform/services/databases/postgres/k8s/handle-service-agent", - "environment": { - "NP_ACTION_CONTEXT": "${NOTIFICATION_CONTEXT}" - } - }, - "type": "exec" - }, - "attributes": { - "schema": { - "type": "object", - "required": [ - "usage_type", - "pii" - ], - "properties": { - "pii": { - "type": "boolean", - "default": false, - "description": "Will you store personal user information (email, name, id, etc)?" - }, - "port": { - "type": "number", - "export": true, - "visibleOn": [ - "read" - ], - "editableOn": [] - }, - "dbname": { - "type": "string", - "export": true, - "visibleOn": [ - "read" - ], - "editableOn": [] - }, - "hostname": { - "type": "string", - "export": true, - "visibleOn": [ - "read" - ], - "editableOn": [] - }, - "usage_type": { - "enum": [ - "transactions", - "cache", - "configurations" - ], - "type": "string", - "description": "What this database is used for?" - }, - "k8s_secret_name": { - "type": "string", - "export": false, - "visibleOn": [], - "editableOn": [] - }, - "helm_release_name": { - "type": "string", - "export": false, - "visibleOn": [], - "editableOn": [] - } - } - }, - "values": {} - }, - "selectors": { - "category": "Database", - "imported": false, - "provider": "K8S", - "sub_category": "Relational Database" - } -} diff --git a/endpoint-exposer/README.md b/endpoint-exposer/README.md deleted file mode 100644 index 83de871..0000000 --- a/endpoint-exposer/README.md +++ /dev/null @@ -1,190 +0,0 @@ -# Endpoint Exposer Service - -## Overview - -The **endpoint-exposer** service is a infrastructure component of Nnullplatform that manages dynamic exposure of application endpoints through public and private domains. It functions as a route orchestrator that translates high-level specifications into native Kubernetes configurations using HttpRoutes. - -## Core Responsibilities - -### 1. Dynamic Endpoint Management -- Expose application endpoints declaratively -- Configure separate public and private domains for different access levels -- Update route configurations with zero downtime -- Maintain configuration synchronized with desired state - -### 2. Route Configuration -- Define route patterns (exact, regex, wildcards) -- Specify allowed HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS) -- Associate routes with nullplatform scopes for access control -- Control route visibility (public vs. private) - -### 3. Kubernetes and Istio Integration -- Generate HTTPRoute resources (Kubernetes Gateway API v1) - -### 4. Scope-Based Access Control -- Map endpoints to specific nullplatform scopes - -## Key Features - -### Route Management -```yaml -routes: - - method: GET - path: /api/users - scope: user-management - visible_on: public -``` - -- **Path Types**: - - Exact: `/api/users` - - Regex with parameters: `/api/users/{id}` - - Wildcard: `/api/users/*` - -- **HTTP Methods**: Supports all standard HTTP methods -- **Visibility**: Public or private routes on separate domains - -### Domain Separation - -**Public Domain:** -- Endpoints accessible from the internet -- Typically for public APIs -- Connected to `gateway-public` gateway - -**Private Domain:** -- Internal organization endpoints -- Requires private network access -- Connected to `gateway-private` gateway - -## Architecture - -### Workflow - -1. **Build Context** - - Extracts service action parameters - - Retrieves Kubernetes namespace information - - Classifies routes by visibility (public/private) - -2. **Build HTTPRoutes** - - Generates base HTTPRoute templates per domain - - Queries scopes associated with each route - - Constructs Istio routing rules - -3. **Process Routes** - - Sorts routes by specificity (exact > regex > prefix) - - Generates AuthorizationPolicies if authorization is enabled - - Maps scope IDs to backend services - -4. **Apply Configuration** - - Applies generated YAML manifests to the cluster - - Manages cleanup of obsolete resources - - Maintains tracking of applied resources - -### Technologies - -- **Kubernetes**: Orchestration platform (Gateway API v1) -- **Istio**: Service mesh for traffic management and security -- **Bash**: Workflow scripting and automation -- **jq**: JSON processing and manipulation -- **gomplate**: Resource template generation -- **kubectl**: Kubernetes resource management - -## File Structure - -``` -/endpoint-exposer -├── configure # Service configuration script -├── entrypoint/ # Entry points for actions -│ ├── service-action # Service action handler -├── specs/ # Service specifications -│ └── service-specification.json -├── workflows/istio/ # Workflow definitions -│ └── service-action.json -├── scripts/istio/ # Core routing logic -│ ├── build_context -│ ├── build_httproute -│ ├── process_routes -│ ├── build_rule -│ └── build_ingress_with_rule -├── scripts/common/ # Shared utilities -│ ├── apply -│ └── delete -├── templates/istio/ # K8s resource templates -│ └── httproute.yaml.tmpl -├── test/ # BATS test suite -└── container-scope-override/ # Custom deployment support for override scope agent -``` - -## Configuration - -### Environment Variables - -- `K8S_NAMESPACE`: Kubernetes namespace for resources (default: `nullplatform`) -- `PUBLIC_GATEWAY_NAME`: Public gateway name (default: `gateway-public`) -- `PRIVATE_GATEWAY_NAME`: Private gateway name (default: `gateway-private`) -- `GATEWAY_NAMESPACE`: Gateway namespace (default: `gateways`) - -### Route Configuration Example - -```json -{ - "routes": [ - { - "method": "GET", - "path": "/api/v1/resource/{id}", - "scope": "resource-read", - "visible_on": "public", - }, - { - "method": "POST", - "path": "/api/v1/resource", - "scope": "resource-write", - "visible_on": "private", - } - ], - "public_domain": "api.example.com", - "private_domain": "internal-api.example.com" -} -``` - -## Testing - -The service uses BATS (Bash Automated Testing System) for testing: - -```bash -# Run all tests -./test/run-tests.sh - -# Run specific tests -bats test/istio/ -``` - -Tests cover: -- Simple routes -- Public and private routes -- Authorization scenarios -- JWT configurations -- Manifest generation - -## Operations - -### Create/Update Endpoints - -The service responds to Nullplatform actions: -- `create`: Generates and applies initial configuration -- `update`: Modifies existing configuration -- `delete`: Cleans up Kubernetes resources - -### Monitoring - -Generated resources can be monitored with: - -```bash -# View HTTPRoutes -kubectl get httproutes -n - -# View AuthorizationPolicies -kubectl get authorizationpolicies -n - -# View gateway status -kubectl get gateway -n gateways -``` \ No newline at end of file diff --git a/endpoint-exposer/container-scope-override/deployment/sync_exposer b/endpoint-exposer/container-scope-override/deployment/sync_exposer deleted file mode 100755 index 06d1058..0000000 --- a/endpoint-exposer/container-scope-override/deployment/sync_exposer +++ /dev/null @@ -1,172 +0,0 @@ -#!/bin/bash - -echo "=== DEBUG: Starting sync_exposer script ===" - -APPLICATION_NRN=$(jq -r .application.nrn <<< "$CONTEXT") - -echo "SERVICE SPECIFICATION SLUG: $SERVICE_SPECIFICATION_SLUG, APPLICATION_NRN: $APPLICATION_NRN" - -# Step 1: Get service specification by slug -echo "DEBUG: Fetching service specifications..." -SERVICE_SPECS=$(np service specification list --nrn "$APPLICATION_NRN" --type dependency --format json) -SERVICE_SPEC=$(jq -c --arg slug "$SERVICE_SPECIFICATION_SLUG" ' - .results - | map(select(.slug == $slug)) - | .[0] -' <<< "$SERVICE_SPECS") - -SERVICE_SPEC_ID=$(jq -r .id <<< "$SERVICE_SPEC") - -if [[ -z "$SERVICE_SPEC_ID" || "$SERVICE_SPEC_ID" == "null" ]]; then - echo "Error: Could not find service specification with slug '$SERVICE_SPECIFICATION_SLUG'" - exit 1 -fi - -echo "DEBUG: SERVICE_SPEC_ID=$SERVICE_SPEC_ID" - -# Step 2: Get service instance that matches the SERVICE_SPEC_ID -echo "DEBUG: Fetching services for application..." -SERVICES=$(np service list --nrn "$APPLICATION_NRN" --format json) - -SERVICE=$(jq -c --arg spec_id "$SERVICE_SPEC_ID" ' - .results - | map(select(.specification_id == $spec_id)) - | .[0] -' <<< "$SERVICES") - -SERVICE_ID=$(jq -r .id <<< "$SERVICE") - -if [[ -z "$SERVICE_ID" || "$SERVICE_ID" == "null" ]]; then - echo "Could not find service instance for specification '$SERVICE_SPEC_ID', skipping exposer sync" - exit 0 -fi - -echo "DEBUG: SERVICE_ID=$SERVICE_ID" - -# Step 3: Get service attributes as parameters -echo "DEBUG: Reading service attributes..." -SERVICE_DATA=$(np service read --id "$SERVICE_ID" --format json) -export PARAMETERS=$(jq -c .attributes <<< "$SERVICE_DATA") - -echo "DEBUG: PARAMETERS=$PARAMETERS" - -# Step 4: Get action specification with slug "update-" -ACTION_SLUG="update-$SERVICE_SPECIFICATION_SLUG" -echo "DEBUG: Fetching action specifications (looking for slug: $ACTION_SLUG)..." -SERVICE_ACTIONS=$(np service specification action specification list --serviceSpecificationId "$SERVICE_SPEC_ID" --format json) - -ACTION_SPEC=$(jq -c --arg slug "$ACTION_SLUG" ' - .results - | map(select(.slug == $slug)) - | .[0] -' <<< "$SERVICE_ACTIONS") - -ACTION_SPEC_ID=$(jq -r .id <<< "$ACTION_SPEC") - -if [[ -z "$ACTION_SPEC_ID" || "$ACTION_SPEC_ID" == "null" ]]; then - echo "Error: Could not find action specification with slug '$ACTION_SLUG' for service specification '$SERVICE_SPEC_ID'" - exit 1 -fi - -echo "DEBUG: ACTION_SPEC_ID=$ACTION_SPEC_ID" - -# Step 5: Create service action with parameters (with retry for concurrency) -echo "DEBUG: Creating service action..." - -MAX_CREATE_RETRIES=10 -RETRY_DELAY=5 -create_attempt=0 -ACTION_ID="" - -while [[ -z "$ACTION_ID" || "$ACTION_ID" == "null" ]]; do - ((create_attempt++)) - echo "DEBUG: Create attempt $create_attempt/$MAX_CREATE_RETRIES" - - if [ "$create_attempt" -gt $MAX_CREATE_RETRIES ]; then - echo "Error: Maximum number of create attempts (${MAX_CREATE_RETRIES}) reached. Could not create action." - exit 1 - fi - - # Add delay before retry (except on first attempt) - if [ "$create_attempt" -gt 1 ]; then - echo "DEBUG: Waiting ${RETRY_DELAY} seconds before retry..." - sleep $RETRY_DELAY - fi - - # Try to create the action - ACTION_RESPONSE=$(np service action create --serviceId "$SERVICE_ID" --body "$(jq -n --argjson params "$PARAMETERS" --arg spec_id "$ACTION_SPEC_ID" '{name: "update", parameters: $params, specification_id: $spec_id}')" --format json 2>&1 || true) - - # Check if response contains an error about action already in progress - if echo "$ACTION_RESPONSE" | grep -q "already an action with status.*in_progress"; then - echo "DEBUG: Action already in progress detected" - - # Try to find the existing in_progress action - echo "DEBUG: Attempting to find existing in_progress action..." - EXISTING_ACTIONS=$(np service action list --serviceId "$SERVICE_ID" --format json) - EXISTING_ACTION=$(echo "$EXISTING_ACTIONS" | jq -c --arg spec_id "$ACTION_SPEC_ID" ' - .results - | map(select(.specification_id == $spec_id and .status == "in_progress")) - | .[0] - ') - - EXISTING_ACTION_ID=$(echo "$EXISTING_ACTION" | jq -r '.id // empty') - - if [[ -n "$EXISTING_ACTION_ID" && "$EXISTING_ACTION_ID" != "null" ]]; then - echo "DEBUG: Found existing in_progress action with ID: $EXISTING_ACTION_ID" - ACTION_ID="$EXISTING_ACTION_ID" - echo "Using existing action instead of creating new one" - break - fi - - echo "DEBUG: No existing action found, will retry..." - elif echo "$ACTION_RESPONSE" | grep -q '"error"'; then - echo "ERROR: Failed to create action: $ACTION_RESPONSE" - echo "DEBUG: Will retry after delay..." - else - # Success - extract action ID - ACTION_ID=$(echo "$ACTION_RESPONSE" | jq -r '.id // empty') - - if [[ -n "$ACTION_ID" && "$ACTION_ID" != "null" ]]; then - echo "DEBUG: ACTION_ID=$ACTION_ID" - echo "Created endpoint exposer update action[id=$ACTION_ID], waiting for its completion" - break - else - echo "DEBUG: Could not extract ACTION_ID from response: $ACTION_RESPONSE" - echo "DEBUG: Will retry after delay..." - fi - fi -done - -# Step 6: Wait for action to complete -MAX_ITERATIONS=20 -iteration=0 - -echo "DEBUG: Starting polling loop for action status..." -while true; do - ((iteration++)) - echo "DEBUG: Iteration $iteration/$MAX_ITERATIONS" - - if [ "$iteration" -gt $MAX_ITERATIONS ]; then - echo "Error: Maximum number of iterations (${MAX_ITERATIONS}) reached. Could not update the endpoint exposer." - exit 1 - fi - - echo "DEBUG: Reading action status..." - ACTION_RESPONSE=$(np service action read --serviceId "$SERVICE_ID" --id "$ACTION_ID" --format json) - ACTION_STATUS=$(jq -r .status <<< "$ACTION_RESPONSE") - - echo "Checking endpoint exposer update action[id=$ACTION_ID, status=$ACTION_STATUS]" - - if [[ "$ACTION_STATUS" == "success" ]]; then - echo "✅ Endpoint exposer successfully updated" - break - elif [[ "$ACTION_STATUS" == "failed" ]]; then - echo "❌ Could not update endpoint exposer, deployment will be rollbacked" - exit 1 - fi - - echo "DEBUG: Sleeping for 5 seconds..." - sleep 5 -done - -echo "=== DEBUG: sync_exposer script completed successfully ===" diff --git a/endpoint-exposer/container-scope-override/deployment/workflows/blue_green.yaml b/endpoint-exposer/container-scope-override/deployment/workflows/blue_green.yaml deleted file mode 100644 index 6d43a5e..0000000 --- a/endpoint-exposer/container-scope-override/deployment/workflows/blue_green.yaml +++ /dev/null @@ -1,5 +0,0 @@ -steps: - - name: sync_exposer - type: script - file: "$OVERRIDES_PATH/deployment/sync_exposer" - after: apply diff --git a/endpoint-exposer/container-scope-override/deployment/workflows/delete.yaml b/endpoint-exposer/container-scope-override/deployment/workflows/delete.yaml deleted file mode 100644 index 6d74ddd..0000000 --- a/endpoint-exposer/container-scope-override/deployment/workflows/delete.yaml +++ /dev/null @@ -1,5 +0,0 @@ -steps: - - name: sync_exposer - type: script - file: "$OVERRIDES_PATH/deployment/sync_exposer" - after: apply traffic \ No newline at end of file diff --git a/endpoint-exposer/container-scope-override/deployment/workflows/finalize.yaml b/endpoint-exposer/container-scope-override/deployment/workflows/finalize.yaml deleted file mode 100644 index 6d43a5e..0000000 --- a/endpoint-exposer/container-scope-override/deployment/workflows/finalize.yaml +++ /dev/null @@ -1,5 +0,0 @@ -steps: - - name: sync_exposer - type: script - file: "$OVERRIDES_PATH/deployment/sync_exposer" - after: apply diff --git a/endpoint-exposer/container-scope-override/deployment/workflows/initial.yaml b/endpoint-exposer/container-scope-override/deployment/workflows/initial.yaml deleted file mode 100644 index 6d43a5e..0000000 --- a/endpoint-exposer/container-scope-override/deployment/workflows/initial.yaml +++ /dev/null @@ -1,5 +0,0 @@ -steps: - - name: sync_exposer - type: script - file: "$OVERRIDES_PATH/deployment/sync_exposer" - after: apply diff --git a/endpoint-exposer/container-scope-override/deployment/workflows/rollback.yaml b/endpoint-exposer/container-scope-override/deployment/workflows/rollback.yaml deleted file mode 100644 index 6d43a5e..0000000 --- a/endpoint-exposer/container-scope-override/deployment/workflows/rollback.yaml +++ /dev/null @@ -1,5 +0,0 @@ -steps: - - name: sync_exposer - type: script - file: "$OVERRIDES_PATH/deployment/sync_exposer" - after: apply diff --git a/endpoint-exposer/container-scope-override/deployment/workflows/switch_traffic.yaml b/endpoint-exposer/container-scope-override/deployment/workflows/switch_traffic.yaml deleted file mode 100644 index 6d43a5e..0000000 --- a/endpoint-exposer/container-scope-override/deployment/workflows/switch_traffic.yaml +++ /dev/null @@ -1,5 +0,0 @@ -steps: - - name: sync_exposer - type: script - file: "$OVERRIDES_PATH/deployment/sync_exposer" - after: apply diff --git a/endpoint-exposer/container-scope-override/values.yaml b/endpoint-exposer/container-scope-override/values.yaml deleted file mode 100644 index 101aee8..0000000 --- a/endpoint-exposer/container-scope-override/values.yaml +++ /dev/null @@ -1,3 +0,0 @@ -configuration: - SERVICE_SPECIFICATION_SLUG: endpoint-exposer - \ No newline at end of file diff --git a/endpoint-exposer/entrypoint/entrypoint b/endpoint-exposer/entrypoint/entrypoint deleted file mode 100755 index 45d50d7..0000000 --- a/endpoint-exposer/entrypoint/entrypoint +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# Check if NP_ACTION_CONTEXT is set -if [ -z "$NP_ACTION_CONTEXT" ]; then - echo "NP_ACTION_CONTEXT is not set. Exiting." - exit 1 -fi - -CLEAN_CONTEXT=$(echo "$NP_ACTION_CONTEXT" | sed "s/^'//;s/'$//") - -export NP_ACTION_CONTEXT="$CLEAN_CONTEXT" - -# Parse the JSON properly - remove the extra quotes -export CONTEXT=$(echo "$CLEAN_CONTEXT" | jq '.notification') -export SERVICE_ACTION=$(echo "$CONTEXT" | jq -r '.slug') -export SERVICE_ACTION_TYPE=$(echo "$CONTEXT" | jq -r '.type') -export NOTIFICATION_ACTION=$(echo "$CONTEXT" | jq -r '.action') - -export LINK=$(echo "$CONTEXT" | jq '.link') - -ACTION_SOURCE=service - -IS_LINK_ACTION=$(echo "$CONTEXT" | jq '.link != null') - -if [ "$IS_LINK_ACTION" = "true" ]; then - ACTION_SOURCE=link -fi - -export WORKING_DIRECTORY="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -SERVICE_PATH="" -OVERRIDES_PATH="" - -for arg in "$@"; do - case $arg in - --service-path=*) - SERVICE_PATH="${arg#*=}" - ;; - --overrides-path=*) - OVERRIDES_PATH="${arg#*=}" - ;; - *) - echo "Unknown argument: $arg" - exit 1 - ;; - esac -done - -# Fall back to deriving SERVICE_PATH from the script's own location when the -# caller doesn't pass --service-path. WORKING_DIRECTORY points at the -# `entrypoint/` directory inside the service; the parent is the service root -# (e.g. `/root/.np/nullplatform/services/endpoint-exposer`). Without this -# fallback, every absolute path below becomes `/workflows/...` instead of -# `/workflows/...`, and the np CLI fails with -# "failed to read workflow file: open /workflows//.yaml". -SERVICE_PATH="${SERVICE_PATH:-$(cd "$WORKING_DIRECTORY/.." && pwd)}" - -OVERRIDES_PATH="${OVERRIDES_PATH:-$SERVICE_PATH/overrides}" - -export SERVICE_PATH -export OVERRIDES_PATH - -# export util functions -#eval "$WORKING_DIRECTORY"/$ACTION_SOURCE - -np service-action exec --live-output --live-report --script="$WORKING_DIRECTORY/$ACTION_SOURCE" diff --git a/endpoint-exposer/entrypoint/link b/endpoint-exposer/entrypoint/link deleted file mode 100755 index 253ef01..0000000 --- a/endpoint-exposer/entrypoint/link +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -echo "Executing link action=$SERVICE_ACTION type=$SERVICE_ACTION_TYPE" - -ACTION_TO_EXECUTE="$SERVICE_ACTION_TYPE" - -case "$SERVICE_ACTION_TYPE" in - "custom") - ACTION_TO_EXECUTE="$SERVICE_ACTION" - ;; - "create") - ACTION_TO_EXECUTE="link" - ;; - "delete") - ACTION_TO_EXECUTE="unlink" - ;; -esac - -INGRESS_TYPE="${INGRESS_TYPE:-alb}" - -echo "INGRESS_TYPE is set to '$INGRESS_TYPE'" - -WORKFLOW_PATH="$SERVICE_PATH/workflows/$INGRESS_TYPE/$ACTION_TO_EXECUTE.yaml" -OVERRIDES_WORKFLOW_PATH="$OVERRIDES_PATH/workflows/$INGRESS_TYPE/$ACTION_TO_EXECUTE.yaml" -VALUES_PATH="$SERVICE_PATH/values.yaml" - -CMD="np service workflow exec --workflow $WORKFLOW_PATH --values $VALUES_PATH" - -if [[ -f "$OVERRIDES_WORKFLOW_PATH" ]]; then - CMD="$CMD --overrides $OVERRIDES_WORKFLOW_PATH" -fi - -echo "Executing command: $CMD" -eval "$CMD" diff --git a/endpoint-exposer/entrypoint/service b/endpoint-exposer/entrypoint/service deleted file mode 100755 index cdf2292..0000000 --- a/endpoint-exposer/entrypoint/service +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash - -echo "Executing service action=$SERVICE_ACTION type=$SERVICE_ACTION_TYPE" - -ACTION_TO_EXECUTE="$SERVICE_ACTION_TYPE" - -case "$SERVICE_ACTION_TYPE" in - "custom") - ACTION_TO_EXECUTE="$SERVICE_ACTION" - ;; -esac - -INGRESS_TYPE="${INGRESS_TYPE:-istio}" - -echo "INGRESS_TYPE is set to '$INGRESS_TYPE'" -echo "OVERRIDES_PATH is set to '$OVERRIDES_PATH'" - -WORKFLOW_PATH="$SERVICE_PATH/workflows/$INGRESS_TYPE/$ACTION_TO_EXECUTE.yaml" -OVERRIDES_WORKFLOW_PATH="$OVERRIDES_PATH/service/workflows/$ACTION_TO_EXECUTE.yaml" -VALUES_PATH="$SERVICE_PATH/values.yaml" - -CMD="np service workflow exec --workflow $WORKFLOW_PATH --values $VALUES_PATH --build-context --include-secrets" - -if [[ -f "$OVERRIDES_WORKFLOW_PATH" ]]; then - CMD="$CMD --overrides $OVERRIDES_WORKFLOW_PATH" -fi - -echo "Executing command: $CMD" - -# Note: The 'np service workflow exec' CLI automatically extracts OVERRIDES_PATH -# It uses regex /[^/]+/workflows/[^/]+\.yaml$ to strip the /folder/workflows/file.yaml part -# Example: --overrides /root/.np/plugin/service/workflows/create.yaml -# Regex matches: /service/workflows/create.yaml -# Results in: OVERRIDES_PATH=/root/.np/plugin (correct) -# Workflow files should use: $OVERRIDES_PATH/scripts/... (no double nesting needed) -# See: cli/cmd/service/workflow/exec/service_workflow_exec.go getOverridesBasePath() -export OVERRIDES_PATH - -eval "$CMD" diff --git a/endpoint-exposer/github/setup-hooks.sh b/endpoint-exposer/github/setup-hooks.sh deleted file mode 100755 index 2b9c89c..0000000 --- a/endpoint-exposer/github/setup-hooks.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -# Get the git repository root -REPO_ROOT="$(git rev-parse --show-toplevel)" - -# Configure git to use .githooks directory instead of .git/hooks -cd "$REPO_ROOT" -git config core.hooksPath .githooks - -echo "✅ Git hooks configured successfully!" -echo "Pre-commit hook will run endpoint-exposer tests before each commit when endpoint-exposer files are changed" diff --git a/endpoint-exposer/install/installation.md b/endpoint-exposer/install/installation.md deleted file mode 100644 index eb265c4..0000000 --- a/endpoint-exposer/install/installation.md +++ /dev/null @@ -1,101 +0,0 @@ -# Endpoint Exposer — Installation Guide - -This guide walks through registering the Endpoint Exposer service in nullplatform using OpenTofu. - -## Overview - -The installation process creates: -- A **service specification** (the form developers fill in to configure HTTP routes) -- **Action specifications** (read, create, update, delete) -- A **notification channel** (connects nullplatform events to the agent) - -## Prerequisites - -See [prerequisites.md](./prerequisites.md) for agent setup, Kubernetes permissions, and required repositories. - -## Steps - -### 1. Clone required repositories - -```bash -git clone https://github.com/nullplatform/services /root/.np/nullplatform/services -git clone https://github.com/nullplatform/tofu-modules /root/.np/nullplatform/tofu-modules -``` - -> The agent cmdline resolves to `////entrypoint/entrypoint`, which defaults to `/root/.np/nullplatform/services/endpoint-exposer/entrypoint/entrypoint`. Adjust the variables if you clone elsewhere. - -### 2. Configure variables - -```bash -cd install/tofu -cp terraform.tfvars.example terraform.tfvars -``` - -Edit `terraform.tfvars` with your values: - -| Variable | Required | Description | -|---|---|---| -| `nrn` | ✅ | Nullplatform Resource Name (`organization=:account=`) | -| `np_api_key` | ✅ | Nullplatform API key used by the agent | -| `tags_selectors` | ✅ | Tags to select the agent (e.g. `{ environment = "production" }`) | -| `github_token` | — | Only required if `repository_org`/`repository_name` point at a private fork. Not needed for the public `nullplatform/services` repo. | -| `repository_org` | — | Org that owns the spec repository (default: `nullplatform`) | -| `repository_name` | — | Spec repository name (default: `services`) | -| `repository_branch` | — | Branch to fetch specs from (default: `main`) | -| `spec_path` | — | In-repo path to `specs/service-spec.json.tpl` (default: `endpoint-exposer/install`) | -| `agent_service_path` | — | In-repo path where the agent runtime lives (default: `endpoint-exposer`) | -| `service_name` | — | Display name in nullplatform (default: `Endpoint Exposer`) | -| `overrides_enabled` | — | Set `true` to pass `--overrides-path` to the agent | -| `overrides_repo_path` | — | Absolute path to the overrides directory on the agent (required when `overrides_enabled = true`) | - -### 3. Initialize OpenTofu - -```bash -tofu init \ - -backend-config="bucket=" \ - -backend-config="region=" -``` - -### 4. Plan and apply - -```bash -tofu plan -tofu apply -``` - -## Domains - -The `publicDomain` / `privateDomain` fields in the service spec are free-text strings. Developers type the concrete FQDN at scope-creation time (via the nullplatform UI, CLI, or API). The base domain must resolve to the appropriate Istio gateway in the target cluster (public or private). - -## Spec fields governed by Terraform - -A few top-level fields in `install/specs/service-spec.json.tpl` are **overridden by the `service_definition` module at apply time**, so their value in the `.tpl` is ignored: - -| Spec field | Source at apply time | -|---|---| -| `name` | `var.service_name` | -| `visible_to` | `concat([var.nrn], var.extra_visibile_to_nrns)` | - -Do not add `{{ env.Getenv ... }}` template expressions to other fields expecting runtime substitution — there is no template engine in the pipeline (the module reads the spec with `data "http"` + `jsondecode()`). Any template string in a non-overridden field will reach the nullplatform API as a literal. - -## Overrides - -If the account requires local configuration overrides (e.g. from a networking repo), enable the override flag so the agent receives `--overrides-path` as an argument: - -```hcl -overrides_enabled = true -overrides_repo_path = "/root/.np/nullplatform/scopes-networking/endpoint-exposer" -``` - -The agent cmdline becomes: -``` -/root/.np/nullplatform/services/endpoint-exposer/entrypoint/entrypoint \ - --overrides-path=/root/.np/nullplatform/scopes-networking/endpoint-exposer -``` - -## Updating specs - -To push spec changes after editing templates in `install/specs/`: - -1. Merge your branch to `main` (or update `repository_branch` in tfvars) -2. Run `tofu apply` — the module fetches templates from GitHub on each run diff --git a/endpoint-exposer/install/prerequisites.md b/endpoint-exposer/install/prerequisites.md deleted file mode 100644 index 4dd1b77..0000000 --- a/endpoint-exposer/install/prerequisites.md +++ /dev/null @@ -1,66 +0,0 @@ -# Endpoint Exposer — Agent Prerequisites - -## Repositories - -The agent pod must have the following repository cloned at the expected path: - -| Repository | Default path on agent | -|---|---| -| [nullplatform/services](https://github.com/nullplatform/services) | `/root/.np/nullplatform/services/endpoint-exposer` | - -Override the default path via the `repository_org` / `repository_name` / `agent_service_path` variables in `terraform.tfvars`. - -## Required tooling on the agent pod - -- `np` CLI (nullplatform CLI) -- `kubectl` -- `jq` -- `gomplate` - -## Kubernetes Access - -The agent runs in a Kubernetes pod and must have `kubectl` access to the cluster. The pod's service account must have RBAC permissions to manage HTTPRoute resources in the target namespace. - ---- - -### Required ClusterRole / Role - -```yaml -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - name: endpoint-exposer-agent - namespace: nullplatform # or the namespace defined in values.yaml K8S_NAMESPACE -rules: - - apiGroups: ["gateway.networking.k8s.io"] - resources: ["httproutes"] - verbs: ["get", "list", "create", "update", "patch", "delete"] -``` - ---- - -### Gateway API CRDs - -The Kubernetes cluster must have the [Gateway API CRDs](https://gateway-api.sigs.k8s.io/guides/#installing-gateway-api) installed: - -```bash -kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.0.0/standard-install.yaml -``` - -Verify the CRDs are available: - -```bash -kubectl get crd httproutes.gateway.networking.k8s.io -``` - ---- - -### Gateway resource - -A `Gateway` resource must exist in the cluster for both public and private traffic. The gateway names and namespaces are configured in `values.yaml` (or via the scope's configuration). - -## GitHub Token - -The `service_definition` module fetches spec templates from GitHub at `tofu apply` time via authenticated or anonymous HTTP. Since `nullplatform/services` is a **public** repository, **no token is required** for the default setup. - -If you point `repository_org` / `repository_name` at a private fork, provide a GitHub personal access token with `contents: read` permission on that repo via the `github_token` variable in `terraform.tfvars`. diff --git a/endpoint-exposer/install/specs/actions/read.json.tpl b/endpoint-exposer/install/specs/actions/read.json.tpl deleted file mode 100644 index f6a4c52..0000000 --- a/endpoint-exposer/install/specs/actions/read.json.tpl +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "Read", - "slug": "read", - "type": "custom", - "annotations": {}, - "enabled_when": "", - "retryable": false, - "service_specification_id": "{{ env.Getenv "SERVICE_SPECIFICATION_ID" }}", - "parameters": { - "schema": { - "type": "object", - "required": [], - "properties": {} - }, - "values": {} - }, - "results": { - "schema": { - "type": "object", - "required": [], - "properties": {} - }, - "values": {} - } -} \ No newline at end of file diff --git a/endpoint-exposer/install/specs/notification-channel.json.tpl b/endpoint-exposer/install/specs/notification-channel.json.tpl deleted file mode 100644 index ee3c798..0000000 --- a/endpoint-exposer/install/specs/notification-channel.json.tpl +++ /dev/null @@ -1,34 +0,0 @@ -{ - "nrn": "{{ env.Getenv "NRN" }}", - "status": "active", - "type": "agent", - "source": [ - "telemetry", - "service" - ], - "configuration": { - "api_key": "{{ env.Getenv "NP_API_KEY" }}", - "command": { - "data": { - "cmdline": "{{ env.Getenv "REPO_PATH" }}/entrypoint --service-path={{ env.Getenv "REPO_PATH" }}/{{ env.Getenv "SERVICE_PATH" }}", - "environment": { - "NP_ACTION_CONTEXT": "'${NOTIFICATION_CONTEXT}'" - } - }, - "type": "exec" - }, - "selector": { - "environment": "{{ env.Getenv "ENVIRONMENT" }}" - } - }, - "filters": { - "$or": [ - { - "service.specification.slug": "{{ env.Getenv "SERVICE_SLUG" }}" - }, - { - "arguments.scope_provider": "{{ env.Getenv "SERVICE_SPECIFICATION_ID" }}" - } - ] - } -} \ No newline at end of file diff --git a/endpoint-exposer/install/specs/service-spec.json.tpl b/endpoint-exposer/install/specs/service-spec.json.tpl deleted file mode 100644 index d184a61..0000000 --- a/endpoint-exposer/install/specs/service-spec.json.tpl +++ /dev/null @@ -1,216 +0,0 @@ -{ - "name": "Endpoint Exposer", - "type": "dependency", - "visible_to": [], - "dimensions": {}, - "scopes": {}, - "assignable_to": "any", - "use_default_actions": true, - "attributes": { - "schema": { - "type": "object", - "$schema": "http://json-schema.org/draft-07/schema#", - "required": [ - "publicDomain" - ], - "uiSchema": { - "type": "VerticalLayout", - "elements": [ - { - "type": "Categorization", - "options": { - "collapsable": { - "label": "Documentation", - "collapsed": true - } - }, - "elements": [ - { - "type": "Category", - "label": "Domains", - "elements": [ - { - "text": "### Public Domain\nBase domain for routes exposed to external traffic. Requests matching routes with `visibility: public` will be served through this domain.\n\n### Private Domain\nBase domain for routes accessible only within the internal network. Use this for service-to-service communication.", - "type": "Label", - "options": { - "format": "markdown" - } - } - ] - }, - { - "type": "Category", - "label": "Routes", - "elements": [ - { - "text": "### Route Configuration\nDefine how incoming requests are matched and forwarded to backend services.\n\n| Field | Description |\n|-------|-------------|\n| **Verb** | HTTP method to match (GET, POST, PUT, etc.) |\n| **Path** | URL path pattern. See *Path Types* below |\n| **Scope** | Target service that will handle the request |\n| **Visibility** | `public` (external) or `private` (internal network only) |\n\n### Path Types\n| Type | Example | Description |\n|------|---------|-------------|\n| **Exact** | `/api/users` | Matches the exact path only |\n| **Parameterized** | `/api/users/{id}` | Matches path with dynamic segments |\n| **Wildcard** | `/api/users/*` | Matches any path starting with the prefix |", - "type": "Label", - "options": { - "format": "markdown" - } - } - ] - }, - { - "type": "Category", - "label": "Examples", - "elements": [ - { - "text": "### Public API Route\n```json\n{\n \"method\": \"GET\",\n \"path\": \"/api/v1/wells\",\n \"scope\": \"wells-service\",\n \"visibility\": \"public\"\n}\n```\n\n### Private Internal Route\n```json\n{\n \"method\": \"POST\",\n \"path\": \"/internal/sync\",\n \"scope\": \"sync-service\",\n \"visibility\": \"private\"\n}\n```", - "type": "Label", - "options": { - "format": "markdown" - } - } - ] - } - ] - }, - { - "type": "Control", - "scope": "#/properties/environment" - }, - { - "type": "Group", - "label": "Domains", - "elements": [ - { - "type": "Control", - "scope": "#/properties/publicDomain" - }, - { - "type": "Control", - "scope": "#/properties/privateDomain" - } - ] - }, - { - "type": "Group", - "label": "Routes", - "elements": [ - { - "type": "Control", - "scope": "#/properties/routes", - "options": { - "detail": { - "type": "VerticalLayout", - "elements": [ - { - "type": "Control", - "label": "Verb", - "scope": "#/properties/method" - }, - { - "type": "HorizontalLayout", - "elements": [ - { - "type": "Control", - "label": "Path", - "scope": "#/properties/path" - }, - { - "type": "Control", - "label": "Scope", - "scope": "#/properties/scope" - }, - { - "type": "Control", - "label": "Visibility", - "scope": "#/properties/visibility" - } - ] - } - ] - }, - "showSortButtons": true - } - } - ] - } - ] - }, - "properties": { - "routes": { - "type": "array", - "items": { - "type": "object", - "required": [ - "method", - "path", - "scope", - "visibility" - ], - "properties": { - "path": { - "type": "string", - "title": "Path" - }, - "scope": { - "type": "string", - "title": "Scope", - "additionalKeywords": { - "enum": "[.scopes[]?.slug] | if length == 0 then [\"No scopes available for selected environment\"] else . end" - } - }, - "method": { - "enum": [ - "GET", - "POST", - "PUT", - "PATCH", - "DELETE", - "HEAD", - "OPTIONS" - ], - "type": "string", - "title": "Verb" - }, - "visibility": { - "enum": [ - "public", - "private" - ], - "type": "string", - "title": "Visibility", - "default": "public" - } - } - }, - "title": "Routes" - }, - "environment": { - "type": "string", - "title": "Environment", - "additionalKeywords": { - "enum": "[.scopes[]?.dimensions?.environment] | unique | if length == 0 then [\"No environments available\"] else . end" - } - }, - "publicDomain": { - "type": "string", - "title": "Public Domain", - "description": "Base domain for routes with visibility=public. Tenant-specific — provide the FQDN that resolves to the public Istio gateway of the target cluster.", - "editableOn": [ - "create", - "update" - ] - }, - "privateDomain": { - "type": "string", - "title": "Private Domain", - "description": "Base domain for routes with visibility=private. Tenant-specific — provide the FQDN that resolves to the private (internal) Istio gateway of the target cluster.", - "editableOn": [ - "create", - "update" - ] - } - } - }, - "values": {} - }, - "selectors": { - "category": "Networking", - "imported": false, - "provider": "K8S", - "sub_category": "HTTP Routing" - } -} diff --git a/endpoint-exposer/install/tofu/.terraform.lock.hcl b/endpoint-exposer/install/tofu/.terraform.lock.hcl deleted file mode 100644 index 955d031..0000000 --- a/endpoint-exposer/install/tofu/.terraform.lock.hcl +++ /dev/null @@ -1,66 +0,0 @@ -# This file is maintained automatically by "tofu init". -# Manual edits may be lost in future updates. - -provider "registry.opentofu.org/hashicorp/http" { - version = "3.5.0" - constraints = "~> 3.0" - hashes = [ - "h1:eClUBisXme48lqiUl3U2+H2a2mzDawS9biqfkd9synw=", - "zh:0a2b33494eec6a91a183629cf217e073be063624c5d3f70870456ddb478308e9", - "zh:180f40124fa01b98b3d2f79128646b151818e09d6a1a9ca08e0b032a0b1e9cb1", - "zh:3e29e1de149dc10bf78620526c7cb8c62cd76087f5630dfaba0e93cda1f3aa7b", - "zh:4420950200cf86042ec940d0e2c9b7c89966bf556bf8038ba36217eae663bca5", - "zh:5d1f7d02109b2e2dca7ec626e5563ee765583792d0fd64081286f16f9433bd0d", - "zh:8500b138d338b1994c4206aa577b5c44e1d7260825babcf43245a7075bfa52a5", - "zh:b42165a6c4cfb22825938272d12b676e4a6946ac4e750f85df870c947685df2d", - "zh:b919bf3ee8e3b01051a0da3433b443a925e272893d3724ee8fc0f666ec7012c9", - "zh:d13b81ea6755cae785b3e11634936cdff2dc1ec009dc9610d8e3c7eb32f42e69", - "zh:f1c9d2eb1a6b618ae77ad86649679241bd8d6aacec06d0a68d86f748687f4eb3", - ] -} - -provider "registry.opentofu.org/integrations/github" { - version = "6.11.1" - constraints = "~> 6.0" - hashes = [ - "h1:nanzeesukYMHAFrSaq7rnWx7iRDHMpme5KzQI3m/ZZo=", - "zh:0a5262b033a30d8a77ebf844dc3afd7e726d5f53ac1c9d4072cf9157820d1f73", - "zh:437236181326f92d1a7c56985b2ac3223efd73f75c528323b90f4b7d1b781090", - "zh:49a12c14d1d3a143a124ba81f15fbf18714af90752c993698c76e84fa85da004", - "zh:61eaf17b559a26ca14deb597375a6678d054d739e8b81c586ef1d0391c307916", - "zh:7f3f1e2c36f4787ca9a5aeb5317b8c3f6cc652368d1f8f00fb80f404109d4db1", - "zh:85a232f2e96e5adafa2676f38a96b8cc074e96f715caf6ee1d169431174897d2", - "zh:979d005af2a9003d887413195948c899e9f5aba4a79cce1eed40f3ba50301af1", - "zh:b8c8cd3254504d2184d2b2233ad41b5fdfda91a36fc864926cbc5c7eee1bfea3", - "zh:d00959e62930fb75d2b97c1d66ab0143120541d5a1b3f26d3551f24cb0361f83", - "zh:d0b544eed171c7563387fe87f0af3d238bb3804798159b4d0453c97927237daf", - "zh:ecfa19b1219aa55b1ece98d8cff5b1494dc0387329c8ae0d8f762ec3871fb75d", - "zh:f2c99825f38c92ac599ad36b9d093ea0c0d790fd0c02e861789e14735a605f86", - "zh:f33b5abe14ad5fb9978da5dbd3bc6989f69766150d4b30ed283a2c281871eda3", - "zh:f6c2fe9dd958c554170dc0c35ca41b60fcc6253304cde0b9941c5c872b18ac54", - "zh:fbd1fee2c9df3aa19cf8851ce134dea6e45ea01cb85695c1726670c285797e25", - ] -} - -provider "registry.opentofu.org/nullplatform/nullplatform" { - version = "0.0.83" - constraints = ">= 0.0.67, ~> 0.0.67, < 0.1.0" - hashes = [ - "h1:OLoy7qBT2p/P9pxLL1QBT/NND3A/ik6JordAv8loU8E=", - "zh:0e9c83e413ea5a8b960520805d2bcda2b73fef7532dc9f95f84814b7fb8a0c91", - "zh:27a46f7bfdcd349f45ff38d38bbda9f6a40eb3d4da8e62711cd1e4317f236abb", - "zh:363b17e7386878e757fde5d696145a77036821bea9435d158f18a7b32e7660b8", - "zh:3750f479550b9451e6af7e3e8748d1df9b4f0eb7b1abf623bcc09e8f07efcb33", - "zh:46be8590448ea119024ddccb24e754cf248b216b4acb132a60ce4a8ba2fdc3bf", - "zh:4efa21083c3f18e46c26767b425fd9eadb71fa332fd2d8b2b78d30612038f8a7", - "zh:6275212e7934e65cbc79b45a70831815d13dc45ee79d055417be66a33643116a", - "zh:92c43a2ed70ba8f065a2d971e6ec8ec7b21733af487afec03f22e8d982275c53", - "zh:c2b45662dd0193d946763513f85957451db8a7117e5d83158e95dfd229eceeed", - "zh:c3e99e0c20d2a8e8aa7a303b5ecfb27cb1d5489ca0748eeb7fd33c09e082641f", - "zh:dce5ca843181ca75f6d1473c2a5022e58505f99aa2c0ee1c184589d1a4c765d7", - "zh:e82a2868ba85f8807bf920ff010d8b6a7eb6eb4f364e53cedae087c348b8689f", - "zh:f3d71d9536d9e866c95d7ae7f2b3e5a8052faa60750122d51910ef7187d40a45", - "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", - "zh:ffad065fb6df9037ae8995d50a1857b6a5e761a000ff879320b109fbe79fa529", - ] -} diff --git a/endpoint-exposer/install/tofu/backend.tf b/endpoint-exposer/install/tofu/backend.tf deleted file mode 100644 index e0c5242..0000000 --- a/endpoint-exposer/install/tofu/backend.tf +++ /dev/null @@ -1,5 +0,0 @@ -terraform { - backend "s3" { - key = "endpoint-exposer/install/terraform.tfstate" - } -} diff --git a/endpoint-exposer/install/tofu/main.tf b/endpoint-exposer/install/tofu/main.tf deleted file mode 100644 index 1bb3901..0000000 --- a/endpoint-exposer/install/tofu/main.tf +++ /dev/null @@ -1,54 +0,0 @@ -################################################################################ -# Service Definition -# Registers the service specification and action specs in nullplatform. -################################################################################ - -module "service_definition" { - source = "../../../../tofu-modules/nullplatform/service_definition" - - nrn = var.nrn - - # Spec templates are fetched from GitHub via HTTP and parsed as JSON. - # The module expects specs at `/specs/service-spec.json.tpl` - # (plus `specs/actions/*.json.tpl` and `specs/links/*.json.tpl` if any). - repository_org = var.repository_org - repository_name = var.repository_name - repository_branch = var.repository_branch - service_path = var.spec_path - repository_token = var.github_token - - service_name = var.service_name - - # Override the module's default `available_links = ["connect"]`: this service - # doesn't ship a `specs/links/connect.json.tpl`, and fetching a non-existent - # template would make `jsondecode()` abort planning. - available_links = [] -} - -################################################################################ -# Service Definition Agent Association -# Creates the notification channel that connects nullplatform events to the agent. -# -# The module constructs the agent cmdline as -# `${base_clone_path}/${repository_service_spec_repo}/${service_path}/entrypoint/entrypoint` -# so the agent must have the repo cloned at that location. `service_path` here -# is the runtime path (e.g. `endpoint-exposer`), NOT the specs path (which -# includes the `install/` prefix for this service). -################################################################################ - -module "service_definition_agent_association" { - source = "../../../../tofu-modules/nullplatform/service_definition_agent_association" - - nrn = var.nrn - api_key = var.np_api_key - tags_selectors = var.tags_selectors - - service_specification_slug = module.service_definition.service_specification_slug - repository_service_spec_repo = "${var.repository_org}/${var.repository_name}" - service_path = var.agent_service_path - - # Pass `--overrides-path=` to the entrypoint when local config - # overrides are enabled. The entrypoint handles the flag; the module just - # forwards arguments verbatim. - agent_arguments = var.overrides_enabled ? ["--overrides-path=${var.overrides_repo_path}"] : [] -} diff --git a/endpoint-exposer/install/tofu/provider.tf b/endpoint-exposer/install/tofu/provider.tf deleted file mode 100644 index 2fece5b..0000000 --- a/endpoint-exposer/install/tofu/provider.tf +++ /dev/null @@ -1,20 +0,0 @@ -terraform { - required_providers { - nullplatform = { - source = "nullplatform/nullplatform" - version = ">= 0.0.67, < 0.1.0" - } - github = { - source = "integrations/github" - version = "~> 6.0" - } - } -} - -provider "nullplatform" { - api_key = var.np_api_key -} - -provider "github" { - token = var.github_token -} diff --git a/endpoint-exposer/install/tofu/terraform.tfvars.example b/endpoint-exposer/install/tofu/terraform.tfvars.example deleted file mode 100644 index 168cc7d..0000000 --- a/endpoint-exposer/install/tofu/terraform.tfvars.example +++ /dev/null @@ -1,40 +0,0 @@ -# Copy this file to terraform.tfvars and fill in the values. -# terraform.tfvars is gitignored — never commit secrets. - -################################################################################ -# Required -################################################################################ - -nrn = "organization=:account=" -np_api_key = "your-nullplatform-api-key" - -tags_selectors = { - environment = "production" -} - -# Only needed if the spec repository is private. nullplatform/services is -# public, so leave commented out unless you're pointing at a fork. -# github_token = "your-github-personal-access-token" - -################################################################################ -# Repository (override if pointing at a fork or a non-default branch) -################################################################################ - -# repository_org = "nullplatform" -# repository_name = "services" -# repository_branch = "main" -# spec_path = "endpoint-exposer/install" -# agent_service_path = "endpoint-exposer" - -################################################################################ -# Service Definition (override to customize the display name) -################################################################################ - -# service_name = "Endpoint Exposer" - -################################################################################ -# Overrides (optional — passes --overrides-path to the agent entrypoint) -################################################################################ - -# overrides_enabled = true -# overrides_repo_path = "/root/.np/nullplatform/scopes-networking/endpoint-exposer" diff --git a/endpoint-exposer/install/tofu/variables.tf b/endpoint-exposer/install/tofu/variables.tf deleted file mode 100644 index 58c6e2f..0000000 --- a/endpoint-exposer/install/tofu/variables.tf +++ /dev/null @@ -1,98 +0,0 @@ -################################################################################ -# Required -################################################################################ - -variable "nrn" { - description = "Nullplatform Resource Name (organization:account format)" - type = string -} - -variable "np_api_key" { - description = "Nullplatform API key used by the agent to authenticate with nullplatform" - type = string - sensitive = true -} - -variable "tags_selectors" { - description = "Map of tags used to select the agent that will handle this service's notification channel" - type = map(string) -} - -variable "github_token" { - description = "GitHub token for fetching spec templates. Only required when the spec repository is private." - type = string - sensitive = true - default = null -} - -################################################################################ -# Repository -# Where the service specs and runtime code live. Both are assumed to be in the -# same repository; `spec_path` and `agent_service_path` can differ if the specs -# are nested deeper (as is the case for endpoint-exposer with its `install/` -# subdirectory). -################################################################################ - -variable "repository_org" { - description = "GitHub organization owning the service repository" - type = string - default = "nullplatform" -} - -variable "repository_name" { - description = "Name of the service repository" - type = string - default = "services" -} - -variable "repository_branch" { - description = "Branch of the service repository to fetch specs from. Must be a short branch name (e.g. \"main\"), not a full ref." - type = string - default = "main" -} - -variable "spec_path" { - description = "Path within the repository where `specs/service-spec.json.tpl` lives (used at registration time by the service_definition module)" - type = string - default = "endpoint-exposer/install" -} - -variable "agent_service_path" { - description = "Path within the repository where the runtime `entrypoint/entrypoint` lives (used at execution time by the agent)" - type = string - default = "endpoint-exposer" -} - -################################################################################ -# Service Definition -################################################################################ - -variable "service_name" { - description = "Display name for the service in nullplatform" - type = string - default = "Endpoint Exposer" -} - -################################################################################ -# Overrides (optional) -# When enabled, the agent receives `--overrides-path=` as -# an argument, so the entrypoint can layer tenant-specific configuration on -# top of the in-repo defaults. -################################################################################ - -variable "overrides_enabled" { - description = "Append `--overrides-path` to the agent arguments for local config overrides" - type = bool - default = false -} - -variable "overrides_repo_path" { - description = "Absolute path inside the agent container where the overrides directory is located. Required when overrides_enabled = true." - type = string - default = null - - validation { - condition = var.overrides_repo_path == null || startswith(coalesce(var.overrides_repo_path, "/"), "/") - error_message = "overrides_repo_path must be an absolute path (start with /)." - } -} diff --git a/endpoint-exposer/scripts/common/apply b/endpoint-exposer/scripts/common/apply deleted file mode 100644 index 1b092ff..0000000 --- a/endpoint-exposer/scripts/common/apply +++ /dev/null @@ -1,90 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -# Load configuration -source "$SERVICE_PATH/scripts/istio/config" - -echo "TEMPLATE DIR: $OUTPUT_DIR, ACTION: $ACTION, DRY_RUN: $DRY_RUN" - -# Helper function to delete a resource if it exists -delete_if_exists() { - local resource_type="$1" - local resource_name="$2" - local namespace="$3" - - if kubectl get "$resource_type" "$resource_name" -n "$namespace" &>/dev/null; then - echo "Deleting $resource_type: $resource_name in namespace $namespace" - if [[ "$DRY_RUN" == "false" ]]; then - kubectl delete "$resource_type" "$resource_name" -n "$namespace" - fi - else - echo "$resource_type $resource_name not found in namespace $namespace (already deleted or never existed)" - fi -} - -# Check for marker files indicating resources should be deleted -if [[ -f "$OUTPUT_DIR/.httproute-public-deleted" ]]; then - echo "Public HTTPRoute marked for deletion" - delete_if_exists "httproute" "$SERVICE_SLUG-$SERVICE_ID-public" "$K8S_NAMESPACE" - rm "$OUTPUT_DIR/.httproute-public-deleted" -fi - -if [[ -f "$OUTPUT_DIR/.httproute-private-deleted" ]]; then - echo "Private HTTPRoute marked for deletion" - delete_if_exists "httproute" "$SERVICE_SLUG-$SERVICE_ID-private" "$K8S_NAMESPACE" - rm "$OUTPUT_DIR/.httproute-private-deleted" -fi - -if [[ -f "$OUTPUT_DIR/.authz-public-deleted" ]]; then - echo "Public AuthorizationPolicy marked for deletion" - delete_if_exists "authorizationpolicy" "$SERVICE_SLUG-$SERVICE_ID-authz-public" "$GATEWAY_NAMESPACE" - rm "$OUTPUT_DIR/.authz-public-deleted" -fi - -if [[ -f "$OUTPUT_DIR/.authz-private-deleted" ]]; then - echo "Private AuthorizationPolicy marked for deletion" - delete_if_exists "authorizationpolicy" "$SERVICE_SLUG-$SERVICE_ID-authz-private" "$GATEWAY_NAMESPACE" - rm "$OUTPUT_DIR/.authz-private-deleted" -fi - -# Collect all yaml files into a temporary directory for batch apply -TEMP_APPLY_DIR="$OUTPUT_DIR/batch-apply" -mkdir -p "$TEMP_APPLY_DIR" - -# Find all .yaml files that were not yet applied / deleted -find "$OUTPUT_DIR" \( -path "*/apply" -o -path "*/delete" -o -path "*/batch-apply" \) -prune -o -type f -name "*.yaml" -print | while read -r TEMPLATE_FILE; do - FILENAME="$(basename "$TEMPLATE_FILE")" - cp "$TEMPLATE_FILE" "$TEMP_APPLY_DIR/$FILENAME" -done - -# Count files to apply -NUM_FILES=$(find "$TEMP_APPLY_DIR" -type f -name "*.yaml" | wc -l | tr -d ' ') - -if [[ "$NUM_FILES" -gt 0 ]]; then - echo "Applying $NUM_FILES resources..." - echo "kubectl $ACTION -f $TEMP_APPLY_DIR/" - - if [[ "$DRY_RUN" == "false" ]]; then - # Apply all resources - kubectl "$ACTION" -f "$TEMP_APPLY_DIR/" - fi -else - echo "No resources to apply" -fi - -# Move processed files to apply directory -find "$OUTPUT_DIR" \( -path "*/apply" -o -path "*/delete" -o -path "*/batch-apply" \) -prune -o -type f -name "*.yaml" -print | while read -r TEMPLATE_FILE; do - BASE_DIR="$(dirname "$TEMPLATE_FILE")" - FILENAME="$(basename "$TEMPLATE_FILE")" - DEST_DIR="${BASE_DIR}/$ACTION" - - mkdir -p "$DEST_DIR" - mv "$TEMPLATE_FILE" "$DEST_DIR/$FILENAME" -done - -# Cleanup temporary directory -rm -rf "$TEMP_APPLY_DIR" - -# Note: DRY_RUN is for testing - we exit 0 even in dry run mode -exit 0 \ No newline at end of file diff --git a/endpoint-exposer/scripts/istio/build_context b/endpoint-exposer/scripts/istio/build_context deleted file mode 100644 index d0b54e2..0000000 --- a/endpoint-exposer/scripts/istio/build_context +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -# Build Context: Extracts service metadata, domains, and routes from service action parameters. -# Splits routes by visibility (public/private) and prepares environment variables for workflow execution. - -set -euo pipefail - -SERVICE_ID=$(echo "$CONTEXT" | jq -r .service.id) -SERVICE_SLUG=$(echo "$CONTEXT" | jq -r .service.slug) - -ACTION_ID=$(echo "$CONTEXT" | jq -r .id) -ACTION_NAME=$(echo "$CONTEXT" | jq -r .slug) - -# Extract domains from parameters -PUBLIC_DOMAIN=$(echo "$CONTEXT" | jq -r '.parameters.publicDomain // .parameters.public_domain // ""') -PRIVATE_DOMAIN=$(echo "$CONTEXT" | jq -r '.parameters.privateDomain // .parameters.private_domain // ""') - -K8S_NAMESPACE="${NAMESPACE_OVERRIDE:-nullplatform}" - -# Extract routes array from parameters -ROUTES_JSON=$(echo "$CONTEXT" | jq -c '.parameters.routes // []') - -# Split routes by visibility -PUBLIC_ROUTES_JSON=$(echo "$ROUTES_JSON" | jq -c '[.[] | select(.visibility == "public" or .visibility == null)]') -PRIVATE_ROUTES_JSON=$(echo "$ROUTES_JSON" | jq -c '[.[] | select(.visibility == "private")]') - -CONTEXT=$(echo "$CONTEXT" | jq \ - --arg k8s_namespace "$K8S_NAMESPACE" \ - '. + {k8s_namespace: $k8s_namespace}') - -# Only set OUTPUT_DIR if not already set (allows tests to override) -if [[ -z "${OUTPUT_DIR:-}" ]]; then - export OUTPUT_DIR="$SERVICE_PATH/output/$SERVICE_SLUG-$SERVICE_ID/$ACTION_NAME-$ACTION_ID" -fi - -mkdir -p "$OUTPUT_DIR" - -export SERVICE_ID -export SERVICE_SLUG -export ACTION_ID -export ACTION_NAME -export PUBLIC_DOMAIN -export PRIVATE_DOMAIN -export ROUTES_JSON -export PUBLIC_ROUTES_JSON -export PRIVATE_ROUTES_JSON \ No newline at end of file diff --git a/endpoint-exposer/scripts/istio/build_httproute b/endpoint-exposer/scripts/istio/build_httproute deleted file mode 100755 index 4ecb710..0000000 --- a/endpoint-exposer/scripts/istio/build_httproute +++ /dev/null @@ -1,111 +0,0 @@ -#!/bin/bash - -# Build HTTPRoute: Creates Istio HTTPRoute resources for public or private traffic. -# Generates HTTPRoute from template, processes all routes, and handles empty resource cleanup. - -set -euo pipefail - -# Load configuration -source "$SERVICE_PATH/scripts/istio/config" - -# Parameters (must be set by caller) -VISIBILITY="${VISIBILITY:-public}" # "public" or "private" - -echo "=== Building ${VISIBILITY} HTTPRoute ===" - -# Set variables based on visibility -if [[ "$VISIBILITY" == "public" ]]; then - ROUTES_JSON="$PUBLIC_ROUTES_JSON" - DOMAIN="$PUBLIC_DOMAIN" - GATEWAY_NAME="$PUBLIC_GATEWAY_NAME" - SUFFIX="public" -elif [[ "$VISIBILITY" == "private" ]]; then - ROUTES_JSON="$PRIVATE_ROUTES_JSON" - DOMAIN="$PRIVATE_DOMAIN" - GATEWAY_NAME="$PRIVATE_GATEWAY_NAME" - SUFFIX="private" -else - echo "ERROR: Invalid VISIBILITY value: $VISIBILITY" - exit 1 -fi - -# Check if we have routes and domain -NUM_ROUTES=$(echo "$ROUTES_JSON" | jq 'length') -echo "Number of $VISIBILITY routes: $NUM_ROUTES" -echo "$VISIBILITY Domain: '$DOMAIN'" - -# Check if domain is empty/null -DOMAIN_EMPTY=false -if [[ -z "$DOMAIN" ]] || [[ "$DOMAIN" == "null" ]] || [[ "$DOMAIN" == "\"null\"" ]]; then - DOMAIN_EMPTY=true -fi - -# Determine if we should create an empty resource -CREATE_EMPTY=false -if [[ "$NUM_ROUTES" -eq 0 ]] || [[ "$DOMAIN_EMPTY" == "true" ]]; then - CREATE_EMPTY=true - echo "No $VISIBILITY routes or domain configured, creating empty resource for cleanup..." -fi - -# Create HTTPRoute -HTTPROUTE_FILE="$OUTPUT_DIR/httproute-$SERVICE_ID-$SUFFIX.yaml" - -if [[ "$CREATE_EMPTY" == "true" ]]; then - # Don't create the file - kubectl apply with --prune will delete it - echo "Skipping $VISIBILITY HTTPRoute generation - resource will be pruned if it exists" - # Still export the file path but point to a marker file for cleanup tracking - touch "$OUTPUT_DIR/.httproute-$SUFFIX-deleted" -else - # Create HTTPRoute from template - TEMPLATE="$SERVICE_PATH/templates/istio/httproute.yaml.tpl" - - # Build context for template - HTTPROUTE_CONTEXT=$(jq -n \ - --arg service_slug "$SERVICE_SLUG" \ - --arg service_id "$SERVICE_ID" \ - --arg k8s_namespace "$K8S_NAMESPACE" \ - --arg domain "$DOMAIN" \ - --arg gateway_name "$GATEWAY_NAME" \ - --arg gateway_namespace "$GATEWAY_NAMESPACE" \ - --arg suffix "$SUFFIX" \ - '{ - service_slug: $service_slug, - service_id: $service_id, - k8s_namespace: $k8s_namespace, - domain: $domain, - gateway_name: $gateway_name, - gateway_namespace: $gateway_namespace, - suffix: $suffix - }') - - CONTEXT_PATH="$OUTPUT_DIR/httproute-$SUFFIX-context-$SERVICE_ID.json" - echo "$HTTPROUTE_CONTEXT" > "$CONTEXT_PATH" - - echo "Generating HTTPRoute from template: $TEMPLATE" - gomplate -c .="$CONTEXT_PATH" \ - -f "$TEMPLATE" \ - -o "$HTTPROUTE_FILE" - - rm "$CONTEXT_PATH" - - # Now process routes using the existing logic - # Temporarily override ROUTES_JSON with visibility-specific routes - ORIGINAL_ROUTES_JSON="${ROUTES_JSON:-[]}" - export ROUTES_JSON="$ROUTES_JSON" - export HTTPROUTE_FILE="$HTTPROUTE_FILE" - - # Process routes - source "$SERVICE_PATH/scripts/istio/process_routes" - - # Restore original ROUTES_JSON - export ROUTES_JSON="$ORIGINAL_ROUTES_JSON" - - echo "✅ $VISIBILITY HTTPRoute created: $HTTPROUTE_FILE" -fi - -# Export file path based on visibility -if [[ "$VISIBILITY" == "public" ]]; then - export HTTPROUTE_PUBLIC_FILE="$HTTPROUTE_FILE" -elif [[ "$VISIBILITY" == "private" ]]; then - export HTTPROUTE_PRIVATE_FILE="$HTTPROUTE_FILE" -fi diff --git a/endpoint-exposer/scripts/istio/build_ingress b/endpoint-exposer/scripts/istio/build_ingress deleted file mode 100644 index 0c571f6..0000000 --- a/endpoint-exposer/scripts/istio/build_ingress +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -# Build Ingress: Generates HTTPRoute resource from gomplate template. -# Legacy script for creating basic HTTPRoute configuration with service domain. - -set -euo pipefail - -# Determine domain and output file -SERVICE_DOMAIN=$(echo "$CONTEXT" | jq -r '.parameters.public_domain // .service.attributes.domain') -HTTPROUTE_FILE="${OUTPUT_FILE:-$OUTPUT_DIR/httproute-$SERVICE_ID-public.yaml}" -echo "Creating HTTPRoute for service $SERVICE_SLUG with domain $SERVICE_DOMAIN" -echo "Output file: $HTTPROUTE_FILE" - -CONTEXT_PATH="$OUTPUT_DIR/context-$SERVICE_ID.json" - -echo "$CONTEXT" > "$CONTEXT_PATH" - -echo "Building Template: $TEMPLATE to $HTTPROUTE_FILE" - -gomplate -c .="$CONTEXT_PATH" \ - --file "$TEMPLATE" \ - --out "$HTTPROUTE_FILE" - -rm "$CONTEXT_PATH" - -# Export the file path for the workflow -export HTTPROUTE_FILE -echo "HTTPRoute created at: $HTTPROUTE_FILE" \ No newline at end of file diff --git a/endpoint-exposer/scripts/istio/build_ingress_with_rule b/endpoint-exposer/scripts/istio/build_ingress_with_rule deleted file mode 100755 index 2518a4e..0000000 --- a/endpoint-exposer/scripts/istio/build_ingress_with_rule +++ /dev/null @@ -1,406 +0,0 @@ -#!/bin/bash - -# Build Ingress with Rule: Updates HTTPRoute by adding or replacing rules for specific paths. -# Supports path types (Exact, PathPrefix, RegularExpression), HTTP methods, and blue/green backends. - -set -euo pipefail - -# Ensure a path starts with "/". The Kubernetes Gateway API rejects -# non-absolute values for the `Exact` and `PathPrefix` match types with: -# spec.rules[N].matches[M].path: Invalid value: ...: value must be an -# absolute path and start with '/' when type one of ['Exact', 'PathPrefix'] -# Developers often enter "health" in the UI expecting it to become "/health", -# so normalize here instead of surfacing a validator error per route. -ensure_absolute_path() { - local path="$1" - if [[ "$path" != /* ]]; then - echo "/$path" - else - echo "$path" - fi -} - -# Detect path type and convert path value accordingly -# Returns: "type:value" format -detect_path_type() { - local path="$1" - - # Check for wildcard (*) - use PathPrefix - if [[ "$path" == *"*"* ]]; then - # Remove trailing /* or * - local prefix_path="${path%/*}" - if [[ -z "$prefix_path" ]]; then - prefix_path="/" - fi - prefix_path=$(ensure_absolute_path "$prefix_path") - echo "PathPrefix:$prefix_path" - return - fi - - # Check for path parameters (:param) - use RegularExpression - if [[ "$path" == *:* ]]; then - # Replace :param with [^/]+ - local regex_path="${path//:+([^\/])/[^/]+}" - # For bash pattern replacement, we need to handle it differently - regex_path=$(echo "$path" | sed 's/:[^/]*/[^\/]+/g') - # RegularExpression values are not required to be absolute by Gateway API, - # so we leave them untouched. - echo "RegularExpression:$regex_path" - return - fi - - # Default: Exact match - path=$(ensure_absolute_path "$path") - echo "Exact:$path" -} - -# Get priority for path type (lower number = higher priority) -get_path_priority() { - local path="$1" - - if [[ "$path" != *":"* && "$path" != *"*"* ]]; then - echo "1" # Exact - highest priority - elif [[ "$path" == *":"* ]]; then - echo "2" # RegularExpression - medium priority - else - echo "3" # PathPrefix - lowest priority - fi -} - -is_httproute_empty() { - local yaml_content="$1" - - local num_rules - local backend_name - local backend_weight - - num_rules=$(yq '.spec.rules | length' <<< "$yaml_content") - backend_name=$(yq '.spec.rules[0].backendRefs[0].name' <<< "$yaml_content") - backend_weight=$(yq '.spec.rules[0].backendRefs[0].weight' <<< "$yaml_content") - - # An HTTPRoute is "empty" if it only has one rule with response-404 backend and weight 0 - if [[ "$num_rules" -eq 1 && \ - "$backend_name" == "response-404" && \ - "$backend_weight" == "0" ]]; then - echo "true" - else - echo "false" - fi -} - -create_http_rule() { - local rule_path="$1" - local service_json="$2" - local blue_green_config="$3" - local method="${4:-}" - - local service_name - local service_port - - service_name=$(echo "$service_json" | jq -r '.name') - service_port=$(echo "$service_json" | jq -r '.port.number // .port.name // 80') - - # Detect path type and get the converted path value - local path_type_value - path_type_value=$(detect_path_type "$rule_path") - local path_type="${path_type_value%%:*}" - local path_value="${path_type_value#*:}" - - echo "DEBUG: Original path='$rule_path', Detected type='$path_type', Converted value='$path_value'" >&2 - - # Build matches array with path and optional method - local matches_json - - # Add method if specified - if [[ -n "$method" && "$method" != "null" ]]; then - matches_json=$(jq -n \ - --arg path "$path_value" \ - --arg path_type "$path_type" \ - --arg method "$method" \ - '[{ - path: { - type: $path_type, - value: $path - }, - method: $method - }]') - else - matches_json=$(jq -n \ - --arg path "$path_value" \ - --arg path_type "$path_type" \ - '[{ - path: { - type: $path_type, - value: $path - } - }]') - fi - - # Check if there's blue/green configuration - if [[ "$blue_green_config" != "null" && -n "$blue_green_config" ]]; then - # Parse blue/green destinations and weights from the annotation - local blue_weight green_weight blue_service green_service - - blue_weight=$(echo "$blue_green_config" | jq -r '.forward.targetGroups[0].weight // 100') - green_weight=$(echo "$blue_green_config" | jq -r '.forward.targetGroups[1].weight // 0') - blue_service=$(echo "$blue_green_config" | jq -r '.forward.targetGroups[0].serviceName') - green_service=$(echo "$blue_green_config" | jq -r '.forward.targetGroups[1].serviceName') - - # Create rule with weighted backends (no URL rewrite) - jq -n \ - --argjson matches "$matches_json" \ - --arg blue_service "$blue_service" \ - --arg green_service "$green_service" \ - --arg service_port "$service_port" \ - --argjson blue_weight "$blue_weight" \ - --argjson green_weight "$green_weight" \ - '{ - matches: $matches, - backendRefs: [ - { - name: $blue_service, - port: ($service_port | tonumber), - weight: $blue_weight - }, - { - name: $green_service, - port: ($service_port | tonumber), - weight: $green_weight - } - ] - }' - else - # Single destination without blue/green (no URL rewrite) - jq -n \ - --argjson matches "$matches_json" \ - --arg service_name "$service_name" \ - --arg service_port "$service_port" \ - '{ - matches: $matches, - backendRefs: [ - { - name: $service_name, - port: ($service_port | tonumber) - } - ] - }' - fi -} - -update_httproute_rule() { - local hr_yaml="$1" - local rule_path="$2" - local service_json="$3" - local blue_green_config="$4" - - local service_name - local service_port - local updated_hr - - service_name=$(echo "$service_json" | jq -r '.name') - service_port=$(echo "$service_json" | jq -r '.port.number // .port.name // 80') - - # Update the first rule's path with Exact type (no URL rewrite) - updated_hr=$(echo "$hr_yaml" | yq eval ".spec.rules[0].matches[0].path.type = \"Exact\"") - updated_hr=$(echo "$updated_hr" | yq eval ".spec.rules[0].matches[0].path.value = \"$rule_path\"") - - # Remove filters (no URL rewrite needed) - updated_hr=$(echo "$updated_hr" | yq eval "del(.spec.rules[0].filters)") - - # Check if there's blue/green configuration - if [[ "$blue_green_config" != "null" && -n "$blue_green_config" ]]; then - # Parse blue/green destinations and weights - local blue_weight green_weight blue_service green_service - - blue_weight=$(echo "$blue_green_config" | jq -r '.forward.targetGroups[0].weight // 100') - green_weight=$(echo "$blue_green_config" | jq -r '.forward.targetGroups[1].weight // 0') - blue_service=$(echo "$blue_green_config" | jq -r '.forward.targetGroups[0].serviceName') - green_service=$(echo "$blue_green_config" | jq -r '.forward.targetGroups[1].serviceName') - - # Set blue backend - updated_hr=$(echo "$updated_hr" | yq eval ".spec.rules[0].backendRefs[0].name = \"${blue_service}\"") - updated_hr=$(echo "$updated_hr" | yq eval ".spec.rules[0].backendRefs[0].port = $service_port") - updated_hr=$(echo "$updated_hr" | yq eval ".spec.rules[0].backendRefs[0].weight = $blue_weight") - - # Add green backend - updated_hr=$(echo "$updated_hr" | yq eval ".spec.rules[0].backendRefs += [{\"name\": \"${green_service}\", \"port\": $service_port, \"weight\": $green_weight}]") - else - # Single destination - updated_hr=$(echo "$updated_hr" | yq eval ".spec.rules[0].backendRefs[0].name = \"${service_name}\"") - updated_hr=$(echo "$updated_hr" | yq eval ".spec.rules[0].backendRefs[0].port = $service_port") - updated_hr=$(echo "$updated_hr" | yq eval "del(.spec.rules[0].backendRefs[0].weight)") - fi - - echo "$updated_hr" -} - -find_rule_index() { - local hr_yaml="$1" - local target_path="$2" - local target_method="${3:-}" - - local num_rules - local i - local current_path - local current_method - - num_rules=$(yq '.spec.rules | length' <<< "$hr_yaml") - - for ((i=0; i "$HTTPROUTE_FILE" -else - # Detect the converted path value to match against existing rules - PATH_TYPE_VALUE=$(detect_path_type "$RULE_PATH") - CONVERTED_PATH="${PATH_TYPE_VALUE#*:}" - - RULE_INDEX=$(find_rule_index "$HTTPROUTE" "$CONVERTED_PATH" "${METHOD:-}") - echo "Found rule index for path '$CONVERTED_PATH' with method '${METHOD:-none}': $RULE_INDEX" - - # if there is a rule for the path we replace it - if [[ "$RULE_INDEX" != "-1" ]]; then - echo "Case 2: Replacing existing rule at index $RULE_INDEX" - UPDATED_HR=$(replace_existing_rule "$HTTPROUTE" "$RULE_PATH" "$SERVICE" "$BLUE_GREEN_CONFIG" "$RULE_INDEX" "${METHOD:-}") - echo "$UPDATED_HR" | yq "." > "$HTTPROUTE_FILE" - else - # if there is no rule for the path we add a new one - echo "Case 3: Adding new rule" - UPDATED_HR=$(add_new_rule "$HTTPROUTE" "$RULE_PATH" "$SERVICE" "$BLUE_GREEN_CONFIG" "${METHOD:-}") - - # Debug: Check if hostnames and parentRefs are present before saving - echo "DEBUG: Checking HTTPRoute before saving..." - HOSTNAMES=$(echo "$UPDATED_HR" | yq eval '.spec.hostnames | length' -) - PARENTREFS=$(echo "$UPDATED_HR" | yq eval '.spec.parentRefs | length' -) - echo "DEBUG: Number of hostnames: $HOSTNAMES" - echo "DEBUG: Number of parentRefs: $PARENTREFS" - - echo "$UPDATED_HR" | yq "." > "$HTTPROUTE_FILE" - fi -fi - -echo "" -echo "=== HTTPRoute configuration saved to: $HTTPROUTE_FILE ===" diff --git a/endpoint-exposer/scripts/istio/build_rule b/endpoint-exposer/scripts/istio/build_rule deleted file mode 100644 index b19ab5d..0000000 --- a/endpoint-exposer/scripts/istio/build_rule +++ /dev/null @@ -1,182 +0,0 @@ -#!/bin/bash - -# Build Rule: Generates routing rules from Kubernetes services for a specific scope. -# Supports single services and blue/green deployments with weighted traffic distribution. - -set -euo pipefail - -echo "=== DEBUG: Starting build_rule script ===" -echo "DEBUG: K8S_NAMESPACE=$K8S_NAMESPACE" -echo "DEBUG: SCOPE_ID=$SCOPE_ID" - -# Check for in-progress deployment -echo "DEBUG: Checking for in-progress deployment..." -SCOPE_JSON=$(np scope read --id "$SCOPE_ID" --format json) -echo "DEBUG: Scope JSON retrieved" - -IN_PROGRESS_DEPLOYMENT=$(echo "$SCOPE_JSON" | jq -r '.in_progress_deployment // "null"') -echo "DEBUG: IN_PROGRESS_DEPLOYMENT=$IN_PROGRESS_DEPLOYMENT" - -DEPLOYMENT_STATUS="" -SWITCHED_TRAFFIC=0 - -if [[ "$IN_PROGRESS_DEPLOYMENT" != "null" ]]; then - echo "DEBUG: Found in-progress deployment, fetching details..." - DEPLOYMENT_JSON=$(np deployment read --id "$IN_PROGRESS_DEPLOYMENT" --format json) - DEPLOYMENT_STATUS=$(echo "$DEPLOYMENT_JSON" | jq -r '.status') - SWITCHED_TRAFFIC=$(echo "$DEPLOYMENT_JSON" | jq -r '.strategy_data.desired_switched_traffic // 0') - echo "DEBUG: DEPLOYMENT_STATUS=$DEPLOYMENT_STATUS" - echo "DEBUG: SWITCHED_TRAFFIC=$SWITCHED_TRAFFIC" -fi - -# Get all services and filter by scope_id in selector -# Note: kubectl -l only filters by labels, not by selectors. scope_id is in the selector field. -echo "DEBUG: Fetching all services from namespace..." -ALL_SERVICES=$(kubectl get services -n "$K8S_NAMESPACE" -o json 2>&1) - -# Try to sanitize the JSON by removing any control characters or ANSI escape codes -echo "DEBUG: Sanitizing JSON output..." -ALL_SERVICES_CLEAN=$(echo "$ALL_SERVICES" | sed $'s/\x1b\\[[0-9;]*m//g' | tr -d '\000-\011\013-\037') -echo "DEBUG: Cleaned JSON length: ${#ALL_SERVICES_CLEAN} characters" - -# Check if we have valid JSON -if echo "$ALL_SERVICES_CLEAN" | jq empty 2>/dev/null; then - echo "DEBUG: JSON is valid after cleaning" - ALL_SERVICES="$ALL_SERVICES_CLEAN" -else - echo "DEBUG: WARNING - JSON may still have issues, attempting to parse anyway" - ALL_SERVICES="$ALL_SERVICES_CLEAN" -fi - -# Filter services by scope_id in selector (not label) -echo "DEBUG: Filtering services with scope_id=$SCOPE_ID in selector..." -SERVICES_JSON=$(echo "$ALL_SERVICES" | jq --arg scope_id "$SCOPE_ID" '{ - apiVersion: .apiVersion, - kind: .kind, - metadata: .metadata, - items: [.items[] | select(.spec.selector.scope_id == $scope_id)] -}') -echo "DEBUG: Filtered services JSON" - -NUM_SERVICES=$(echo "$SERVICES_JSON" | jq '.items | length') -echo "DEBUG: NUM_SERVICES=$NUM_SERVICES" - -if [[ "$NUM_SERVICES" -eq 0 ]]; then - echo "There is no service for scope_id=$SCOPE_ID. Publishing the rule with an empty backend" - - SCOPE_RULE='{"service": {"name": "response-404", "port": { "number": 80} }}' - echo "DEBUG: SCOPE_RULE (no services)=$SCOPE_RULE" -elif [[ "$NUM_SERVICES" -eq 1 ]]; then - echo "Found single service for scope_id=$SCOPE_ID" - - echo "DEBUG: Extracting service name and port..." - SERVICE_NAME=$(echo "$SERVICES_JSON" | jq -r '.items[0].metadata.name') - SERVICE_PORT=$(echo "$SERVICES_JSON" | jq -r '.items[0].spec.ports[0].port') - - echo "Service: $SERVICE_NAME, Port: $SERVICE_PORT" - echo "DEBUG: SERVICE_NAME=$SERVICE_NAME, SERVICE_PORT=$SERVICE_PORT" - - echo "DEBUG: Building SCOPE_RULE for single service..." - SCOPE_RULE=$(jq -n \ - --arg name "$SERVICE_NAME" \ - --argjson port "$SERVICE_PORT" \ - '{ - service: { - name: $name, - port: { - number: $port - } - } - }') - echo "DEBUG: SCOPE_RULE (single service)=$SCOPE_RULE" -else - echo "Detected blue/green deployment with $NUM_SERVICES services for scope_id=$SCOPE_ID" - - # Check if deployment is finalized - if so, only use the latest service - if [[ "$DEPLOYMENT_STATUS" == "finalized" ]]; then - echo "DEBUG: Deployment is finalized, using only the latest service" - - # Use only the first service (latest deployment) - BLUE_SERVICE=$(echo "$SERVICES_JSON" | jq -r '.items[0].metadata.name') - BLUE_PORT=$(echo "$SERVICES_JSON" | jq -r '.items[0].spec.ports[0].port') - - echo "Deployment finalized. Using service: $BLUE_SERVICE" - echo "DEBUG: SERVICE_NAME=$BLUE_SERVICE, SERVICE_PORT=$BLUE_PORT" - - SCOPE_RULE=$(jq -n \ - --arg name "$BLUE_SERVICE" \ - --argjson port "$BLUE_PORT" \ - '{ - service: { - name: $name, - port: { - number: $port - } - } - }') - echo "DEBUG: SCOPE_RULE (finalized deployment)=$SCOPE_RULE" - else - # Extract blue and green services - echo "DEBUG: Extracting blue service details..." - BLUE_SERVICE=$(echo "$SERVICES_JSON" | jq -r '.items[0].metadata.name') - BLUE_PORT=$(echo "$SERVICES_JSON" | jq -r '.items[0].spec.ports[0].port') - echo "DEBUG: BLUE_SERVICE=$BLUE_SERVICE, BLUE_PORT=$BLUE_PORT" - - echo "DEBUG: Extracting green service details..." - GREEN_SERVICE=$(echo "$SERVICES_JSON" | jq -r '.items[1].metadata.name') - GREEN_PORT=$(echo "$SERVICES_JSON" | jq -r '.items[1].spec.ports[0].port') - echo "DEBUG: GREEN_SERVICE=$GREEN_SERVICE, GREEN_PORT=$GREEN_PORT" - - # Determine weights based on deployment status - if [[ "$DEPLOYMENT_STATUS" == "running" ]]; then - echo "DEBUG: Deployment is running, using switched_traffic for weights" - # New service (green) gets the switched traffic percentage - GREEN_WEIGHT=$SWITCHED_TRAFFIC - # Old service (blue) gets the remaining traffic - BLUE_WEIGHT=$((100 - SWITCHED_TRAFFIC)) - echo "DEBUG: Using deployment weights - BLUE_WEIGHT=$BLUE_WEIGHT, GREEN_WEIGHT=$GREEN_WEIGHT" - else - # Fallback to annotation-based weights - echo "DEBUG: No running deployment, using annotation-based weights" - BLUE_WEIGHT=$(echo "$SERVICES_JSON" | jq -r '.items[0].metadata.annotations["weight"] // "100"' | sed 's/"//g') - GREEN_WEIGHT=$(echo "$SERVICES_JSON" | jq -r '.items[1].metadata.annotations["weight"] // "0"' | sed 's/"//g') - echo "DEBUG: BLUE_WEIGHT=$BLUE_WEIGHT (from annotation), GREEN_WEIGHT=$GREEN_WEIGHT (from annotation)" - fi - - echo "Blue: $BLUE_SERVICE (weight: $BLUE_WEIGHT), Green: $GREEN_SERVICE (weight: $GREEN_WEIGHT)" - - # Build blue/green annotation similar to ALB format - echo "DEBUG: Building SCOPE_RULE for blue/green deployment..." - SCOPE_RULE=$(jq -n \ - --arg blue_service "$BLUE_SERVICE" \ - --argjson blue_weight "$BLUE_WEIGHT" \ - --arg green_service "$GREEN_SERVICE" \ - --argjson green_weight "$GREEN_WEIGHT" \ - --argjson port "$BLUE_PORT" \ - '{ - blue_green_annotation: { - forward: { - targetGroups: [ - { - serviceName: $blue_service, - weight: $blue_weight - }, - { - serviceName: $green_service, - weight: $green_weight - } - ] - } - }, - service: { - name: $blue_service, - port: { - number: $port - } - } - }') - echo "DEBUG: SCOPE_RULE (blue/green)=$SCOPE_RULE" - fi -fi - -export SCOPE_RULE \ No newline at end of file diff --git a/endpoint-exposer/scripts/istio/config b/endpoint-exposer/scripts/istio/config deleted file mode 100755 index 1f11985..0000000 --- a/endpoint-exposer/scripts/istio/config +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# Configuration: Defines default gateway names and namespaces for public/private traffic routing. -# These values can be overridden by environment variables to support different cluster configurations. - -# Gateway configuration -# These values can be overridden by environment variables -export PUBLIC_GATEWAY_NAME="${PUBLIC_GATEWAY_NAME:-gateway-public}" -export PRIVATE_GATEWAY_NAME="${PRIVATE_GATEWAY_NAME:-gateway-private}" -export GATEWAY_NAMESPACE="${GATEWAY_NAMESPACE:-gateways}" - -# OPA configuration -export OPA_PROVIDER_NAME="${OPA_PROVIDER_NAME:-opa-ext-authz}" diff --git a/endpoint-exposer/scripts/istio/fetch_provider_data b/endpoint-exposer/scripts/istio/fetch_provider_data deleted file mode 100755 index f3fcbbe..0000000 --- a/endpoint-exposer/scripts/istio/fetch_provider_data +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -# Fetch Provider Data: Retrieves Kubernetes namespace from the container orchestration provider. -# Queries provider data based on service dimensions and exports K8S_NAMESPACE for downstream scripts. - -NRN=$(echo "$CONTEXT" | jq -r .entity_nrn) - -DIMENSIONS=$(echo "$CONTEXT" | jq .service.dimensions) - -DIMENSION_FILTER=$(echo "$DIMENSIONS" | jq -r 'to_entries | map("\(.key):\(.value)") | join(",")') - -if [ -z "$DIMENSION_FILTER" ] || [ "$DIMENSION_FILTER" = "" ]; then - PROVIDER_DATA=$(np provider list --categories container-orchestration --nrn "$NRN" --format json | jq -r ".results[0]") -else - PROVIDER_DATA=$(np provider list --categories container-orchestration --nrn "$NRN" --dimensions "$DIMENSION_FILTER" --format json | jq -r ".results[0]") -fi - -# K8S_NAMESPACE=$(echo "$PROVIDER_DATA" | jq -r .attributes.cluster.namespace) - -export K8S_NAMESPACE \ No newline at end of file diff --git a/endpoint-exposer/scripts/istio/process_routes b/endpoint-exposer/scripts/istio/process_routes deleted file mode 100755 index 69aaaff..0000000 --- a/endpoint-exposer/scripts/istio/process_routes +++ /dev/null @@ -1,116 +0,0 @@ -#!/bin/bash - -# Process Routes: Iterates through all configured routes and updates HTTPRoute with rules. -# Sorts routes by specificity (Exact > RegularExpression > PathPrefix) and builds rules for each scope. - -set -euo pipefail - -echo "=== Starting process_routes script ===" -echo "SERVICE_ID: $SERVICE_ID" -echo "SERVICE_SLUG: $SERVICE_SLUG" -echo "K8S_NAMESPACE: $K8S_NAMESPACE" -echo "ROUTES_JSON: $ROUTES_JSON" - -# Check if we have any routes to process -NUM_ROUTES=$(echo "$ROUTES_JSON" | jq 'length') -echo "Number of routes to process: $NUM_ROUTES" - -if [[ "$NUM_ROUTES" -eq 0 ]]; then - echo "No routes to process" - exit 0 -fi - -# Get application ID once -APPLICATION_ID=$(echo "$CONTEXT" | jq -r '.tags.application_id // empty') -if [[ -n "$APPLICATION_ID" ]]; then - echo "Application ID: $APPLICATION_ID" -else - echo "No Application ID found in context" - exit 1 -fi - -# Fetch all scopes once -echo "Fetching scopes for application $APPLICATION_ID..." -SCOPES_JSON=$(np scope list --application_id "$APPLICATION_ID" --format json | jq -rs ".[].results") -echo "Scopes fetched successfully" - -# Sort routes by path specificity (Exact > RegularExpression > PathPrefix) -# Priority: 1=Exact, 2=RegularExpression, 3=PathPrefix -echo "" -echo "=== Sorting routes by specificity ===" -SORTED_ROUTES=$(echo "$ROUTES_JSON" | jq 'sort_by( - if (.path | contains("*")) then 3 - elif (.path | contains(":")) then 2 - else 1 - end -)') -ROUTES_JSON="$SORTED_ROUTES" -echo "Routes sorted by specificity (Exact > RegularExpression > PathPrefix)" - -# Use existing HTTPROUTE_FILE if set, otherwise default to public -if [[ -z "${HTTPROUTE_FILE:-}" ]]; then - HTTPROUTE_FILE="$OUTPUT_DIR/httproute-$SERVICE_ID-public.yaml" -fi - -HTTPROUTE_NAME="${SERVICE_SLUG}-${SERVICE_ID}-route" - -export HTTPROUTE_FILE -echo "HTTPRoute file: $HTTPROUTE_FILE" -echo "HTTPRoute name: $HTTPROUTE_NAME" - -# Read the HTTPRoute from the file created in the previous step -if [[ ! -f "$HTTPROUTE_FILE" ]]; then - echo "ERROR: HTTPRoute file not found at $HTTPROUTE_FILE" - exit 1 -fi - -# Process each route -for ((i=0; i "$HTTPROUTE_FILE" - -echo "HTTPRoute hostname updated to: $DOMAIN" -echo "HTTPRoute parentRefs set to: $GATEWAY" - -# Debug: Verify the file was saved correctly -echo "DEBUG: Verifying saved file..." -SAVED_HOSTNAMES=$(cat "$HTTPROUTE_FILE" | yq eval '.spec.hostnames | length' -) -SAVED_PARENTREFS=$(cat "$HTTPROUTE_FILE" | yq eval '.spec.parentRefs | length' -) -echo "DEBUG: Saved file has $SAVED_HOSTNAMES hostnames" -echo "DEBUG: Saved file has $SAVED_PARENTREFS parentRefs" diff --git a/endpoint-exposer/templates/istio/httproute.yaml.tpl b/endpoint-exposer/templates/istio/httproute.yaml.tpl deleted file mode 100644 index 728c0aa..0000000 --- a/endpoint-exposer/templates/istio/httproute.yaml.tpl +++ /dev/null @@ -1,26 +0,0 @@ -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: {{ .service_slug }}-{{ .service_id }}-{{ .suffix }} - namespace: {{ .k8s_namespace }} - labels: - nullplatform.com/managed-by: endpoint-exposer - nullplatform.com/service-id: "{{ .service_id }}" - app.kubernetes.io/name: {{ .service_slug }} -spec: - parentRefs: - - name: {{ .gateway_name }} - namespace: {{ .gateway_namespace }} - group: gateway.networking.k8s.io - kind: Gateway - hostnames: - - {{ .domain }} - rules: - - matches: - - path: - type: PathPrefix - value: / - backendRefs: - - name: response-404 - port: 80 - weight: 0 diff --git a/endpoint-exposer/test/.gitignore b/endpoint-exposer/test/.gitignore deleted file mode 100644 index f426236..0000000 --- a/endpoint-exposer/test/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -# Test temporary files -*.tmp -*.log - -# BATS test outputs -test-*.tap -test-*.xml - -# Temporary directories created during tests -tmp/ -temp/ diff --git a/endpoint-exposer/test/CONTRIBUTING.md b/endpoint-exposer/test/CONTRIBUTING.md deleted file mode 100644 index 7da1759..0000000 --- a/endpoint-exposer/test/CONTRIBUTING.md +++ /dev/null @@ -1,302 +0,0 @@ -# Contributing to Tests - -## Adding New Tests - -### 1. Create a New Test File - -Create a new file named `test_.bats`: - -```bash -#!/usr/bin/env bats - -load helpers - -@test "feature: description of what is being tested" { - # Setup test data - export CONTEXT=$(load_fixture "fixture-name") - source "$SERVICE_PATH/scripts/istio/build_context" - - # Execute the code under test - run bash "$SERVICE_PATH/scripts/your-script" - - # Assert results - assert_success - assert_output --partial "expected output" - assert_file_exists "$OUTPUT_DIR/expected-file.yaml" - assert_file_contains "$OUTPUT_DIR/expected-file.yaml" "expected content" -} -``` - -### 2. Add Test Fixtures - -Create fixture files in `fixtures/` directory: - -```bash -# fixtures/my-new-scenario.json -{ - "service": { - "id": "test-id", - "slug": "test-service" - }, - "parameters": { - "publicDomain": "test.example.com", - "privateDomain": "test-private.example.com", - "authorization": { - "enabled": true - } - }, - "routes": [ - { - "path": "/api/test", - "method": "GET", - "scope": "test:read", - "visibility": "public" - } - ] -} -``` - -### 3. Use Helper Functions - -Available helpers from `helpers.bash`: - -#### Setup/Teardown -- `setup()` - Automatically called before each test -- `teardown()` - Automatically called after each test - -#### File Assertions -- `assert_file_exists ` - Assert file exists -- `assert_file_not_exists ` - Assert file does not exist -- `assert_file_contains ` - Assert file contains string -- `assert_file_not_contains ` - Assert file does not contain string -- `assert_yaml_contains ` - Assert YAML has key-value pair - -#### Fixtures -- `load_fixture ` - Load a fixture JSON file -- `create_test_context ` - Create minimal context -- `add_route_to_context ` - Add route to context - -#### Mocking -- `mock_kubectl()` - Create a mock kubectl command - -### 4. Test Structure Best Practices - -#### Arrange-Act-Assert Pattern - -```bash -@test "description" { - # Arrange - Setup test data - export CONTEXT=$(load_fixture "scenario") - source "$SERVICE_PATH/scripts/istio/build_context" - - # Act - Execute the code - run bash "$SERVICE_PATH/scripts/my-script" - - # Assert - Verify results - assert_success - assert_file_exists "$OUTPUT_DIR/output.yaml" -} -``` - -#### Test One Thing - -Each test should verify one specific behavior: - -```bash -# Good - tests one thing -@test "build_httproute: creates public HTTPRoute when routes exist" { - # ... -} - -# Good - tests one thing -@test "build_httproute: creates marker when no routes exist" { - # ... -} - -# Bad - tests multiple things -@test "build_httproute: handles all scenarios" { - # ... tests too many things -} -``` - -#### Descriptive Test Names - -Use the format: `: ` - -```bash -@test "build_httproute: creates HTTPRoute when routes exist" -@test "build_httproute: creates marker when no routes exist" -@test "build_httproute: fails with invalid visibility parameter" -``` - -### 5. Testing Different Scenarios - -#### Test Success Cases - -```bash -@test "script: succeeds with valid input" { - export CONTEXT=$(load_fixture "valid-scenario") - run bash "$SERVICE_PATH/scripts/my-script" - assert_success -} -``` - -#### Test Failure Cases - -```bash -@test "script: fails with invalid input" { - export CONTEXT='{"invalid": "data"}' - run bash "$SERVICE_PATH/scripts/my-script" - assert_failure -} -``` - -#### Test Edge Cases - -```bash -@test "script: handles empty routes array" { - export CONTEXT=$(create_test_context "id" "slug" "" "") - # ... -} - -@test "script: handles missing optional parameters" { - export CONTEXT='{ - "service": {"id": "test", "slug": "test"}, - "parameters": {}, - "routes": [] - }' - # ... -} -``` - -### 6. Integration Tests - -For end-to-end workflow tests: - -```bash -@test "integration: complete update workflow" { - export CONTEXT=$(load_fixture "complete-scenario") - - # Step 1: Build context - source "$SERVICE_PATH/scripts/istio/build_context" - - # Step 2: Build httproutes - export VISIBILITY="public" - bash "$SERVICE_PATH/scripts/istio/build_httproute" - - export VISIBILITY="private" - bash "$SERVICE_PATH/scripts/istio/build_httproute" - - # Step 3: Apply - run bash "$SERVICE_PATH/scripts/common/apply" - - # Assert complete workflow - assert_success - assert_file_exists "$OUTPUT_DIR/httproute-*-public.yaml" - # ... more assertions -} -``` - -### 7. Running Your Tests - -Run a specific test file: -```bash -bats test_my_feature.bats -``` - -Run all tests: -```bash -./run-tests.sh -``` - -Run with verbose output: -```bash -bats -t test_my_feature.bats -``` - -### 8. Debugging Tests - -Add debug output: -```bash -@test "my test" { - # Print variable values - echo "CONTEXT: $CONTEXT" >&3 - echo "OUTPUT_DIR: $OUTPUT_DIR" >&3 - - # Show file contents - cat "$OUTPUT_DIR/somefile.yaml" >&3 - - # ... rest of test -} -``` - -Run with trace: -```bash -bats -x test_my_feature.bats -``` - -### 9. Common Patterns - -#### Testing with Different Contexts - -```bash -@test "script: handles scenario A" { - export CONTEXT=$(load_fixture "scenario-a") - # ... test -} - -@test "script: handles scenario B" { - export CONTEXT=$(load_fixture "scenario-b") - # ... test -} -``` - -#### Testing File Generation - -```bash -@test "script: generates correct file" { - # ... run script - - # Check file exists - assert_file_exists "$OUTPUT_DIR/generated.yaml" - - # Check content - assert_file_contains "$OUTPUT_DIR/generated.yaml" "expected: value" - - # Check YAML structure - assert_yaml_contains "$OUTPUT_DIR/generated.yaml" ".metadata.name" "expected-name" -} -``` - -#### Testing Cleanup Behavior - -```bash -@test "script: creates cleanup marker when needed" { - # ... run script that should create marker - - assert_file_exists "$OUTPUT_DIR/.marker-deleted" - assert_file_not_exists "$OUTPUT_DIR/actual-resource.yaml" -} -``` - -### 10. Adding Tests to CI/CD - -The test suite can be integrated into CI/CD pipelines: - -```yaml -# Example GitHub Actions workflow -- name: Run tests - run: | - cd test - ./run-tests.sh -``` - -### 11. Test Coverage Guidelines - -Aim to test: -- ✅ Happy paths (normal operation) -- ✅ Error conditions (invalid input, missing data) -- ✅ Edge cases (empty arrays, null values, special characters) -- ✅ Integration scenarios (complete workflows) -- ✅ Cleanup behavior (resource deletion) -- ✅ Configuration variations (enabled/disabled features) diff --git a/endpoint-exposer/test/README.md b/endpoint-exposer/test/README.md deleted file mode 100644 index 7fc102b..0000000 --- a/endpoint-exposer/test/README.md +++ /dev/null @@ -1,103 +0,0 @@ -# Endpoint Exposer Tests - -This directory contains tests for the endpoint-exposer service using BATS (Bash Automated Testing System). - -## Prerequisites - -Install BATS: -```bash -# macOS -brew install bats-core - -# Linux -git clone https://github.com/bats-core/bats-core.git -cd bats-core -sudo ./install.sh /usr/local -``` - -## Running Tests - -Run all tests: -```bash -cd test -./run-tests.sh -``` - -Run a specific test file: -```bash -bats test_istio_workflows.bats -``` - -## Git Hooks - -The repository includes a pre-commit hook that automatically runs tests before each commit. - -Setup the git hooks: -```bash -./scripts/setup-hooks.sh -``` - -This configures git to use the `.githooks` directory. The pre-commit hook will: -- Run all BATS tests before allowing a commit -- Skip tests if BATS is not installed (with a warning) -- Prevent commits if tests fail - -## Test Structure - -- `fixtures/` - Test data and context files -- `helpers.bash` - Common test helper functions -- `test_*.bats` - Test files -- `run-tests.sh` - Script to run all tests - -## Writing Tests - -Tests validate that given a specific context, the correct output files are generated without actually applying to Kubernetes. - -### Context Structure - -The test fixtures use the full nullplatform action context structure: - -```json -{ - "action": "service:action:update", - "id": "action-id", - "parameters": { - "routes": [...], - "public_domain": "...", - "private_domain": "...", - "authorization": { "enabled": true/false } - }, - "service": { - "id": "service-id", - "slug": "service-slug", - "attributes": { - "routes": [...], - "public_domain": "...", - "authorization": { "enabled": true/false } - } - }, - "tags": {...}, - ... -} -``` - -### Example Test - -```bash -@test "description" { - # Load a fixture with the full context structure - export CONTEXT=$(load_fixture "simple-public-routes") - - # Run workflow step - run bash "$SERVICE_PATH/scripts/istio/build_context" - - # Assert results - assert_success - assert_output --partial "expected output" - - # Verify generated files - assert_file_exists "$OUTPUT_DIR/httproute-service-id-public.yaml" - assert_file_contains "$OUTPUT_DIR/httproute-service-id-public.yaml" "expected content" -} -``` -# Test diff --git a/endpoint-exposer/test/fixtures/authorization-disabled.json b/endpoint-exposer/test/fixtures/authorization-disabled.json deleted file mode 100644 index d9ed236..0000000 --- a/endpoint-exposer/test/fixtures/authorization-disabled.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "action": "service:action:update", - "id": "5b7636e1-304b-4ef9-92a9-2a0b102686f4", - "name": "update-api", - "slug": "update-api", - "status": "pending", - "created_at": "2026-01-12T19:50:09.357Z", - "updated_at": "2026-01-12T19:50:09.357Z", - "parameters": { - "routes": [ - { - "visibility": "public", - "path": "/api/users", - "scope": "users:read", - "method": "GET" - }, - { - "visibility": "private", - "path": "/api/admin", - "scope": "admin:read", - "method": "GET" - } - ], - "public_domain": "api.edenred.nullimplementation.com", - "authorization": { - "enabled": false - }, - "private_domain": "api-private.edenred.nullimplementation.com" - }, - "results": {}, - "type": "update", - "specification": { - "id": "4c85dfb2-b489-4cd0-af0f-651f670ac32a", - "slug": "update-endpoint-exposer" - }, - "service": { - "id": "fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd", - "slug": "api", - "attributes": { - "routes": [ - { - "visibility": "public", - "path": "/api/users", - "scope": "users:read", - "method": "GET" - }, - { - "visibility": "private", - "path": "/api/admin", - "scope": "admin:read", - "method": "GET" - } - ], - "public_domain": "api.edenred.nullimplementation.com", - "authorization": { - "enabled": false - }, - "private_domain": "api-private.edenred.nullimplementation.com" - }, - "type": "dependency", - "specification": { - "id": "7e71962b-1282-4131-84ae-bf7687238c74", - "slug": "endpoint-exposer" - }, - "dimensions": {} - }, - "link": null, - "user": { - "id": 1621446846, - "email": "javier.solis+edenred@nullplatform.io" - }, - "tags": { - "organization_id": "1858797910", - "organization": "edenred", - "namespace_id": "1340017944", - "namespace": "playground", - "account_id": "758973013", - "account": "playground", - "application_id": "179976948", - "application": "floppy-bird-api" - }, - "entity_nrn": "organization=1858797910:account=758973013:namespace=1340017944:application=179976948" -} diff --git a/endpoint-exposer/test/fixtures/no-public-routes.json b/endpoint-exposer/test/fixtures/no-public-routes.json deleted file mode 100644 index 0980832..0000000 --- a/endpoint-exposer/test/fixtures/no-public-routes.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "action": "service:action:update", - "id": "5b7636e1-304b-4ef9-92a9-2a0b102686f4", - "name": "update-api", - "slug": "update-api", - "status": "pending", - "created_at": "2026-01-12T19:50:09.357Z", - "updated_at": "2026-01-12T19:50:09.357Z", - "parameters": { - "routes": [ - { - "visibility": "private", - "path": "/api/admin", - "scope": "admin:read", - "method": "GET" - } - ], - "public_domain": "", - "authorization": { - "enabled": false - }, - "private_domain": "api-private.edenred.nullimplementation.com" - }, - "results": {}, - "type": "update", - "specification": { - "id": "4c85dfb2-b489-4cd0-af0f-651f670ac32a", - "slug": "update-endpoint-exposer" - }, - "service": { - "id": "fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd", - "slug": "api", - "attributes": { - "routes": [ - { - "visibility": "private", - "path": "/api/admin", - "scope": "admin:read", - "method": "GET" - } - ], - "public_domain": "", - "authorization": { - "enabled": false - }, - "private_domain": "api-private.edenred.nullimplementation.com" - }, - "type": "dependency", - "specification": { - "id": "7e71962b-1282-4131-84ae-bf7687238c74", - "slug": "endpoint-exposer" - }, - "dimensions": {} - }, - "link": null, - "user": { - "id": 1621446846, - "email": "javier.solis+edenred@nullplatform.io" - }, - "tags": { - "organization_id": "1858797910", - "organization": "edenred", - "namespace_id": "1340017944", - "namespace": "playground", - "account_id": "758973013", - "account": "playground", - "application_id": "179976948", - "application": "floppy-bird-api" - }, - "entity_nrn": "organization=1858797910:account=758973013:namespace=1340017944:application=179976948" -} diff --git a/endpoint-exposer/test/fixtures/public-and-private-routes.json b/endpoint-exposer/test/fixtures/public-and-private-routes.json deleted file mode 100644 index efff3d4..0000000 --- a/endpoint-exposer/test/fixtures/public-and-private-routes.json +++ /dev/null @@ -1,95 +0,0 @@ -{ - "action": "service:action:update", - "id": "5b7636e1-304b-4ef9-92a9-2a0b102686f4", - "name": "update-api", - "slug": "update-api", - "status": "pending", - "created_at": "2026-01-12T19:50:09.357Z", - "updated_at": "2026-01-12T19:50:09.357Z", - "parameters": { - "routes": [ - { - "visibility": "public", - "path": "/api/users", - "scope": "users:read", - "method": "GET" - }, - { - "visibility": "private", - "path": "/api/admin", - "scope": "admin:read", - "method": "GET" - }, - { - "visibility": "private", - "path": "/api/admin/users", - "scope": "admin:users:write", - "method": "POST" - } - ], - "public_domain": "api.edenred.nullimplementation.com", - "authorization": { - "enabled": true - }, - "private_domain": "api-private.edenred.nullimplementation.com" - }, - "results": {}, - "type": "update", - "specification": { - "id": "4c85dfb2-b489-4cd0-af0f-651f670ac32a", - "slug": "update-endpoint-exposer" - }, - "service": { - "id": "fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd", - "slug": "api", - "attributes": { - "routes": [ - { - "visibility": "public", - "path": "/api/users", - "scope": "users:read", - "method": "GET" - }, - { - "visibility": "private", - "path": "/api/admin", - "scope": "admin:read", - "method": "GET" - }, - { - "visibility": "private", - "path": "/api/admin/users", - "scope": "admin:users:write", - "method": "POST" - } - ], - "public_domain": "api.edenred.nullimplementation.com", - "authorization": { - "enabled": true - }, - "private_domain": "api-private.edenred.nullimplementation.com" - }, - "type": "dependency", - "specification": { - "id": "7e71962b-1282-4131-84ae-bf7687238c74", - "slug": "endpoint-exposer" - }, - "dimensions": {} - }, - "link": null, - "user": { - "id": 1621446846, - "email": "javier.solis+edenred@nullplatform.io" - }, - "tags": { - "organization_id": "1858797910", - "organization": "edenred", - "namespace_id": "1340017944", - "namespace": "playground", - "account_id": "758973013", - "account": "playground", - "application_id": "179976948", - "application": "floppy-bird-api" - }, - "entity_nrn": "organization=1858797910:account=758973013:namespace=1340017944:application=179976948" -} diff --git a/endpoint-exposer/test/fixtures/simple-public-routes.json b/endpoint-exposer/test/fixtures/simple-public-routes.json deleted file mode 100644 index 1a1d16e..0000000 --- a/endpoint-exposer/test/fixtures/simple-public-routes.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "action": "service:action:update", - "id": "5b7636e1-304b-4ef9-92a9-2a0b102686f4", - "name": "update-api", - "slug": "update-api", - "status": "pending", - "created_at": "2026-01-12T19:50:09.357Z", - "updated_at": "2026-01-12T19:50:09.357Z", - "parameters": { - "routes": [ - { - "visibility": "public", - "path": "/api/users", - "scope": "users:read", - "method": "GET" - }, - { - "visibility": "public", - "path": "/api/users", - "scope": "users:write", - "method": "POST" - } - ], - "public_domain": "api.edenred.nullimplementation.com", - "authorization": { - "enabled": false - }, - "private_domain": "" - }, - "results": {}, - "type": "update", - "specification": { - "id": "4c85dfb2-b489-4cd0-af0f-651f670ac32a", - "slug": "update-endpoint-exposer" - }, - "service": { - "id": "fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd", - "slug": "api", - "attributes": { - "routes": [ - { - "visibility": "public", - "path": "/api/users", - "scope": "users:read", - "method": "GET" - }, - { - "visibility": "public", - "path": "/api/users", - "scope": "users:write", - "method": "POST" - } - ], - "public_domain": "api.edenred.nullimplementation.com", - "authorization": { - "enabled": false - }, - "private_domain": "api-private.edenred.nullimplementation.com" - }, - "type": "dependency", - "specification": { - "id": "7e71962b-1282-4131-84ae-bf7687238c74", - "slug": "endpoint-exposer" - }, - "dimensions": {} - }, - "link": null, - "user": { - "id": 1621446846, - "email": "javier.solis+edenred@nullplatform.io" - }, - "tags": { - "organization_id": "1858797910", - "organization": "edenred", - "namespace_id": "1340017944", - "namespace": "playground", - "account_id": "758973013", - "account": "playground", - "application_id": "179976948", - "application": "floppy-bird-api" - }, - "entity_nrn": "organization=1858797910:account=758973013:namespace=1340017944:application=179976948" -} diff --git a/endpoint-exposer/test/helpers.bash b/endpoint-exposer/test/helpers.bash deleted file mode 100644 index 115840e..0000000 --- a/endpoint-exposer/test/helpers.bash +++ /dev/null @@ -1,298 +0,0 @@ -#!/bin/bash - -# Test helpers for endpoint-exposer tests - -# Setup function called before each test -setup() { - # Create temporary output directory - export TEST_TEMP_DIR="$(mktemp -d)" - export OUTPUT_DIR="$TEST_TEMP_DIR/output" - mkdir -p "$OUTPUT_DIR" - - # Set SERVICE_PATH to parent directory - export SERVICE_PATH="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)" - - # Mock DRY_RUN to true by default to avoid actual kubectl calls - export DRY_RUN="${DRY_RUN:-true}" - export ACTION="${ACTION:-apply}" - - # Load bats support libraries if available - load_bats_support_libraries -} - -# Teardown function called after each test -teardown() { - # Clean up temporary directory - if [[ -n "$TEST_TEMP_DIR" ]] && [[ -d "$TEST_TEMP_DIR" ]]; then - rm -rf "$TEST_TEMP_DIR" - fi -} - -# Load bats support libraries or define basic assertions -load_bats_support_libraries() { - # Try to load bats-support and bats-assert if available - local loaded=false - if [[ -f "/usr/local/lib/bats-support/load.bash" ]]; then - load "/usr/local/lib/bats-support/load.bash" - loaded=true - fi - if [[ -f "/usr/local/lib/bats-assert/load.bash" ]]; then - load "/usr/local/lib/bats-assert/load.bash" - loaded=true - fi - - # If libraries not loaded, define basic assertion functions - if [[ "$loaded" == "false" ]]; then - # Define assert_success - assert_success() { - if [[ "$status" -ne 0 ]]; then - echo "Expected success (exit 0) but got: $status" >&2 - echo "Output: $output" >&2 - return 1 - fi - } - - # Define assert_failure - assert_failure() { - if [[ "$status" -eq 0 ]]; then - echo "Expected failure (non-zero exit) but got: $status" >&2 - echo "Output: $output" >&2 - return 1 - fi - } - - # Define assert_output - assert_output() { - local expected="" - local partial=false - - while [[ $# -gt 0 ]]; do - case $1 in - --partial) - partial=true - shift - ;; - *) - expected="$1" - shift - ;; - esac - done - - if [[ "$partial" == "true" ]]; then - if [[ "$output" != *"$expected"* ]]; then - echo "Expected output to contain: $expected" >&2 - echo "Actual output: $output" >&2 - return 1 - fi - else - if [[ "$output" != "$expected" ]]; then - echo "Expected output: $expected" >&2 - echo "Actual output: $output" >&2 - return 1 - fi - fi - } - fi -} - -# Assert that a file exists -assert_file_exists() { - local file="$1" - if [[ ! -f "$file" ]]; then - echo "File does not exist: $file" >&2 - return 1 - fi -} - -# Assert that a file does not exist -assert_file_not_exists() { - local file="$1" - if [[ -f "$file" ]]; then - echo "File exists but should not: $file" >&2 - return 1 - fi -} - -# Assert that a file contains a string -assert_file_contains() { - local file="$1" - local expected="$2" - - if [[ ! -f "$file" ]]; then - echo "File does not exist: $file" >&2 - return 1 - fi - - if ! grep -q "$expected" "$file"; then - echo "File does not contain expected string: $expected" >&2 - echo "File contents:" >&2 - cat "$file" >&2 - return 1 - fi -} - -# Assert that a file does not contain a string -assert_file_not_contains() { - local file="$1" - local unexpected="$2" - - if [[ ! -f "$file" ]]; then - echo "File does not exist: $file" >&2 - return 1 - fi - - if grep -q "$unexpected" "$file"; then - echo "File contains unexpected string: $unexpected" >&2 - echo "File contents:" >&2 - cat "$file" >&2 - return 1 - fi -} - -# Assert that a YAML file has a specific key-value pair -assert_yaml_contains() { - local file="$1" - local key="$2" - local expected_value="$3" - - if [[ ! -f "$file" ]]; then - echo "File does not exist: $file" >&2 - return 1 - fi - - local actual_value - actual_value=$(yq eval "$key" "$file" 2>/dev/null || echo "") - - if [[ "$actual_value" != "$expected_value" ]]; then - echo "YAML key '$key' has unexpected value" >&2 - echo "Expected: $expected_value" >&2 - echo "Actual: $actual_value" >&2 - return 1 - fi -} - -# Count the number of YAML documents in a file -count_yaml_documents() { - local file="$1" - grep -c "^---" "$file" || echo "0" -} - -# Load a fixture context file -load_fixture() { - local fixture_name="$1" - local fixture_file="$BATS_TEST_DIRNAME/fixtures/$fixture_name.json" - - if [[ ! -f "$fixture_file" ]]; then - echo "Fixture not found: $fixture_file" >&2 - return 1 - fi - - cat "$fixture_file" -} - -# Mock kubectl to avoid actual API calls -mock_kubectl() { - # Create a mock kubectl script - cat > "$TEST_TEMP_DIR/kubectl" << 'EOF' -#!/bin/bash -echo "Mock kubectl called with: $@" >&2 -exit 0 -EOF - chmod +x "$TEST_TEMP_DIR/kubectl" - export PATH="$TEST_TEMP_DIR:$PATH" -} - -# Create a minimal valid context for testing with full structure -create_test_context() { - local service_id="${1:-test-service-id}" - local service_slug="${2:-test-service}" - local public_domain="${3:-test.example.com}" - local private_domain="${4:-test-private.example.com}" - - cat < /dev/null; then - echo -e "${RED}Error: bats is not installed${NC}" - echo "" - echo "Install bats:" - echo " macOS: brew install bats-core" - echo " Linux: git clone https://github.com/bats-core/bats-core.git && cd bats-core && sudo ./install.sh /usr/local" - echo "" - exit 1 -fi - -# Check if jq is installed (required by tests) -if ! command -v jq &> /dev/null; then - echo -e "${RED}Error: jq is not installed${NC}" - echo "" - echo "Install jq:" - echo " macOS: brew install jq" - echo " Linux: sudo apt-get install jq" - echo "" - exit 1 -fi - -# Change to test directory -cd "$(dirname "$0")" - -# Run tests -echo "Running tests..." -echo "" - -TEST_FILES=( - "test_build_context.bats" - "test_build_httproute.bats" - "test_authorization_policy.bats" - "test_apply_cleanup.bats" - "test_integration.bats" -) - -FAILED=0 -PASSED=0 - -for test_file in "${TEST_FILES[@]}"; do - if [[ -f "$test_file" ]]; then - echo -e "${YELLOW}Running $test_file...${NC}" - if bats "$test_file"; then - ((PASSED++)) - echo -e "${GREEN}✓ $test_file passed${NC}" - else - ((FAILED++)) - echo -e "${RED}✗ $test_file failed${NC}" - fi - echo "" - fi -done - -echo "================================================" -echo " Test Summary" -echo "================================================" -echo -e "Passed: ${GREEN}$PASSED${NC}" -echo -e "Failed: ${RED}$FAILED${NC}" -echo "" - -if [[ $FAILED -gt 0 ]]; then - echo -e "${RED}Some tests failed${NC}" - exit 1 -else - echo -e "${GREEN}All tests passed!${NC}" - exit 0 -fi diff --git a/endpoint-exposer/test/test_apply_cleanup.bats b/endpoint-exposer/test/test_apply_cleanup.bats deleted file mode 100644 index cfc76bd..0000000 --- a/endpoint-exposer/test/test_apply_cleanup.bats +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env bats - -load helpers - -setup() { - export TEST_TEMP_DIR="$(mktemp -d)" - export OUTPUT_DIR="$TEST_TEMP_DIR/output" - mkdir -p "$OUTPUT_DIR" - export SERVICE_PATH="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)" - - # Load assert functions - load_bats_support_libraries - - export K8S_NAMESPACE="test-namespace" - export SERVICE_ID="test-service-id" - export SERVICE_SLUG="test-service" - export ACTION="apply" - export DRY_RUN="true" - - # Mock kubectl - mock_kubectl -} - -@test "apply: detects public httproute marker and attempts deletion" { - # Create marker file - touch "$OUTPUT_DIR/.httproute-public-deleted" - - run bash "$SERVICE_PATH/scripts/common/apply" - - assert_success - assert_output --partial "Public HTTPRoute marked for deletion" - assert_output --partial "httproute" - assert_output --partial "$SERVICE_SLUG-$SERVICE_ID-public" -} - -@test "apply: detects private httproute marker and attempts deletion" { - # Create marker file - touch "$OUTPUT_DIR/.httproute-private-deleted" - - run bash "$SERVICE_PATH/scripts/common/apply" - - assert_success - assert_output --partial "Private HTTPRoute marked for deletion" - assert_output --partial "httproute" - assert_output --partial "$SERVICE_SLUG-$SERVICE_ID-private" -} - -@test "apply: detects public authz marker and attempts deletion" { - # Create marker file - touch "$OUTPUT_DIR/.authz-public-deleted" - - run bash "$SERVICE_PATH/scripts/common/apply" - - assert_success - assert_output --partial "Public AuthorizationPolicy marked for deletion" - assert_output --partial "authorizationpolicy" - assert_output --partial "$SERVICE_SLUG-$SERVICE_ID-authz-public" -} - -@test "apply: detects private authz marker and attempts deletion" { - # Create marker file - touch "$OUTPUT_DIR/.authz-private-deleted" - - run bash "$SERVICE_PATH/scripts/common/apply" - - assert_success - assert_output --partial "Private AuthorizationPolicy marked for deletion" - assert_output --partial "authorizationpolicy" - assert_output --partial "$SERVICE_SLUG-$SERVICE_ID-authz-private" -} - -@test "apply: handles multiple marker files" { - # Create multiple marker files - touch "$OUTPUT_DIR/.httproute-public-deleted" - touch "$OUTPUT_DIR/.httproute-private-deleted" - touch "$OUTPUT_DIR/.authz-public-deleted" - touch "$OUTPUT_DIR/.authz-private-deleted" - - run bash "$SERVICE_PATH/scripts/common/apply" - - assert_success - assert_output --partial "Public HTTPRoute marked for deletion" - assert_output --partial "Private HTTPRoute marked for deletion" - assert_output --partial "Public AuthorizationPolicy marked for deletion" - assert_output --partial "Private AuthorizationPolicy marked for deletion" -} - -@test "apply: applies yaml files when present" { - # Create a test yaml file - cat > "$OUTPUT_DIR/test-resource.yaml" << EOF -apiVersion: v1 -kind: ConfigMap -metadata: - name: test -EOF - - run bash "$SERVICE_PATH/scripts/common/apply" - - assert_success - assert_output --partial "Applying 1 resources" -} - -@test "apply: handles no resources to apply" { - # No yaml files, no markers - - run bash "$SERVICE_PATH/scripts/common/apply" - - assert_success - assert_output --partial "No resources to apply" -} - -@test "apply: removes marker files after processing" { - # Create marker files - touch "$OUTPUT_DIR/.httproute-public-deleted" - touch "$OUTPUT_DIR/.authz-private-deleted" - - bash "$SERVICE_PATH/scripts/common/apply" - - # Marker files should be removed - assert_file_not_exists "$OUTPUT_DIR/.httproute-public-deleted" - assert_file_not_exists "$OUTPUT_DIR/.authz-private-deleted" -} - -@test "apply: moves yaml files to apply directory after processing" { - # Create a test yaml file - cat > "$OUTPUT_DIR/test-resource.yaml" << EOF -apiVersion: v1 -kind: ConfigMap -metadata: - name: test -EOF - - bash "$SERVICE_PATH/scripts/common/apply" - - # Original file should be moved - assert_file_not_exists "$OUTPUT_DIR/test-resource.yaml" - # Should be in apply directory - assert_file_exists "$OUTPUT_DIR/apply/test-resource.yaml" -} diff --git a/endpoint-exposer/test/test_build_context.bats b/endpoint-exposer/test/test_build_context.bats deleted file mode 100644 index a337351..0000000 --- a/endpoint-exposer/test/test_build_context.bats +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env bats - -load helpers - -setup() { - # Call parent setup - export TEST_TEMP_DIR="$(mktemp -d)" - export OUTPUT_DIR="$TEST_TEMP_DIR/output" - mkdir -p "$OUTPUT_DIR" - export SERVICE_PATH="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)" - - # Load assert functions - load_bats_support_libraries - - # Mock K8S_NAMESPACE (required by build_context) - export K8S_NAMESPACE="test-namespace" -} - -teardown() { - if [[ -n "$TEST_TEMP_DIR" ]] && [[ -d "$TEST_TEMP_DIR" ]]; then - rm -rf "$TEST_TEMP_DIR" - fi -} - -@test "build_context: extracts service id and slug correctly" { - export CONTEXT=$(load_fixture "simple-public-routes") - - source "$SERVICE_PATH/scripts/istio/build_context" - - [[ "$SERVICE_ID" == "fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd" ]] - [[ "$SERVICE_SLUG" == "api" ]] -} - -@test "build_context: extracts public and private domains" { - export CONTEXT=$(load_fixture "public-and-private-routes") - - source "$SERVICE_PATH/scripts/istio/build_context" - - [[ "$PUBLIC_DOMAIN" == "api.edenred.nullimplementation.com" ]] - [[ "$PRIVATE_DOMAIN" == "api-private.edenred.nullimplementation.com" ]] -} - -@test "build_context: splits routes by visibility" { - export CONTEXT=$(load_fixture "public-and-private-routes") - - source "$SERVICE_PATH/scripts/istio/build_context" - - # Check public routes - local num_public=$(echo "$PUBLIC_ROUTES_JSON" | jq 'length') - [[ "$num_public" == "1" ]] - - # Check private routes - local num_private=$(echo "$PRIVATE_ROUTES_JSON" | jq 'length') - [[ "$num_private" == "2" ]] -} - -@test "build_context: handles missing visibility as public" { - export CONTEXT='{ - "service": {"id": "test-id", "slug": "test"}, - "parameters": {"publicDomain": "test.com", "privateDomain": ""}, - "routes": [ - {"path": "/test", "method": "GET", "scope": "test:read"} - ] - }' - - source "$SERVICE_PATH/scripts/istio/build_context" - - # Route without visibility should be treated as public - local num_public=$(echo "$PUBLIC_ROUTES_JSON" | jq 'length') - [[ "$num_public" == "1" ]] - - local num_private=$(echo "$PRIVATE_ROUTES_JSON" | jq 'length') - [[ "$num_private" == "0" ]] -} - -@test "build_context: handles empty private domain" { - export CONTEXT=$(load_fixture "simple-public-routes") - - source "$SERVICE_PATH/scripts/istio/build_context" - - [[ "$PUBLIC_DOMAIN" == "api.edenred.nullimplementation.com" ]] - [[ -z "$PRIVATE_DOMAIN" ]] -} - -@test "build_context: exports all required variables" { - export CONTEXT=$(load_fixture "public-and-private-routes") - - source "$SERVICE_PATH/scripts/istio/build_context" - - # Check that all required variables are exported - [[ -n "$SERVICE_ID" ]] - [[ -n "$SERVICE_SLUG" ]] - [[ -n "$PUBLIC_DOMAIN" ]] - [[ -n "$PRIVATE_DOMAIN" ]] - [[ -n "$ROUTES_JSON" ]] - [[ -n "$PUBLIC_ROUTES_JSON" ]] - [[ -n "$PRIVATE_ROUTES_JSON" ]] -} diff --git a/endpoint-exposer/test/test_build_httproute.bats b/endpoint-exposer/test/test_build_httproute.bats deleted file mode 100644 index 6a9bf23..0000000 --- a/endpoint-exposer/test/test_build_httproute.bats +++ /dev/null @@ -1,179 +0,0 @@ -#!/usr/bin/env bats - -load helpers - -setup() { - # Call parent setup - export TEST_TEMP_DIR="$(mktemp -d)" - export OUTPUT_DIR="$TEST_TEMP_DIR/output" - mkdir -p "$OUTPUT_DIR" - export SERVICE_PATH="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)" - - # Load assert functions - load_bats_support_libraries - - # Mock kubectl and provider data - export K8S_NAMESPACE="test-namespace" - export ALB_NAME="test-alb" - - # Mock gomplate - cat > "$TEST_TEMP_DIR/gomplate" << 'EOF' -#!/bin/bash -# Simple gomplate mock - just copy template to output -TEMPLATE_FILE="" -OUTPUT_FILE="" - -while [[ $# -gt 0 ]]; do - case $1 in - -f) TEMPLATE_FILE="$2"; shift 2 ;; - -o) OUTPUT_FILE="$2"; shift 2 ;; - -c) shift 2 ;; # Ignore context - *) shift ;; - esac -done - -if [[ -n "$TEMPLATE_FILE" ]] && [[ -n "$OUTPUT_FILE" ]]; then - # For testing, just create a valid YAML with the service info - cat > "$OUTPUT_FILE" << YAML -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: ${SERVICE_SLUG}-${SERVICE_ID}-${SUFFIX:-public} - namespace: ${K8S_NAMESPACE} -spec: - hostnames: - - ${DOMAIN} -YAML -fi -EOF - chmod +x "$TEST_TEMP_DIR/gomplate" - export PATH="$TEST_TEMP_DIR:$PATH" - - # Mock process_routes script - if [[ ! -f "$SERVICE_PATH/scripts/istio/process_routes.bak" ]]; then - if [[ -f "$SERVICE_PATH/scripts/istio/process_routes" ]]; then - cp "$SERVICE_PATH/scripts/istio/process_routes" "$SERVICE_PATH/scripts/istio/process_routes.bak" - fi - fi - cat > "$SERVICE_PATH/scripts/istio/process_routes" << 'MOCKEOF' -#!/bin/bash -# Mock - does nothing -# Use return instead of exit so it doesn't exit the sourcing shell -return 0 2>/dev/null || true -MOCKEOF - chmod +x "$SERVICE_PATH/scripts/istio/process_routes" -} - -teardown() { - # Always restore original process_routes if backup exists - if [[ -f "$SERVICE_PATH/scripts/istio/process_routes.bak" ]]; then - mv -f "$SERVICE_PATH/scripts/istio/process_routes.bak" "$SERVICE_PATH/scripts/istio/process_routes" - fi - - # Clean up temp directory - if [[ -n "$TEST_TEMP_DIR" ]] && [[ -d "$TEST_TEMP_DIR" ]]; then - rm -rf "$TEST_TEMP_DIR" - fi -} - -@test "build_httproute: generates public HTTPRoute with routes" { - export CONTEXT=$(load_fixture "simple-public-routes") - source "$SERVICE_PATH/scripts/istio/build_context" - - export VISIBILITY="public" - - run bash "$SERVICE_PATH/scripts/istio/build_httproute" - - assert_success - assert_file_exists "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-public.yaml" -} - -@test "build_httproute: generates private HTTPRoute with routes" { - export CONTEXT=$(load_fixture "public-and-private-routes") - source "$SERVICE_PATH/scripts/istio/build_context" - - export VISIBILITY="private" - - run bash "$SERVICE_PATH/scripts/istio/build_httproute" - - assert_success - assert_file_exists "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-private.yaml" -} - -@test "build_httproute: creates marker file when no public routes" { - export CONTEXT=$(load_fixture "no-public-routes") - source "$SERVICE_PATH/scripts/istio/build_context" - - export VISIBILITY="public" - - run bash "$SERVICE_PATH/scripts/istio/build_httproute" - - assert_success - assert_file_not_exists "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-public.yaml" - assert_file_exists "$OUTPUT_DIR/.httproute-public-deleted" -} - -@test "build_httproute: creates marker file when no public domain" { - export CONTEXT='{ - "service": {"id": "test-id", "slug": "test"}, - "parameters": {"publicDomain": "", "privateDomain": "private.test.com"}, - "routes": [{"path": "/test", "method": "GET", "scope": "test", "visibility": "public"}] - }' - source "$SERVICE_PATH/scripts/istio/build_context" - - export VISIBILITY="public" - - run bash "$SERVICE_PATH/scripts/istio/build_httproute" - - assert_success - assert_file_not_exists "$OUTPUT_DIR/httproute-test-id-public.yaml" - assert_file_exists "$OUTPUT_DIR/.httproute-public-deleted" -} - -@test "build_httproute: creates marker file when no private routes" { - export CONTEXT=$(load_fixture "simple-public-routes") - source "$SERVICE_PATH/scripts/istio/build_context" - - export VISIBILITY="private" - - run bash "$SERVICE_PATH/scripts/istio/build_httproute" - - assert_success - assert_file_not_exists "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-private.yaml" - assert_file_exists "$OUTPUT_DIR/.httproute-private-deleted" -} - -@test "build_httproute: fails with invalid visibility" { - export CONTEXT=$(load_fixture "simple-public-routes") - source "$SERVICE_PATH/scripts/istio/build_context" - - export VISIBILITY="invalid" - - run bash "$SERVICE_PATH/scripts/istio/build_httproute" - - assert_failure -} - -@test "build_httproute: exports HTTPROUTE_PUBLIC_FILE for public" { - export CONTEXT=$(load_fixture "simple-public-routes") - source "$SERVICE_PATH/scripts/istio/build_context" - - export VISIBILITY="public" - - source "$SERVICE_PATH/scripts/istio/build_httproute" - - [[ -n "$HTTPROUTE_PUBLIC_FILE" ]] - [[ "$HTTPROUTE_PUBLIC_FILE" == *"public.yaml" ]] -} - -@test "build_httproute: exports HTTPROUTE_PRIVATE_FILE for private" { - export CONTEXT=$(load_fixture "public-and-private-routes") - source "$SERVICE_PATH/scripts/istio/build_context" - - export VISIBILITY="private" - - source "$SERVICE_PATH/scripts/istio/build_httproute" - - [[ -n "$HTTPROUTE_PRIVATE_FILE" ]] - [[ "$HTTPROUTE_PRIVATE_FILE" == *"private.yaml" ]] -} diff --git a/endpoint-exposer/test/test_integration.bats b/endpoint-exposer/test/test_integration.bats deleted file mode 100644 index d094fe5..0000000 --- a/endpoint-exposer/test/test_integration.bats +++ /dev/null @@ -1,229 +0,0 @@ -#!/usr/bin/env bats - -load helpers - -setup() { - export TEST_TEMP_DIR="$(mktemp -d)" - export OUTPUT_DIR="$TEST_TEMP_DIR/output" - mkdir -p "$OUTPUT_DIR" - export SERVICE_PATH="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)" - - # Load assert functions - load_bats_support_libraries - - export K8S_NAMESPACE="test-namespace" - export ALB_NAME="test-alb" - export ACTION="apply" - export DRY_RUN="true" - - # Mock kubectl - mock_kubectl - - # Mock gomplate - cat > "$TEST_TEMP_DIR/gomplate" << 'EOF' -#!/bin/bash -TEMPLATE_FILE="" -OUTPUT_FILE="" -CONTEXT_FILE="" - -while [[ $# -gt 0 ]]; do - case $1 in - -f) TEMPLATE_FILE="$2"; shift 2 ;; - -o) OUTPUT_FILE="$2"; shift 2 ;; - -c) CONTEXT_FILE="${2#.=}"; shift 2 ;; - *) shift ;; - esac -done - -if [[ -n "$TEMPLATE_FILE" ]] && [[ -n "$OUTPUT_FILE" ]]; then - # Read context if provided - if [[ -n "$CONTEXT_FILE" ]] && [[ -f "$CONTEXT_FILE" ]]; then - CONTEXT_JSON=$(cat "$CONTEXT_FILE") - SERVICE_SLUG=$(echo "$CONTEXT_JSON" | jq -r '.service_slug // ""') - SERVICE_ID=$(echo "$CONTEXT_JSON" | jq -r '.service_id // ""') - SUFFIX=$(echo "$CONTEXT_JSON" | jq -r '.suffix // ""') - DOMAIN=$(echo "$CONTEXT_JSON" | jq -r '.domain // ""') - NAMESPACE=$(echo "$CONTEXT_JSON" | jq -r '.k8s_namespace // .gateway_namespace // ""') - fi - - # Determine resource type from template - if [[ "$TEMPLATE_FILE" == *"httproute"* ]]; then - cat > "$OUTPUT_FILE" << YAML -apiVersion: gateway.networking.k8s.io/v1 -kind: HTTPRoute -metadata: - name: ${SERVICE_SLUG}-${SERVICE_ID}-${SUFFIX} - namespace: ${NAMESPACE} - labels: - nullplatform.com/managed-by: endpoint-exposer - nullplatform.com/service-id: "${SERVICE_ID}" - app.kubernetes.io/name: ${SERVICE_SLUG} -spec: - hostnames: - - ${DOMAIN} -YAML - elif [[ "$TEMPLATE_FILE" == *"authorization"* ]]; then - cat > "$OUTPUT_FILE" << YAML -apiVersion: security.istio.io/v1 -kind: AuthorizationPolicy -metadata: - name: ${SERVICE_SLUG}-${SERVICE_ID}-authz-${SUFFIX} - namespace: ${NAMESPACE} - labels: - nullplatform.com/managed-by: endpoint-exposer - nullplatform.com/service-id: "${SERVICE_ID}" - app.kubernetes.io/name: ${SERVICE_SLUG} -spec: - action: CUSTOM -YAML - fi -fi -EOF - chmod +x "$TEST_TEMP_DIR/gomplate" - export PATH="$TEST_TEMP_DIR:$PATH" - - # Mock process_routes script (it's sourced by build_httproute) - mkdir -p "$SERVICE_PATH/scripts/istio" - if [[ ! -f "$SERVICE_PATH/scripts/istio/process_routes.bak" ]]; then - # Backup original if exists - if [[ -f "$SERVICE_PATH/scripts/istio/process_routes" ]]; then - cp "$SERVICE_PATH/scripts/istio/process_routes" "$SERVICE_PATH/scripts/istio/process_routes.bak" - fi - fi - - # Create a minimal mock that does nothing (for testing we just need the HTTPRoute YAML) - cat > "$SERVICE_PATH/scripts/istio/process_routes" << 'MOCKEOF' -#!/bin/bash -# Mock process_routes for testing - does nothing -# In real tests, the gomplate mock already creates the YAML we need -# Use return instead of exit so it doesn't exit the sourcing shell -return 0 2>/dev/null || true -MOCKEOF - chmod +x "$SERVICE_PATH/scripts/istio/process_routes" -} - -teardown() { - # Always restore original process_routes if backup exists - if [[ -f "$SERVICE_PATH/scripts/istio/process_routes.bak" ]]; then - mv -f "$SERVICE_PATH/scripts/istio/process_routes.bak" "$SERVICE_PATH/scripts/istio/process_routes" - fi - - # Clean up temp directory - if [[ -n "$TEST_TEMP_DIR" ]] && [[ -d "$TEST_TEMP_DIR" ]]; then - rm -rf "$TEST_TEMP_DIR" - fi -} - -@test "integration: complete workflow with public routes only" { - export CONTEXT=$(load_fixture "simple-public-routes") - - # Step 1: Build context - source "$SERVICE_PATH/scripts/istio/build_context" - - # Step 2: Build public httproute - export VISIBILITY="public" - bash "$SERVICE_PATH/scripts/istio/build_httproute" - - # Step 3: Build private httproute (should create marker) - export VISIBILITY="private" - bash "$SERVICE_PATH/scripts/istio/build_httproute" - - # Verify outputs - assert_file_exists "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-public.yaml" - assert_file_not_exists "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-private.yaml" - assert_file_exists "$OUTPUT_DIR/.httproute-private-deleted" - - # Verify public HTTPRoute content - assert_file_contains "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-public.yaml" "HTTPRoute" - assert_file_contains "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-public.yaml" "api.edenred.nullimplementation.com" -} - -@test "integration: complete workflow with public and private routes" { - export CONTEXT=$(load_fixture "public-and-private-routes") - - # Build context - source "$SERVICE_PATH/scripts/istio/build_context" - - # Build httproutes - export VISIBILITY="public" - bash "$SERVICE_PATH/scripts/istio/build_httproute" - - export VISIBILITY="private" - bash "$SERVICE_PATH/scripts/istio/build_httproute" - - # Verify all resources created - assert_file_exists "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-public.yaml" - assert_file_exists "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-private.yaml" - - # Verify no marker files (all resources should be created) - assert_file_not_exists "$OUTPUT_DIR/.httproute-public-deleted" - assert_file_not_exists "$OUTPUT_DIR/.httproute-private-deleted" - - # Verify content - assert_file_contains "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-public.yaml" "api.edenred.nullimplementation.com" - assert_file_contains "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-private.yaml" "api-private.edenred.nullimplementation.com" -} - -@test "integration: workflow with authorization disabled creates cleanup markers" { - export CONTEXT=$(load_fixture "authorization-disabled") - - # Build context - source "$SERVICE_PATH/scripts/istio/build_context" - - # Build httproutes - export VISIBILITY="public" - bash "$SERVICE_PATH/scripts/istio/build_httproute" - - export VISIBILITY="private" - bash "$SERVICE_PATH/scripts/istio/build_httproute" - - # Verify httproutes created - assert_file_exists "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-public.yaml" - assert_file_exists "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-private.yaml" -} - -@test "integration: apply step handles markers and resources correctly" { - export CONTEXT=$(load_fixture "simple-public-routes") - - # Build context - source "$SERVICE_PATH/scripts/istio/build_context" - - # Build httproutes - export VISIBILITY="public" - bash "$SERVICE_PATH/scripts/istio/build_httproute" - - export VISIBILITY="private" - bash "$SERVICE_PATH/scripts/istio/build_httproute" - - # Run apply - run bash "$SERVICE_PATH/scripts/common/apply" - - assert_success - - # Should detect and process markers - assert_output --partial "Private HTTPRoute marked for deletion" - - # Should apply the public httproute - assert_output --partial "Applying 1 resources" -} - -@test "integration: all resources have correct labels for management" { - export CONTEXT=$(load_fixture "public-and-private-routes") - - # Build context - source "$SERVICE_PATH/scripts/istio/build_context" - - # Build httproutes - export VISIBILITY="public" - bash "$SERVICE_PATH/scripts/istio/build_httproute" - - export VISIBILITY="private" - bash "$SERVICE_PATH/scripts/istio/build_httproute" - - # Verify all resources have required labels - assert_file_contains "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-public.yaml" "nullplatform.com/managed-by: endpoint-exposer" - assert_file_contains "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-private.yaml" "nullplatform.com/managed-by: endpoint-exposer" - - assert_file_contains "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-public.yaml" "nullplatform.com/service-id:" - assert_file_contains "$OUTPUT_DIR/httproute-fbcf7a60-8ca8-4bf2-b1b5-5c59bb5bc4fd-private.yaml" "nullplatform.com/service-id:" -} diff --git a/endpoint-exposer/values.yaml b/endpoint-exposer/values.yaml deleted file mode 100644 index 6831afc..0000000 --- a/endpoint-exposer/values.yaml +++ /dev/null @@ -1,2 +0,0 @@ -configuration: - K8S_NAMESPACE: nullplatform \ No newline at end of file diff --git a/endpoint-exposer/workflows/istio/create.yaml b/endpoint-exposer/workflows/istio/create.yaml deleted file mode 100644 index 6c633bc..0000000 --- a/endpoint-exposer/workflows/istio/create.yaml +++ /dev/null @@ -1,53 +0,0 @@ -steps: - - name: "find k8s namespace" - type: script - file: "$SERVICE_PATH/scripts/istio/fetch_provider_data" - output: - - name: K8S_NAMESPACE - type: environment - - name: "build context" - type: script - file: "$SERVICE_PATH/scripts/istio/build_context" - output: - - name: SERVICE_ID - type: environment - - name: SERVICE_SLUG - type: environment - - name: ACTION_ID - type: environment - - name: ACTION_NAME - type: environment - - name: PUBLIC_DOMAIN - type: environment - - name: PRIVATE_DOMAIN - type: environment - - name: ROUTES_JSON - type: environment - - name: PUBLIC_ROUTES_JSON - type: environment - - name: PRIVATE_ROUTES_JSON - type: environment - - name: "build public httproute" - type: script - file: "$SERVICE_PATH/scripts/istio/build_httproute" - configuration: - VISIBILITY: "public" - output: - - name: HTTPROUTE_PUBLIC_FILE - type: file - file: "$OUTPUT_DIR/httproute-$SERVICE_ID-public.yaml" - - name: "build private httproute" - type: script - file: "$SERVICE_PATH/scripts/istio/build_httproute" - configuration: - VISIBILITY: "private" - output: - - name: HTTPROUTE_PRIVATE_FILE - type: file - file: "$OUTPUT_DIR/httproute-$SERVICE_ID-private.yaml" - - name: apply - type: script - file: "$SERVICE_PATH/scripts/common/apply" - configuration: - ACTION: apply - DRY_RUN: false \ No newline at end of file diff --git a/endpoint-exposer/workflows/istio/delete.yaml b/endpoint-exposer/workflows/istio/delete.yaml deleted file mode 100644 index 1f4d320..0000000 --- a/endpoint-exposer/workflows/istio/delete.yaml +++ /dev/null @@ -1,6 +0,0 @@ -include: - - "$SERVICE_PATH/workflows/istio/create.yaml" -steps: - - name: apply - configuration: - ACTION: delete \ No newline at end of file diff --git a/endpoint-exposer/workflows/istio/read.yaml b/endpoint-exposer/workflows/istio/read.yaml deleted file mode 100644 index 8de54ea..0000000 --- a/endpoint-exposer/workflows/istio/read.yaml +++ /dev/null @@ -1,30 +0,0 @@ -steps: - - name: "find k8s namespace" - type: script - file: "$SERVICE_PATH/scripts/istio/fetch_provider_data" - output: - - name: K8S_NAMESPACE - type: environment - - name: "build context" - type: script - file: "$SERVICE_PATH/scripts/istio/build_context" - output: - - name: SERVICE_ID - type: environment - - name: SERVICE_SLUG - type: environment - - name: ACTION_ID - type: environment - - name: ACTION_NAME - type: environment - - name: LINK_ID - type: environment - - name: LINK_NAME - type: environment - - name: SCOPE_ID - type: environment - - name: RULE_PATH - type: environment - - name: read - type: script - file: "$SERVICE_PATH/scripts/istio/read_ingress" \ No newline at end of file diff --git a/endpoint-exposer/workflows/istio/update.yaml b/endpoint-exposer/workflows/istio/update.yaml deleted file mode 100644 index 9a6f977..0000000 --- a/endpoint-exposer/workflows/istio/update.yaml +++ /dev/null @@ -1,7 +0,0 @@ -include: - - "$SERVICE_PATH/workflows/istio/create.yaml" -steps: - - name: apply - configuration: - ACTION: apply - DRY_RUN: false From 6911333ae3959168c87c2d069b949561be400d69 Mon Sep 17 00:00:00 2001 From: Agustin Celentano <12614595+agustincelentano@users.noreply.github.com> Date: Wed, 1 Jul 2026 13:55:11 -0300 Subject: [PATCH 2/2] chore: stop tracking .DS_Store files and add to gitignore --- .DS_Store | Bin 6148 -> 0 bytes .gitignore | 3 ++- databases/.DS_Store | Bin 8196 -> 0 bytes 3 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 .DS_Store delete mode 100644 databases/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index cda7ef07dc37d702abc0622fd147d693f1e4a42c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKy-veG4ED8=NCiVA76yhqL8VHpNTCWFTVH_wsZ?r}N^J%thP(m10K5Xc1uG*f z8ygGkd_G^pRSAdzA%twn_g#E;?0h-JIU+LMeAFR|h$w_IHd+{Jgx6Us(r}g?pt1MJ zX+-1Mq|+N_6>l~CMF#lYZBd(sG^0Lw?{B_v<=#|1=2@B!X4wEM;qBu~>-qBjsLpHj z4X?!+@0N8o-iH*Ro(WB9B|Ayhnr{bB{+eII_3q(*{$Oh;W9QjN_PTXHZxG&b-WGOm zpH|QTbV*}c`V~a^$wj@FU(58hyRN0?etuP7d;0Z7=T}^xiZY-KC<8ym0D3k{xGkuo zGN24710@6eeTboqiNiwBemXGNBLFaf*$U?N9}XC^0hl-}1Yv;~2?a{1aYqaz;jqWf zFL781N;nyt8TWCSjXR+jn;rJpx|2x+byNnFflUUQav5>|KmPpuzZs-g%78NPuNW{v z+Dp55B-dLj568VWhMq!M*sl;QLol(e7{1(!_n=l_k9h)292SDGK=enz(x8Jf@T&~G E13$=cWB>pF diff --git a/.gitignore b/.gitignore index 83eef9e..c75279f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ gen *.tfstate *.tfstate.backup .terraform/ -*.tfvars \ No newline at end of file +*.tfvars +.DS_Store diff --git a/databases/.DS_Store b/databases/.DS_Store deleted file mode 100644 index 44fdf2e3ca8238ac9148a5e0e4ac73019fee49fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHMJxc>Y5S@({0l^OxjNKKs0sRAVhS&=MYfVm6$Z^pa3qd$6?EM2`Wh2-r2sTzW z`V#~z3rnp9-|Q}C&r9OPLJZEp?o0OOWoO=9ZZa1lQl(ZfPgEeHJO<G*C_?HUs{lUXv z^ex5)^{oSwZUKP9Sk{Ku=mRvzv*=rl4QeVr({vBYQk88nl%eCe$L>JiVrAEoNZ_KVUUB-RMrS4elfj{S0E4Hgrx+Hv^)>hfY3j%oo>3 z)1wDE=G13}Q9H_Ber{Z(mN~95L=$LLzr>f;ndtuPdxjhH@yc6U=brnx8DwWA^2zCZ zCVS-5#I>|TdpsxAKY2u68JTW=x7&>ydmUwFx6f4n>_oom2|?3D*L?Y#vW0I^n9Ox% zAsfrh^ZfGjJZ9L>J(vA46ZzR9%Sk%MrPjk>^ex5)d5PC`6$VQEXFK)iz