From 0c924fca65b0a2e1c71b0116016a4c29f1d9cf4d Mon Sep 17 00:00:00 2001 From: Tongtong Zhou Date: Wed, 11 Mar 2026 10:21:47 +0800 Subject: [PATCH 1/4] HYPERFLEET-525 - ci: add CI validation targets and OWNERS for pre submit --- Makefile | 136 +++++++++++++++++++++++++++++++++++++++++++++++++++---- OWNERS | 35 ++++++++++++++ 2 files changed, 163 insertions(+), 8 deletions(-) create mode 100644 OWNERS diff --git a/Makefile b/Makefile index c1562b2..9094ce1 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,8 @@ REGISTRY ?= quay.io/openshift-hyperfleet API_IMAGE_TAG ?= v0.1.1 SENTINEL_IMAGE_TAG ?= v0.1.1 ADAPTER_IMAGE_TAG ?= v0.1.1 +DRY_RUN ?= +AUTO_APPROVE ?= # Chart source configuration (helm-git plugin) # Chart refs are independent of image tags so that overriding an image tag @@ -109,7 +111,7 @@ install-maestro: check-helm check-kubectl check-maestro-namespace ## Install Mae helm dependency update $(HELM_DIR)/maestro @echo "Installing Maestro..." - if ! helm upgrade --install $(MAESTRO_NS)-maestro $(HELM_DIR)/maestro \ + if ! helm upgrade --install $(DRY_RUN) $(MAESTRO_NS)-maestro $(HELM_DIR)/maestro \ --namespace $(MAESTRO_NS) \ --kubeconfig $(KUBECONFIG) \ --set agent.messageBroker.mqtt.host=maestro-mqtt.$(MAESTRO_NS) \ @@ -147,7 +149,7 @@ endef install-api: check-helm check-kubectl check-namespace ## Install HyperFleet API $(call set-chart-ref,$(HELM_DIR)/api,$(API_CHART_REF)) helm dependency update $(HELM_DIR)/api - helm upgrade --install $(NAMESPACE)-api $(HELM_DIR)/api \ + helm upgrade --install $(DRY_RUN) $(NAMESPACE)-api $(HELM_DIR)/api \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ $(if $(REGISTRY),--set hyperfleet-api.image.registry=$(REGISTRY)) \ @@ -157,7 +159,7 @@ install-api: check-helm check-kubectl check-namespace ## Install HyperFleet API install-sentinel-clusters: check-helm check-kubectl check-namespace ## Install Sentinel for clusters $(call set-chart-ref,$(HELM_DIR)/sentinel-clusters,$(SENTINEL_CHART_REF)) helm dependency update $(HELM_DIR)/sentinel-clusters - helm upgrade --install $(NAMESPACE)-sentinel-clusters $(HELM_DIR)/sentinel-clusters \ + helm upgrade --install $(DRY_RUN) $(NAMESPACE)-sentinel-clusters $(HELM_DIR)/sentinel-clusters \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set sentinel.broker.type=$(BROKER_TYPE) \ @@ -169,7 +171,7 @@ install-sentinel-clusters: check-helm check-kubectl check-namespace ## Install S install-sentinel-nodepools: check-helm check-kubectl check-namespace ## Install Sentinel for nodepools $(call set-chart-ref,$(HELM_DIR)/sentinel-nodepools,$(SENTINEL_CHART_REF)) helm dependency update $(HELM_DIR)/sentinel-nodepools - helm upgrade --install $(NAMESPACE)-sentinel-nodepools $(HELM_DIR)/sentinel-nodepools \ + helm upgrade --install $(DRY_RUN) $(NAMESPACE)-sentinel-nodepools $(HELM_DIR)/sentinel-nodepools \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set sentinel.broker.type=$(BROKER_TYPE) \ @@ -181,7 +183,7 @@ install-sentinel-nodepools: check-helm check-kubectl check-namespace ## Install install-adapter1: check-helm check-kubectl check-namespace ## Install adapter1 $(call set-chart-ref,$(HELM_DIR)/adapter1,$(ADAPTER_CHART_REF)) helm dependency update $(HELM_DIR)/adapter1 - helm upgrade --install $(NAMESPACE)-adapter1 $(HELM_DIR)/adapter1 \ + helm upgrade --install $(DRY_RUN) $(NAMESPACE)-adapter1 $(HELM_DIR)/adapter1 \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ @@ -195,7 +197,7 @@ install-adapter1: check-helm check-kubectl check-namespace ## Install adapter1 install-adapter2: check-helm check-kubectl check-namespace ## Install adapter2 $(call set-chart-ref,$(HELM_DIR)/adapter2,$(ADAPTER_CHART_REF)) helm dependency update $(HELM_DIR)/adapter2 - helm upgrade --install $(NAMESPACE)-adapter2 $(HELM_DIR)/adapter2 \ + helm upgrade --install $(DRY_RUN) $(NAMESPACE)-adapter2 $(HELM_DIR)/adapter2 \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ @@ -209,7 +211,7 @@ install-adapter2: check-helm check-kubectl check-namespace ## Install adapter2 install-adapter3: check-helm check-kubectl check-namespace ## Install adapter3 $(call set-chart-ref,$(HELM_DIR)/adapter3,$(ADAPTER_CHART_REF)) helm dependency update $(HELM_DIR)/adapter3 - helm upgrade --install $(NAMESPACE)-adapter3 $(HELM_DIR)/adapter3 \ + helm upgrade --install $(DRY_RUN) $(NAMESPACE)-adapter3 $(HELM_DIR)/adapter3 \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ @@ -222,7 +224,7 @@ install-adapter3: check-helm check-kubectl check-namespace ## Install adapter3 .PHONY: install-terraform install-terraform: check-terraform check-tf-files ## Run Terraform init and apply cd $(TF_DIR) && terraform init -backend-config=$(TF_BACKEND) - cd $(TF_DIR) && terraform apply -var-file=$(TF_VARS) + cd $(TF_DIR) && terraform apply -var-file=$(TF_VARS) $(AUTO_APPROVE) # ────────────────────────────────────────────── # Aggregate install targets @@ -244,6 +246,122 @@ install-all: install-terraform get-credentials tf-helm-values install-maestro cr install-all-rabbitmq: BROKER_TYPE = rabbitmq install-all-rabbitmq: install-rabbitmq tf-helm-values install-hyperfleet install-maestro create-maestro-consumer ## Full RabbitMQ install (rabbitmq + hyperfleet + maestro, no terraform) +# ────────────────────────────────────────────── +# CI validation targets +# ────────────────────────────────────────────── + +# --- Layer 1: Static validation --- + +.PHONY: validate-terraform +validate-terraform: check-terraform ## Validate Terraform syntax and formatting + cd $(TF_DIR) && terraform init -backend=false + cd $(TF_DIR) && terraform fmt -check -recursive -diff + cd $(TF_DIR) && terraform validate + +.PHONY: lint-helm +lint-helm: check-helm deps ## Lint all Helm charts + @for chart in $(HELM_DIR)/*/; do \ + echo "Linting $$chart..."; \ + helm lint "$$chart" || exit 1; \ + done + +.PHONY: lint-shellcheck +lint-shellcheck: ## Validate shell scripts with shellcheck + @if command -v shellcheck >/dev/null 2>&1; then \ + find . -name '*.sh' -not -path './.terraform/*' -not -path './.git/*' -exec shellcheck {} +; \ + else \ + echo "WARN: shellcheck not installed, skipping"; \ + fi + +.PHONY: ci-validate +ci-validate: validate-terraform lint-helm lint-shellcheck ## Layer 1: Static validation + +# --- Layer 2: Dry-run validation --- + +.PHONY: plan-terraform +plan-terraform: check-terraform check-tf-files ## Run terraform plan (preview only, no apply) + cd $(TF_DIR) && terraform init -backend-config=$(TF_BACKEND) + cd $(TF_DIR) && terraform plan -var-file=$(TF_VARS) + +.PHONY: validate-helm-charts +validate-helm-charts: check-helm ## Render all Helm charts with helm template (no cluster required) + $(call set-chart-ref,$(HELM_DIR)/api,$(API_CHART_REF)) + helm dependency update $(HELM_DIR)/api + @echo "Validating api chart..." + helm template $(NAMESPACE)-api $(HELM_DIR)/api \ + $(if $(REGISTRY),--set hyperfleet-api.image.registry=$(REGISTRY)) \ + --set hyperfleet-api.image.tag=$(API_IMAGE_TAG) > /dev/null + $(call set-chart-ref,$(HELM_DIR)/sentinel-clusters,$(SENTINEL_CHART_REF)) + helm dependency update $(HELM_DIR)/sentinel-clusters + @echo "Validating sentinel-clusters chart..." + helm template $(NAMESPACE)-sentinel-clusters $(HELM_DIR)/sentinel-clusters \ + --set sentinel.broker.type=$(BROKER_TYPE) \ + $(if $(REGISTRY),--set sentinel.image.registry=$(REGISTRY)) \ + --set sentinel.image.tag=$(SENTINEL_IMAGE_TAG) > /dev/null + $(call set-chart-ref,$(HELM_DIR)/sentinel-nodepools,$(SENTINEL_CHART_REF)) + helm dependency update $(HELM_DIR)/sentinel-nodepools + @echo "Validating sentinel-nodepools chart..." + helm template $(NAMESPACE)-sentinel-nodepools $(HELM_DIR)/sentinel-nodepools \ + --set sentinel.broker.type=$(BROKER_TYPE) \ + $(if $(REGISTRY),--set sentinel.image.registry=$(REGISTRY)) \ + --set sentinel.image.tag=$(SENTINEL_IMAGE_TAG) > /dev/null + $(call set-chart-ref,$(HELM_DIR)/adapter1,$(ADAPTER_CHART_REF)) + helm dependency update $(HELM_DIR)/adapter1 + @echo "Validating adapter1 chart..." + helm template $(NAMESPACE)-adapter1 $(HELM_DIR)/adapter1 \ + --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ + $(if $(REGISTRY),--set hyperfleet-adapter.image.registry=$(REGISTRY)) \ + --set hyperfleet-adapter.image.tag=$(ADAPTER_IMAGE_TAG) \ + --set-file hyperfleet-adapter.adapterConfig.yaml=$(HELM_DIR)/adapter1/adapter-config.yaml \ + --set-file hyperfleet-adapter.adapterTaskConfig.yaml=$(HELM_DIR)/adapter1/adapter-task-config.yaml > /dev/null + $(call set-chart-ref,$(HELM_DIR)/adapter2,$(ADAPTER_CHART_REF)) + helm dependency update $(HELM_DIR)/adapter2 + @echo "Validating adapter2 chart..." + helm template $(NAMESPACE)-adapter2 $(HELM_DIR)/adapter2 \ + --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ + $(if $(REGISTRY),--set hyperfleet-adapter.image.registry=$(REGISTRY)) \ + --set hyperfleet-adapter.image.tag=$(ADAPTER_IMAGE_TAG) \ + --set-file hyperfleet-adapter.adapterConfig.yaml=$(HELM_DIR)/adapter2/adapter-config.yaml \ + --set-file hyperfleet-adapter.adapterTaskConfig.yaml=$(HELM_DIR)/adapter2/adapter-task-config.yaml > /dev/null + $(call set-chart-ref,$(HELM_DIR)/adapter3,$(ADAPTER_CHART_REF)) + helm dependency update $(HELM_DIR)/adapter3 + @echo "Validating adapter3 chart..." + helm template $(NAMESPACE)-adapter3 $(HELM_DIR)/adapter3 \ + --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ + $(if $(REGISTRY),--set hyperfleet-adapter.image.registry=$(REGISTRY)) \ + --set hyperfleet-adapter.image.tag=$(ADAPTER_IMAGE_TAG) \ + --set-file hyperfleet-adapter.adapterConfig.yaml=$(HELM_DIR)/adapter3/adapter-config.yaml \ + --set-file hyperfleet-adapter.adapterTaskConfig.yaml=$(HELM_DIR)/adapter3/adapter-task-config.yaml > /dev/null + helm dependency update $(HELM_DIR)/maestro + @echo "Validating maestro chart..." + helm template $(MAESTRO_NS)-maestro $(HELM_DIR)/maestro \ + --set agent.messageBroker.mqtt.host=maestro-mqtt.$(MAESTRO_NS) > /dev/null + @echo "OK: all Helm charts rendered successfully" + +.PHONY: ci-dry-run +ci-dry-run: ci-validate validate-helm-charts ## Layer 2: Static + dry-run validation (no credentials required) + +# --- Layer 3: Full integration test --- + +.PHONY: health-check +health-check: check-kubectl ## Verify all HyperFleet components are healthy + @echo "Checking HyperFleet components..." + @kubectl wait --for=condition=ready pods --all --namespace $(NAMESPACE) --kubeconfig $(KUBECONFIG) --timeout=300s + @echo "Checking Maestro components..." + @kubectl wait --for=condition=ready pods --all --namespace $(MAESTRO_NS) --kubeconfig $(KUBECONFIG) --timeout=300s + @echo "OK: all components healthy" + +.PHONY: destroy-terraform +destroy-terraform: check-terraform check-tf-files ## Destroy Terraform-managed infrastructure + cd $(TF_DIR) && terraform init -backend-config=$(TF_BACKEND) + cd $(TF_DIR) && terraform destroy -var-file=$(TF_VARS) -auto-approve + +.PHONY: ci-test +ci-test: install-all health-check ## Layer 3: Full integration test + +.PHONY: ci-cleanup +ci-cleanup: uninstall-all destroy-terraform ## Layer 3: Cleanup after integration test + # ────────────────────────────────────────────── # Uninstall targets # ────────────────────────────────────────────── @@ -328,6 +446,8 @@ help: ## Print available targets @echo " SENTINEL_CHART_REF Git ref for sentinel helm chart source (default: SENTINEL_IMAGE_TAG)" @echo " ADAPTER_CHART_REF Git ref for adapter helm chart source (default: ADAPTER_IMAGE_TAG)" @echo " MAESTRO_CONSUMER Maestro consumer name (default: cluster1)" + @echo " DRY_RUN Set to --dry-run for Helm dry-run mode (default: empty)" + @echo " AUTO_APPROVE Set to -auto-approve for non-interactive Terraform (default: empty)" @echo "" @echo "Targets:" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-28s\033[0m %s\n", $$1, $$2}' diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..4f27c40 --- /dev/null +++ b/OWNERS @@ -0,0 +1,35 @@ +approvers: +- "86254860" +- aredenba-rh +- ciaranRoche +- crizzo71 +- jsell-rh +- mbrudnoy +- Mischulee +- pnguyen44 +- rafabene +- rh-amarin +- tirthct +- tzhou5 +- vkareh +- xueli181114 +- yasun1 +- yingzhanredhat + +reviewers: +- "86254860" +- aredenba-rh +- ciaranRoche +- crizzo71 +- jsell-rh +- mbrudnoy +- Mischulee +- pnguyen44 +- rafabene +- rh-amarin +- tirthct +- tzhou5 +- vkareh +- xueli181114 +- yasun1 +- yingzhanredhat From 97d3dd9154ed2e2caf766cb4e03d520f11682698 Mon Sep 17 00:00:00 2001 From: Tongtong Zhou Date: Wed, 11 Mar 2026 20:14:07 +0800 Subject: [PATCH 2/4] address PR review feedback --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 9094ce1..83cb35d 100644 --- a/Makefile +++ b/Makefile @@ -269,6 +269,8 @@ lint-helm: check-helm deps ## Lint all Helm charts lint-shellcheck: ## Validate shell scripts with shellcheck @if command -v shellcheck >/dev/null 2>&1; then \ find . -name '*.sh' -not -path './.terraform/*' -not -path './.git/*' -exec shellcheck {} +; \ + elif [ -n "$$CI" ]; then \ + echo "ERROR: shellcheck is required in CI but not installed"; exit 1; \ else \ echo "WARN: shellcheck not installed, skipping"; \ fi @@ -354,6 +356,7 @@ health-check: check-kubectl ## Verify all HyperFleet components are healthy .PHONY: destroy-terraform destroy-terraform: check-terraform check-tf-files ## Destroy Terraform-managed infrastructure cd $(TF_DIR) && terraform init -backend-config=$(TF_BACKEND) + # Always use -auto-approve to prevent CI cleanup from hanging on interactive prompt cd $(TF_DIR) && terraform destroy -var-file=$(TF_VARS) -auto-approve .PHONY: ci-test From 45c3393e7871e0b8af17f7d0164b37b5ebee9345 Mon Sep 17 00:00:00 2001 From: Tongtong Zhou Date: Fri, 13 Mar 2026 11:59:03 +0800 Subject: [PATCH 3/4] validate both broker types --- Makefile | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 83cb35d..8bf6fb1 100644 --- a/Makefile +++ b/Makefile @@ -111,7 +111,7 @@ install-maestro: check-helm check-kubectl check-maestro-namespace ## Install Mae helm dependency update $(HELM_DIR)/maestro @echo "Installing Maestro..." - if ! helm upgrade --install $(DRY_RUN) $(MAESTRO_NS)-maestro $(HELM_DIR)/maestro \ + if ! helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(MAESTRO_NS)-maestro $(HELM_DIR)/maestro \ --namespace $(MAESTRO_NS) \ --kubeconfig $(KUBECONFIG) \ --set agent.messageBroker.mqtt.host=maestro-mqtt.$(MAESTRO_NS) \ @@ -149,7 +149,7 @@ endef install-api: check-helm check-kubectl check-namespace ## Install HyperFleet API $(call set-chart-ref,$(HELM_DIR)/api,$(API_CHART_REF)) helm dependency update $(HELM_DIR)/api - helm upgrade --install $(DRY_RUN) $(NAMESPACE)-api $(HELM_DIR)/api \ + helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(NAMESPACE)-api $(HELM_DIR)/api \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ $(if $(REGISTRY),--set hyperfleet-api.image.registry=$(REGISTRY)) \ @@ -159,7 +159,7 @@ install-api: check-helm check-kubectl check-namespace ## Install HyperFleet API install-sentinel-clusters: check-helm check-kubectl check-namespace ## Install Sentinel for clusters $(call set-chart-ref,$(HELM_DIR)/sentinel-clusters,$(SENTINEL_CHART_REF)) helm dependency update $(HELM_DIR)/sentinel-clusters - helm upgrade --install $(DRY_RUN) $(NAMESPACE)-sentinel-clusters $(HELM_DIR)/sentinel-clusters \ + helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(NAMESPACE)-sentinel-clusters $(HELM_DIR)/sentinel-clusters \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set sentinel.broker.type=$(BROKER_TYPE) \ @@ -171,7 +171,7 @@ install-sentinel-clusters: check-helm check-kubectl check-namespace ## Install S install-sentinel-nodepools: check-helm check-kubectl check-namespace ## Install Sentinel for nodepools $(call set-chart-ref,$(HELM_DIR)/sentinel-nodepools,$(SENTINEL_CHART_REF)) helm dependency update $(HELM_DIR)/sentinel-nodepools - helm upgrade --install $(DRY_RUN) $(NAMESPACE)-sentinel-nodepools $(HELM_DIR)/sentinel-nodepools \ + helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(NAMESPACE)-sentinel-nodepools $(HELM_DIR)/sentinel-nodepools \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set sentinel.broker.type=$(BROKER_TYPE) \ @@ -183,7 +183,7 @@ install-sentinel-nodepools: check-helm check-kubectl check-namespace ## Install install-adapter1: check-helm check-kubectl check-namespace ## Install adapter1 $(call set-chart-ref,$(HELM_DIR)/adapter1,$(ADAPTER_CHART_REF)) helm dependency update $(HELM_DIR)/adapter1 - helm upgrade --install $(DRY_RUN) $(NAMESPACE)-adapter1 $(HELM_DIR)/adapter1 \ + helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(NAMESPACE)-adapter1 $(HELM_DIR)/adapter1 \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ @@ -197,7 +197,7 @@ install-adapter1: check-helm check-kubectl check-namespace ## Install adapter1 install-adapter2: check-helm check-kubectl check-namespace ## Install adapter2 $(call set-chart-ref,$(HELM_DIR)/adapter2,$(ADAPTER_CHART_REF)) helm dependency update $(HELM_DIR)/adapter2 - helm upgrade --install $(DRY_RUN) $(NAMESPACE)-adapter2 $(HELM_DIR)/adapter2 \ + helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(NAMESPACE)-adapter2 $(HELM_DIR)/adapter2 \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ @@ -211,7 +211,7 @@ install-adapter2: check-helm check-kubectl check-namespace ## Install adapter2 install-adapter3: check-helm check-kubectl check-namespace ## Install adapter3 $(call set-chart-ref,$(HELM_DIR)/adapter3,$(ADAPTER_CHART_REF)) helm dependency update $(HELM_DIR)/adapter3 - helm upgrade --install $(DRY_RUN) $(NAMESPACE)-adapter3 $(HELM_DIR)/adapter3 \ + helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(NAMESPACE)-adapter3 $(HELM_DIR)/adapter3 \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ @@ -341,7 +341,9 @@ validate-helm-charts: check-helm ## Render all Helm charts with helm template (n @echo "OK: all Helm charts rendered successfully" .PHONY: ci-dry-run -ci-dry-run: ci-validate validate-helm-charts ## Layer 2: Static + dry-run validation (no credentials required) +ci-dry-run: ci-validate ## Layer 2: Static + dry-run validation (no credentials required) + $(MAKE) validate-helm-charts BROKER_TYPE=rabbitmq + $(MAKE) validate-helm-charts BROKER_TYPE=googlepubsub # --- Layer 3: Full integration test --- From 446ec3a958756e42803734f288350581b076d283 Mon Sep 17 00:00:00 2001 From: Tongtong Zhou Date: Fri, 13 Mar 2026 18:32:50 +0800 Subject: [PATCH 4/4] refactor: address reviewer feedback --- Dockerfile.ci | 16 ++++++++++ Makefile | 87 ++++++++++++++++++++++++++------------------------- 2 files changed, 60 insertions(+), 43 deletions(-) create mode 100644 Dockerfile.ci diff --git a/Dockerfile.ci b/Dockerfile.ci new file mode 100644 index 0000000..aa36bc1 --- /dev/null +++ b/Dockerfile.ci @@ -0,0 +1,16 @@ +FROM src +WORKDIR /go/src/github.com/openshift-hyperfleet/hyperfleet-infra +USER root +RUN yum -y install --setopt=skip_missing_names_on_install=False \ + shellcheck \ + jq \ + unzip \ + && yum clean all +RUN curl -fsSL -o /tmp/get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 \ + && chmod +x /tmp/get_helm.sh && /tmp/get_helm.sh && rm /tmp/get_helm.sh +RUN TERRAFORM_VERSION=1.9.8 \ + && curl -fsSL -o /tmp/terraform.zip "https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip" \ + && unzip -o /tmp/terraform.zip -d /usr/local/bin/ && rm /tmp/terraform.zip +RUN curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \ + && chmod 755 kubectl && mv kubectl /usr/local/bin/ +RUN helm plugin install https://github.com/aslafy-z/helm-git diff --git a/Makefile b/Makefile index 8bf6fb1..5fcc1a1 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,9 @@ SENTINEL_IMAGE_TAG ?= v0.1.1 ADAPTER_IMAGE_TAG ?= v0.1.1 DRY_RUN ?= AUTO_APPROVE ?= +# Derived flags from boolean variables +DRY_RUN_FLAG := $(if $(DRY_RUN),--dry-run) +AUTO_APPROVE_FLAG := $(if $(AUTO_APPROVE),-auto-approve) # Chart source configuration (helm-git plugin) # Chart refs are independent of image tags so that overriding an image tag @@ -111,7 +114,7 @@ install-maestro: check-helm check-kubectl check-maestro-namespace ## Install Mae helm dependency update $(HELM_DIR)/maestro @echo "Installing Maestro..." - if ! helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(MAESTRO_NS)-maestro $(HELM_DIR)/maestro \ + if ! helm upgrade --install $(DRY_RUN_FLAG) $(MAESTRO_NS)-maestro $(HELM_DIR)/maestro \ --namespace $(MAESTRO_NS) \ --kubeconfig $(KUBECONFIG) \ --set agent.messageBroker.mqtt.host=maestro-mqtt.$(MAESTRO_NS) \ @@ -149,7 +152,7 @@ endef install-api: check-helm check-kubectl check-namespace ## Install HyperFleet API $(call set-chart-ref,$(HELM_DIR)/api,$(API_CHART_REF)) helm dependency update $(HELM_DIR)/api - helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(NAMESPACE)-api $(HELM_DIR)/api \ + helm upgrade --install $(DRY_RUN_FLAG) $(NAMESPACE)-api $(HELM_DIR)/api \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ $(if $(REGISTRY),--set hyperfleet-api.image.registry=$(REGISTRY)) \ @@ -159,7 +162,7 @@ install-api: check-helm check-kubectl check-namespace ## Install HyperFleet API install-sentinel-clusters: check-helm check-kubectl check-namespace ## Install Sentinel for clusters $(call set-chart-ref,$(HELM_DIR)/sentinel-clusters,$(SENTINEL_CHART_REF)) helm dependency update $(HELM_DIR)/sentinel-clusters - helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(NAMESPACE)-sentinel-clusters $(HELM_DIR)/sentinel-clusters \ + helm upgrade --install $(DRY_RUN_FLAG) $(NAMESPACE)-sentinel-clusters $(HELM_DIR)/sentinel-clusters \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set sentinel.broker.type=$(BROKER_TYPE) \ @@ -171,7 +174,7 @@ install-sentinel-clusters: check-helm check-kubectl check-namespace ## Install S install-sentinel-nodepools: check-helm check-kubectl check-namespace ## Install Sentinel for nodepools $(call set-chart-ref,$(HELM_DIR)/sentinel-nodepools,$(SENTINEL_CHART_REF)) helm dependency update $(HELM_DIR)/sentinel-nodepools - helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(NAMESPACE)-sentinel-nodepools $(HELM_DIR)/sentinel-nodepools \ + helm upgrade --install $(DRY_RUN_FLAG) $(NAMESPACE)-sentinel-nodepools $(HELM_DIR)/sentinel-nodepools \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set sentinel.broker.type=$(BROKER_TYPE) \ @@ -183,7 +186,7 @@ install-sentinel-nodepools: check-helm check-kubectl check-namespace ## Install install-adapter1: check-helm check-kubectl check-namespace ## Install adapter1 $(call set-chart-ref,$(HELM_DIR)/adapter1,$(ADAPTER_CHART_REF)) helm dependency update $(HELM_DIR)/adapter1 - helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(NAMESPACE)-adapter1 $(HELM_DIR)/adapter1 \ + helm upgrade --install $(DRY_RUN_FLAG) $(NAMESPACE)-adapter1 $(HELM_DIR)/adapter1 \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ @@ -197,7 +200,7 @@ install-adapter1: check-helm check-kubectl check-namespace ## Install adapter1 install-adapter2: check-helm check-kubectl check-namespace ## Install adapter2 $(call set-chart-ref,$(HELM_DIR)/adapter2,$(ADAPTER_CHART_REF)) helm dependency update $(HELM_DIR)/adapter2 - helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(NAMESPACE)-adapter2 $(HELM_DIR)/adapter2 \ + helm upgrade --install $(DRY_RUN_FLAG) $(NAMESPACE)-adapter2 $(HELM_DIR)/adapter2 \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ @@ -211,7 +214,7 @@ install-adapter2: check-helm check-kubectl check-namespace ## Install adapter2 install-adapter3: check-helm check-kubectl check-namespace ## Install adapter3 $(call set-chart-ref,$(HELM_DIR)/adapter3,$(ADAPTER_CHART_REF)) helm dependency update $(HELM_DIR)/adapter3 - helm upgrade --install $(if $(DRY_RUN),$(DRY_RUN)) $(NAMESPACE)-adapter3 $(HELM_DIR)/adapter3 \ + helm upgrade --install $(DRY_RUN_FLAG) $(NAMESPACE)-adapter3 $(HELM_DIR)/adapter3 \ --namespace $(NAMESPACE) \ --kubeconfig $(KUBECONFIG) \ --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ @@ -224,7 +227,7 @@ install-adapter3: check-helm check-kubectl check-namespace ## Install adapter3 .PHONY: install-terraform install-terraform: check-terraform check-tf-files ## Run Terraform init and apply cd $(TF_DIR) && terraform init -backend-config=$(TF_BACKEND) - cd $(TF_DIR) && terraform apply -var-file=$(TF_VARS) $(AUTO_APPROVE) + cd $(TF_DIR) && terraform apply -var-file=$(TF_VARS) $(AUTO_APPROVE_FLAG) # ────────────────────────────────────────────── # Aggregate install targets @@ -254,9 +257,10 @@ install-all-rabbitmq: install-rabbitmq tf-helm-values install-hyperfleet install .PHONY: validate-terraform validate-terraform: check-terraform ## Validate Terraform syntax and formatting - cd $(TF_DIR) && terraform init -backend=false - cd $(TF_DIR) && terraform fmt -check -recursive -diff - cd $(TF_DIR) && terraform validate + cd $(TF_DIR) && \ + terraform init -backend=false && \ + terraform fmt -check -recursive -diff && \ + terraform validate .PHONY: lint-helm lint-helm: check-helm deps ## Lint all Helm charts @@ -285,55 +289,52 @@ plan-terraform: check-terraform check-tf-files ## Run terraform plan (preview on cd $(TF_DIR) && terraform init -backend-config=$(TF_BACKEND) cd $(TF_DIR) && terraform plan -var-file=$(TF_VARS) +# validate-chart: validate a single Helm chart with helm template +# Usage: $(call validate-chart,,,) +define validate-chart + $(call set-chart-ref,$(HELM_DIR)/$(1),$(2)) + helm dependency update $(HELM_DIR)/$(1) + @echo "Validating $(1) chart..." + helm template $(NAMESPACE)-$(1) $(HELM_DIR)/$(1) $(3) > /dev/null +endef + .PHONY: validate-helm-charts validate-helm-charts: check-helm ## Render all Helm charts with helm template (no cluster required) - $(call set-chart-ref,$(HELM_DIR)/api,$(API_CHART_REF)) - helm dependency update $(HELM_DIR)/api - @echo "Validating api chart..." - helm template $(NAMESPACE)-api $(HELM_DIR)/api \ + $(call validate-chart,api,$(API_CHART_REF),\ $(if $(REGISTRY),--set hyperfleet-api.image.registry=$(REGISTRY)) \ - --set hyperfleet-api.image.tag=$(API_IMAGE_TAG) > /dev/null - $(call set-chart-ref,$(HELM_DIR)/sentinel-clusters,$(SENTINEL_CHART_REF)) - helm dependency update $(HELM_DIR)/sentinel-clusters - @echo "Validating sentinel-clusters chart..." - helm template $(NAMESPACE)-sentinel-clusters $(HELM_DIR)/sentinel-clusters \ + --set hyperfleet-api.image.tag=$(API_IMAGE_TAG)) + + $(call validate-chart,sentinel-clusters,$(SENTINEL_CHART_REF),\ --set sentinel.broker.type=$(BROKER_TYPE) \ $(if $(REGISTRY),--set sentinel.image.registry=$(REGISTRY)) \ - --set sentinel.image.tag=$(SENTINEL_IMAGE_TAG) > /dev/null - $(call set-chart-ref,$(HELM_DIR)/sentinel-nodepools,$(SENTINEL_CHART_REF)) - helm dependency update $(HELM_DIR)/sentinel-nodepools - @echo "Validating sentinel-nodepools chart..." - helm template $(NAMESPACE)-sentinel-nodepools $(HELM_DIR)/sentinel-nodepools \ + --set sentinel.image.tag=$(SENTINEL_IMAGE_TAG)) + + $(call validate-chart,sentinel-nodepools,$(SENTINEL_CHART_REF),\ --set sentinel.broker.type=$(BROKER_TYPE) \ $(if $(REGISTRY),--set sentinel.image.registry=$(REGISTRY)) \ - --set sentinel.image.tag=$(SENTINEL_IMAGE_TAG) > /dev/null - $(call set-chart-ref,$(HELM_DIR)/adapter1,$(ADAPTER_CHART_REF)) - helm dependency update $(HELM_DIR)/adapter1 - @echo "Validating adapter1 chart..." - helm template $(NAMESPACE)-adapter1 $(HELM_DIR)/adapter1 \ + --set sentinel.image.tag=$(SENTINEL_IMAGE_TAG)) + + $(call validate-chart,adapter1,$(ADAPTER_CHART_REF),\ --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ $(if $(REGISTRY),--set hyperfleet-adapter.image.registry=$(REGISTRY)) \ --set hyperfleet-adapter.image.tag=$(ADAPTER_IMAGE_TAG) \ --set-file hyperfleet-adapter.adapterConfig.yaml=$(HELM_DIR)/adapter1/adapter-config.yaml \ - --set-file hyperfleet-adapter.adapterTaskConfig.yaml=$(HELM_DIR)/adapter1/adapter-task-config.yaml > /dev/null - $(call set-chart-ref,$(HELM_DIR)/adapter2,$(ADAPTER_CHART_REF)) - helm dependency update $(HELM_DIR)/adapter2 - @echo "Validating adapter2 chart..." - helm template $(NAMESPACE)-adapter2 $(HELM_DIR)/adapter2 \ + --set-file hyperfleet-adapter.adapterTaskConfig.yaml=$(HELM_DIR)/adapter1/adapter-task-config.yaml) + + $(call validate-chart,adapter2,$(ADAPTER_CHART_REF),\ --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ $(if $(REGISTRY),--set hyperfleet-adapter.image.registry=$(REGISTRY)) \ --set hyperfleet-adapter.image.tag=$(ADAPTER_IMAGE_TAG) \ --set-file hyperfleet-adapter.adapterConfig.yaml=$(HELM_DIR)/adapter2/adapter-config.yaml \ - --set-file hyperfleet-adapter.adapterTaskConfig.yaml=$(HELM_DIR)/adapter2/adapter-task-config.yaml > /dev/null - $(call set-chart-ref,$(HELM_DIR)/adapter3,$(ADAPTER_CHART_REF)) - helm dependency update $(HELM_DIR)/adapter3 - @echo "Validating adapter3 chart..." - helm template $(NAMESPACE)-adapter3 $(HELM_DIR)/adapter3 \ + --set-file hyperfleet-adapter.adapterTaskConfig.yaml=$(HELM_DIR)/adapter2/adapter-task-config.yaml) + + $(call validate-chart,adapter3,$(ADAPTER_CHART_REF),\ --set hyperfleet-adapter.broker.type=$(BROKER_TYPE) \ $(if $(REGISTRY),--set hyperfleet-adapter.image.registry=$(REGISTRY)) \ --set hyperfleet-adapter.image.tag=$(ADAPTER_IMAGE_TAG) \ --set-file hyperfleet-adapter.adapterConfig.yaml=$(HELM_DIR)/adapter3/adapter-config.yaml \ - --set-file hyperfleet-adapter.adapterTaskConfig.yaml=$(HELM_DIR)/adapter3/adapter-task-config.yaml > /dev/null + --set-file hyperfleet-adapter.adapterTaskConfig.yaml=$(HELM_DIR)/adapter3/adapter-task-config.yaml) + helm dependency update $(HELM_DIR)/maestro @echo "Validating maestro chart..." helm template $(MAESTRO_NS)-maestro $(HELM_DIR)/maestro \ @@ -451,8 +452,8 @@ help: ## Print available targets @echo " SENTINEL_CHART_REF Git ref for sentinel helm chart source (default: SENTINEL_IMAGE_TAG)" @echo " ADAPTER_CHART_REF Git ref for adapter helm chart source (default: ADAPTER_IMAGE_TAG)" @echo " MAESTRO_CONSUMER Maestro consumer name (default: cluster1)" - @echo " DRY_RUN Set to --dry-run for Helm dry-run mode (default: empty)" - @echo " AUTO_APPROVE Set to -auto-approve for non-interactive Terraform (default: empty)" + @echo " DRY_RUN Set to any value (e.g., true) for Helm dry-run mode (default: empty)" + @echo " AUTO_APPROVE Set to any value (e.g., true) for non-interactive Terraform (default: empty)" @echo "" @echo "Targets:" @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-28s\033[0m %s\n", $$1, $$2}'