Client Architecture Specification
Status: Proposal
Version: 1.0 Draft
Date: December 23, 2024
Author: IDP Builder Team
Executive Summary
This specification proposes a new unified client architecture for idpbuilder that replaces the current localbuilder implementation and existing CLI with a more modular, extensible design. The new client will provide three primary sets of functionality:
- Infrastructure Management - Spins up underlying infrastructure for local development (e.g., statically linking with kind for local Kubernetes clusters)
- Flavor Selection - Allows selection of an idpbuilder "flavor" - pre-defined sets of Custom Resources (CRs) that deploy a complete IDP instance on Kubernetes
- Status Monitoring - Watches Platform resources and provides user-friendly status information during deployment and operation
This architecture aligns with the controller-based architecture detailed in controller-architecture-spec.md and builds upon the resource tracking patterns described in resource-creation-sequencing.md.
Goals
Primary Goals
- Separation of Concerns: Clear separation between infrastructure provisioning, platform configuration, and status monitoring
- Modular Design: Each client component is independently testable and replaceable
- Flavor Extensibility: Easy to define new platform flavors without code changes
- Excellent UX: Provide clear, real-time feedback to users during all operations
- Development/Production Parity: Same client works for both local development and production deployments
Non-Goals
- Building a general-purpose Kubernetes installer (we focus on IDP-specific use cases)
- Supporting non-Kubernetes deployment targets
- Managing infrastructure beyond what's needed for IDP deployment
Architecture Overview
High-Level Design
graph TB
subgraph "IDP Builder Client"
CLI[CLI Interface]
InfraManager[Infrastructure Manager]
FlavorManager[Flavor Manager]
StatusWatcher[Status Watcher]
CLI --> InfraManager
CLI --> FlavorManager
CLI --> StatusWatcher
InfraManager --> KindProvider[Kind Provider]
InfraManager --> K3sProvider[K3s Provider]
InfraManager --> ExternalProvider[External Cluster Provider]
FlavorManager --> FlavorRegistry[Flavor Registry]
FlavorManager --> CRGenerator[CR Generator]
StatusWatcher --> PlatformMonitor[Platform Monitor]
StatusWatcher --> UIRenderer[UI Renderer]
end
subgraph "Kubernetes Infrastructure"
K8sCluster[Kubernetes Cluster]
K8sAPI[Kubernetes API Server]
K8sCluster --> K8sAPI
end
KindProvider -.provisions.-> K8sCluster
K3sProvider -.provisions.-> K8sCluster
ExternalProvider -.connects to.-> K8sCluster
InfraManager -.provides kubeconfig.-> CRGenerator
InfraManager -.provides kubeconfig.-> PlatformMonitor
CRGenerator --> K8sAPI
PlatformMonitor --> K8sAPI
UIRenderer --> Terminal[Terminal Output]Component Interaction Flow
The architecture follows a clear separation where the Infrastructure Manager provisions the Kubernetes cluster and provides access credentials to other components:
- Infrastructure Manager provisions or connects to a Kubernetes cluster
- Infrastructure Manager returns a
kubeconfigviaGetKubeConfig() - Flavor Manager's CR Generator uses the kubeconfig to create Custom Resources in the cluster
- Status Watcher's Platform Monitor uses the kubeconfig to watch resources in the cluster
- All Kubernetes API interactions go through the cluster provisioned by Infrastructure Manager
This design ensures:
- Single source of truth for cluster access (Infrastructure Manager)
- No ambiguity about which Kubernetes cluster is being used
- Clean dependency injection pattern
- Components can be tested independently with mock kubeconfigs
Controller Installation and CRD Management
A critical aspect of the architecture is how controllers for provider resources (GiteaProvider, NginxGateway, ArgoCDProvider, etc.) are installed before their CRs are created.
ArgoCD-Driven Dependency Installation:
Flavors explicitly declare their dependencies (Helm charts or Kustomize packages) that provide additional controllers and CRDs beyond the core IDP Builder controllers. The Flavor Manager creates ArgoCD Applications for these dependencies and waits for them to become healthy before proceeding.
Important: The core idpbuilder-controllers (including Flavor CRD, Platform CRD, and provider CRDs) are installed by the Infrastructure Manager during cluster provisioning, NOT as flavor dependencies. This avoids a circular dependency where flavors would need to declare the controller that defines the Flavor CRD itself.
Flavor Dependency Declaration:
apiVersion: idpbuilder.cnoe.io/v1alpha1
kind: Flavor
metadata:
name: basic-dev
spec:
# Dependencies installed via ArgoCD (additional controllers beyond core idpbuilder-controllers)
# Core idpbuilder-controllers are already installed by Infrastructure Manager
dependencies:
- name: nginx-ingress
type: helm
source:
repoURL: https://kubernetes.github.io/ingress-nginx
chart: ingress-nginx
targetRevision: "4.8.0"
syncWave: 1 # Install first
condition: gateway.enabled # Optional
- name: custom-operators
type: kustomize
source:
repoURL: https://github.com/example/operators
path: deploy/overlays/production
targetRevision: main
syncWave: 1Flavor Manager ArgoCD Application Creation:
The Flavor Manager generates ArgoCD Applications for each dependency:
type FlavorManager interface {
// InstallDependencies creates ArgoCD Applications for flavor dependencies
InstallDependencies(ctx context.Context, flavor *Flavor, namespace string) error
// WaitForDependencies waits until all dependency Applications are healthy
WaitForDependencies(ctx context.Context, flavor *Flavor, timeout time.Duration) error
// InstallComponents creates provider CRs after dependencies are ready
InstallComponents(ctx context.Context, flavor *Flavor) error
}
func (m *Manager) InstallDependencies(ctx context.Context, flavor *Flavor, namespace string) error {
for _, dep := range flavor.Spec.Dependencies {
// Skip if condition not met
if dep.Condition != "" && !evaluateCondition(dep.Condition, flavor) {
continue
}
// Create ArgoCD Application for this dependency
app := &argocdv1alpha1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: fmt.Sprintf("%s-%s", flavor.Name, dep.Name),
Namespace: namespace,
Annotations: map[string]string{
"argocd.argoproj.io/sync-wave": strconv.Itoa(dep.SyncWave),
},
},
Spec: argocdv1alpha1.ApplicationSpec{
Project: "default",
Source: argocdv1alpha1.ApplicationSource{
RepoURL: dep.Source.RepoURL,
TargetRevision: dep.Source.TargetRevision,
},
Destination: argocdv1alpha1.ApplicationDestination{
Server: "https://kubernetes.default.svc",
Namespace: namespace,
},
SyncPolicy: &argocdv1alpha1.SyncPolicy{
Automated: &argocdv1alpha1.SyncPolicyAutomated{
Prune: true,
SelfHeal: true,
},
},
},
}
// Set source type-specific fields
if dep.Type == "helm" {
app.Spec.Source.Chart = dep.Source.Chart
} else if dep.Type == "kustomize" {
app.Spec.Source.Path = dep.Source.Path
}
// Create the Application
err := kubeClient.Create(ctx, app)
if err != nil && !errors.IsAlreadyExists(err) {
return fmt.Errorf("failed to create Application for %s: %w", dep.Name, err)
}
}
return nil
}
func (m *Manager) WaitForDependencies(ctx context.Context, flavor *Flavor, timeout time.Duration) error {
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
for _, dep := range flavor.Spec.Dependencies {
if dep.Condition != "" && !evaluateCondition(dep.Condition, flavor) {
continue
}
appName := fmt.Sprintf("%s-%s", flavor.Name, dep.Name)
// Poll until Application is Healthy and Synced
err := wait.PollUntilContextTimeout(ctx, 5*time.Second, timeout, true, func(ctx context.Context) (bool, error) {
app := &argocdv1alpha1.Application{}
err := kubeClient.Get(ctx, types.NamespacedName{
Name: appName,
Namespace: "argocd",
}, app)
if err != nil {
return false, err
}
// Check if Application is healthy and synced
if app.Status.Health.Status == argocdv1alpha1.HealthStatusHealthy &&
app.Status.Sync.Status == argocdv1alpha1.SyncStatusCodeSynced {
return true, nil
}
return false, nil
})
if err != nil {
return fmt.Errorf("dependency %s not ready: %w", dep.Name, err)
}
}
return nil
}Installation Sequence:
- Infrastructure Manager provisions cluster and installs:
- ArgoCD (required for flavor dependency management)
idpbuilder-controllers(Flavor CRD, Platform CRD, provider CRDs like GiteaProvider/NginxGateway, and their controllers)
- Flavor Manager can now read Flavor CRs and create ArgoCD Applications for additional dependencies in sync-wave order
- ArgoCD installs additional dependencies (e.g., nginx-ingress controller) and reports health status
- Flavor Manager waits for all dependency Applications to become Healthy
- Flavor Manager creates provider CRs (components) as additional ArgoCD Applications with higher sync-wave
- ArgoCD installs components after dependencies are ready
- Flavor Manager creates Platform CR to coordinate all components
Benefits of ArgoCD-Driven Dependencies:
- ✅ Declarative dependency management in flavor spec
- ✅ Automatic retry and self-healing via ArgoCD
- ✅ Clear health status and sync state visibility
- ✅ Sync waves ensure correct installation order
- ✅ Works with both Helm and Kustomize sources
- ✅ GitOps-friendly: dependencies tracked in Git
- ✅ Conditional dependencies (e.g., only install if gateway.enabled)
This ensures controllers are always installed and healthy before the CRs that depend on them.
Component Responsibilities
1. Infrastructure Manager
Purpose: Provisions and manages the underlying Kubernetes infrastructure.
Responsibilities:
- Create local Kubernetes clusters (kind, k3s, etc.)
- Connect to existing/remote Kubernetes clusters
- Install ArgoCD as core dependency (required for flavor dependency management)
- Install
idpbuilder-controllers(Flavor CRD, Platform CRD, provider CRDs, and controllers) - Configure networking (CoreDNS, ingress)
- Set up TLS certificates
- Manage cluster lifecycle
Key Architectural Note: The Infrastructure Manager installs core idpbuilder-controllers to avoid circular dependency. Flavors need the Flavor CRD to be defined, and provider CRs (GiteaProvider, NginxGateway, etc.) need their CRDs installed before flavor processing begins. This makes these controllers a platform-level concern, not a flavor dependency.
Interfaces:
type InfrastructureManager interface {
// Provision creates or connects to Kubernetes infrastructure
Provision(ctx context.Context, config InfraConfig) (*InfraResult, error)
// Teardown cleans up infrastructure resources
Teardown(ctx context.Context) error
// GetKubeConfig returns kubeconfig for the provisioned infrastructure
GetKubeConfig() (*rest.Config, error)
// Status returns current infrastructure status
Status(ctx context.Context) (*InfraStatus, error)
}
type InfraProvider interface {
// Name returns the provider name (e.g., "kind", "k3s")
Name() string
// CreateCluster creates a new cluster
CreateCluster(ctx context.Context, config ClusterConfig) error
// DeleteCluster deletes the cluster
DeleteCluster(ctx context.Context, name string) error
// ClusterExists checks if cluster exists
ClusterExists(ctx context.Context, name string) (bool, error)
}Example Usage:
// Create infrastructure manager with kind provider
infraMgr := infrastructure.NewManager(
infrastructure.WithProvider(kind.NewProvider()),
infrastructure.WithClusterName("my-idp"),
)
// Provision infrastructure with ArgoCD and IDP Builder controllers
result, err := infraMgr.Provision(ctx, infrastructure.Config{
KubernetesVersion: "1.28.0",
InstallArgoCD: true, // Install ArgoCD (required for flavor dependencies)
InstallIDPBuilderControllers: true, // Install core idpbuilder-controllers
IDPBuilderControllersVersion: "v0.5.0", // Includes Flavor, Platform, provider CRDs+controllers
Networking: infrastructure.NetworkConfig{
ServiceCIDR: "10.96.0.0/16",
PodCIDR: "10.244.0.0/16",
},
})
// ArgoCD and IDP Builder core controllers are now installed and ready
// Flavor CRD exists, so flavors can now be processed
// Provider CRDs exist, so flavor components can create provider CRs
// Ready to install flavors with additional dependencies2. Flavor Manager
Purpose: Manages idpbuilder "flavors" - pre-defined platform configurations.
Responsibilities:
- Load flavor definitions from files or embedded resources
- Create ArgoCD Applications for flavor dependencies (Helm charts, Kustomize packages)
- Wait for dependency Applications to become Healthy before proceeding
- Generate and install provider Custom Resources as ArgoCD Applications
- Support flavor composition (extending base flavors)
- Handle flavor-specific configuration overrides
- Coordinate installation sequence using ArgoCD sync waves
Flavor Definition Format:
# flavors/basic-dev.yaml
apiVersion: idpbuilder.cnoe.io/v1alpha1
kind: Flavor
metadata:
name: basic-dev
description: Basic development environment with Gitea, Nginx, and ArgoCD
spec:
# Dependencies to install via ArgoCD before components
# Note: Core idpbuilder-controllers already installed by Infrastructure Manager
# These are additional controllers needed by this flavor
dependencies:
- name: nginx-ingress
type: helm
source:
repoURL: https://kubernetes.github.io/ingress-nginx
chart: ingress-nginx
targetRevision: "4.8.0"
syncWave: 1 # Install first
condition: gateway.enabled # Optional dependency
# Components to install (creates CRs after dependencies are ready)
# CRDs for these (GiteaProvider, NginxGateway, ArgoCDProvider) already exist from core controllers
components:
gitProvider:
kind: GiteaProvider
version: "1.21.0"
config:
adminAutoGenerate: true
syncWave: 2 # Install after dependencies
gateway:
kind: NginxGateway
version: "1.13.0"
config:
ingressClass: nginx
syncWave: 2
gitOpsProvider:
kind: ArgoCDProvider
version: "v2.12.0"
config:
adminAutoGenerate: true
ssoEnabled: false
syncWave: 2
# Platform configuration
# Platform CRD already exists from core controllers
platform:
domain: "cnoe.localtest.me"
tls:
enabled: true
selfSigned: true
syncWave: 3 # Install after components
# Custom packages to include
customPackages:
- name: backstage
type: kustomize
source:
repoURL: https://github.com/cnoe-io/backstage-app
path: deploy/kubernetes
targetRevision: main
syncWave: 4
- name: crossplane
type: helm
source:
repoURL: https://charts.crossplane.io/stable
chart: crossplane
targetRevision: "1.14.0"
syncWave: 4Interfaces:
type FlavorManager interface {
// ListFlavors returns all available flavors
ListFlavors() ([]FlavorInfo, error)
// GetFlavor loads a specific flavor definition
GetFlavor(name string) (*Flavor, error)
// InstallDependencies creates ArgoCD Applications for flavor dependencies
InstallDependencies(ctx context.Context, flavor *Flavor, namespace string) error
// WaitForDependencies waits until all dependency Applications are healthy
WaitForDependencies(ctx context.Context, flavor *Flavor, timeout time.Duration) error
// InstallComponents creates provider CRs after dependencies are ready
InstallComponents(ctx context.Context, flavor *Flavor) error
// GenerateResources generates CRs for the given flavor (for non-ArgoCD usage)
GenerateResources(flavor *Flavor, overrides map[string]interface{}) ([]client.Object, error)
}
type FlavorRegistry interface {
// RegisterFlavor adds a flavor to the registry
RegisterFlavor(flavor *Flavor) error
// GetFlavor retrieves a flavor by name
GetFlavor(name string) (*Flavor, error)
// ListFlavors returns all registered flavors
ListFlavors() ([]FlavorInfo, error)
}Built-in Flavors:
Built-in flavors are included with IDP Builder and do not depend on external cloud providers or third-party proprietary software:
minimal: Absolute minimum for testing- Gitea only (Git provider)
- No gateway
- No GitOps provider
basic-dev: Standard local development setup- Gitea (Git provider)
- Nginx Ingress (Gateway)
- ArgoCD (GitOps)
Example Flavors:
Additional flavors are provided as examples and can be customized for specific environments. These may depend on cloud providers or third-party services:
full-dev: Extended development environment with Backstage, Crossplane, and Vaultproduction-aws: AWS EKS optimized with GitHub, ALB, and production-grade configurationsproduction-azure: Azure AKS optimized with Azure DevOps and Application Gatewayproduction-gcp: GCP GKE optimized with Cloud Source Repos and GKE Gateway
See Appendix B: Example Flavors for complete definitions.
Example Usage:
// 1. Provision infrastructure with ArgoCD and IDP Builder controllers
infraMgr := infrastructure.NewManager(
infrastructure.WithProvider(kind.NewProvider()),
infrastructure.WithClusterName("my-idp"),
)
result, err := infraMgr.Provision(ctx, infrastructure.Config{
KubernetesVersion: "1.28.0",
InstallArgoCD: true, // Required for dependency management
InstallControllers: true, // Install IDP Builder controllers
})
// 2. Get kubeconfig from infrastructure manager
kubeConfig, err := infraMgr.GetKubeConfig()
kubeClient, err := client.New(kubeConfig, client.Options{})
// 3. Load a flavor
flavorMgr := flavor.NewManager(
flavor.WithBuiltInFlavors(),
flavor.WithCustomFlavorPath("./my-flavors"),
)
flavor, err := flavorMgr.GetFlavor("basic-dev")
// 4. Install flavor dependencies via ArgoCD
err = flavorMgr.InstallDependencies(ctx, flavor, "argocd")
if err != nil {
return fmt.Errorf("failed to install dependencies: %w", err)
}
// 5. Wait for dependencies to become healthy
err = flavorMgr.WaitForDependencies(ctx, flavor, 10*time.Minute)
if err != nil {
return fmt.Errorf("dependencies not ready: %w", err)
}
// 6. Install components (provider CRs) after dependencies are ready
err = flavorMgr.InstallComponents(ctx, flavor)
if err != nil {
return fmt.Errorf("failed to install components: %w", err)
}
// ArgoCD now manages the entire flavor installation
// Check Application status for deployment progressFlavor Packaging, Distribution, and Consumption
Flavors leverage standard Kubernetes packaging systems rather than creating custom mechanisms. This section describes how flavors are packaged, distributed, and consumed.
Packaging Formats
Option 1: Helm Charts (Recommended)
Flavors are packaged as Helm charts with pre-configured values files:
idpbuilder-flavor-basic-dev/
├── Chart.yaml # Helm chart metadata with dependencies
├── values.yaml # Default values
├── values-examples/ # Example configurations
│ ├── dev.yaml
│ └── staging.yaml
└── templates/
├── platform.yaml # Platform CR template
├── gitea.yaml # GiteaProvider CR template
├── nginx.yaml # NginxGateway CR template
└── argocd.yaml # ArgoCDProvider CR template
Chart.yaml with controller dependencies:
apiVersion: v2
name: idpbuilder-basic-dev
description: Basic development environment flavor for IDP Builder
version: 1.0.0
appVersion: "1.0"
dependencies:
# Note: Core idpbuilder-controllers already installed by Infrastructure Manager
# Only declare additional controllers needed by this flavor
# Optional: Pre-install provider-specific controllers if needed
- name: gitea-operator
version: "1.21.0"
repository: "https://dl.gitea.io/charts"
condition: gitProvider.operator.installOption 2: Kustomize Overlays
Flavors as Kustomize directory structures:
flavors/
├── base/
│ ├── kustomization.yaml
│ ├── platform.yaml
│ └── namespace.yaml
├── basic-dev/
│ ├── kustomization.yaml # References base + patches
│ ├── gitea-provider.yaml
│ ├── nginx-gateway.yaml
│ ├── argocd-provider.yaml
│ └── patches/
│ └── platform-domain.yaml
└── production-aws/
├── kustomization.yaml
├── github-provider.yaml
└── patches/
├── platform-tls.yaml
└── argocd-ha.yaml
kustomization.yaml example:
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: idpbuilder-system
# Note: Core idpbuilder-controllers already installed by Infrastructure Manager
# Only include additional resources needed by this flavor
resources:
- ../../base
- gitea-provider.yaml
- nginx-gateway.yaml
- argocd-provider.yaml
patches:
- path: patches/platform-domain.yaml
target:
kind: PlatformOption 3: OCI Artifacts
Package flavors as OCI artifacts for container registry distribution:
# Package flavor as OCI artifact
helm package flavors/basic-dev
helm push idpbuilder-basic-dev-1.0.0.tgz oci://ghcr.io/cnoe-io/flavors
# Consume from OCI registry
helm install my-idp oci://ghcr.io/cnoe-io/flavors/idpbuilder-basic-dev --version 1.0.0Distribution Channels
1. Official Flavor Repository
Central catalog of example flavors and community contributions:
https://github.com/cnoe-io/idpbuilder-flavors/
├── minimal/ # Built-in (also embedded in CLI)
├── basic-dev/ # Built-in (also embedded in CLI)
├── full-dev/ # Example flavor
├── production-aws/ # Example flavor
├── production-azure/ # Example flavor
├── production-gcp/ # Example flavor
└── index.yaml # Helm repository index
Note: Built-in flavors (minimal, basic-dev) are embedded in the IDP Builder CLI and don't require external repositories for basic usage.
2. Helm Chart Repository
# Add repository
helm repo add idpbuilder https://cnoe-io.github.io/idpbuilder-flavors
helm repo update
# Search available flavors
helm search repo idpbuilder
# Install flavor
helm install my-idp idpbuilder/basic-dev3. OCI Registry
# List available flavors
helm search repo oci://ghcr.io/cnoe-io/flavors
# Pull flavor locally
helm pull oci://ghcr.io/cnoe-io/flavors/idpbuilder-basic-dev --version 1.0.0
# Install from OCI
helm install my-idp oci://ghcr.io/cnoe-io/flavors/idpbuilder-basic-dev4. Git Repositories
# Kustomize from Git
kubectl apply -k https://github.com/cnoe-io/idpbuilder-flavors//basic-dev
# ArgoCD Application
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: idpbuilder
spec:
source:
repoURL: https://github.com/cnoe-io/idpbuilder-flavors
path: basic-dev
targetRevision: mainController Dependencies
Flavors declare controller dependencies that must be installed before provider CRs can be reconciled.
Important Note: Core idpbuilder-controllers are installed by the Infrastructure Manager during cluster provisioning. Flavors only declare additional controller dependencies beyond the core controllers.
Dependency Declaration in Helm
# Chart.yaml
dependencies:
# Note: Core idpbuilder-controllers already installed by Infrastructure Manager
# Only declare additional provider-specific controllers
- name: nginx-ingress-controller
version: "4.8.0"
repository: "https://kubernetes.github.io/ingress-nginx"
condition: gateway.kind=NginxGateway
- name: external-secrets
version: "0.9.0"
repository: "https://charts.external-secrets.io"
condition: secrets.provider=ExternalSecretsInstallation Sequence with Helm Hooks
# templates/00-namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: idpbuilder-system
annotations:
"helm.sh/hook": pre-install
"helm.sh/hook-weight": "-10"
---
# Note: Core idpbuilder-controllers already installed by Infrastructure Manager
# Additional controller installation hooks can be added here if neededInstallation Sequence with Kustomize
# kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# Note: Core idpbuilder-controllers already installed by Infrastructure Manager
# Only include additional resources
resources:
# Provider CRs (CRDs already exist from core controllers)
- providers/gitea-provider.yaml
- providers/nginx-gateway.yaml
- providers/argocd-provider.yaml
# Platform CR (CRD already exists from core controllers)
- platform/platform.yaml
# ArgoCD sync waves for ordering
patches:
- target:
kind: CustomResourceDefinition
patch: |-
- op: add
path: /metadata/annotations/argocd.argoproj.io~1sync-wave
value: "1"
- target:
kind: Deployment
namespace: idpbuilder-system
patch: |-
- op: add
path: /metadata/annotations/argocd.argoproj.io~1sync-wave
value: "2"
- target:
group: idpbuilder.cnoe.io
kind: GiteaProvider
patch: |-
- op: add
path: /metadata/annotations/argocd.argoproj.io~1sync-wave
value: "3"Consumption Patterns
1. CLI-Driven (Development)
# Using Helm
idpbuilder create --flavor helm://idpbuilder/basic-dev --set domain=dev.local
# Using Kustomize
idpbuilder create --flavor kustomize://github.com/cnoe-io/idpbuilder-flavors//basic-dev
# Using OCI
idpbuilder create --flavor oci://ghcr.io/cnoe-io/flavors/basic-dev:1.0.0Internally, CLI:
- Fetches flavor package
- Resolves and installs controller dependencies
- Applies provider and platform CRs
- Monitors installation progress
2. GitOps-Driven (Production)
ArgoCD Application:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: idpbuilder-platform
namespace: argocd
spec:
project: default
source:
# Helm chart flavor
chart: idpbuilder-basic-dev
repoURL: https://cnoe-io.github.io/idpbuilder-flavors
targetRevision: 1.0.0
helm:
values: |
domain: production.company.com
platform:
tls:
enabled: true
certManager: true
destination:
server: https://kubernetes.default.svc
namespace: idpbuilder-system
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3mFlux Kustomization:
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: idpbuilder-platform
namespace: flux-system
spec:
interval: 10m
path: ./flavors/basic-dev
prune: true
sourceRef:
kind: GitRepository
name: idpbuilder-flavors
healthChecks:
- apiVersion: idpbuilder.cnoe.io/v1alpha1
kind: Platform
name: my-platform
namespace: idpbuilder-system3. Direct Kubernetes Apply
# Helm
helm install my-idp idpbuilder/basic-dev \
--namespace idpbuilder-system \
--create-namespace \
--set domain=my-company.dev \
--wait --timeout 10m
# Kustomize
kubectl apply -k https://github.com/cnoe-io/idpbuilder-flavors//basic-dev
# OCI
helm install my-idp oci://ghcr.io/cnoe-io/flavors/idpbuilder-basic-dev \
--version 1.0.0 \
--namespace idpbuilder-system \
--create-namespaceFlavor Versioning and Compatibility
Semantic Versioning
# Chart.yaml
version: 1.2.3 # Flavor version
appVersion: "0.5.0" # IDP Builder version compatibility
# Version constraints
dependencies:
- name: idpbuilder-controllers
version: "^0.5.0" # Compatible with 0.5.xCompatibility Matrix
# flavor-metadata.yaml
apiVersion: idpbuilder.cnoe.io/v1alpha1
kind: FlavorMetadata
metadata:
name: basic-dev
spec:
version: 1.2.3
compatibility:
idpbuilderVersion: ">=0.5.0,<0.7.0"
kubernetesVersion: ">=1.26.0"
# Note: Core idpbuilder-controllers are platform requirement, not flavor dependency
# Only list additional controllers specific to this flavor
dependencies:
controllers:
- name: nginx-ingress-controller
version: "4.8.0"
required: false
condition: gateway.kind=NginxGatewayCustom Flavor Creation
Users can create custom flavors by:
1. Fork and Customize
# Clone flavor repository
git clone https://github.com/cnoe-io/idpbuilder-flavors
cd idpbuilder-flavors
# Copy and customize
cp -r basic-dev my-custom-flavor
cd my-custom-flavor
# Edit Chart.yaml, values.yaml, templates
vi values.yaml
# Package and distribute
helm package .
helm push my-custom-flavor-1.0.0.tgz oci://myregistry.io/flavors2. Compose from Existing
# Chart.yaml - extend basic-dev
apiVersion: v2
name: my-company-dev
version: 1.0.0
dependencies:
- name: idpbuilder-basic-dev
version: "1.0.0"
repository: "https://cnoe-io.github.io/idpbuilder-flavors"
# Add company-specific components
- name: company-monitoring
version: "2.1.0"
repository: "https://charts.company.com"3. Create from Scratch
# Initialize new Helm chart
helm create my-flavor
# Add IDP Builder templates
cat > templates/platform.yaml <<EOF
apiVersion: idpbuilder.cnoe.io/v1alpha1
kind: Platform
metadata:
name: {{ .Release.Name }}
spec:
domain: {{ .Values.domain }}
# ... rest of configuration
EOF
# Define dependencies in Chart.yaml
# Package and distributeFlavor Discovery and Registry
Helm Repository Index
# index.yaml
apiVersion: v1
entries:
idpbuilder-minimal:
- name: idpbuilder-minimal
version: 1.0.0
description: Minimal setup with just Git provider (built-in)
urls:
- https://cnoe-io.github.io/idpbuilder-flavors/minimal-1.0.0.tgz
annotations:
type: built-in
idpbuilder-basic-dev:
- name: idpbuilder-basic-dev
version: 1.0.0
description: Standard local development setup (built-in)
urls:
- https://cnoe-io.github.io/idpbuilder-flavors/basic-dev-1.0.0.tgz
annotations:
type: built-in
idpbuilder-full-dev:
- name: idpbuilder-full-dev
version: 1.0.0
description: Extended development environment (example)
urls:
- https://cnoe-io.github.io/idpbuilder-flavors/full-dev-1.0.0.tgz
annotations:
type: example
idpbuilder-production-aws:
- name: idpbuilder-production-aws
version: 1.0.0
description: Production-ready on AWS EKS (example)
urls:
- https://cnoe-io.github.io/idpbuilder-flavors/production-aws-1.0.0.tgz
annotations:
type: example
cloud: awsFlavor Catalog API
# List available flavors
idpbuilder flavor list
# Search flavors
idpbuilder flavor search --keyword production --cloud aws
# Show flavor details
idpbuilder flavor show basic-dev
# Update flavor catalog
idpbuilder flavor update3. Status Watcher
Purpose: Monitors Platform and Provider resources and displays status to users.
Responsibilities:
- Watch Platform CR for status changes
- Monitor Provider CRs (Git, Gateway, GitOps)
- Display real-time progress in terminal
- Show detailed error messages and troubleshooting hints
- Support different output formats (human-readable, JSON, etc.)
Interfaces:
type StatusWatcher interface {
// Watch monitors the platform and reports status
Watch(ctx context.Context, platformName string) error
// WaitForReady blocks until platform is ready or timeout
WaitForReady(ctx context.Context, platformName string, timeout time.Duration) error
// GetStatus returns current platform status
GetStatus(ctx context.Context, platformName string) (*PlatformStatus, error)
}
type UIRenderer interface {
// RenderProgress displays progress information
RenderProgress(status *PlatformStatus)
// RenderError displays error information
RenderError(err error)
// RenderCompletion displays completion message
RenderCompletion(status *PlatformStatus)
}Display Modes:
Interactive Mode (default for TTY):
┌─ IDP Platform: my-idp ─────────────────────────────────┐ │ Status: Initializing │ │ Domain: cnoe.localtest.me │ │ │ │ Components: │ │ ✓ Gitea Ready (2m34s) │ │ ✓ Nginx Gateway Ready (1m12s) │ │ ⟳ ArgoCD Installing... 45% │ │ │ │ Recent Events: │ │ • ArgoCD deployment scaling up (replicas: 1/2) │ │ • ArgoCD API server initializing │ └─────────────────────────────────────────────────────────┘Simple Mode (non-TTY):
[INFO] Platform: my-idp [INFO] Status: Initializing [OK] Gitea: Ready (2m34s) [OK] Nginx Gateway: Ready (1m12s) [PROGRESS] ArgoCD: Installing (45%)JSON Mode:
{ "platform": "my-idp", "status": "Initializing", "components": [ {"name": "gitea", "kind": "GiteaProvider", "ready": true, "elapsed": "2m34s"}, {"name": "nginx", "kind": "NginxGateway", "ready": true, "elapsed": "1m12s"}, {"name": "argocd", "kind": "ArgoCDProvider", "ready": false, "progress": 45} ] }
Example Usage:
// Get kubeconfig from infrastructure manager
kubeConfig, err := infraMgr.GetKubeConfig()
kubeClient, err := client.New(kubeConfig, client.Options{})
// Create status watcher with kubeClient from infrastructure
watcher := status.NewWatcher(kubeClient,
status.WithRenderer(status.NewInteractiveRenderer()),
status.WithUpdateInterval(5 * time.Second),
)
// Watch platform status
err := watcher.Watch(ctx, "my-idp-platform")
// Or wait for ready with timeout
err := watcher.WaitForReady(ctx, "my-idp-platform", 10*time.Minute)Client Command Structure
New CLI Command Hierarchy
idpbuilder
├── create Create a new IDP instance
│ ├── --flavor Flavor to use (default: basic-dev)
│ ├── --name Name of the IDP instance
│ ├── --infra Infrastructure provider (kind, k3s, external)
│ ├── --kubeconfig Path to kubeconfig (for external)
│ └── --set Override flavor values (key=value)
│
├── delete Delete an IDP instance
│ ├── --name Name of the IDP instance
│ └── --keep-infra Keep infrastructure (don't delete cluster)
│
├── get Get information about IDP instances
│ ├── platforms List all platforms
│ ├── providers List all providers
│ ├── flavors List available flavors
│ └── status Get detailed status of a platform
│ └── --name Platform name
│
├── apply Apply a flavor to existing infrastructure
│ ├── --flavor Flavor to apply
│ ├── --kubeconfig Path to kubeconfig
│ └── --set Override flavor values
│
├── watch Watch platform status (real-time monitoring)
│ ├── --name Platform name
│ └── --output Output format (interactive, simple, json)
│
└── version Display version information
Command Examples
Create with default flavor:
idpbuilder create --name my-idp
# Uses: flavor=basic-dev, infra=kindCreate with specific flavor and overrides:
idpbuilder create \
--name my-idp \
--flavor full-dev \
--set platform.domain=my-company.dev \
--set gitProvider.config.adminPassword=secret123Create on existing cluster:
idpbuilder create \
--name my-idp \
--flavor production-aws \
--infra external \
--kubeconfig ~/.kube/my-eks-clusterWatch platform status:
idpbuilder watch --name my-idp
# Or during creation:
idpbuilder create --name my-idp --watchList available flavors:
idpbuilder get flavors
# Output:
# NAME DESCRIPTION COMPONENTS
# NAME DESCRIPTION COMPONENTS TYPE
# minimal Minimal setup for testing gitea built-in
# basic-dev Standard local development setup gitea, nginx, argocd built-in
# full-dev Extended development environment gitea, nginx, argocd, +3 example
# production-aws Production-ready on AWS EKS github, alb, argocd example
# production-azure Production-ready on Azure AKS azurerepos, appgw, flux example
# production-gcp Production-ready on GCP GKE cloudrepos, gke-gw, argocd exampleGet platform status:
idpbuilder get status --name my-idp
# Output:
# Platform: my-idp
# Status: Ready
# Domain: cnoe.localtest.me
#
# Components:
# Gitea (GiteaProvider) Ready https://gitea.cnoe.localtest.me
# Nginx (NginxGateway) Ready
# ArgoCD (ArgoCDProvider) Ready https://argocd.cnoe.localtest.meDelete platform:
# Delete platform and infrastructure
idpbuilder delete --name my-idp
# Delete platform but keep cluster
idpbuilder delete --name my-idp --keep-infraImplementation Plan
Phase 1: Infrastructure Manager (Week 1-2)
Objectives:
- Extract infrastructure provisioning logic from current
pkg/build - Create pluggable provider interface
- Implement kind provider (refactor existing code)
- Add support for external cluster provider
Deliverables:
-
pkg/client/infrastructurepackage -
InfrastructureManagerinterface and implementation -
InfraProviderinterface -
KindProviderimplementation -
ExternalProviderimplementation - Unit tests for infrastructure components
- Integration tests for cluster creation
Success Criteria:
- Can create/delete kind clusters programmatically
- Can connect to external clusters with kubeconfig
- Infrastructure manager is independently testable
- Maintains feature parity with current implementation
Phase 2: Flavor Manager (Week 3-4)
Objectives:
- Design flavor definition format
- Implement flavor registry and loader
- Create built-in flavor definitions
- Implement CR generation from flavors
Deliverables:
-
pkg/client/flavorpackage - Flavor CRD and types
-
FlavorManagerimplementation - Built-in flavors (minimal, basic-dev)
- Example flavors (full-dev, production-aws, production-azure, production-gcp)
- CR generator with override support
- Flavor validation logic
- Unit tests for flavor processing
- Documentation for creating custom flavors
Success Criteria:
- Can load and validate flavor definitions
- Can generate correct CRs from flavors
- Can apply overrides to flavor values
- Built-in flavors work correctly
Phase 3: Status Watcher (Week 5)
Objectives:
- Implement Platform/Provider status monitoring
- Create UI renderers for different output modes
- Integrate with existing status reporter
Deliverables:
-
pkg/client/statuspackage (refactor existing) -
StatusWatcherimplementation - Interactive renderer with progress tracking
- Simple renderer for non-TTY
- JSON renderer for scripting
- Real-time status updates via watches
- Error reporting with troubleshooting hints
Success Criteria:
- Displays real-time platform status
- Shows progress for all components
- Handles long-running operations gracefully
- Provides clear error messages
Phase 4: CLI Integration (Week 6)
Objectives:
- Refactor CLI commands to use new client components
- Implement new command structure
- Maintain backward compatibility where possible
Deliverables:
- Refactored
pkg/cmd/createusing new client - New
pkg/cmd/applycommand - Enhanced
pkg/cmd/getcommand - New
pkg/cmd/watchcommand - Updated help text and examples
- Migration guide for users
Success Criteria:
- All CLI commands work with new architecture
- User experience is improved or maintained
- Breaking changes are documented
- Migration path is clear
Phase 5: Testing and Documentation (Week 7-8)
Objectives:
- Comprehensive testing of all components
- Complete documentation
- Performance optimization
Deliverables:
- E2E tests for complete workflows
- Performance benchmarks
- User documentation
- Developer documentation
- Migration guide
- Tutorial for creating custom flavors
Success Criteria:
80% test coverage for new components
- All E2E scenarios pass
- Documentation is complete and clear
- Performance meets or exceeds current implementation
Phase 6: Deprecation and Cleanup (Week 9-10)
Objectives:
- Deprecate old localbuilder implementation
- Remove deprecated code after migration period
- Final polish and optimization
Deliverables:
- Deprecation notices in old code
- Removal of
pkg/build(after migration) - Removal of localbuilder controller dependencies in CLI
- Performance optimizations
- Final documentation updates
Success Criteria:
- Old implementation is fully deprecated
- No breaking changes for users who migrate
- Clean, maintainable codebase
Migration Strategy
For Users
Current workflow:
idpbuilder create --name my-idpNew workflow (same command, new implementation):
idpbuilder create --name my-idp
# Now uses flavor=basic-dev by defaultAdvanced usage (new capabilities):
idpbuilder create --name my-idp --flavor full-devFor Developers
Before: Tightly coupled CLI and build logic
// pkg/cmd/create/create.go
build := build.NewBuild(cfg)
build.Run(ctx)After: Modular client components
// pkg/cmd/create/create.go
infraMgr := infrastructure.NewManager(...)
flavorMgr := flavor.NewManager(...)
statusWatcher := status.NewWatcher(...)
// Provision infrastructure
result, err := infraMgr.Provision(ctx, infraConfig)
// Apply flavor
resources, err := flavorMgr.GenerateResources(selectedFlavor, overrides)
for _, res := range resources {
kubeClient.Create(ctx, res)
}
// Watch status
statusWatcher.WaitForReady(ctx, platformName, timeout)Backward Compatibility
- Phase 1-5: Both old and new implementations coexist
- Phase 6: Add deprecation warnings to old implementation
- Future release: Remove old implementation after migration period
Security Considerations
Credentials Management:
- Never log sensitive configuration values
- Use Kubernetes secrets for credentials
- Support external secret management (Vault, etc.)
Network Security:
- TLS by default for all exposed services
- Support for custom CA certificates
- Network policies for inter-component communication
RBAC:
- Minimal permissions for client operations
- Support for assuming different roles
- Audit logging of client actions
Performance Considerations
Concurrent Operations:
- Parallel CR creation where possible
- Efficient watch/poll mechanisms
- Resource pooling for API clients
Resource Usage:
- Minimal memory footprint
- Efficient handling of large flavor definitions
- Streaming output for long-running operations
Testing Strategy
Unit Tests
- All public interfaces have unit tests
- Mock infrastructure providers for testing
- Flavor validation and CR generation logic
- Status parsing and rendering logic
Integration Tests
- Real cluster creation/deletion (kind)
- CR generation and application
- Status watching with real Platform CRs
- Complete workflows end-to-end
E2E Tests
- Full
create→watch→deleteworkflow - Multiple flavors
- Override handling
- Error scenarios and recovery
Documentation Requirements
User Documentation
- Getting Started Guide: Using the new CLI
- Flavor Guide: Understanding and selecting flavors
- Custom Flavor Tutorial: Creating custom flavors
- Advanced Configuration: Overrides and customization
- Troubleshooting Guide: Common issues and solutions
Developer Documentation
- Architecture Overview: High-level design
- Component API Reference: Detailed interface documentation
- Provider Development Guide: Creating new infrastructure providers
- Flavor Development Guide: Creating new flavors
- Contributing Guide: How to contribute to the client
Success Metrics
User Experience:
- Time to first successful deployment < 5 minutes
- Clear error messages with actionable guidance
90% user satisfaction in surveys
Code Quality:
80% test coverage
- Zero critical security vulnerabilities
- <100ms command startup time
Functionality:
- Support for 5+ built-in flavors
- Easy custom flavor creation
- Real-time status updates
Related Documentation
- Controller Architecture Spec - Controller design
- Resource Creation Sequencing - Resource tracking
- Implementation Roadmap - Current implementation status and remaining work
Appendix A: Flavor Schema
apiVersion: idpbuilder.cnoe.io/v1alpha1
kind: Flavor
metadata:
name: string # Unique flavor name
description: string # Human-readable description
labels:
environment: string # e.g., "development", "production"
complexity: string # e.g., "minimal", "basic", "full"
spec:
# Base flavor to extend (optional)
extends: string
# Component definitions
components:
gitProvider:
kind: string # e.g., GiteaProvider, GitHubProvider
version: string
config: {} # Provider-specific configuration
gateway:
kind: string # e.g., NginxGateway, IstioGateway
version: string
config: {}
gitOpsProvider:
kind: string # e.g., ArgoCDProvider, FluxProvider
version: string
config: {}
# Additional providers (optional)
additionalProviders:
- kind: string
version: string
config: {}
# Platform configuration
platform:
domain: string
namespace: string
tls:
enabled: bool
selfSigned: bool
certManager: bool
# Custom packages
customPackages:
- name: string
source: string # URL or path
priority: int # Installation order
config: {} # Package-specific config
# Infrastructure hints (for validation)
infrastructure:
minimumNodes: int
minimumMemory: string # e.g., "4Gi"
minimumCPU: string # e.g., "2"Appendix B: Example Flavors
This appendix provides complete flavor definitions. The first two (minimal and basic-dev) are built-in flavors, while the others are examples that may require additional dependencies or cloud provider services.
Minimal Flavor (Built-in)
apiVersion: idpbuilder.cnoe.io/v1alpha1
kind: Flavor
metadata:
name: minimal
description: Minimal setup with just Git provider
labels:
environment: development
complexity: minimal
type: built-in
spec:
components:
gitProvider:
kind: GiteaProvider
version: "1.21.0"
config:
adminAutoGenerate: true
platform:
domain: "cnoe.localtest.me"
tls:
enabled: falseBasic Development Flavor (Built-in)
apiVersion: idpbuilder.cnoe.io/v1alpha1
kind: Flavor
metadata:
name: basic-dev
description: Standard local development setup
labels:
environment: development
complexity: basic
type: built-in
spec:
# Note: Core idpbuilder-controllers already installed by Infrastructure Manager
# Only additional dependencies needed for this flavor
dependencies:
- name: nginx-ingress
type: helm
source:
repoURL: https://kubernetes.github.io/ingress-nginx
chart: ingress-nginx
targetRevision: "4.8.0"
syncWave: 1
# CRDs for these components already exist from core controllers
components:
gitProvider:
kind: GiteaProvider
version: "1.21.0"
config:
adminAutoGenerate: true
syncWave: 2
gateway:
kind: NginxGateway
version: "1.13.0"
config:
ingressClass: nginx
syncWave: 2
gitOpsProvider:
kind: ArgoCDProvider
version: "v2.12.0"
config:
adminAutoGenerate: true
ssoEnabled: false
syncWave: 2
platform:
domain: "cnoe.localtest.me"
tls:
enabled: true
selfSigned: true
syncWave: 3Full Development Flavor (Example)
This flavor extends basic-dev with additional development tools. May require additional dependencies.
apiVersion: idpbuilder.cnoe.io/v1alpha1
kind: Flavor
metadata:
name: full-dev
description: Extended development environment with additional tools
labels:
environment: development
complexity: full
type: example
spec:
extends: basic-dev
# Additional dependencies for extended tools
dependencies:
- name: crossplane
type: helm
source:
repoURL: https://charts.crossplane.io/stable
chart: crossplane
targetRevision: "1.14.0"
syncWave: 2
customPackages:
- name: backstage
type: kustomize
source:
repoURL: https://github.com/cnoe-io/backstage-app
path: deploy/kubernetes
targetRevision: main
syncWave: 5
- name: crossplane-configs
type: kustomize
source:
repoURL: https://github.com/cnoe-io/crossplane-configs
path: configs
targetRevision: main
syncWave: 6
- name: vault
type: helm
source:
repoURL: https://helm.releases.hashicorp.com
chart: vault
targetRevision: "0.27.0"
syncWave: 5
values:
server:
dev:
enabled: true- name: vault
source: https://github.com/cnoe-io/vault-config
priority: 150
config:
mode: dev
unsealed: true
### Production AWS Flavor (Example)
This flavor demonstrates AWS-specific integrations and requires AWS EKS and related services.
```yaml
apiVersion: idpbuilder.cnoe.io/v1alpha1
kind: Flavor
metadata:
name: production-aws
description: Production-ready on AWS EKS
labels:
environment: production
cloud: aws
type: example
spec:
components:
gitProvider:
kind: GitHubProvider
version: "latest"
config:
appAuth: true
gateway:
kind: ALBIngressController
version: "v2.6.0"
config:
aws:
region: us-west-2
gitOpsProvider:
kind: ArgoCDProvider
version: "v2.12.0"
config:
sso:
enabled: true
provider: okta
ha:
enabled: true
platform:
domain: "idp.example.com"
tls:
enabled: true
certManager: true
issuer: letsencrypt-prod
customPackages:
- name: external-secrets
source: https://github.com/cnoe-io/external-secrets-aws
config:
provider: aws
infrastructure:
minimumNodes: 3
minimumMemory: "16Gi"
minimumCPU: "4"