Files
Reloader/test/e2e/utils/workload_adapter.go
2026-01-08 11:06:45 +01:00

161 lines
5.2 KiB
Go

package utils
import (
"context"
"time"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
)
// WorkloadType represents the type of Kubernetes workload.
type WorkloadType string
const (
WorkloadDeployment WorkloadType = "Deployment"
WorkloadDaemonSet WorkloadType = "DaemonSet"
WorkloadStatefulSet WorkloadType = "StatefulSet"
WorkloadCronJob WorkloadType = "CronJob"
WorkloadJob WorkloadType = "Job"
WorkloadArgoRollout WorkloadType = "ArgoRollout"
WorkloadDeploymentConfig WorkloadType = "DeploymentConfig"
)
// ReloadStrategy represents the reload strategy used by Reloader.
type ReloadStrategy string
const (
StrategyAnnotations ReloadStrategy = "annotations"
StrategyEnvVars ReloadStrategy = "envvars"
)
// WorkloadConfig holds configuration for workload creation.
type WorkloadConfig struct {
// Resource references
ConfigMapName string
SecretName string
// Annotations to set on the workload
Annotations map[string]string
// Reference methods (flags - multiple can be true)
UseConfigMapEnvFrom bool
UseSecretEnvFrom bool
UseConfigMapVolume bool
UseSecretVolume bool
UseProjectedVolume bool
UseConfigMapKeyRef bool
UseSecretKeyRef bool
UseInitContainer bool
UseInitContainerVolume bool
// For valueFrom references
ConfigMapKey string
SecretKey string
EnvVarName string
// Special options
MultipleContainers int // Number of containers (0 or 1 means single container)
}
// WorkloadAdapter provides a unified interface for all workload types.
// This allows tests to be parameterized across different workload types.
type WorkloadAdapter interface {
// Type returns the workload type.
Type() WorkloadType
// Create creates the workload with the given config.
Create(ctx context.Context, namespace, name string, cfg WorkloadConfig) error
// Delete removes the workload.
Delete(ctx context.Context, namespace, name string) error
// WaitReady waits for the workload to be ready.
WaitReady(ctx context.Context, namespace, name string, timeout time.Duration) error
// WaitReloaded waits for the workload to have the reload annotation.
// Returns true if the annotation was found, false if timeout occurred.
WaitReloaded(ctx context.Context, namespace, name, annotationKey string, timeout time.Duration) (bool, error)
// WaitEnvVar waits for the workload to have a STAKATER_ env var (for envvars strategy).
// Returns true if the env var was found, false if timeout occurred.
WaitEnvVar(ctx context.Context, namespace, name, prefix string, timeout time.Duration) (bool, error)
// SupportsEnvVarStrategy returns true if the workload supports env var reload strategy.
// CronJob does not support this as it uses job creation instead.
SupportsEnvVarStrategy() bool
// RequiresSpecialHandling returns true for workloads that need special handling.
// For example, CronJob triggers a new job instead of rolling restart.
RequiresSpecialHandling() bool
}
// AdapterRegistry holds adapters for all workload types.
type AdapterRegistry struct {
kubeClient kubernetes.Interface
dynamicClient dynamic.Interface
adapters map[WorkloadType]WorkloadAdapter
}
// NewAdapterRegistry creates a new adapter registry with all standard adapters.
func NewAdapterRegistry(kubeClient kubernetes.Interface, dynamicClient dynamic.Interface) *AdapterRegistry {
r := &AdapterRegistry{
kubeClient: kubeClient,
dynamicClient: dynamicClient,
adapters: make(map[WorkloadType]WorkloadAdapter),
}
// Register standard adapters
r.adapters[WorkloadDeployment] = NewDeploymentAdapter(kubeClient)
r.adapters[WorkloadDaemonSet] = NewDaemonSetAdapter(kubeClient)
r.adapters[WorkloadStatefulSet] = NewStatefulSetAdapter(kubeClient)
r.adapters[WorkloadCronJob] = NewCronJobAdapter(kubeClient)
r.adapters[WorkloadJob] = NewJobAdapter(kubeClient)
// Argo and OpenShift adapters are registered separately via RegisterAdapter
// as they require specific cluster support
return r
}
// RegisterAdapter registers a custom adapter for a workload type.
// Use this to add Argo Rollout or DeploymentConfig adapters.
func (r *AdapterRegistry) RegisterAdapter(adapter WorkloadAdapter) {
r.adapters[adapter.Type()] = adapter
}
// Get returns the adapter for the given workload type.
// Returns nil if the adapter is not registered.
func (r *AdapterRegistry) Get(wt WorkloadType) WorkloadAdapter {
return r.adapters[wt]
}
// GetStandardWorkloads returns the standard workload types that are always available.
func (r *AdapterRegistry) GetStandardWorkloads() []WorkloadType {
return []WorkloadType{
WorkloadDeployment,
WorkloadDaemonSet,
WorkloadStatefulSet,
}
}
// GetAllWorkloads returns all registered workload types.
func (r *AdapterRegistry) GetAllWorkloads() []WorkloadType {
result := make([]WorkloadType, 0, len(r.adapters))
for wt := range r.adapters {
result = append(result, wt)
}
return result
}
// GetEnvVarWorkloads returns workload types that support env var reload strategy.
func (r *AdapterRegistry) GetEnvVarWorkloads() []WorkloadType {
result := make([]WorkloadType, 0)
for wt, adapter := range r.adapters {
if adapter.SupportsEnvVarStrategy() {
result = append(result, wt)
}
}
return result
}