Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions .github/workflows/helm_vs_kustomize_verification.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Verify Helm vs Kustomize Manifests

on:
pull_request:
paths:
- .github/workflows/helm_vs_kustomize_verification.yaml
- tests/install_KinD_create_KinD_cluster_install_kustomize.sh
- tests/helm_install.sh
- tests/helm_kustomize_compare_manifests.sh
- tests/helm_kustomize_compare_manifests.py
- applications/spark/spark-operator/**
- common/cert-manager/**
- experimental/helm/scripts/**

jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
matrix:
component: [spark-operator, cert-manager]
fail-fast: false

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install KinD, Create KinD cluster and Install kustomize
run: ./tests/install_KinD_create_KinD_cluster_install_kustomize.sh

- name: Install Helm
run: ./tests/helm_install.sh

- name: Setup Helm chart structure
run: ./experimental/helm/scripts/setup-test-chart.sh

- name: Generate Helm templates for ${{ matrix.component }}
run: ./experimental/helm/scripts/synchronize-${{ matrix.component }}.sh

- name: Run Helm vs Kustomize verification for ${{ matrix.component }}
run: ./tests/helm_kustomize_compare_manifests.sh ${{ matrix.component }}

- name: Cleanup generated Helm templates
if: always()
run: |
rm -rf experimental/helm/kubeflow/templates/external/${{ matrix.component }}
rm -f experimental/helm/kubeflow/crds/*-${{ matrix.component }}*.yaml
7 changes: 7 additions & 0 deletions experimental/helm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Helm dependency charts
**/charts/*.tgz
**/Chart.lock

# Helm temporary files
*.tmp
*.backup
72 changes: 72 additions & 0 deletions experimental/helm/scripts/patch-templates.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env python3
import yaml
import sys
import os
from pathlib import Path

def patch_yaml_file(file_path, component):
"""Patch a YAML file to add conditional rendering and namespace"""
with open(file_path, 'r') as f:
content = f.read()

component_map = {
'spark-operator': 'sparkOperator.enabled',
'cert-manager': 'certManager.enabled',
}

condition = component_map.get(component, f'{component}.enabled')
condition_check = f'{{{{- if .Values.{condition} }}}}'

if condition_check in content:
return

try:
docs = list(yaml.safe_load_all(content))
patched_docs = []

for doc in docs:
if doc and isinstance(doc, dict):
if 'metadata' in doc and doc.get('kind') in [
'Deployment', 'Service', 'ServiceAccount', 'Role', 'RoleBinding'
]:
if not isinstance(doc['metadata'].get('namespace'), str) or '{{' not in doc['metadata'].get('namespace', ''):
if component == 'cert-manager':
if doc.get('kind') in ['Role', 'RoleBinding'] and 'leaderelection' in doc['metadata'].get('name', ''):
doc['metadata']['namespace'] = 'kube-system'
else:
doc['metadata']['namespace'] = '{{ .Values.global.certManagerNamespace }}'
else:
doc['metadata']['namespace'] = '{{ include "kubeflow.namespace" . }}'

if doc.get('kind') == 'Deployment' and 'spec' in doc and component == 'spark-operator':
if 'template' in doc['spec'] and 'metadata' in doc['spec']['template']:
template_meta = doc['spec']['template']['metadata']
if 'labels' not in template_meta:
template_meta['labels'] = {}
template_meta['labels']['sidecar.istio.io/inject'] = 'false'

patched_docs.append(doc)

with open(file_path, 'w') as f:
f.write(f'{condition_check}\n')
for doc in patched_docs:
f.write('---\n')
yaml.dump(doc, f, default_flow_style=False, sort_keys=False)
f.write('{{- end }}\n')

except Exception as e:
print(f"Warning: Could not patch {file_path}: {e}")
with open(file_path, 'w') as f:
f.write(f'{condition_check}\n')
f.write(content)
f.write('{{- end }}\n')

if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: patch-templates.py <templates_dir> <component>")
sys.exit(1)

templates_dir = sys.argv[1]
component = sys.argv[2]
for yaml_file in Path(templates_dir).rglob("*.yaml"):
patch_yaml_file(str(yaml_file), component)
151 changes: 151 additions & 0 deletions experimental/helm/scripts/setup-test-chart.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#!/usr/bin/env bash

set -euo pipefail

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
HELM_DIR="$(dirname "$SCRIPT_DIR")"
CHART_DIR="$HELM_DIR/kubeflow"


mkdir -p "$CHART_DIR/templates/external"
mkdir -p "$CHART_DIR/templates/integrations"
mkdir -p "$CHART_DIR/templates/_helpers"
mkdir -p "$CHART_DIR/crds"

cat > "$CHART_DIR/Chart.yaml" << 'EOF'
apiVersion: v2
name: kubeflow
description: Kubeflow All-in-One Helm Chart (Test Version)
type: application
version: 0.1.0
appVersion: "v1.10.0"
EOF

cat > "$CHART_DIR/values.yaml" << 'EOF'
# Global configuration
global:
kubeflowNamespace: kubeflow
certManagerNamespace: cert-manager

# Component configurations
sparkOperator:
enabled: false
kubeflowRBAC:
enabled: false
spark:
jobNamespaces: []
webhook:
enable: true
port: 9443

certManager:
enabled: false
installCRDs: true
global:
leaderElection:
namespace: kube-system
startupapicheck:
enabled: false
kubeflowIssuer:
enabled: true
name: kubeflow-self-signing-issuer
EOF

cat > "$CHART_DIR/templates/_helpers.tpl" << 'EOF'
{{/*
Common labels
*/}}
{{- define "kubeflow.labels" -}}
app.kubernetes.io/name: {{ include "kubeflow.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Chart name
*/}}
{{- define "kubeflow.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Kubeflow namespace
*/}}
{{- define "kubeflow.namespace" -}}
{{- .Values.global.kubeflowNamespace | default "kubeflow" }}
{{- end }}
EOF

cat > "$CHART_DIR/templates/integrations/spark-operator-rbac.yaml" << 'EOF'
{{- if and .Values.sparkOperator.enabled .Values.sparkOperator.kubeflowRBAC.enabled }}
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kubeflow-spark-admin
labels:
app: spark-operator
app.kubernetes.io/name: spark-operator
rbac.authorization.kubeflow.org/aggregate-to-kubeflow-admin: "true"
rules: []
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kubeflow-spark-edit
labels:
app: spark-operator
app.kubernetes.io/name: spark-operator
rbac.authorization.kubeflow.org/aggregate-to-kubeflow-edit: "true"
rbac.authorization.kubeflow.org/aggregate-to-kubeflow-admin: "true"
rules:
- apiGroups:
- sparkoperator.k8s.io
resources:
- sparkapplications
- scheduledsparkapplications
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- sparkoperator.k8s.io
resources:
- sparkapplications/status
- scheduledsparkapplications/status
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: kubeflow-spark-view
labels:
app: spark-operator
app.kubernetes.io/name: spark-operator
rbac.authorization.kubeflow.org/aggregate-to-kubeflow-view: "true"
rules:
- apiGroups:
- sparkoperator.k8s.io
resources:
- sparkapplications
- scheduledsparkapplications
verbs:
- get
- list
- watch
- apiGroups:
- sparkoperator.k8s.io
resources:
- sparkapplications/status
- scheduledsparkapplications/status
verbs:
- get
{{- end }}
EOF

29 changes: 29 additions & 0 deletions experimental/helm/scripts/synchronize-all-charts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Master script to sync all upstream charts for Kubeflow AIO Helm chart

set -euo pipefail

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
HELM_DIR="$(dirname "$SCRIPT_DIR")"
CHART_DIR="$HELM_DIR/kubeflow"

COMPONENTS=(
"spark-operator"
"cert-manager"
# Add more components as we implement them
# "training-operator"
# "istio"
# "oauth2-proxy"
# "dex"
)

for component in "${COMPONENTS[@]}"; do
sync_script="$SCRIPT_DIR/synchronize-${component}.sh"
if [ -f "$sync_script" ]; then
echo "Syncing $component..."
bash "$sync_script"
fi
done

cd "$CHART_DIR"
helm template kubeflow . --debug --dry-run > /dev/null && echo "Success: AIO chart templates correctly!"
80 changes: 80 additions & 0 deletions experimental/helm/scripts/synchronize-cert-manager.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#!/usr/bin/env bash
# Script to sync Cert Manager templates for AIO Helm chart

set -euo pipefail

SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
HELM_DIR="$(dirname "$SCRIPT_DIR")"
CHART_DIR="$HELM_DIR/kubeflow"

COMPONENT="cert-manager"
VERSION="v1.16.1"
REPO="https://charts.jetstack.io"
TEMPLATES_DIR="$CHART_DIR/templates/external/${COMPONENT}"
CRDS_DIR="$CHART_DIR/crds"
NAMESPACE="cert-manager"

rm -rf "$TEMPLATES_DIR"
mkdir -p "$TEMPLATES_DIR"
mkdir -p "$CRDS_DIR"

TEMP_DIR=$(mktemp -d)
cd "$TEMP_DIR"

# Generate templates using same settings as existing Kustomize setup
# Disable startupapicheck to match Kustomize manifests that don't include it
helm template "$COMPONENT" "$COMPONENT" \
--version "$VERSION" \
--repo "$REPO" \
--namespace "$NAMESPACE" \
--include-crds \
--set installCRDs=true \
--set global.leaderElection.namespace="kube-system" \
--set startupapicheck.enabled=false \
--output-dir .

for file in "$COMPONENT/templates/"*.yaml; do
if [ -f "$file" ] && [[ ! "$(basename "$file")" == crds.yaml ]]; then
cp "$file" "$TEMPLATES_DIR/"
fi
done
cat "$COMPONENT/templates/crds.yaml" > "$CRDS_DIR/cert-manager-crds.yaml"

python3 "$SCRIPT_DIR/patch-templates.py" "$TEMPLATES_DIR" "$COMPONENT"

# Add namespace template since cert-manager chart doesn't include it
cat > "$TEMPLATES_DIR/namespace.yaml" << 'EOF'
{{- if .Values.certManager.enabled }}
apiVersion: v1
kind: Namespace
metadata:
name: {{ .Values.global.certManagerNamespace }}
labels:
pod-security.kubernetes.io/enforce: restricted
{{- end }}
EOF

# Create kubeflow-issuer template
mkdir -p "$TEMPLATES_DIR/kubeflow-issuer"
cat > "$TEMPLATES_DIR/kubeflow-issuer/cluster-issuer.yaml" << 'EOF'
{{- if .Values.certManager.enabled }}
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: kubeflow-self-signing-issuer
labels:
{{- include "kubeflow.labels" . | nindent 4 }}
app.kubernetes.io/component: cert-manager
app.kubernetes.io/name: cert-manager
kustomize.component: cert-manager
spec:
selfSigned: {}
{{- end }}
EOF

cd "$CHART_DIR"
rm -rf "$TEMP_DIR"

helm template kubeflow . --debug --dry-run > /dev/null

echo "Cert Manager templates synchronized successfully"
Loading
Loading