210 lines
6.8 KiB
Bash
Executable File
210 lines
6.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# Kubernetes/Helm Configuration Validator
|
|
# Validates all applications without deploying them
|
|
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Counters
|
|
TOTAL=0
|
|
PASSED=0
|
|
FAILED=0
|
|
|
|
echo -e "${BLUE}=== Kubernetes Configuration Validator ===${NC}\n"
|
|
|
|
# Function to validate a Helm chart
|
|
validate_helm_chart() {
|
|
local app_path=$1
|
|
local app_name=$(basename "$app_path")
|
|
local namespace=$2
|
|
|
|
TOTAL=$((TOTAL + 1))
|
|
|
|
echo -e "${YELLOW}[$TOTAL] Validating: $app_name (namespace: $namespace)${NC}"
|
|
|
|
# Check if Chart.yaml exists
|
|
if [ ! -f "$app_path/Chart.yaml" ]; then
|
|
echo -e "${RED} ✗ No Chart.yaml found${NC}\n"
|
|
FAILED=$((FAILED + 1))
|
|
return 1
|
|
fi
|
|
|
|
# Check if dependencies are built (build to temp location if not)
|
|
if [ -f "$app_path/Chart.yaml" ] && grep -q "dependencies:" "$app_path/Chart.yaml"; then
|
|
if [ ! -d "$app_path/charts" ]; then
|
|
echo " → Dependencies not built - building to temporary location..."
|
|
|
|
# Create temp directory
|
|
local temp_dir=$(mktemp -d)
|
|
trap "rm -rf $temp_dir" EXIT
|
|
|
|
# Copy chart to temp location
|
|
cp -r "$app_path" "$temp_dir/"
|
|
local temp_chart="$temp_dir/$(basename "$app_path")"
|
|
|
|
# Build dependencies in temp location
|
|
if ! (cd "$temp_chart" && helm dependency build > /dev/null 2>&1); then
|
|
echo -e "${RED} ✗ Failed to build dependencies${NC}\n"
|
|
FAILED=$((FAILED + 1))
|
|
return 1
|
|
fi
|
|
|
|
# Use temp location for validation
|
|
app_path="$temp_chart"
|
|
fi
|
|
fi
|
|
|
|
# Lint the chart
|
|
echo " → Running Helm lint..."
|
|
if ! (cd "$app_path" && helm lint . 2>&1 | grep -q "0 chart(s) failed"); then
|
|
echo -e "${RED} ✗ Helm lint failed${NC}"
|
|
(cd "$app_path" && helm lint .)
|
|
echo ""
|
|
FAILED=$((FAILED + 1))
|
|
return 1
|
|
fi
|
|
|
|
# Template the chart
|
|
echo " → Rendering Helm templates..."
|
|
if ! (cd "$app_path" && helm template "$app_name" . --namespace "$namespace" --validate > /dev/null 2>&1); then
|
|
echo -e "${RED} ✗ Helm template failed${NC}"
|
|
(cd "$app_path" && helm template "$app_name" . --namespace "$namespace" --validate 2>&1 | head -20)
|
|
echo ""
|
|
FAILED=$((FAILED + 1))
|
|
return 1
|
|
fi
|
|
|
|
# Validate with kubeval (if installed)
|
|
if command -v kubeval &> /dev/null; then
|
|
echo " → Validating manifests with kubeval..."
|
|
if ! (cd "$app_path" && helm template "$app_name" . --namespace "$namespace" | kubeval --ignore-missing-schemas > /dev/null 2>&1); then
|
|
echo -e "${YELLOW} ⚠ Kubeval warnings (may be acceptable)${NC}"
|
|
fi
|
|
fi
|
|
|
|
# Check for common issues
|
|
echo " → Checking for common issues..."
|
|
local rendered=$(cd "$app_path" && helm template "$app_name" . --namespace "$namespace" 2>&1)
|
|
|
|
# Check for placeholder secrets
|
|
if echo "$rendered" | grep -qi "changeme\|placeholder\|CHANGE_ME\|TODO"; then
|
|
echo -e "${YELLOW} ⚠ Warning: Found placeholder values (changeme/placeholder/TODO)${NC}"
|
|
fi
|
|
|
|
# Check for resource requests/limits
|
|
if ! echo "$rendered" | grep -q "resources:"; then
|
|
echo -e "${YELLOW} ⚠ Warning: No resource requests/limits found${NC}"
|
|
fi
|
|
|
|
echo -e "${GREEN} ✓ Validation passed${NC}\n"
|
|
PASSED=$((PASSED + 1))
|
|
return 0
|
|
}
|
|
|
|
# Function to validate an ArgoCD Application manifest
|
|
validate_argocd_app() {
|
|
local app_file=$1
|
|
local app_name=$(basename "$(dirname "$app_file")")
|
|
|
|
TOTAL=$((TOTAL + 1))
|
|
|
|
echo -e "${YELLOW}[$TOTAL] Validating ArgoCD Application: $app_name${NC}"
|
|
|
|
# Check YAML syntax
|
|
if ! python3 -c "import yaml; yaml.safe_load(open('$app_file'))" 2>/dev/null; then
|
|
echo -e "${RED} ✗ Invalid YAML syntax${NC}\n"
|
|
FAILED=$((FAILED + 1))
|
|
return 1
|
|
fi
|
|
|
|
# Check for required fields
|
|
local missing_fields=()
|
|
grep -q "kind: Application" "$app_file" || missing_fields+=("kind: Application")
|
|
grep -q "metadata:" "$app_file" || missing_fields+=("metadata")
|
|
grep -q "spec:" "$app_file" || missing_fields+=("spec")
|
|
grep -q "source:" "$app_file" || missing_fields+=("source")
|
|
grep -q "destination:" "$app_file" || missing_fields+=("destination")
|
|
|
|
if [ ${#missing_fields[@]} -gt 0 ]; then
|
|
echo -e "${RED} ✗ Missing required fields: ${missing_fields[*]}${NC}\n"
|
|
FAILED=$((FAILED + 1))
|
|
return 1
|
|
fi
|
|
|
|
echo -e "${GREEN} ✓ Validation passed${NC}\n"
|
|
PASSED=$((PASSED + 1))
|
|
return 0
|
|
}
|
|
|
|
# Main validation flow
|
|
echo -e "${BLUE}Validating Monitoring Stack...${NC}\n"
|
|
|
|
# Thanos
|
|
if [ -d "apps/monitoring/thanos" ]; then
|
|
validate_helm_chart "apps/monitoring/thanos" "monitoring"
|
|
validate_argocd_app "apps/monitoring/thanos/application.yaml"
|
|
fi
|
|
|
|
# Prometheus
|
|
if [ -d "apps/monitoring/prometheus" ]; then
|
|
validate_helm_chart "apps/monitoring/prometheus" "monitoring"
|
|
validate_argocd_app "apps/monitoring/prometheus/application.yaml"
|
|
fi
|
|
|
|
# Grafana
|
|
if [ -d "apps/monitoring/grafana" ]; then
|
|
validate_helm_chart "apps/monitoring/grafana" "monitoring"
|
|
validate_argocd_app "apps/monitoring/grafana/application.yaml"
|
|
fi
|
|
|
|
echo -e "${BLUE}Validating Logging Stack...${NC}\n"
|
|
|
|
# Loki
|
|
if [ -d "apps/logging/loki" ]; then
|
|
validate_helm_chart "apps/logging/loki" "logging"
|
|
validate_argocd_app "apps/logging/loki/application.yaml"
|
|
fi
|
|
|
|
# Promtail
|
|
if [ -d "apps/logging/promtail" ]; then
|
|
validate_helm_chart "apps/logging/promtail" "logging"
|
|
validate_argocd_app "apps/logging/promtail/application.yaml"
|
|
fi
|
|
|
|
# Additional apps (if they exist)
|
|
echo -e "${BLUE}Validating Other Applications...${NC}\n"
|
|
|
|
for app_dir in apps/*/; do
|
|
app_name=$(basename "$app_dir")
|
|
if [ -f "$app_dir/Chart.yaml" ] && [ -f "$app_dir/application.yaml" ]; then
|
|
# Skip if already validated
|
|
if [[ "$app_name" != "monitoring" ]] && [[ "$app_name" != "logging" ]]; then
|
|
# Try to extract namespace from application.yaml
|
|
namespace=$(grep -A 10 "destination:" "$app_dir/application.yaml" | grep "namespace:" | head -1 | awk '{print $2}')
|
|
[ -z "$namespace" ] && namespace="default"
|
|
validate_helm_chart "$app_dir" "$namespace"
|
|
validate_argocd_app "$app_dir/application.yaml"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# Summary
|
|
echo -e "${BLUE}=== Validation Summary ===${NC}"
|
|
echo -e "Total checks: $TOTAL"
|
|
echo -e "${GREEN}Passed: $PASSED${NC}"
|
|
echo -e "${RED}Failed: $FAILED${NC}\n"
|
|
|
|
if [ $FAILED -eq 0 ]; then
|
|
echo -e "${GREEN}✓ All validations passed!${NC}"
|
|
exit 0
|
|
else
|
|
echo -e "${RED}✗ Some validations failed. Please review the errors above.${NC}"
|
|
exit 1
|
|
fi
|