diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c669497fb..994cecaa1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,10 +7,19 @@ repos: - id: mixed-line-ending args: [--fix=lf] - id: check-yaml - exclude: packages/apps/postgres/templates/init-script.yaml + exclude: .*/init-script\.yaml$ args: [--unsafe] - repo: https://github.com/igorshubovych/markdownlint-cli rev: v0.41.0 hooks: - - id: markdownlint - args: [--fix, --disable, MD013, MD041, --] + - id: markdownlint + args: [--fix, --disable, MD013, MD041, --] +- repo: local + hooks: + - id: gen-versions-map + name: Generate versions map and check for changes + entry: bash -c 'cd packages/apps && make check-version-map' + language: system + types: [file] + pass_filenames: false + description: Run the script and fail if it generates changes diff --git a/hack/Makefile b/hack/Makefile new file mode 100644 index 000000000..c77632555 --- /dev/null +++ b/hack/Makefile @@ -0,0 +1,16 @@ +.PHONY: test clean help + +SCRIPT=./e2e.applications.sh +PRECHECKS=./pre-checks.sh + +help: + @echo "Usage: make {test|clean}" + @echo " test - Run the end-to-end tests." + @echo " clean - Clean up resources." + +test: + @bash $(PRECHECKS) test + @bash $(SCRIPT) test + +clean: + @bash $(SCRIPT) clean diff --git a/hack/e2e.applications.sh b/hack/e2e.applications.sh new file mode 100755 index 000000000..fae502c94 --- /dev/null +++ b/hack/e2e.applications.sh @@ -0,0 +1,47 @@ +for file in ./modules/*.sh; do + source "$file" +done + +ROOT_NS="tenant-root" +TEST_TENANT="tenant-e2e" + +function test() { + install_tenant $TEST_TENANT $ROOT_NS + check_helmrelease_status $TEST_TENANT $ROOT_NS + + install_all_apps "../packages/apps" "$TEST_TENANT" cozystack-apps cozy-public + + if true; then + echo -e "${GREEN}All tests passed!${RESET}" + return 0 + else + echo -e "${RED}Some tests failed!${RESET}" + return 1 + fi +} + +function clean() { + kubectl delete helmrelease.helm.toolkit.fluxcd.io $TEST_TENANT -n $ROOT_NS + if true; then + echo -e "${GREEN}Cleanup successful!${RESET}" + return 0 + else + echo -e "${RED}Cleanup failed!${RESET}" + return 1 + fi +} + +case "$1" in + test) + echo -e "${YELLOW}Running tests...${RESET}" + test + ;; + clean) + echo -e "${YELLOW}Cleaning up...${RESET}" + clean + ;; + *) + echo -e "${RED}Usage: $0 {test|clean}${RESET}" + exit 1 + ;; +esac diff --git a/hack/modules/check_helmrelease_status.sh b/hack/modules/check_helmrelease_status.sh new file mode 100755 index 000000000..b4178fb5e --- /dev/null +++ b/hack/modules/check_helmrelease_status.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +source ./modules/colors.sh + +function check_helmrelease_status() { + local release_name="$1" + local namespace="$2" + local timeout=300 # Timeout in seconds + local interval=5 # Interval between checks in seconds + local elapsed=0 + + while [[ $elapsed -lt $timeout ]]; do + local status_output + status_output=$(kubectl get helmrelease "$release_name" -n "$namespace" -o json | jq -r '.status.conditions[-1].reason') + + if [[ "$status_output" == "InstallSucceeded" ]]; then + echo -e "${GREEN}Helm release '$release_name' is ready.${RESET}" + return 0 + elif [[ "$status_output" == "InstallFailed" ]]; then + echo -e "${RED}Helm release '$release_name': InstallFailed${RESET}" + exit 1 + else + echo -e "${YELLOW}Helm release '$release_name' is not ready. Current status: $status_output${RESET}" + fi + + sleep "$interval" + elapsed=$((elapsed + interval)) + done + + echo -e "${RED}Timeout reached. Helm release '$release_name' is still not ready after $timeout seconds.${RESET}" + exit 1 +} diff --git a/hack/modules/colors.sh b/hack/modules/colors.sh new file mode 100755 index 000000000..ed80c40dc --- /dev/null +++ b/hack/modules/colors.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +RED='\033[0;31m' +GREEN='\033[0;32m' +RESET='\033[0m' +YELLOW='\033[0;33m' diff --git a/hack/modules/ignored_charts b/hack/modules/ignored_charts new file mode 100644 index 000000000..916dad6a5 --- /dev/null +++ b/hack/modules/ignored_charts @@ -0,0 +1,6 @@ +tenant +http-cache +mysql +rabbitmq +virtual-machine +vpn diff --git a/hack/modules/install_all_apps.sh b/hack/modules/install_all_apps.sh new file mode 100755 index 000000000..a697fd092 --- /dev/null +++ b/hack/modules/install_all_apps.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +source ./modules/colors.sh + +# Function to load ignored charts from a file +function load_ignored_charts() { + local ignore_file="$1" + local ignored_charts=() + + if [[ -f "$ignore_file" ]]; then + while IFS= read -r chart; do + ignored_charts+=("$chart") + done < "$ignore_file" + else + echo "Ignore file not found: $ignore_file" + fi + + # Return the array of ignored charts + echo "${ignored_charts[@]}" +} + +# Function to check if a chart is in the ignored list +function is_chart_ignored() { + local chart_name="$1" + shift + local ignored_charts=("$@") + + for ignored_chart in "${ignored_charts[@]}"; do + if [[ "$ignored_chart" == "$chart_name" ]]; then + return 0 + fi + done + return 1 +} + +function install_all_apps() { + local charts_dir="$1" + local namespace="$2" + local repo_name="$3" + local repo_ns="$4" + + local ignore_file="./modules/ignored_charts" + local ignored_charts + ignored_charts=($(load_ignored_charts "$ignore_file")) + + for chart_path in "$charts_dir"/*; do + if [[ -d "$chart_path" ]]; then + local chart_name + chart_name=$(basename "$chart_path") + # Check if the chart is in the ignored list + if is_chart_ignored "$chart_name" "${ignored_charts[@]}"; then + echo "Skipping chart: $chart_name (listed in ignored charts)" + continue + fi + + release_name="$chart_name-e2e" + echo "Installing release: $release_name" + install_helmrelease "$release_name" "$namespace" "$chart_name" "$repo_name" "$repo_ns" + + echo "Checking status for HelmRelease: $release_name" + check_helmrelease_status "$release_name" "$namespace" + else + echo "$chart_path is not a directory. Skipping." + fi + done +} diff --git a/hack/modules/install_chart.sh b/hack/modules/install_chart.sh new file mode 100755 index 000000000..5e45ba408 --- /dev/null +++ b/hack/modules/install_chart.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +source ./modules/colors.sh + +function install_helmrelease() { + local release_name="$1" + local namespace="$2" + local chart_path="$3" + local repo_name="$4" + local repo_ns="$5" + local values_file="$6" + + if [[ -z "$release_name" ]]; then + echo -e "${RED}Error: Release name is required.${RESET}" + exit 1 + fi + + if [[ -z "$namespace" ]]; then + echo -e "${RED}Error: Namespace name is required.${RESET}" + exit 1 + fi + + if [[ -z "$chart_path" ]]; then + echo -e "${RED}Error: Chart path name is required.${RESET}" + exit 1 + fi + + local helmrelease_file=$(mktemp /tmp/HelmRelease.XXXXXX.yaml) + + { + echo "apiVersion: helm.toolkit.fluxcd.io/v2" + echo "kind: HelmRelease" + echo "metadata:" + echo " labels:" + echo " cozystack.io/ui: \"true\"" + echo " name: \"$release_name\"" + echo " namespace: \"$namespace\"" + echo "spec:" + echo " chart:" + echo " spec:" + echo " chart: \"$chart_path\"" + echo " reconcileStrategy: Revision" + echo " sourceRef:" + echo " kind: HelmRepository" + echo " name: \"$repo_name\"" + echo " namespace: \"$repo_ns\"" + echo " version: '*'" + echo " interval: 1m0s" + echo " timeout: 5m0s" + + if [[ -n "$values_file" && -f "$values_file" ]]; then + echo " values:" + cat "$values_file" | sed 's/^/ /' + fi + } > "$helmrelease_file" + + kubectl apply -f "$helmrelease_file" + + rm -f "$helmrelease_file" +} diff --git a/hack/modules/install_tenant.sh b/hack/modules/install_tenant.sh new file mode 100755 index 000000000..f1cab14d6 --- /dev/null +++ b/hack/modules/install_tenant.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +function install_tenant (){ + local release_name="$1" + local namespace="$2" + local values_file="${3:-tenant.yaml}" + local repo_name="cozystack-apps" + local repo_ns="cozy-public" + + install_helmrelease "$release_name" "$namespace" "tenant" "$repo_name" "$repo_ns" "$values_file" +} diff --git a/hack/pre-checks.sh b/hack/pre-checks.sh index be0e2a675..d8fc94e0e 100755 --- a/hack/pre-checks.sh +++ b/hack/pre-checks.sh @@ -5,7 +5,7 @@ RED='\033[31m' RESET='\033[0m' check-yq-version() { - current_version=$(yq -V | grep -oP 'v[0-9]+\.[0-9]+\.[0-9]+') + current_version=$(yq -V | awk '$(NF-1) == "version" {print $NF}') if [ -z "$current_version" ]; then echo "yq is not installed or version cannot be determined." exit 1 diff --git a/hack/values/tenant.yaml b/hack/values/tenant.yaml new file mode 100644 index 000000000..1a7862d7b --- /dev/null +++ b/hack/values/tenant.yaml @@ -0,0 +1,6 @@ +host: "" +etcd: false +monitoring: true +ingress: false +seaweedfs: true +isolated: true diff --git a/packages/apps/ferretdb/Chart.yaml b/packages/apps/ferretdb/Chart.yaml index d23dfe5e3..0b8fc9935 100644 --- a/packages/apps/ferretdb/Chart.yaml +++ b/packages/apps/ferretdb/Chart.yaml @@ -16,7 +16,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.4.0 +version: 0.4.1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/packages/apps/ferretdb/templates/init-script.yaml b/packages/apps/ferretdb/templates/init-script.yaml index beef5a5aa..35723edee 100644 --- a/packages/apps/ferretdb/templates/init-script.yaml +++ b/packages/apps/ferretdb/templates/init-script.yaml @@ -34,6 +34,9 @@ stringData: init.sh: | #!/bin/bash set -e + + until pg_isready ; do sleep 5; done + echo "== create users" {{- if .Values.users }} psql -v ON_ERROR_STOP=1 <<\EOT @@ -60,7 +63,7 @@ stringData: DROP USER $user; EOT done - + echo "== create roles" psql -v ON_ERROR_STOP=1 --echo-all <<\EOT SELECT 'CREATE ROLE app_admin NOINHERIT;' @@ -80,7 +83,7 @@ stringData: FOR schema_record IN SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('pg_catalog', 'information_schema') LOOP -- Changing Schema Ownership EXECUTE format('ALTER SCHEMA %I OWNER TO %I', schema_record.schema_name, 'app_admin'); - + -- Add rights for the admin role EXECUTE format('GRANT ALL ON SCHEMA %I TO %I', schema_record.schema_name, 'app_admin'); EXECUTE format('GRANT ALL ON ALL TABLES IN SCHEMA %I TO %I', schema_record.schema_name, 'app_admin'); diff --git a/packages/apps/versions_map b/packages/apps/versions_map index 5e06c3325..a88b0f9e9 100644 --- a/packages/apps/versions_map +++ b/packages/apps/versions_map @@ -9,7 +9,8 @@ ferretdb 0.1.0 4ffa8615 ferretdb 0.1.1 5ca8823 ferretdb 0.2.0 adaf603 ferretdb 0.3.0 aa2f553 -ferretdb 0.4.0 HEAD +ferretdb 0.4.0 def2eb0f +ferretdb 0.4.1 HEAD http-cache 0.1.0 a956713 http-cache 0.2.0 5ca8823 http-cache 0.3.0 fab5940