157 lines
5.0 KiB
Python
157 lines
5.0 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Generate ArgoCD ApplicationSet manifests for multi-cluster deployments.
|
|
Supports Cluster, List, and Matrix generators (ArgoCD 3.x).
|
|
"""
|
|
|
|
import argparse
|
|
import sys
|
|
import yaml
|
|
|
|
|
|
APPLICATIONSET_TEMPLATE = """---
|
|
apiVersion: argoproj.io/v1alpha1
|
|
kind: ApplicationSet
|
|
metadata:
|
|
name: {name}
|
|
namespace: argocd
|
|
spec:
|
|
goTemplate: true
|
|
goTemplateOptions: ["missingkey=error"]
|
|
generators:
|
|
{generators}
|
|
template:
|
|
metadata:
|
|
name: '{{{{.name}}}}-{name}'
|
|
labels:
|
|
environment: '{{{{.environment}}}}'
|
|
spec:
|
|
project: default
|
|
source:
|
|
repoURL: {repo_url}
|
|
targetRevision: {target_revision}
|
|
path: '{path}'
|
|
destination:
|
|
server: '{{{{.server}}}}'
|
|
namespace: {namespace}
|
|
syncPolicy:
|
|
automated:
|
|
prune: true
|
|
selfHeal: true
|
|
syncOptions:
|
|
- CreateNamespace=true
|
|
"""
|
|
|
|
|
|
def generate_cluster_generator(label_selector: str = "") -> str:
|
|
"""Generate Cluster generator."""
|
|
selector = f"\n selector:\n matchLabels:\n {label_selector}" if label_selector else ""
|
|
return f""" - cluster: {{{selector}}}"""
|
|
|
|
|
|
def generate_list_generator(clusters: list) -> str:
|
|
"""Generate List generator."""
|
|
elements = "\n".join([f" - name: {c['name']}\n server: {c['server']}\n environment: {c.get('environment', 'production')}"
|
|
for c in clusters])
|
|
return f""" - list:
|
|
elements:
|
|
{elements}"""
|
|
|
|
|
|
def generate_matrix_generator(cluster_label: str, git_directories: list) -> str:
|
|
"""Generate Matrix generator (Cluster x Git directories)."""
|
|
git_list = "\n".join([f" - path: {d}" for d in git_directories])
|
|
return f""" - matrix:
|
|
generators:
|
|
- cluster:
|
|
selector:
|
|
matchLabels:
|
|
environment: {cluster_label}
|
|
- git:
|
|
repoURL: https://github.com/example/apps
|
|
revision: HEAD
|
|
directories:
|
|
{git_list}"""
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description='Generate ArgoCD ApplicationSet manifests',
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
Examples:
|
|
# Cluster generator (all clusters)
|
|
python3 applicationset_generator.py cluster \\
|
|
--name my-apps \\
|
|
--repo-url https://github.com/org/repo \\
|
|
--path apps/
|
|
|
|
# List generator (specific clusters)
|
|
python3 applicationset_generator.py list \\
|
|
--name my-apps \\
|
|
--clusters prod=https://prod.k8s.local,staging=https://staging.k8s.local
|
|
|
|
# Matrix generator (cluster x directories)
|
|
python3 applicationset_generator.py matrix \\
|
|
--name my-apps \\
|
|
--cluster-label production \\
|
|
--directories app1,app2,app3
|
|
"""
|
|
)
|
|
|
|
parser.add_argument('generator_type', choices=['cluster', 'list', 'matrix'],
|
|
help='Generator type')
|
|
parser.add_argument('--name', required=True, help='ApplicationSet name')
|
|
parser.add_argument('--repo-url', default='https://github.com/example/repo',
|
|
help='Git repository URL')
|
|
parser.add_argument('--path', default='apps/', help='Path in repository')
|
|
parser.add_argument('--namespace', default='default', help='Target namespace')
|
|
parser.add_argument('--target-revision', default='main', help='Git branch/tag')
|
|
parser.add_argument('--cluster-label', help='Cluster label selector')
|
|
parser.add_argument('--clusters', help='Cluster list (name=server,name=server)')
|
|
parser.add_argument('--directories', help='Git directories (comma-separated)')
|
|
parser.add_argument('--output', help='Output file')
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Generate based on type
|
|
if args.generator_type == 'cluster':
|
|
generators = generate_cluster_generator(args.cluster_label or "")
|
|
elif args.generator_type == 'list':
|
|
if not args.clusters:
|
|
print("❌ --clusters required for list generator")
|
|
sys.exit(1)
|
|
cluster_list = []
|
|
for c in args.clusters.split(','):
|
|
name, server = c.split('=')
|
|
cluster_list.append({'name': name, 'server': server})
|
|
generators = generate_list_generator(cluster_list)
|
|
elif args.generator_type == 'matrix':
|
|
if not args.cluster_label or not args.directories:
|
|
print("❌ --cluster-label and --directories required for matrix generator")
|
|
sys.exit(1)
|
|
directories = args.directories.split(',')
|
|
generators = generate_matrix_generator(args.cluster_label, directories)
|
|
|
|
# Create ApplicationSet
|
|
appset = APPLICATIONSET_TEMPLATE.format(
|
|
name=args.name,
|
|
generators=generators,
|
|
repo_url=args.repo_url,
|
|
target_revision=args.target_revision,
|
|
path=args.path,
|
|
namespace=args.namespace
|
|
)
|
|
|
|
# Output
|
|
if args.output:
|
|
with open(args.output, 'w') as f:
|
|
f.write(appset)
|
|
print(f"✅ ApplicationSet written to: {args.output}")
|
|
else:
|
|
print(appset)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|