768 lines
20 KiB
Go
768 lines
20 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
"kforge/pkg/interpolate"
|
|
)
|
|
|
|
// ------------------------------------------------------------
|
|
// Default values — single source of truth for every default
|
|
// referenced in the schema. Change a default here and it
|
|
// propagates everywhere automatically.
|
|
// ------------------------------------------------------------
|
|
|
|
const (
|
|
DefaultTLSIssuer = "letsencrypt-prod"
|
|
DefaultIngressClass = "nginx"
|
|
DefaultCNPGHost = "cnpg-main-rw.default.svc.cluster.local"
|
|
DefaultCNPGClusterName = "cnpg-main"
|
|
DefaultCNPGSuperuserSecret = "cnpg-main-superuser"
|
|
DefaultNamespacePattern = "${env}"
|
|
DefaultImagePullPolicy = "Always"
|
|
DefaultServiceType = "ClusterIP"
|
|
DefaultDockerfile = "Dockerfile"
|
|
DefaultImageTag = "latest"
|
|
DefaultPullSecret = "regcred"
|
|
DefaultHealthCheckPath = "/healthcheck"
|
|
DefaultRegistryURL = "registry.natelubitz.com"
|
|
|
|
DefaultPort = 3000
|
|
DefaultReplicas = 1
|
|
DefaultInitialDelaySecs = 15
|
|
DefaultPeriodSecs = 10
|
|
DefaultTimeoutSecs = 5
|
|
DefaultFailureThreshold = 3
|
|
DefaultDeleteGraceSecs = 300
|
|
DefaultSuccessfulJobsHist = 3
|
|
DefaultFailedJobsHist = 1
|
|
|
|
DefaultCacheProvider = "valkey"
|
|
DefaultCacheMode = "standalone"
|
|
DefaultStorageProvider = "minio"
|
|
DefaultStorageMode = "standalone"
|
|
DefaultQueueProvider = "nats"
|
|
DefaultSearchProvider = "meilisearch"
|
|
DefaultMonProvider = "prometheus"
|
|
DefaultMetricsPath = "/metrics"
|
|
|
|
DefaultRestartPolicy = "OnFailure"
|
|
DefaultConcurrencyPolicy = "Forbid"
|
|
|
|
DefaultPreviewNamespacePrefix = "preview-pr"
|
|
)
|
|
|
|
// boolPtr / intPtr are helpers for pointer defaults.
|
|
func boolPtr(b bool) *bool { return &b }
|
|
func intPtr(i int) *int { return &i }
|
|
|
|
// isEnabled returns true if the InfraBase has no explicit Enabled
|
|
// value set (nil = inherits root default, which is true when the
|
|
// block exists) or if Enabled is explicitly true.
|
|
func isEnabled(b *bool) bool {
|
|
return b == nil || *b
|
|
}
|
|
|
|
// ------------------------------------------------------------
|
|
// ApplyDefaults fills in every zero/nil value in the config
|
|
// with the canonical default. Called once after unmarshalling,
|
|
// before any environment resolution.
|
|
// ------------------------------------------------------------
|
|
|
|
func ApplyDefaults(cfg *KforgeConfig) {
|
|
applyClusterDefaults(&cfg.Cluster)
|
|
applyRegistryDefaults(&cfg.Registry, &cfg.Meta)
|
|
applyDeploymentDefaults(&cfg.Defaults)
|
|
applyRootInfraDefaults(&cfg.Infrastructure)
|
|
}
|
|
|
|
func applyClusterDefaults(c *ClusterConfig) {
|
|
if c.TLSIssuer == "" {
|
|
c.TLSIssuer = DefaultTLSIssuer
|
|
}
|
|
if c.IngressClass == "" {
|
|
c.IngressClass = DefaultIngressClass
|
|
}
|
|
if c.CNPG.Host == "" {
|
|
c.CNPG.Host = DefaultCNPGHost
|
|
}
|
|
if c.CNPG.ClusterName == "" {
|
|
c.CNPG.ClusterName = DefaultCNPGClusterName
|
|
}
|
|
if c.CNPG.SuperuserSecret == "" {
|
|
c.CNPG.SuperuserSecret = DefaultCNPGSuperuserSecret
|
|
}
|
|
if c.NamespacePattern == "" {
|
|
c.NamespacePattern = DefaultNamespacePattern
|
|
}
|
|
}
|
|
|
|
func applyRegistryDefaults(r *RegistryConfig, m *MetaConfig) {
|
|
if r.URL == "" {
|
|
r.URL = DefaultRegistryURL
|
|
}
|
|
if r.PullSecret == "" {
|
|
r.PullSecret = DefaultPullSecret
|
|
}
|
|
if r.Repository == "" {
|
|
r.Repository = "${tenant}/${name}"
|
|
}
|
|
}
|
|
|
|
func applyDeploymentDefaults(d *DefaultsConfig) {
|
|
if d.ImagePullPolicy == "" {
|
|
d.ImagePullPolicy = DefaultImagePullPolicy
|
|
}
|
|
if d.Replicas == nil {
|
|
d.Replicas = intPtr(DefaultReplicas)
|
|
}
|
|
if d.Port == nil {
|
|
d.Port = intPtr(DefaultPort)
|
|
}
|
|
if d.ServiceType == "" {
|
|
d.ServiceType = DefaultServiceType
|
|
}
|
|
if d.Dockerfile == "" {
|
|
d.Dockerfile = DefaultDockerfile
|
|
}
|
|
applyHealthCheckDefaults(&d.HealthCheck, d.Port)
|
|
applyResourceDefaults(&d.Resources)
|
|
}
|
|
|
|
func applyHealthCheckDefaults(h *HealthCheckConfig, defaultPort *int) {
|
|
if h.Path == "" {
|
|
h.Path = DefaultHealthCheckPath
|
|
}
|
|
if h.Port == nil {
|
|
h.Port = defaultPort
|
|
}
|
|
if h.InitialDelaySeconds == 0 {
|
|
h.InitialDelaySeconds = DefaultInitialDelaySecs
|
|
}
|
|
if h.PeriodSeconds == 0 {
|
|
h.PeriodSeconds = DefaultPeriodSecs
|
|
}
|
|
if h.TimeoutSeconds == 0 {
|
|
h.TimeoutSeconds = DefaultTimeoutSecs
|
|
}
|
|
if h.FailureThreshold == 0 {
|
|
h.FailureThreshold = DefaultFailureThreshold
|
|
}
|
|
if h.Liveness == nil {
|
|
h.Liveness = boolPtr(true)
|
|
}
|
|
if h.Readiness == nil {
|
|
h.Readiness = boolPtr(true)
|
|
}
|
|
}
|
|
|
|
func applyResourceDefaults(r *ResourceConfig) {
|
|
if r.Requests.CPU == "" {
|
|
r.Requests.CPU = "100m"
|
|
}
|
|
if r.Requests.Memory == "" {
|
|
r.Requests.Memory = "128Mi"
|
|
}
|
|
if r.Limits.CPU == "" {
|
|
r.Limits.CPU = "500m"
|
|
}
|
|
if r.Limits.Memory == "" {
|
|
r.Limits.Memory = "512Mi"
|
|
}
|
|
}
|
|
|
|
// applyRootInfraDefaults sets provider/mode defaults on the root
|
|
// infrastructure block.
|
|
func applyRootInfraDefaults(infra *InfrastructureConfig) {
|
|
if infra.Cache != nil {
|
|
if infra.Cache.Provider == "" {
|
|
infra.Cache.Provider = DefaultCacheProvider
|
|
}
|
|
if infra.Cache.Mode == "" {
|
|
infra.Cache.Mode = DefaultCacheMode
|
|
}
|
|
if infra.Cache.Replicas == nil {
|
|
infra.Cache.Replicas = intPtr(1)
|
|
}
|
|
}
|
|
if infra.Storage != nil {
|
|
if infra.Storage.Provider == "" {
|
|
infra.Storage.Provider = DefaultStorageProvider
|
|
}
|
|
if infra.Storage.Mode == "" {
|
|
infra.Storage.Mode = DefaultStorageMode
|
|
}
|
|
}
|
|
if infra.Queue != nil {
|
|
if infra.Queue.Provider == "" {
|
|
infra.Queue.Provider = DefaultQueueProvider
|
|
}
|
|
}
|
|
if infra.Search != nil {
|
|
if infra.Search.Provider == "" {
|
|
infra.Search.Provider = DefaultSearchProvider
|
|
}
|
|
}
|
|
if infra.Monitoring != nil {
|
|
if infra.Monitoring.Provider == "" {
|
|
infra.Monitoring.Provider = DefaultMonProvider
|
|
}
|
|
if infra.Monitoring.MetricsPath == "" {
|
|
infra.Monitoring.MetricsPath = DefaultMetricsPath
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------
|
|
// ResolveEnvironment produces a fully-merged, fully-defaulted
|
|
// ResolvedEnvironment for a given environment key.
|
|
//
|
|
// Merge order (last wins):
|
|
// 1. Compiled defaults (from ApplyDefaults)
|
|
// 2. Root infrastructure block
|
|
// 3. Per-environment overrides
|
|
// ------------------------------------------------------------
|
|
|
|
// ResolvedEnvironment is the flattened, ready-to-generate view
|
|
// of a single environment. Generators consume this type only —
|
|
// they never touch raw config or merge logic.
|
|
type ResolvedEnvironment struct {
|
|
// Identity
|
|
EnvKey string
|
|
EnvPrefix string
|
|
Namespace string
|
|
FullName string // ${env_prefix}-${tenant}-${name}
|
|
|
|
// Deployment
|
|
Image string
|
|
ImagePullPolicy string
|
|
ImagePullSecret string
|
|
Replicas int
|
|
Port int
|
|
ServiceType string
|
|
HealthCheck HealthCheckConfig
|
|
Resources ResourceConfig
|
|
EnvVars []EnvVarConfig
|
|
|
|
// Ingress
|
|
Ingress IngressConfig
|
|
|
|
// Infrastructure (merged root + env override)
|
|
Infrastructure ResolvedInfrastructure
|
|
|
|
// Cron jobs
|
|
CronJobs []ResolvedCronJob
|
|
|
|
// Cluster-level settings (carried through for generators)
|
|
TLSIssuer string
|
|
IngressClass string
|
|
CNPGHost string
|
|
CNPGClusterName string
|
|
CNPGSuperuserSecret string
|
|
|
|
// DNS (for external-dns Ingress annotations)
|
|
DNSTarget string
|
|
SkipDNS bool
|
|
|
|
// Lifecycle
|
|
Lifecycle LifecycleConfig
|
|
}
|
|
|
|
// ResolvedInfrastructure holds the fully-merged infra state for
|
|
// one environment. Each field is nil if the service is disabled.
|
|
type ResolvedInfrastructure struct {
|
|
Database *DatabaseInfraConfig
|
|
Cache *CacheInfraConfig
|
|
Storage *StorageInfraConfig
|
|
Queue *QueueInfraConfig
|
|
Search *SearchInfraConfig
|
|
Monitoring *MonitoringInfraConfig
|
|
}
|
|
|
|
// ResolvedCronJob is a fully-defaulted cron job ready for the
|
|
// CronJob manifest generator.
|
|
type ResolvedCronJob struct {
|
|
CronJobConfig
|
|
Image string
|
|
EnvVars []EnvVarConfig // merged: deployment vars + job-specific vars
|
|
}
|
|
|
|
// ResolveEnvironment merges root config + env overrides into a
|
|
// single ResolvedEnvironment. cfg must have had ApplyDefaults
|
|
// called on it first.
|
|
func ResolveEnvironment(cfg *KforgeConfig, envKey string) (ResolvedEnvironment, error) {
|
|
env, ok := cfg.Environments[envKey]
|
|
if !ok {
|
|
return ResolvedEnvironment{}, &UnknownEnvironmentError{Key: envKey}
|
|
}
|
|
|
|
prefix := resolveEnvPrefix(envKey, env.EnvPrefix)
|
|
namespace := resolveNamespace(envKey, env.Namespace, cfg.Cluster.NamespacePattern)
|
|
fullName := resolveFullName(cfg, prefix, env)
|
|
|
|
registry := resolveRegistry(cfg, env)
|
|
imageTag := env.ImageTag
|
|
if imageTag == "" {
|
|
imageTag = DefaultImageTag
|
|
}
|
|
// Allow the action entrypoint (or CI) to override the image tag at generate
|
|
// time without modifying kforge.yml (e.g. KFORGE_IMAGE_TAG=abc1234).
|
|
if override := os.Getenv("KFORGE_IMAGE_TAG"); override != "" {
|
|
imageTag = override
|
|
}
|
|
image := registry.URL + "/" + registry.Repository + ":" + imageTag
|
|
|
|
replicas := *cfg.Defaults.Replicas
|
|
if env.Replicas != nil {
|
|
replicas = *env.Replicas
|
|
}
|
|
|
|
port := *cfg.Defaults.Port
|
|
hc := cfg.Defaults.HealthCheck
|
|
if hc.Port == nil || *hc.Port == 0 {
|
|
hc.Port = intPtr(port)
|
|
}
|
|
|
|
envVars := mergeEnvVars(cfg.Defaults.EnvVars, env.EnvVars)
|
|
|
|
infra := mergeInfrastructure(&cfg.Infrastructure, &env.Infrastructure)
|
|
|
|
cronJobs := resolveCronJobs(env.CronJobs, image, envVars, cfg.Defaults.Resources)
|
|
|
|
lifecycle := env.Lifecycle
|
|
if lifecycle.DeleteGraceSeconds == 0 {
|
|
lifecycle.DeleteGraceSeconds = DefaultDeleteGraceSecs
|
|
}
|
|
|
|
auth := env.Ingress.Auth
|
|
if auth.SecretName == "" {
|
|
auth.SecretName = fullName + "-basic-auth"
|
|
}
|
|
ingress := IngressConfig{
|
|
Hosts: env.Ingress.Hosts,
|
|
Auth: auth,
|
|
}
|
|
|
|
// Resolve DNS target token (${KFORGE_NODE_IP} etc.) from env.
|
|
tokens := interpolate.FromEnvironment(
|
|
cfg.Meta.Name, cfg.Meta.Tenant, envKey, prefix, fullName, imageTag, namespace,
|
|
)
|
|
dnsTarget := interpolate.Apply(cfg.DNS.Target, tokens)
|
|
|
|
return ResolvedEnvironment{
|
|
EnvKey: envKey,
|
|
EnvPrefix: prefix,
|
|
Namespace: namespace,
|
|
FullName: fullName,
|
|
Image: image,
|
|
ImagePullPolicy: cfg.Defaults.ImagePullPolicy,
|
|
ImagePullSecret: registry.PullSecret,
|
|
Replicas: replicas,
|
|
Port: port,
|
|
ServiceType: cfg.Defaults.ServiceType,
|
|
HealthCheck: hc,
|
|
Resources: cfg.Defaults.Resources,
|
|
EnvVars: envVars,
|
|
Ingress: ingress,
|
|
Infrastructure: infra,
|
|
CronJobs: cronJobs,
|
|
TLSIssuer: cfg.Cluster.TLSIssuer,
|
|
IngressClass: cfg.Cluster.IngressClass,
|
|
CNPGHost: cfg.Cluster.CNPG.Host,
|
|
CNPGClusterName: cfg.Cluster.CNPG.ClusterName,
|
|
CNPGSuperuserSecret: cfg.Cluster.CNPG.SuperuserSecret,
|
|
DNSTarget: dnsTarget,
|
|
SkipDNS: cfg.DNS.SkipDNS,
|
|
Lifecycle: lifecycle,
|
|
}, nil
|
|
}
|
|
|
|
// ------------------------------------------------------------
|
|
// SynthesizePreviewEnvironment creates a ResolvedEnvironment
|
|
// for a PR preview from the preview config + a base environment.
|
|
// ------------------------------------------------------------
|
|
|
|
// SynthesizePreviewEnvironment derives a preview environment by
|
|
// cloning the base environment and overriding namespace, hostname,
|
|
// full name, and image tag for the given PR number.
|
|
func SynthesizePreviewEnvironment(cfg *KforgeConfig, prNumber string) (ResolvedEnvironment, error) {
|
|
if !cfg.Preview.Enabled {
|
|
return ResolvedEnvironment{}, fmt.Errorf("preview is not enabled in kforge.yml")
|
|
}
|
|
if cfg.Preview.BaseEnvironment == "" {
|
|
return ResolvedEnvironment{}, fmt.Errorf("preview.base_environment is required")
|
|
}
|
|
|
|
env, err := ResolveEnvironment(cfg, cfg.Preview.BaseEnvironment)
|
|
if err != nil {
|
|
return ResolvedEnvironment{}, fmt.Errorf("resolving base environment %q: %w", cfg.Preview.BaseEnvironment, err)
|
|
}
|
|
|
|
nsPrefix := cfg.Preview.NamespacePrefix
|
|
if nsPrefix == "" {
|
|
nsPrefix = DefaultPreviewNamespacePrefix
|
|
}
|
|
|
|
env.EnvKey = "preview-" + prNumber
|
|
env.Namespace = nsPrefix + "-" + prNumber
|
|
env.FullName = "pr" + prNumber + "-" + cfg.Meta.Tenant + "-" + cfg.Meta.Name
|
|
|
|
// Override image tag to a PR-specific tag.
|
|
if idx := strings.LastIndex(env.Image, ":"); idx >= 0 {
|
|
env.Image = env.Image[:idx+1] + "pr-" + prNumber
|
|
}
|
|
|
|
// Override ingress hostname using the template.
|
|
hostnameTemplate := cfg.Preview.HostnameTemplate
|
|
if hostnameTemplate == "" {
|
|
hostnameTemplate = "pr-${PR_NUMBER}.${name}.example.com"
|
|
}
|
|
previewTokens := interpolate.Tokens{
|
|
"PR_NUMBER": prNumber,
|
|
"name": cfg.Meta.Name,
|
|
"tenant": cfg.Meta.Tenant,
|
|
}
|
|
hostname := interpolate.Apply(hostnameTemplate, previewTokens)
|
|
|
|
env.Ingress = IngressConfig{
|
|
Hosts: []IngressHost{{
|
|
Hostname: hostname,
|
|
TLS: true,
|
|
DNSRecord: true,
|
|
}},
|
|
Auth: IngressAuth{
|
|
SecretName: env.FullName + "-basic-auth",
|
|
},
|
|
}
|
|
|
|
return env, nil
|
|
}
|
|
|
|
// ------------------------------------------------------------
|
|
// Internal resolution helpers
|
|
// ------------------------------------------------------------
|
|
|
|
func resolveEnvPrefix(envKey string, override *string) string {
|
|
if override != nil && *override != "" {
|
|
return *override
|
|
}
|
|
if len(envKey) <= 4 {
|
|
return envKey
|
|
}
|
|
return envKey[:4]
|
|
}
|
|
|
|
func resolveNamespace(envKey, explicit, pattern string) string {
|
|
if explicit != "" {
|
|
return explicit
|
|
}
|
|
if pattern == "" {
|
|
return envKey
|
|
}
|
|
return pattern
|
|
}
|
|
|
|
func resolveFullName(cfg *KforgeConfig, prefix string, env EnvironmentConfig) string {
|
|
if cfg.Meta.NameOverride != nil && *cfg.Meta.NameOverride != "" {
|
|
return *cfg.Meta.NameOverride
|
|
}
|
|
return prefix + "-" + cfg.Meta.Tenant + "-" + cfg.Meta.Name
|
|
}
|
|
|
|
func resolveRegistry(cfg *KforgeConfig, env EnvironmentConfig) RegistryConfig {
|
|
base := cfg.Registry
|
|
if base.Repository == "${tenant}/${name}" || base.Repository == "" {
|
|
base.Repository = cfg.Meta.Tenant + "/" + cfg.Meta.Name
|
|
}
|
|
if env.Registry != nil {
|
|
r := *env.Registry
|
|
if r.URL == "" {
|
|
r.URL = base.URL
|
|
}
|
|
if r.Repository == "" {
|
|
r.Repository = base.Repository
|
|
}
|
|
if r.PullSecret == "" {
|
|
r.PullSecret = base.PullSecret
|
|
}
|
|
return r
|
|
}
|
|
return base
|
|
}
|
|
|
|
// MergeEnvVars is the exported form of mergeEnvVars, used by the
|
|
// generate command to inject infrastructure env vars into deployments.
|
|
func MergeEnvVars(base, override []EnvVarConfig) []EnvVarConfig {
|
|
return mergeEnvVars(base, override)
|
|
}
|
|
|
|
// mergeEnvVars combines base and override slices. If an env var
|
|
// with the same Name appears in both, the override wins.
|
|
func mergeEnvVars(base, override []EnvVarConfig) []EnvVarConfig {
|
|
merged := make([]EnvVarConfig, 0, len(base)+len(override))
|
|
seen := make(map[string]int) // name → index in merged
|
|
|
|
for _, v := range base {
|
|
seen[v.Name] = len(merged)
|
|
merged = append(merged, v)
|
|
}
|
|
for _, v := range override {
|
|
if idx, ok := seen[v.Name]; ok {
|
|
merged[idx] = v // override
|
|
} else {
|
|
seen[v.Name] = len(merged)
|
|
merged = append(merged, v)
|
|
}
|
|
}
|
|
return merged
|
|
}
|
|
|
|
// mergeInfrastructure performs a shallow merge of root infra
|
|
// defaults with per-environment overrides.
|
|
func mergeInfrastructure(root, env *InfrastructureConfig) ResolvedInfrastructure {
|
|
return ResolvedInfrastructure{
|
|
Database: mergeDatabase(root.Database, env.Database),
|
|
Cache: mergeCache(root.Cache, env.Cache),
|
|
Storage: mergeStorage(root.Storage, env.Storage),
|
|
Queue: mergeQueue(root.Queue, env.Queue),
|
|
Search: mergeSearch(root.Search, env.Search),
|
|
Monitoring: mergeMonitoring(root.Monitoring, env.Monitoring),
|
|
}
|
|
}
|
|
|
|
func mergeDatabase(root, env *DatabaseInfraConfig) *DatabaseInfraConfig {
|
|
if root == nil && env == nil {
|
|
return nil
|
|
}
|
|
merged := &DatabaseInfraConfig{}
|
|
if root != nil {
|
|
*merged = *root
|
|
}
|
|
if env != nil {
|
|
if env.Enabled != nil {
|
|
merged.Enabled = env.Enabled
|
|
}
|
|
if env.Provider != "" {
|
|
merged.Provider = env.Provider
|
|
}
|
|
if env.DatabaseName != "" {
|
|
merged.DatabaseName = env.DatabaseName
|
|
}
|
|
}
|
|
if !isEnabled(merged.Enabled) {
|
|
return nil
|
|
}
|
|
if merged.Provider == "" {
|
|
merged.Provider = "cnpg"
|
|
}
|
|
return merged
|
|
}
|
|
|
|
func mergeCache(root, env *CacheInfraConfig) *CacheInfraConfig {
|
|
if root == nil && env == nil {
|
|
return nil
|
|
}
|
|
merged := &CacheInfraConfig{}
|
|
if root != nil {
|
|
*merged = *root
|
|
}
|
|
if env != nil {
|
|
if env.Enabled != nil {
|
|
merged.Enabled = env.Enabled
|
|
}
|
|
if env.Provider != "" {
|
|
merged.Provider = env.Provider
|
|
}
|
|
if env.Mode != "" {
|
|
merged.Mode = env.Mode
|
|
}
|
|
if env.Replicas != nil {
|
|
merged.Replicas = env.Replicas
|
|
}
|
|
}
|
|
if !isEnabled(merged.Enabled) {
|
|
return nil
|
|
}
|
|
if merged.Provider == "" {
|
|
merged.Provider = DefaultCacheProvider
|
|
}
|
|
if merged.Mode == "" {
|
|
merged.Mode = DefaultCacheMode
|
|
}
|
|
if merged.Replicas == nil {
|
|
merged.Replicas = intPtr(1)
|
|
}
|
|
return merged
|
|
}
|
|
|
|
func mergeStorage(root, env *StorageInfraConfig) *StorageInfraConfig {
|
|
if root == nil && env == nil {
|
|
return nil
|
|
}
|
|
merged := &StorageInfraConfig{}
|
|
if root != nil {
|
|
*merged = *root
|
|
}
|
|
if env != nil {
|
|
if env.Enabled != nil {
|
|
merged.Enabled = env.Enabled
|
|
}
|
|
if env.Provider != "" {
|
|
merged.Provider = env.Provider
|
|
}
|
|
if env.Mode != "" {
|
|
merged.Mode = env.Mode
|
|
}
|
|
}
|
|
if !isEnabled(merged.Enabled) {
|
|
return nil
|
|
}
|
|
if merged.Provider == "" {
|
|
merged.Provider = DefaultStorageProvider
|
|
}
|
|
if merged.Mode == "" {
|
|
merged.Mode = DefaultStorageMode
|
|
}
|
|
return merged
|
|
}
|
|
|
|
func mergeQueue(root, env *QueueInfraConfig) *QueueInfraConfig {
|
|
if root == nil && env == nil {
|
|
return nil
|
|
}
|
|
merged := &QueueInfraConfig{}
|
|
if root != nil {
|
|
*merged = *root
|
|
}
|
|
if env != nil {
|
|
if env.Enabled != nil {
|
|
merged.Enabled = env.Enabled
|
|
}
|
|
if env.Provider != "" {
|
|
merged.Provider = env.Provider
|
|
}
|
|
}
|
|
if !isEnabled(merged.Enabled) {
|
|
return nil
|
|
}
|
|
if merged.Provider == "" {
|
|
merged.Provider = DefaultQueueProvider
|
|
}
|
|
return merged
|
|
}
|
|
|
|
func mergeSearch(root, env *SearchInfraConfig) *SearchInfraConfig {
|
|
if root == nil && env == nil {
|
|
return nil
|
|
}
|
|
merged := &SearchInfraConfig{}
|
|
if root != nil {
|
|
*merged = *root
|
|
}
|
|
if env != nil {
|
|
if env.Enabled != nil {
|
|
merged.Enabled = env.Enabled
|
|
}
|
|
if env.Provider != "" {
|
|
merged.Provider = env.Provider
|
|
}
|
|
}
|
|
if !isEnabled(merged.Enabled) {
|
|
return nil
|
|
}
|
|
if merged.Provider == "" {
|
|
merged.Provider = DefaultSearchProvider
|
|
}
|
|
return merged
|
|
}
|
|
|
|
func mergeMonitoring(root, env *MonitoringInfraConfig) *MonitoringInfraConfig {
|
|
if root == nil && env == nil {
|
|
return nil
|
|
}
|
|
merged := &MonitoringInfraConfig{}
|
|
if root != nil {
|
|
*merged = *root
|
|
}
|
|
if env != nil {
|
|
if env.Enabled != nil {
|
|
merged.Enabled = env.Enabled
|
|
}
|
|
if env.Provider != "" {
|
|
merged.Provider = env.Provider
|
|
}
|
|
if env.MetricsPath != "" {
|
|
merged.MetricsPath = env.MetricsPath
|
|
}
|
|
if env.MetricsPort != nil {
|
|
merged.MetricsPort = env.MetricsPort
|
|
}
|
|
}
|
|
if !isEnabled(merged.Enabled) {
|
|
return nil
|
|
}
|
|
if merged.Provider == "" {
|
|
merged.Provider = DefaultMonProvider
|
|
}
|
|
if merged.MetricsPath == "" {
|
|
merged.MetricsPath = DefaultMetricsPath
|
|
}
|
|
return merged
|
|
}
|
|
|
|
// resolveCronJobs applies defaults to each cron job and merges
|
|
// env vars from the parent deployment.
|
|
func resolveCronJobs(jobs []CronJobConfig, deploymentImage string, deploymentEnvVars []EnvVarConfig, defaultResources ResourceConfig) []ResolvedCronJob {
|
|
resolved := make([]ResolvedCronJob, 0, len(jobs))
|
|
for _, job := range jobs {
|
|
r := ResolvedCronJob{CronJobConfig: job}
|
|
|
|
if job.ImageOverride != nil && *job.ImageOverride != "" {
|
|
r.Image = *job.ImageOverride
|
|
} else {
|
|
r.Image = deploymentImage
|
|
}
|
|
|
|
inheritEnv := job.InheritEnv == nil || *job.InheritEnv
|
|
if inheritEnv {
|
|
r.EnvVars = mergeEnvVars(deploymentEnvVars, job.EnvVars)
|
|
} else {
|
|
r.EnvVars = job.EnvVars
|
|
}
|
|
|
|
if job.Resources == nil {
|
|
r.Resources = &defaultResources
|
|
}
|
|
|
|
if r.RestartPolicy == "" {
|
|
r.RestartPolicy = DefaultRestartPolicy
|
|
}
|
|
if r.ConcurrencyPolicy == "" {
|
|
r.ConcurrencyPolicy = DefaultConcurrencyPolicy
|
|
}
|
|
if r.SuccessfulJobsHistoryLimit == nil {
|
|
r.SuccessfulJobsHistoryLimit = intPtr(DefaultSuccessfulJobsHist)
|
|
}
|
|
if r.FailedJobsHistoryLimit == nil {
|
|
r.FailedJobsHistoryLimit = intPtr(DefaultFailedJobsHist)
|
|
}
|
|
|
|
resolved = append(resolved, r)
|
|
}
|
|
return resolved
|
|
}
|
|
|
|
// ------------------------------------------------------------
|
|
// Errors
|
|
// ------------------------------------------------------------
|
|
|
|
type UnknownEnvironmentError struct {
|
|
Key string
|
|
}
|
|
|
|
func (e *UnknownEnvironmentError) Error() string {
|
|
return "unknown environment: " + e.Key
|
|
}
|