diff --git a/api/formance.com/v1beta1/auth_types.go b/api/formance.com/v1beta1/auth_types.go index 19140cfff..0cfc189ff 100644 --- a/api/formance.com/v1beta1/auth_types.go +++ b/api/formance.com/v1beta1/auth_types.go @@ -52,6 +52,9 @@ type AuthSpec struct { // in this case, if authenticated, it is ok. // +kubebuilder:default:=false EnableScopes bool `json:"enableScopes"` + // Issuers lists the OIDC issuer URLs the auth server should advertise. + // +optional + Issuers []string `json:"issuers,omitempty"` } type AuthStatus struct { diff --git a/api/formance.com/v1beta1/gateway_types.go b/api/formance.com/v1beta1/gateway_types.go index 5828da2a7..01edd0ade 100644 --- a/api/formance.com/v1beta1/gateway_types.go +++ b/api/formance.com/v1beta1/gateway_types.go @@ -46,11 +46,53 @@ type GatewayIngress struct { // Custom annotations to add on the ingress Annotations map[string]string `json:"annotations,omitempty"` + // Custom labels to add on the ingress + //+optional + Labels map[string]string `json:"labels,omitempty"` // Allow to customize the tls part of the ingress //+optional TLS *GatewayIngressTLS `json:"tls,omitempty"` } +// GatewayCaddyfileConfig holds Caddyfile-level tuning options. +type GatewayCaddyfileConfig struct { + // +optional + TrustedProxies []string `json:"trustedProxies,omitempty"` + // +optional + TrustedProxiesStrict *bool `json:"trustedProxiesStrict,omitempty"` + // +optional + ShutdownDelay *metav1.Duration `json:"shutdownDelay,omitempty"` + // +optional + GracePeriod *metav1.Duration `json:"gracePeriod,omitempty"` +} + +// GatewayServerConfig holds HTTP server tuning options. +type GatewayServerConfig struct { + // +optional + IdleTimeout *metav1.Duration `json:"idleTimeout,omitempty"` +} + +// GatewayDNSEndpoint configures a DNS endpoint managed by the gateway. +// Name identifies the entry (e.g. "private", "public") and yields a +// DNSEndpoint resource named "-". +type GatewayDNSEndpoint struct { + // +required + Name string `json:"name"` + // +optional + Enabled *bool `json:"enabled,omitempty"` + // +optional + DNSNames []string `json:"dnsNames,omitempty"` + // +optional + Targets []string `json:"targets,omitempty"` + // +optional + // +kubebuilder:default:="CNAME" + RecordType string `json:"recordType,omitempty"` + // +optional + Annotations map[string]string `json:"annotations,omitempty"` + // +optional + ProviderSpecific map[string]string `json:"providerSpecific,omitempty"` +} + // DedupHosts returns the given hosts deduplicated, preserving order and skipping empty strings. func DedupHosts(input []string) []string { seen := map[string]struct{}{} @@ -79,6 +121,22 @@ type GatewaySpec struct { //+optional // Allow to customize the generated ingress Ingress *GatewayIngress `json:"ingress,omitempty"` + //+optional + Caddyfile *GatewayCaddyfileConfig `json:"caddyfile,omitempty"` + //+optional + Config *GatewayServerConfig `json:"config,omitempty"` + //+optional + DNS []GatewayDNSEndpoint `json:"dns,omitempty"` +} + +// FindDNSEndpoint returns the entry from Spec.DNS matching name, or nil. +func (in *GatewaySpec) FindDNSEndpoint(name string) *GatewayDNSEndpoint { + for i := range in.DNS { + if in.DNS[i].Name == name { + return &in.DNS[i] + } + } + return nil } type GatewayStatus struct { diff --git a/api/formance.com/v1beta1/ledger_types.go b/api/formance.com/v1beta1/ledger_types.go index 3062ccc47..922309ce4 100644 --- a/api/formance.com/v1beta1/ledger_types.go +++ b/api/formance.com/v1beta1/ledger_types.go @@ -20,11 +20,73 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// LedgerAPIConfig configures the ledger HTTP API behavior. +type LedgerAPIConfig struct { + // +optional + DefaultPageSize *int `json:"defaultPageSize,omitempty"` + // +optional + MaxPageSize *int `json:"maxPageSize,omitempty"` + // +optional + BulkMaxSize *int `json:"bulkMaxSize,omitempty"` +} + +// LedgerAsyncBlockHasherConfig configures the worker async block hasher. +type LedgerAsyncBlockHasherConfig struct { + // +optional + MaxBlockSize string `json:"maxBlockSize,omitempty"` + // +optional + Schedule string `json:"schedule,omitempty"` +} + +// LedgerPipelinesConfig configures the worker pipelines. +type LedgerPipelinesConfig struct { + // +optional + PullInterval string `json:"pullInterval,omitempty"` + // +optional + PushRetryPeriod string `json:"pushRetryPeriod,omitempty"` + // +optional + SyncPeriod string `json:"syncPeriod,omitempty"` + // +optional + LogsPageSize string `json:"logsPageSize,omitempty"` +} + +// LedgerBucketCleanupConfig configures the worker bucket cleanup. +type LedgerBucketCleanupConfig struct { + // +optional + RetentionPeriod string `json:"retentionPeriod,omitempty"` + // +optional + Schedule string `json:"schedule,omitempty"` +} + +// LedgerWorkerConfig configures the ledger worker. +type LedgerWorkerConfig struct { + // +optional + AsyncBlockHasher *LedgerAsyncBlockHasherConfig `json:"asyncBlockHasher,omitempty"` + // +optional + BucketCleanup *LedgerBucketCleanupConfig `json:"bucketCleanup,omitempty"` + // +optional + Pipelines *LedgerPipelinesConfig `json:"pipelines,omitempty"` +} + type LedgerSpec struct { ModuleProperties `json:",inline"` StackDependency `json:",inline"` // +optional Auth *AuthConfig `json:"auth,omitempty"` + // +optional + ExperimentalFeatures *bool `json:"experimentalFeatures,omitempty"` + // +optional + ExperimentalNumscript *bool `json:"experimentalNumscript,omitempty"` + // +optional + ExperimentalNumscriptFlags []string `json:"experimentalNumscriptFlags,omitempty"` + // +optional + ExperimentalExporters *bool `json:"experimentalExporters,omitempty"` + // +optional + SchemaEnforcementMode string `json:"schemaEnforcementMode,omitempty"` + // +optional + API *LedgerAPIConfig `json:"api,omitempty"` + // +optional + Worker *LedgerWorkerConfig `json:"worker,omitempty"` } type LedgerStatus struct { diff --git a/api/formance.com/v1beta1/orchestration_types.go b/api/formance.com/v1beta1/orchestration_types.go index 20ab1e2b1..3b9ee6aef 100644 --- a/api/formance.com/v1beta1/orchestration_types.go +++ b/api/formance.com/v1beta1/orchestration_types.go @@ -25,6 +25,8 @@ type OrchestrationSpec struct { ModuleProperties `json:",inline"` // +optional Auth *AuthConfig `json:"auth,omitempty"` + // +optional + MaxParallelActivities *int `json:"maxParallelActivities,omitempty"` } type OrchestrationStatus struct { diff --git a/api/formance.com/v1beta1/payments_types.go b/api/formance.com/v1beta1/payments_types.go index feabcb0d5..bcd152252 100644 --- a/api/formance.com/v1beta1/payments_types.go +++ b/api/formance.com/v1beta1/payments_types.go @@ -20,6 +20,18 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) +// PaymentsWorkerConfig configures the payments worker temporal client. +type PaymentsWorkerConfig struct { + // +optional + TemporalMaxConcurrentWorkflowTaskPollers *int `json:"temporalMaxConcurrentWorkflowTaskPollers,omitempty"` + // +optional + TemporalMaxConcurrentActivityTaskPollers *int `json:"temporalMaxConcurrentActivityTaskPollers,omitempty"` + // +optional + TemporalMaxSlotsPerPoller *int `json:"temporalMaxSlotsPerPoller,omitempty"` + // +optional + TemporalMaxLocalActivitySlots *int `json:"temporalMaxLocalActivitySlots,omitempty"` +} + type PaymentsSpec struct { StackDependency `json:",inline"` ModuleProperties `json:",inline"` @@ -27,6 +39,12 @@ type PaymentsSpec struct { EncryptionKey string `json:"encryptionKey"` // +optional Auth *AuthConfig `json:"auth,omitempty"` + // ClearTemporal controls whether the Temporal namespace/schedule is + // torn down when the resource is deleted. Defaults to true when unset. + // +optional + ClearTemporal *bool `json:"clearTemporal,omitempty"` + // +optional + Worker *PaymentsWorkerConfig `json:"worker,omitempty"` } type PaymentsStatus struct { diff --git a/api/formance.com/v1beta1/shared.go b/api/formance.com/v1beta1/shared.go index 5894e65c1..2f24382ba 100644 --- a/api/formance.com/v1beta1/shared.go +++ b/api/formance.com/v1beta1/shared.go @@ -246,6 +246,9 @@ type AuthConfig struct { ReadKeySetMaxRetries int `json:"readKeySetMaxRetries"` // +optional CheckScopes bool `json:"checkScopes"` + // Issuers lists the OIDC issuer URLs the module should trust. + // +optional + Issuers []string `json:"issuers,omitempty"` } // +kubebuilder:object:generate=false diff --git a/api/formance.com/v1beta1/transactionplane_types.go b/api/formance.com/v1beta1/transactionplane_types.go index 1d16711f6..2a6229d44 100644 --- a/api/formance.com/v1beta1/transactionplane_types.go +++ b/api/formance.com/v1beta1/transactionplane_types.go @@ -25,6 +25,8 @@ type TransactionPlaneSpec struct { ModuleProperties `json:",inline"` // +optional Auth *AuthConfig `json:"auth,omitempty"` + // +optional + WorkerEnabled *bool `json:"workerEnabled,omitempty"` } type TransactionPlaneStatus struct { diff --git a/api/formance.com/v1beta1/zz_generated.deepcopy.go b/api/formance.com/v1beta1/zz_generated.deepcopy.go index 552862474..f9a9b30e8 100644 --- a/api/formance.com/v1beta1/zz_generated.deepcopy.go +++ b/api/formance.com/v1beta1/zz_generated.deepcopy.go @@ -167,6 +167,11 @@ func (in *AuthClientStatus) DeepCopy() *AuthClientStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AuthConfig) DeepCopyInto(out *AuthConfig) { *out = *in + if in.Issuers != nil { + in, out := &in.Issuers, &out.Issuers + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthConfig. @@ -226,6 +231,11 @@ func (in *AuthSpec) DeepCopyInto(out *AuthSpec) { *out = new(v1.SecretKeySelector) (*in).DeepCopyInto(*out) } + if in.Issuers != nil { + in, out := &in.Issuers, &out.Issuers + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthSpec. @@ -965,6 +975,85 @@ func (in *Gateway) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GatewayCaddyfileConfig) DeepCopyInto(out *GatewayCaddyfileConfig) { + *out = *in + if in.TrustedProxies != nil { + in, out := &in.TrustedProxies, &out.TrustedProxies + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.TrustedProxiesStrict != nil { + in, out := &in.TrustedProxiesStrict, &out.TrustedProxiesStrict + *out = new(bool) + **out = **in + } + if in.ShutdownDelay != nil { + in, out := &in.ShutdownDelay, &out.ShutdownDelay + *out = new(metav1.Duration) + **out = **in + } + if in.GracePeriod != nil { + in, out := &in.GracePeriod, &out.GracePeriod + *out = new(metav1.Duration) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayCaddyfileConfig. +func (in *GatewayCaddyfileConfig) DeepCopy() *GatewayCaddyfileConfig { + if in == nil { + return nil + } + out := new(GatewayCaddyfileConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GatewayDNSEndpoint) DeepCopyInto(out *GatewayDNSEndpoint) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } + if in.DNSNames != nil { + in, out := &in.DNSNames, &out.DNSNames + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Targets != nil { + in, out := &in.Targets, &out.Targets + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.ProviderSpecific != nil { + in, out := &in.ProviderSpecific, &out.ProviderSpecific + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayDNSEndpoint. +func (in *GatewayDNSEndpoint) DeepCopy() *GatewayDNSEndpoint { + if in == nil { + return nil + } + out := new(GatewayDNSEndpoint) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GatewayHTTPAPI) DeepCopyInto(out *GatewayHTTPAPI) { *out = *in @@ -1103,6 +1192,13 @@ func (in *GatewayIngress) DeepCopyInto(out *GatewayIngress) { (*out)[key] = val } } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } if in.TLS != nil { in, out := &in.TLS, &out.TLS *out = new(GatewayIngressTLS) @@ -1167,6 +1263,26 @@ func (in *GatewayList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GatewayServerConfig) DeepCopyInto(out *GatewayServerConfig) { + *out = *in + if in.IdleTimeout != nil { + in, out := &in.IdleTimeout, &out.IdleTimeout + *out = new(metav1.Duration) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayServerConfig. +func (in *GatewayServerConfig) DeepCopy() *GatewayServerConfig { + if in == nil { + return nil + } + out := new(GatewayServerConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GatewaySpec) DeepCopyInto(out *GatewaySpec) { *out = *in @@ -1177,6 +1293,23 @@ func (in *GatewaySpec) DeepCopyInto(out *GatewaySpec) { *out = new(GatewayIngress) (*in).DeepCopyInto(*out) } + if in.Caddyfile != nil { + in, out := &in.Caddyfile, &out.Caddyfile + *out = new(GatewayCaddyfileConfig) + (*in).DeepCopyInto(*out) + } + if in.Config != nil { + in, out := &in.Config, &out.Config + *out = new(GatewayServerConfig) + (*in).DeepCopyInto(*out) + } + if in.DNS != nil { + in, out := &in.DNS, &out.DNS + *out = make([]GatewayDNSEndpoint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewaySpec. @@ -1237,6 +1370,66 @@ func (in *Ledger) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LedgerAPIConfig) DeepCopyInto(out *LedgerAPIConfig) { + *out = *in + if in.DefaultPageSize != nil { + in, out := &in.DefaultPageSize, &out.DefaultPageSize + *out = new(int) + **out = **in + } + if in.MaxPageSize != nil { + in, out := &in.MaxPageSize, &out.MaxPageSize + *out = new(int) + **out = **in + } + if in.BulkMaxSize != nil { + in, out := &in.BulkMaxSize, &out.BulkMaxSize + *out = new(int) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LedgerAPIConfig. +func (in *LedgerAPIConfig) DeepCopy() *LedgerAPIConfig { + if in == nil { + return nil + } + out := new(LedgerAPIConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LedgerAsyncBlockHasherConfig) DeepCopyInto(out *LedgerAsyncBlockHasherConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LedgerAsyncBlockHasherConfig. +func (in *LedgerAsyncBlockHasherConfig) DeepCopy() *LedgerAsyncBlockHasherConfig { + if in == nil { + return nil + } + out := new(LedgerAsyncBlockHasherConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LedgerBucketCleanupConfig) DeepCopyInto(out *LedgerBucketCleanupConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LedgerBucketCleanupConfig. +func (in *LedgerBucketCleanupConfig) DeepCopy() *LedgerBucketCleanupConfig { + if in == nil { + return nil + } + out := new(LedgerBucketCleanupConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LedgerList) DeepCopyInto(out *LedgerList) { *out = *in @@ -1269,6 +1462,21 @@ func (in *LedgerList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LedgerPipelinesConfig) DeepCopyInto(out *LedgerPipelinesConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LedgerPipelinesConfig. +func (in *LedgerPipelinesConfig) DeepCopy() *LedgerPipelinesConfig { + if in == nil { + return nil + } + out := new(LedgerPipelinesConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LedgerSpec) DeepCopyInto(out *LedgerSpec) { *out = *in @@ -1277,8 +1485,38 @@ func (in *LedgerSpec) DeepCopyInto(out *LedgerSpec) { if in.Auth != nil { in, out := &in.Auth, &out.Auth *out = new(AuthConfig) + (*in).DeepCopyInto(*out) + } + if in.ExperimentalFeatures != nil { + in, out := &in.ExperimentalFeatures, &out.ExperimentalFeatures + *out = new(bool) + **out = **in + } + if in.ExperimentalNumscript != nil { + in, out := &in.ExperimentalNumscript, &out.ExperimentalNumscript + *out = new(bool) **out = **in } + if in.ExperimentalNumscriptFlags != nil { + in, out := &in.ExperimentalNumscriptFlags, &out.ExperimentalNumscriptFlags + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ExperimentalExporters != nil { + in, out := &in.ExperimentalExporters, &out.ExperimentalExporters + *out = new(bool) + **out = **in + } + if in.API != nil { + in, out := &in.API, &out.API + *out = new(LedgerAPIConfig) + (*in).DeepCopyInto(*out) + } + if in.Worker != nil { + in, out := &in.Worker, &out.Worker + *out = new(LedgerWorkerConfig) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LedgerSpec. @@ -1307,6 +1545,36 @@ func (in *LedgerStatus) DeepCopy() *LedgerStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *LedgerWorkerConfig) DeepCopyInto(out *LedgerWorkerConfig) { + *out = *in + if in.AsyncBlockHasher != nil { + in, out := &in.AsyncBlockHasher, &out.AsyncBlockHasher + *out = new(LedgerAsyncBlockHasherConfig) + **out = **in + } + if in.BucketCleanup != nil { + in, out := &in.BucketCleanup, &out.BucketCleanup + *out = new(LedgerBucketCleanupConfig) + **out = **in + } + if in.Pipelines != nil { + in, out := &in.Pipelines, &out.Pipelines + *out = new(LedgerPipelinesConfig) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LedgerWorkerConfig. +func (in *LedgerWorkerConfig) DeepCopy() *LedgerWorkerConfig { + if in == nil { + return nil + } + out := new(LedgerWorkerConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *MCP) DeepCopyInto(out *MCP) { *out = *in @@ -1482,6 +1750,11 @@ func (in *OrchestrationSpec) DeepCopyInto(out *OrchestrationSpec) { if in.Auth != nil { in, out := &in.Auth, &out.Auth *out = new(AuthConfig) + (*in).DeepCopyInto(*out) + } + if in.MaxParallelActivities != nil { + in, out := &in.MaxParallelActivities, &out.MaxParallelActivities + *out = new(int) **out = **in } } @@ -1583,8 +1856,18 @@ func (in *PaymentsSpec) DeepCopyInto(out *PaymentsSpec) { if in.Auth != nil { in, out := &in.Auth, &out.Auth *out = new(AuthConfig) + (*in).DeepCopyInto(*out) + } + if in.ClearTemporal != nil { + in, out := &in.ClearTemporal, &out.ClearTemporal + *out = new(bool) **out = **in } + if in.Worker != nil { + in, out := &in.Worker, &out.Worker + *out = new(PaymentsWorkerConfig) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PaymentsSpec. @@ -1613,6 +1896,41 @@ func (in *PaymentsStatus) DeepCopy() *PaymentsStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PaymentsWorkerConfig) DeepCopyInto(out *PaymentsWorkerConfig) { + *out = *in + if in.TemporalMaxConcurrentWorkflowTaskPollers != nil { + in, out := &in.TemporalMaxConcurrentWorkflowTaskPollers, &out.TemporalMaxConcurrentWorkflowTaskPollers + *out = new(int) + **out = **in + } + if in.TemporalMaxConcurrentActivityTaskPollers != nil { + in, out := &in.TemporalMaxConcurrentActivityTaskPollers, &out.TemporalMaxConcurrentActivityTaskPollers + *out = new(int) + **out = **in + } + if in.TemporalMaxSlotsPerPoller != nil { + in, out := &in.TemporalMaxSlotsPerPoller, &out.TemporalMaxSlotsPerPoller + *out = new(int) + **out = **in + } + if in.TemporalMaxLocalActivitySlots != nil { + in, out := &in.TemporalMaxLocalActivitySlots, &out.TemporalMaxLocalActivitySlots + *out = new(int) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PaymentsWorkerConfig. +func (in *PaymentsWorkerConfig) DeepCopy() *PaymentsWorkerConfig { + if in == nil { + return nil + } + out := new(PaymentsWorkerConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Reconciliation) DeepCopyInto(out *Reconciliation) { *out = *in @@ -1680,7 +1998,7 @@ func (in *ReconciliationSpec) DeepCopyInto(out *ReconciliationSpec) { if in.Auth != nil { in, out := &in.Auth, &out.Auth *out = new(AuthConfig) - **out = **in + (*in).DeepCopyInto(*out) } } @@ -1873,7 +2191,7 @@ func (in *SearchSpec) DeepCopyInto(out *SearchSpec) { if in.Auth != nil { in, out := &in.Auth, &out.Auth *out = new(AuthConfig) - **out = **in + (*in).DeepCopyInto(*out) } } @@ -2309,6 +2627,11 @@ func (in *TransactionPlaneSpec) DeepCopyInto(out *TransactionPlaneSpec) { if in.Auth != nil { in, out := &in.Auth, &out.Auth *out = new(AuthConfig) + (*in).DeepCopyInto(*out) + } + if in.WorkerEnabled != nil { + in, out := &in.WorkerEnabled, &out.WorkerEnabled + *out = new(bool) **out = **in } } @@ -2480,7 +2803,7 @@ func (in *WalletsSpec) DeepCopyInto(out *WalletsSpec) { if in.Auth != nil { in, out := &in.Auth, &out.Auth *out = new(AuthConfig) - **out = **in + (*in).DeepCopyInto(*out) } } @@ -2577,7 +2900,7 @@ func (in *WebhooksSpec) DeepCopyInto(out *WebhooksSpec) { if in.Auth != nil { in, out := &in.Auth, &out.Auth *out = new(AuthConfig) - **out = **in + (*in).DeepCopyInto(*out) } } diff --git a/config/crd/bases/formance.com_auths.yaml b/config/crd/bases/formance.com_auths.yaml index 93360ca5f..6d8c70c0b 100644 --- a/config/crd/bases/formance.com_auths.yaml +++ b/config/crd/bases/formance.com_auths.yaml @@ -126,6 +126,12 @@ spec: If not enabled, each service will check the authentication but will not restrict access following scopes. in this case, if authenticated, it is ok. type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the auth server should + advertise. + items: + type: string + type: array signingKey: description: Allow to override the default signing key used to sign JWT tokens. diff --git a/config/crd/bases/formance.com_gateways.yaml b/config/crd/bases/formance.com_gateways.yaml index aaf0f6acc..f3d127349 100644 --- a/config/crd/bases/formance.com_gateways.yaml +++ b/config/crd/bases/formance.com_gateways.yaml @@ -61,6 +61,26 @@ spec: type: object spec: properties: + caddyfile: + description: GatewayCaddyfileConfig holds Caddyfile-level tuning options. + properties: + gracePeriod: + type: string + shutdownDelay: + type: string + trustedProxies: + items: + type: string + type: array + trustedProxiesStrict: + type: boolean + type: object + config: + description: GatewayServerConfig holds HTTP server tuning options. + properties: + idleTimeout: + type: string + type: object debug: default: false description: Allow to enable debug mode on the module @@ -71,6 +91,40 @@ spec: Allow to enable dev mode on the module Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) type: boolean + dns: + items: + description: |- + GatewayDNSEndpoint configures a DNS endpoint managed by the gateway. + Name identifies the entry (e.g. "private", "public") and yields a + DNSEndpoint resource named "-". + properties: + annotations: + additionalProperties: + type: string + type: object + dnsNames: + items: + type: string + type: array + enabled: + type: boolean + name: + type: string + providerSpecific: + additionalProperties: + type: string + type: object + recordType: + default: CNAME + type: string + targets: + items: + type: string + type: array + required: + - name + type: object + type: array ingress: description: Allow to customize the generated ingress properties: @@ -92,6 +146,11 @@ spec: ingressClassName: description: Ingress class to use type: string + labels: + additionalProperties: + type: string + description: Custom labels to add on the ingress + type: object scheme: default: https description: |- diff --git a/config/crd/bases/formance.com_ledgers.yaml b/config/crd/bases/formance.com_ledgers.yaml index d2c3cf95e..275b4a0bf 100644 --- a/config/crd/bases/formance.com_ledgers.yaml +++ b/config/crd/bases/formance.com_ledgers.yaml @@ -61,10 +61,26 @@ spec: type: object spec: properties: + api: + description: LedgerAPIConfig configures the ledger HTTP API behavior. + properties: + bulkMaxSize: + type: integer + defaultPageSize: + type: integer + maxPageSize: + type: integer + type: object auth: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object @@ -78,6 +94,18 @@ spec: Allow to enable dev mode on the module Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) type: boolean + experimentalExporters: + type: boolean + experimentalFeatures: + type: boolean + experimentalNumscript: + type: boolean + experimentalNumscriptFlags: + items: + type: string + type: array + schemaEnforcementMode: + type: string stack: description: Stack indicates the stack on which the module is installed type: string @@ -85,6 +113,40 @@ spec: description: Version allow to override global version defined at stack level for a specific module type: string + worker: + description: LedgerWorkerConfig configures the ledger worker. + properties: + asyncBlockHasher: + description: LedgerAsyncBlockHasherConfig configures the worker + async block hasher. + properties: + maxBlockSize: + type: string + schedule: + type: string + type: object + bucketCleanup: + description: LedgerBucketCleanupConfig configures the worker bucket + cleanup. + properties: + retentionPeriod: + type: string + schedule: + type: string + type: object + pipelines: + description: LedgerPipelinesConfig configures the worker pipelines. + properties: + logsPageSize: + type: string + pullInterval: + type: string + pushRetryPeriod: + type: string + syncPeriod: + type: string + type: object + type: object type: object status: properties: diff --git a/config/crd/bases/formance.com_orchestrations.yaml b/config/crd/bases/formance.com_orchestrations.yaml index 6c92989e5..724c8335e 100644 --- a/config/crd/bases/formance.com_orchestrations.yaml +++ b/config/crd/bases/formance.com_orchestrations.yaml @@ -62,6 +62,12 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object @@ -75,6 +81,8 @@ spec: Allow to enable dev mode on the module Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) type: boolean + maxParallelActivities: + type: integer stack: description: Stack indicates the stack on which the module is installed type: string diff --git a/config/crd/bases/formance.com_payments.yaml b/config/crd/bases/formance.com_payments.yaml index 6dc457d84..bd29a2bbf 100644 --- a/config/crd/bases/formance.com_payments.yaml +++ b/config/crd/bases/formance.com_payments.yaml @@ -61,9 +61,20 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object + clearTemporal: + description: |- + ClearTemporal controls whether the Temporal namespace/schedule is + torn down when the resource is deleted. Defaults to true when unset. + type: boolean debug: default: false description: Allow to enable debug mode on the module @@ -83,6 +94,19 @@ spec: description: Version allow to override global version defined at stack level for a specific module type: string + worker: + description: PaymentsWorkerConfig configures the payments worker temporal + client. + properties: + temporalMaxConcurrentActivityTaskPollers: + type: integer + temporalMaxConcurrentWorkflowTaskPollers: + type: integer + temporalMaxLocalActivitySlots: + type: integer + temporalMaxSlotsPerPoller: + type: integer + type: object type: object status: properties: diff --git a/config/crd/bases/formance.com_reconciliations.yaml b/config/crd/bases/formance.com_reconciliations.yaml index 590dcc37f..57fe08c64 100644 --- a/config/crd/bases/formance.com_reconciliations.yaml +++ b/config/crd/bases/formance.com_reconciliations.yaml @@ -62,6 +62,12 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object diff --git a/config/crd/bases/formance.com_searches.yaml b/config/crd/bases/formance.com_searches.yaml index 770ae0899..a9478e1a8 100644 --- a/config/crd/bases/formance.com_searches.yaml +++ b/config/crd/bases/formance.com_searches.yaml @@ -62,6 +62,12 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object diff --git a/config/crd/bases/formance.com_transactionplanes.yaml b/config/crd/bases/formance.com_transactionplanes.yaml index 2ffa0043c..4764d7221 100644 --- a/config/crd/bases/formance.com_transactionplanes.yaml +++ b/config/crd/bases/formance.com_transactionplanes.yaml @@ -61,6 +61,12 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object @@ -81,6 +87,8 @@ spec: description: Version allow to override global version defined at stack level for a specific module type: string + workerEnabled: + type: boolean type: object status: properties: diff --git a/config/crd/bases/formance.com_wallets.yaml b/config/crd/bases/formance.com_wallets.yaml index 29173e53e..cf6408bea 100644 --- a/config/crd/bases/formance.com_wallets.yaml +++ b/config/crd/bases/formance.com_wallets.yaml @@ -62,6 +62,12 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object diff --git a/config/crd/bases/formance.com_webhooks.yaml b/config/crd/bases/formance.com_webhooks.yaml index 6aa0fc9e9..0cb14465b 100644 --- a/config/crd/bases/formance.com_webhooks.yaml +++ b/config/crd/bases/formance.com_webhooks.yaml @@ -62,6 +62,12 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object diff --git a/docs/09-Configuration reference/02-Custom Resource Definitions.md b/docs/09-Configuration reference/02-Custom Resource Definitions.md index 3d03b7035..aa54e1401 100644 --- a/docs/09-Configuration reference/02-Custom Resource Definitions.md +++ b/docs/09-Configuration reference/02-Custom Resource Definitions.md @@ -442,6 +442,7 @@ The auth service is basically a proxy to another OIDC compliant server. | `signingKey` _string_ | Allow to override the default signing key used to sign JWT tokens. | | | | `signingKeyFromSecret` _[SecretKeySelector](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#secretkeyselector-v1-core)_ | Allow to override the default signing key used to sign JWT tokens using a k8s secret | | | | `enableScopes` _boolean_ | Allow to enable scopes usage on authentication.
If not enabled, each service will check the authentication but will not restrict access following scopes.
in this case, if authenticated, it is ok. | false | | +| `issuers` _string array_ | Issuers lists the OIDC issuer URLs the auth server should advertise. | | | @@ -531,6 +532,9 @@ Gateway is the Schema for the gateways API | `dev` _boolean_ | Allow to enable dev mode on the module
Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) | false | | | `version` _string_ | Version allow to override global version defined at stack level for a specific module | | | | `ingress` _[GatewayIngress](#gatewayingress)_ | Allow to customize the generated ingress | | | +| `caddyfile` _[GatewayCaddyfileConfig](#gatewaycaddyfileconfig)_ | | | | +| `config` _[GatewayServerConfig](#gatewayserverconfig)_ | | | | +| `dns` _[GatewayDNSEndpoint](#gatewaydnsendpoint) array_ | | | | @@ -622,6 +626,13 @@ and maintains an immutable audit trail. | `dev` _boolean_ | Allow to enable dev mode on the module
Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) | false | | | `version` _string_ | Version allow to override global version defined at stack level for a specific module | | | | `stack` _string_ | Stack indicates the stack on which the module is installed | | | +| `experimentalFeatures` _boolean_ | | | | +| `experimentalNumscript` _boolean_ | | | | +| `experimentalNumscriptFlags` _string array_ | | | | +| `experimentalExporters` _boolean_ | | | | +| `schemaEnforcementMode` _string_ | | | | +| `api` _[LedgerAPIConfig](#ledgerapiconfig)_ | | | | +| `worker` _[LedgerWorkerConfig](#ledgerworkerconfig)_ | | | | @@ -799,6 +810,7 @@ Orchestration is the Schema for the orchestrations API | `debug` _boolean_ | Allow to enable debug mode on the module | false | | | `dev` _boolean_ | Allow to enable dev mode on the module
Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) | false | | | `version` _string_ | Version allow to override global version defined at stack level for a specific module | | | +| `maxParallelActivities` _integer_ | | | | @@ -888,6 +900,8 @@ Payments is the Schema for the payments API | `dev` _boolean_ | Allow to enable dev mode on the module
Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) | false | | | `version` _string_ | Version allow to override global version defined at stack level for a specific module | | | | `encryptionKey` _string_ | | | | +| `clearTemporal` _boolean_ | ClearTemporal controls whether the Temporal namespace/schedule is
torn down when the resource is deleted. Defaults to true when unset. | | | +| `worker` _[PaymentsWorkerConfig](#paymentsworkerconfig)_ | | | | @@ -1242,6 +1256,7 @@ TransactionPlane is the Schema for the transactionplanes API | `debug` _boolean_ | Allow to enable debug mode on the module | false | | | `dev` _boolean_ | Allow to enable dev mode on the module
Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) | false | | | `version` _string_ | Version allow to override global version defined at stack level for a specific module | | | +| `workerEnabled` _boolean_ | | | | diff --git a/docs/09-Configuration reference/settings.catalog.json b/docs/09-Configuration reference/settings.catalog.json index a4316ca86..b2e340afc 100644 --- a/docs/09-Configuration reference/settings.catalog.json +++ b/docs/09-Configuration reference/settings.catalog.json @@ -5,15 +5,7 @@ "key": "auth.\u003cmodule-name\u003e.check-scopes", "valueType": "bool", "sources": [ - "internal/resources/auths/env.go:79" - ] - }, - { - "key": "auth.issuers", - "valueType": "string", - "sources": [ - "internal/resources/auths/deployment.go:69", - "internal/resources/auths/env.go:34" + "internal/resources/auths/env.go:80" ] }, { @@ -191,53 +183,18 @@ "internal/resources/applications/application.go:357" ] }, - { - "key": "gateway.caddyfile.grace-period", - "valueType": "string", - "sources": [ - "internal/resources/gateways/configuration.go:41" - ] - }, - { - "key": "gateway.caddyfile.shutdown-delay", - "valueType": "string", - "sources": [ - "internal/resources/gateways/configuration.go:33" - ] - }, - { - "key": "gateway.caddyfile.trusted-proxies", - "valueType": "string[]", - "sources": [ - "internal/resources/gateways/configuration.go:17" - ] - }, - { - "key": "gateway.caddyfile.trusted-proxies-strict", - "valueType": "bool", - "sources": [ - "internal/resources/gateways/configuration.go:25" - ] - }, - { - "key": "gateway.config.idle-timeout", - "valueType": "string", - "sources": [ - "internal/resources/gateways/configuration.go:49" - ] - }, { "key": "gateway.dns.\u003cdns-type\u003e.annotations", "valueType": "map[string]string", "sources": [ - "internal/resources/gateways/dnsendpoints.go:58" + "internal/resources/gateways/dnsendpoints.go:86" ] }, { "key": "gateway.dns.\u003cdns-type\u003e.dns-names", "valueType": "string[]", "sources": [ - "internal/resources/gateways/dnsendpoints.go:37" + "internal/resources/gateways/dnsendpoints.go:65" ] }, { @@ -245,14 +202,14 @@ "valueType": "bool", "default": "false", "sources": [ - "internal/resources/gateways/dnsendpoints.go:28" + "internal/resources/gateways/dnsendpoints.go:54" ] }, { "key": "gateway.dns.\u003cdns-type\u003e.provider-specific", "valueType": "map[string]string", "sources": [ - "internal/resources/gateways/dnsendpoints.go:53" + "internal/resources/gateways/dnsendpoints.go:81" ] }, { @@ -260,49 +217,42 @@ "valueType": "string", "default": "CNAME", "sources": [ - "internal/resources/gateways/dnsendpoints.go:63" + "internal/resources/gateways/dnsendpoints.go:91" ] }, { "key": "gateway.dns.\u003cdns-type\u003e.targets", "valueType": "string[]", "sources": [ - "internal/resources/gateways/dnsendpoints.go:45" + "internal/resources/gateways/dnsendpoints.go:73" ] }, { "key": "gateway.ingress.annotations", "valueType": "map[string]string", "sources": [ - "internal/resources/gateways/ingress.go:17" - ] - }, - { - "key": "gateway.ingress.class", - "valueType": "string", - "sources": [ - "internal/resources/gateways/ingress.go:93" + "internal/resources/gateways/ingress.go:16" ] }, { "key": "gateway.ingress.hosts", "valueType": "string[]", "sources": [ - "internal/resources/gateways/ingress.go:54" + "internal/resources/gateways/ingress.go:67" ] }, { "key": "gateway.ingress.labels", "valueType": "map[string]string", "sources": [ - "internal/resources/gateways/ingress.go:39" + "internal/resources/gateways/ingress.go:42" ] }, { "key": "gateway.ingress.tls.enabled", "valueType": "bool", "sources": [ - "internal/resources/gateways/ingress.go:70" + "internal/resources/gateways/ingress.go:88" ] }, { @@ -362,64 +312,6 @@ "internal/resources/jobs/job.go:150" ] }, - { - "key": "ledger.api.bulk-max-size", - "valueType": "int", - "sources": [ - "internal/resources/ledgers/deployments.go:123" - ] - }, - { - "key": "ledger.api.default-page-size", - "valueType": "int", - "sources": [ - "internal/resources/ledgers/deployments.go:77" - ] - }, - { - "key": "ledger.api.max-page-size", - "valueType": "int", - "sources": [ - "internal/resources/ledgers/deployments.go:87" - ] - }, - { - "key": "ledger.experimental-exporters", - "valueType": "bool", - "sources": [ - "internal/resources/ledgers/deployments.go:149", - "internal/resources/ledgers/deployments.go:264" - ] - }, - { - "key": "ledger.experimental-features", - "valueType": "bool", - "sources": [ - "internal/resources/ledgers/deployments.go:49" - ] - }, - { - "key": "ledger.experimental-numscript", - "valueType": "bool", - "sources": [ - "internal/resources/ledgers/deployments.go:59" - ] - }, - { - "key": "ledger.experimental-numscript-flags", - "valueType": "string[]", - "sources": [ - "internal/resources/ledgers/deployments.go:69" - ] - }, - { - "key": "ledger.schema-enforcement-mode", - "valueType": "string", - "sources": [ - "internal/resources/ledgers/deployments.go:131", - "internal/resources/ledgers/deployments.go:239" - ] - }, { "key": "ledger.worker.async-block-hasher", "valueType": "object", @@ -435,7 +327,7 @@ } ], "sources": [ - "internal/resources/ledgers/deployments.go:209" + "internal/resources/ledgers/deployments.go:415" ] }, { @@ -453,7 +345,7 @@ } ], "sources": [ - "internal/resources/ledgers/deployments.go:248" + "internal/resources/ledgers/deployments.go:457" ] }, { @@ -479,7 +371,7 @@ } ], "sources": [ - "internal/resources/ledgers/deployments.go:221" + "internal/resources/ledgers/deployments.go:437" ] }, { @@ -557,60 +449,6 @@ "internal/resources/settings/opentelemetry.go:38" ] }, - { - "key": "orchestration.max-parallel-activities", - "valueType": "int", - "default": "10", - "sources": [ - "internal/resources/orchestrations/deployments.go:173" - ] - }, - { - "key": "payments.clear-temporal", - "valueType": "bool", - "sources": [ - "internal/resources/payments/finalizer.go:26" - ] - }, - { - "key": "payments.encryption-key", - "valueType": "string", - "sources": [ - "internal/resources/payments/deployments.go:31" - ] - }, - { - "key": "payments.worker.temporal-max-concurrent-activity-task-pollers", - "valueType": "int", - "default": "4", - "sources": [ - "internal/resources/payments/deployments.go:124" - ] - }, - { - "key": "payments.worker.temporal-max-concurrent-workflow-task-pollers", - "valueType": "int", - "default": "4", - "sources": [ - "internal/resources/payments/deployments.go:116" - ] - }, - { - "key": "payments.worker.temporal-max-local-activity-slots", - "valueType": "int", - "default": "50", - "sources": [ - "internal/resources/payments/deployments.go:140" - ] - }, - { - "key": "payments.worker.temporal-max-slots-per-poller", - "valueType": "int", - "default": "10", - "sources": [ - "internal/resources/payments/deployments.go:132" - ] - }, { "key": "postgres.\u003cmodule-name\u003e.uri", "valueType": "uri", @@ -651,7 +489,7 @@ "valueType": "uri", "sources": [ "internal/resources/orchestrations/deployments.go:80", - "internal/resources/payments/deployments.go:43" + "internal/resources/payments/deployments.go:40" ] }, { @@ -659,7 +497,7 @@ "valueType": "string", "sources": [ "internal/resources/orchestrations/deployments.go:124", - "internal/resources/payments/deployments.go:81" + "internal/resources/payments/deployments.go:78" ] }, { @@ -667,15 +505,7 @@ "valueType": "string", "sources": [ "internal/resources/orchestrations/deployments.go:129", - "internal/resources/payments/deployments.go:89" - ] - }, - { - "key": "transactionplane.worker-enabled", - "valueType": "bool", - "default": "false", - "sources": [ - "internal/resources/transactionplane/deployments.go:125" + "internal/resources/payments/deployments.go:86" ] } ] diff --git a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_auths.formance.com.yaml b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_auths.formance.com.yaml index 6b74d3f2f..2b49dab04 100644 --- a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_auths.formance.com.yaml +++ b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_auths.formance.com.yaml @@ -129,6 +129,12 @@ spec: If not enabled, each service will check the authentication but will not restrict access following scopes. in this case, if authenticated, it is ok. type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the auth server should + advertise. + items: + type: string + type: array signingKey: description: Allow to override the default signing key used to sign JWT tokens. diff --git a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_gateways.formance.com.yaml b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_gateways.formance.com.yaml index 91c103c20..159173531 100644 --- a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_gateways.formance.com.yaml +++ b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_gateways.formance.com.yaml @@ -64,6 +64,26 @@ spec: type: object spec: properties: + caddyfile: + description: GatewayCaddyfileConfig holds Caddyfile-level tuning options. + properties: + gracePeriod: + type: string + shutdownDelay: + type: string + trustedProxies: + items: + type: string + type: array + trustedProxiesStrict: + type: boolean + type: object + config: + description: GatewayServerConfig holds HTTP server tuning options. + properties: + idleTimeout: + type: string + type: object debug: default: false description: Allow to enable debug mode on the module @@ -74,6 +94,40 @@ spec: Allow to enable dev mode on the module Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) type: boolean + dns: + items: + description: |- + GatewayDNSEndpoint configures a DNS endpoint managed by the gateway. + Name identifies the entry (e.g. "private", "public") and yields a + DNSEndpoint resource named "-". + properties: + annotations: + additionalProperties: + type: string + type: object + dnsNames: + items: + type: string + type: array + enabled: + type: boolean + name: + type: string + providerSpecific: + additionalProperties: + type: string + type: object + recordType: + default: CNAME + type: string + targets: + items: + type: string + type: array + required: + - name + type: object + type: array ingress: description: Allow to customize the generated ingress properties: @@ -95,6 +149,11 @@ spec: ingressClassName: description: Ingress class to use type: string + labels: + additionalProperties: + type: string + description: Custom labels to add on the ingress + type: object scheme: default: https description: |- diff --git a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_ledgers.formance.com.yaml b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_ledgers.formance.com.yaml index 66cd05889..475cb14b3 100644 --- a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_ledgers.formance.com.yaml +++ b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_ledgers.formance.com.yaml @@ -64,10 +64,26 @@ spec: type: object spec: properties: + api: + description: LedgerAPIConfig configures the ledger HTTP API behavior. + properties: + bulkMaxSize: + type: integer + defaultPageSize: + type: integer + maxPageSize: + type: integer + type: object auth: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object @@ -81,6 +97,18 @@ spec: Allow to enable dev mode on the module Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) type: boolean + experimentalExporters: + type: boolean + experimentalFeatures: + type: boolean + experimentalNumscript: + type: boolean + experimentalNumscriptFlags: + items: + type: string + type: array + schemaEnforcementMode: + type: string stack: description: Stack indicates the stack on which the module is installed type: string @@ -88,6 +116,40 @@ spec: description: Version allow to override global version defined at stack level for a specific module type: string + worker: + description: LedgerWorkerConfig configures the ledger worker. + properties: + asyncBlockHasher: + description: LedgerAsyncBlockHasherConfig configures the worker + async block hasher. + properties: + maxBlockSize: + type: string + schedule: + type: string + type: object + bucketCleanup: + description: LedgerBucketCleanupConfig configures the worker bucket + cleanup. + properties: + retentionPeriod: + type: string + schedule: + type: string + type: object + pipelines: + description: LedgerPipelinesConfig configures the worker pipelines. + properties: + logsPageSize: + type: string + pullInterval: + type: string + pushRetryPeriod: + type: string + syncPeriod: + type: string + type: object + type: object type: object status: properties: diff --git a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_orchestrations.formance.com.yaml b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_orchestrations.formance.com.yaml index 590d1c406..b90b7fb48 100644 --- a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_orchestrations.formance.com.yaml +++ b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_orchestrations.formance.com.yaml @@ -65,6 +65,12 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object @@ -78,6 +84,8 @@ spec: Allow to enable dev mode on the module Dev mode is used to allow some application to do custom setup in development mode (allow insecure certificates for example) type: boolean + maxParallelActivities: + type: integer stack: description: Stack indicates the stack on which the module is installed type: string diff --git a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_payments.formance.com.yaml b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_payments.formance.com.yaml index cde937b92..8bb659ebe 100644 --- a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_payments.formance.com.yaml +++ b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_payments.formance.com.yaml @@ -64,9 +64,20 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object + clearTemporal: + description: |- + ClearTemporal controls whether the Temporal namespace/schedule is + torn down when the resource is deleted. Defaults to true when unset. + type: boolean debug: default: false description: Allow to enable debug mode on the module @@ -86,6 +97,19 @@ spec: description: Version allow to override global version defined at stack level for a specific module type: string + worker: + description: PaymentsWorkerConfig configures the payments worker temporal + client. + properties: + temporalMaxConcurrentActivityTaskPollers: + type: integer + temporalMaxConcurrentWorkflowTaskPollers: + type: integer + temporalMaxLocalActivitySlots: + type: integer + temporalMaxSlotsPerPoller: + type: integer + type: object type: object status: properties: diff --git a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_reconciliations.formance.com.yaml b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_reconciliations.formance.com.yaml index 69bcd631e..47c74a887 100644 --- a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_reconciliations.formance.com.yaml +++ b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_reconciliations.formance.com.yaml @@ -65,6 +65,12 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object diff --git a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_searches.formance.com.yaml b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_searches.formance.com.yaml index 85701a9c1..f2a4150c4 100644 --- a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_searches.formance.com.yaml +++ b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_searches.formance.com.yaml @@ -65,6 +65,12 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object diff --git a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_transactionplanes.formance.com.yaml b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_transactionplanes.formance.com.yaml index 3881fed1e..7e3a4501c 100644 --- a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_transactionplanes.formance.com.yaml +++ b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_transactionplanes.formance.com.yaml @@ -64,6 +64,12 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object @@ -84,6 +90,8 @@ spec: description: Version allow to override global version defined at stack level for a specific module type: string + workerEnabled: + type: boolean type: object status: properties: diff --git a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_wallets.formance.com.yaml b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_wallets.formance.com.yaml index 898582514..5bf049427 100644 --- a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_wallets.formance.com.yaml +++ b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_wallets.formance.com.yaml @@ -65,6 +65,12 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object diff --git a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_webhooks.formance.com.yaml b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_webhooks.formance.com.yaml index 872cca464..b5363ac98 100644 --- a/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_webhooks.formance.com.yaml +++ b/helm/crds/templates/crds/apiextensions.k8s.io_v1_customresourcedefinition_webhooks.formance.com.yaml @@ -65,6 +65,12 @@ spec: properties: checkScopes: type: boolean + issuers: + description: Issuers lists the OIDC issuer URLs the module should + trust. + items: + type: string + type: array readKeySetMaxRetries: type: integer type: object diff --git a/internal/resources/auths/deployment.go b/internal/resources/auths/deployment.go index 5b9f84e73..e9d6c9778 100644 --- a/internal/resources/auths/deployment.go +++ b/internal/resources/auths/deployment.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "encoding/json" "fmt" + "strings" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -66,7 +67,12 @@ func createDeployment(ctx Context, stack *v1beta1.Stack, auth *v1beta1.Auth, dat } env = append(env, Env("BASE_URL", authUrl)) - issuers, err := settings.GetStringOrEmpty(ctx, stack.Name, "auth", "issuers") + var issuersSpec string + if len(auth.Spec.Issuers) > 0 { + issuersSpec = strings.Join(auth.Spec.Issuers, ",") + } + issuers, err := settings.PreferSpecString(ctx, stack.Name, issuersSpec, + "Auth.Spec.Issuers", "auth", "issuers") if err != nil { return err } diff --git a/internal/resources/auths/env.go b/internal/resources/auths/env.go index c916694f7..7885cc7d1 100644 --- a/internal/resources/auths/env.go +++ b/internal/resources/auths/env.go @@ -2,6 +2,7 @@ package auths import ( "strconv" + "strings" v1 "k8s.io/api/core/v1" @@ -31,7 +32,7 @@ func ProtectedEnvVars(ctx Context, stack *v1beta1.Stack, moduleName string, auth Env("AUTH_ISSUER", url), ) - issuers, err := settings.GetStringOrEmpty(ctx, stack.Name, "auth", "issuers") + issuers, err := resolveIssuers(ctx, stack.Name, auth) if err != nil { return nil, err } @@ -83,8 +84,18 @@ func shouldCheckScopes(ctx Context, stackName, moduleName string, auth *v1beta1. // If Settings exists, use it if checkScopesFromSettings != nil { + settings.LogDeprecation(ctx, stackName, ".Spec.Auth.CheckScopes", "auth", moduleName, "check-scopes") return *checkScopesFromSettings, nil } return false, nil } + +// resolveIssuers returns the comma-separated list of trusted issuers, +// preferring Spec.Auth.Issuers over the stack-level auth.issuers setting. +func resolveIssuers(ctx Context, stackName string, auth *v1beta1.AuthConfig) (string, error) { + if auth != nil && len(auth.Issuers) > 0 { + return strings.Join(auth.Issuers, ","), nil + } + return settings.PreferSpecString(ctx, stackName, "", ".Spec.Auth.Issuers", "auth", "issuers") +} diff --git a/internal/resources/gateways/configuration.go b/internal/resources/gateways/configuration.go index 1902ad650..7ffa89909 100644 --- a/internal/resources/gateways/configuration.go +++ b/internal/resources/gateways/configuration.go @@ -1,6 +1,8 @@ package gateways import ( + "time" + v1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" @@ -14,7 +16,14 @@ func createConfigMap(ctx core.Context, stack *v1beta1.Stack, options := []CaddyOptions{} - trustedProxies, err := settings.GetStringSlice(ctx, stack.Name, "gateway", "caddyfile", "trusted-proxies") + caddyfileSpec := gateway.Spec.Caddyfile + + var trustedProxiesSpec []string + if caddyfileSpec != nil { + trustedProxiesSpec = caddyfileSpec.TrustedProxies + } + trustedProxies, err := settings.PreferSpecStringSlice(ctx, stack.Name, trustedProxiesSpec, + "Gateway.Spec.Caddyfile.TrustedProxies", "gateway", "caddyfile", "trusted-proxies") if err != nil { return nil, err } @@ -22,36 +31,56 @@ func createConfigMap(ctx core.Context, stack *v1beta1.Stack, options = append(options, withTrustedProxies(trustedProxies)) } - trustedProxiesStrict, err := settings.GetBool(ctx, stack.Name, "gateway", "caddyfile", "trusted-proxies-strict") + var trustedProxiesStrictSpec *bool + if caddyfileSpec != nil { + trustedProxiesStrictSpec = caddyfileSpec.TrustedProxiesStrict + } + trustedProxiesStrict, err := settings.PreferSpecBool(ctx, stack.Name, trustedProxiesStrictSpec, + "Gateway.Spec.Caddyfile.TrustedProxiesStrict", "gateway", "caddyfile", "trusted-proxies-strict") if err != nil { return nil, err } - if trustedProxiesStrict != nil && *trustedProxiesStrict { + if trustedProxiesStrict { options = append(options, withTrustedProxiesStrict()) } - shutdownDelay, err := settings.GetDuration(ctx, stack.Name, "gateway", "caddyfile", "shutdown-delay") + var shutdownDelaySpec time.Duration + if caddyfileSpec != nil && caddyfileSpec.ShutdownDelay != nil { + shutdownDelaySpec = caddyfileSpec.ShutdownDelay.Duration + } + shutdownDelay, err := settings.PreferSpecDuration(ctx, stack.Name, shutdownDelaySpec, 0, + "Gateway.Spec.Caddyfile.ShutdownDelay", "gateway", "caddyfile", "shutdown-delay") if err != nil { return nil, err } - if shutdownDelay != nil { - options = append(options, withShutdownDelay(*shutdownDelay)) + if shutdownDelay != 0 { + options = append(options, withShutdownDelay(shutdownDelay)) } - gracePeriod, err := settings.GetDuration(ctx, stack.Name, "gateway", "caddyfile", "grace-period") + var gracePeriodSpec time.Duration + if caddyfileSpec != nil && caddyfileSpec.GracePeriod != nil { + gracePeriodSpec = caddyfileSpec.GracePeriod.Duration + } + gracePeriod, err := settings.PreferSpecDuration(ctx, stack.Name, gracePeriodSpec, 0, + "Gateway.Spec.Caddyfile.GracePeriod", "gateway", "caddyfile", "grace-period") if err != nil { return nil, err } - if gracePeriod != nil { - options = append(options, withGracePeriod(*gracePeriod)) + if gracePeriod != 0 { + options = append(options, withGracePeriod(gracePeriod)) } - idleTimeout, err := settings.GetDuration(ctx, stack.Name, "gateway", "config", "idle-timeout") + var idleTimeoutSpec time.Duration + if gateway.Spec.Config != nil && gateway.Spec.Config.IdleTimeout != nil { + idleTimeoutSpec = gateway.Spec.Config.IdleTimeout.Duration + } + idleTimeout, err := settings.PreferSpecDuration(ctx, stack.Name, idleTimeoutSpec, 0, + "Gateway.Spec.Config.IdleTimeout", "gateway", "config", "idle-timeout") if err != nil { return nil, err } - if idleTimeout != nil { - options = append(options, withIdleTimeout(*idleTimeout)) + if idleTimeout != 0 { + options = append(options, withIdleTimeout(idleTimeout)) } caddyfile, err := CreateCaddyfile(ctx, stack, gateway, httpAPIs, broker, options...) diff --git a/internal/resources/gateways/dnsendpoints.go b/internal/resources/gateways/dnsendpoints.go index af8ba40bd..dfbb94561 100644 --- a/internal/resources/gateways/dnsendpoints.go +++ b/internal/resources/gateways/dnsendpoints.go @@ -24,7 +24,33 @@ type DNSConfig struct { RecordType string } -func getDNSConfig(ctx core.Context, stack string, dnsType string) (*DNSConfig, error) { +func getDNSConfig(ctx core.Context, gateway *v1beta1.Gateway, dnsType string) (*DNSConfig, error) { + stack := gateway.Spec.Stack + + if spec := gateway.Spec.FindDNSEndpoint(dnsType); spec != nil { + if spec.Enabled == nil || !*spec.Enabled { + return nil, nil + } + if len(spec.DNSNames) == 0 { + return nil, fmt.Errorf("Gateway.Spec.DNS[%q].dnsNames is required when enabled is true", dnsType) + } + if len(spec.Targets) == 0 { + return nil, fmt.Errorf("Gateway.Spec.DNS[%q].targets is required when enabled is true", dnsType) + } + recordType := spec.RecordType + if recordType == "" { + recordType = "CNAME" + } + return &DNSConfig{ + Enabled: true, + DNSPatterns: spec.DNSNames, + Targets: spec.Targets, + ProviderSpec: spec.ProviderSpecific, + Annotations: spec.Annotations, + RecordType: recordType, + }, nil + } + enabled, err := settings.GetBoolOrDefault(ctx, stack, false, "gateway", "dns", dnsType, "enabled") if err != nil { return nil, err @@ -34,6 +60,8 @@ func getDNSConfig(ctx core.Context, stack string, dnsType string) (*DNSConfig, e return nil, nil } + settings.LogDeprecation(ctx, stack, "Gateway.Spec.DNS", "gateway", "dns", dnsType, "*") + dnsNames, err := settings.GetTrimmedStringSlice(ctx, stack, "gateway", "dns", dnsType, "dns-names") if err != nil { return nil, err @@ -133,12 +161,12 @@ func createDNSEndpoint(ctx core.Context, gateway v1beta1.Dependent, dnsType stri return err } -func reconcileDNSEndpoints(ctx core.Context, gateway v1beta1.Dependent) error { +func reconcileDNSEndpoints(ctx core.Context, gateway *v1beta1.Gateway) error { stackName := gateway.GetStack() gatewayName := gateway.GetName() // Handle private DNS endpoint - privateConfig, err := getDNSConfig(ctx, stackName, "private") + privateConfig, err := getDNSConfig(ctx, gateway, "private") if err != nil { return err } @@ -154,7 +182,7 @@ func reconcileDNSEndpoints(ctx core.Context, gateway v1beta1.Dependent) error { } // Handle public DNS endpoint - publicConfig, err := getDNSConfig(ctx, stackName, "public") + publicConfig, err := getDNSConfig(ctx, gateway, "public") if err != nil { return err } diff --git a/internal/resources/gateways/ingress.go b/internal/resources/gateways/ingress.go index 9be299199..480908c1a 100644 --- a/internal/resources/gateways/ingress.go +++ b/internal/resources/gateways/ingress.go @@ -5,7 +5,6 @@ import ( v1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/types" - "sigs.k8s.io/controller-runtime/pkg/client" "github.com/formancehq/operator/v3/api/formance.com/v1beta1" "github.com/formancehq/operator/v3/internal/core" @@ -18,10 +17,14 @@ func withAnnotations(ctx core.Context, stack *v1beta1.Stack, gateway *v1beta1.Ga if err != nil { return err } + if len(annotations) > 0 { + settings.LogDeprecation(ctx, stack.Name, "Gateway.Spec.Ingress.Annotations", + "gateway", "ingress", "annotations") + } if annotations == nil { annotations = map[string]string{} } - + // Spec annotations win on key collision. if gateway.Spec.Ingress.Annotations != nil { for k, v := range gateway.Spec.Ingress.Annotations { annotations[k] = v @@ -34,15 +37,25 @@ func withAnnotations(ctx core.Context, stack *v1beta1.Stack, gateway *v1beta1.Ga } } -func withLabels(ctx core.Context, stack *v1beta1.Stack, owner client.Object) core.ObjectMutator[*v1.Ingress] { +func withLabels(ctx core.Context, stack *v1beta1.Stack, gateway *v1beta1.Gateway) core.ObjectMutator[*v1.Ingress] { return func(t *v1.Ingress) error { labels, err := settings.GetMap(ctx, stack.Name, "gateway", "ingress", "labels") if err != nil { return err } + if len(labels) > 0 { + settings.LogDeprecation(ctx, stack.Name, "Gateway.Spec.Ingress.Labels", + "gateway", "ingress", "labels") + } if labels == nil { labels = map[string]string{} } + // Spec labels win on key collision. + if gateway.Spec.Ingress != nil { + for k, v := range gateway.Spec.Ingress.Labels { + labels[k] = v + } + } labels["app.kubernetes.io/component"] = "gateway" labels["app.kubernetes.io/name"] = stack.Name t.SetLabels(labels) @@ -56,6 +69,11 @@ func getAllHosts(ctx core.Context, gateway *v1beta1.Gateway) ([]string, error) { return nil, err } + if len(settingsHosts) > 0 { + settings.LogDeprecation(ctx, gateway.Spec.Stack, "Gateway.Spec.Ingress.Hosts", + "gateway", "ingress", "hosts") + } + for i, h := range settingsHosts { settingsHosts[i] = strings.ReplaceAll(h, "{stack}", gateway.Spec.Stack) } @@ -67,13 +85,15 @@ func withTls(ctx core.Context, gateway *v1beta1.Gateway, hosts []string) core.Ob return func(t *v1.Ingress) error { var secretName string if gateway.Spec.Ingress.TLS == nil { - tlsEnabled, err := settings.GetBoolOrFalse(ctx, gateway.Spec.Stack, "gateway", "ingress", "tls", "enabled") + tlsEnabled, err := settings.GetBool(ctx, gateway.Spec.Stack, "gateway", "ingress", "tls", "enabled") if err != nil { return err } - if !tlsEnabled { + if tlsEnabled == nil || !*tlsEnabled { return nil } + settings.LogDeprecation(ctx, gateway.Spec.Stack, "Gateway.Spec.Ingress.TLS", + "gateway", "ingress", "tls", "enabled") secretName = gateway.Name + "-tls" } else { secretName = gateway.Spec.Ingress.TLS.SecretName @@ -90,18 +110,18 @@ func withTls(ctx core.Context, gateway *v1beta1.Gateway, hosts []string) core.Ob func withIngressClassName(ctx core.Context, stack *v1beta1.Stack, gateway *v1beta1.Gateway) core.ObjectMutator[*v1.Ingress] { return func(t *v1.Ingress) error { - ingressClassName, err := settings.GetString(ctx, stack.Name, "gateway", "ingress", "class") + var specClass string + if gateway.Spec.Ingress.IngressClassName != nil { + specClass = *gateway.Spec.Ingress.IngressClassName + } + ingressClassName, err := settings.PreferSpecString(ctx, stack.Name, specClass, + "Gateway.Spec.Ingress.IngressClassName", "gateway", "ingress", "class") if err != nil { return err } - if gateway.Spec.Ingress.IngressClassName != nil { - t.Spec.IngressClassName = gateway.Spec.Ingress.IngressClassName - return nil - } - - if ingressClassName != nil { - t.Spec.IngressClassName = ingressClassName + if ingressClassName != "" { + t.Spec.IngressClassName = &ingressClassName } return nil diff --git a/internal/resources/ledgers/deployments.go b/internal/resources/ledgers/deployments.go index 2e6249c30..facc0f267 100644 --- a/internal/resources/ledgers/deployments.go +++ b/internal/resources/ledgers/deployments.go @@ -46,7 +46,8 @@ func installLedgerStateless(ctx core.Context, stack *v1beta1.Stack, ledger *v1be core.Env("BIND", ":8080"), ) - experimentalFeatures, err := settings.GetBoolOrFalse(ctx, stack.Name, "ledger", "experimental-features") + experimentalFeatures, err := settings.PreferSpecBool(ctx, stack.Name, ledger.Spec.ExperimentalFeatures, + "Ledger.Spec.ExperimentalFeatures", "ledger", "experimental-features") if err != nil { return fmt.Errorf("failed to get experimental features: %w", err) } @@ -56,7 +57,8 @@ func installLedgerStateless(ctx core.Context, stack *v1beta1.Stack, ledger *v1be ) } - experimentalNumscript, err := settings.GetBoolOrFalse(ctx, stack.Name, "ledger", "experimental-numscript") + experimentalNumscript, err := settings.PreferSpecBool(ctx, stack.Name, ledger.Spec.ExperimentalNumscript, + "Ledger.Spec.ExperimentalNumscript", "ledger", "experimental-numscript") if err != nil { return fmt.Errorf("failed to get experimental numscript: %w", err) } @@ -66,7 +68,8 @@ func installLedgerStateless(ctx core.Context, stack *v1beta1.Stack, ledger *v1be ) } - experimentalNumscriptFlags, err := settings.GetStringSlice(ctx, stack.Name, "ledger", "experimental-numscript-flags") + experimentalNumscriptFlags, err := settings.PreferSpecStringSlice(ctx, stack.Name, ledger.Spec.ExperimentalNumscriptFlags, + "Ledger.Spec.ExperimentalNumscriptFlags", "ledger", "experimental-numscript-flags") if err != nil { return fmt.Errorf("failed to get experimental numscript: %w", err) } @@ -74,7 +77,8 @@ func installLedgerStateless(ctx core.Context, stack *v1beta1.Stack, ledger *v1be container.Env = append(container.Env, core.Env("EXPERIMENTAL_NUMSCRIPT_INTERPRETER_FLAGS", strings.Join(experimentalNumscriptFlags, " "))) } - defaultPageSize, err := settings.GetInt(ctx, stack.Name, "ledger", "api", "default-page-size") + defaultPageSize, err := settings.PreferSpecInt(ctx, stack.Name, ledgerAPIField(ledger, func(a *v1beta1.LedgerAPIConfig) *int { return a.DefaultPageSize }), + "Ledger.Spec.API.DefaultPageSize", "ledger", "api", "default-page-size") if err != nil { return fmt.Errorf("failed to get default page size: %w", err) } @@ -84,7 +88,8 @@ func installLedgerStateless(ctx core.Context, stack *v1beta1.Stack, ledger *v1be ) } - maxPageSize, err := settings.GetInt(ctx, stack.Name, "ledger", "api", "max-page-size") + maxPageSize, err := settings.PreferSpecInt(ctx, stack.Name, ledgerAPIField(ledger, func(a *v1beta1.LedgerAPIConfig) *int { return a.MaxPageSize }), + "Ledger.Spec.API.MaxPageSize", "ledger", "api", "max-page-size") if err != nil { return fmt.Errorf("failed to get max page size: %w", err) } @@ -120,7 +125,8 @@ func installLedgerStateless(ctx core.Context, stack *v1beta1.Stack, ledger *v1be container.Env = append(container.Env, brokers.GetPublisherEnvVars(stack, broker, "ledger")...) } - bulkMaxSize, err := settings.GetInt(ctx, stack.Name, "ledger", "api", "bulk-max-size") + bulkMaxSize, err := settings.PreferSpecInt(ctx, stack.Name, ledgerAPIField(ledger, func(a *v1beta1.LedgerAPIConfig) *int { return a.BulkMaxSize }), + "Ledger.Spec.API.BulkMaxSize", "ledger", "api", "bulk-max-size") if err != nil { return err } @@ -128,7 +134,8 @@ func installLedgerStateless(ctx core.Context, stack *v1beta1.Stack, ledger *v1be container.Env = append(container.Env, core.Env("BULK_MAX_SIZE", fmt.Sprint(*bulkMaxSize))) } - schemaEnforcementMode, err := settings.GetStringOrEmpty(ctx, stack.Name, "ledger", "schema-enforcement-mode") + schemaEnforcementMode, err := settings.PreferSpecString(ctx, stack.Name, ledger.Spec.SchemaEnforcementMode, + "Ledger.Spec.SchemaEnforcementMode", "ledger", "schema-enforcement-mode") if err != nil { return err } @@ -146,7 +153,8 @@ func installLedgerStateless(ctx core.Context, stack *v1beta1.Stack, ledger *v1be return err } - exportersEnabled, err := settings.GetBoolOrFalse(ctx, stack.Name, "ledger", "experimental-exporters") + exportersEnabled, err := settings.PreferSpecBool(ctx, stack.Name, ledger.Spec.ExperimentalExporters, + "Ledger.Spec.ExperimentalExporters", "ledger", "experimental-exporters") if err != nil { return fmt.Errorf("failed to get experimental exporters setting: %w", err) } @@ -206,7 +214,7 @@ func installLedgerWorker(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1 } // Async block hasher settings - asyncBlockHasher, err := settings.GetAs[asyncBlockHasherConfiguration](ctx, stack.Name, "ledger", "worker", "async-block-hasher") + asyncBlockHasher, err := resolveAsyncBlockHasher(ctx, stack.Name, ledger) if err != nil { return err } @@ -218,7 +226,7 @@ func installLedgerWorker(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1 } // Pipelines settings - pipelines, err := settings.GetAs[pipelinesConfiguration](ctx, stack.Name, "ledger", "worker", "pipelines") + pipelines, err := resolvePipelines(ctx, stack.Name, ledger) if err != nil { return err } @@ -236,7 +244,8 @@ func installLedgerWorker(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1 } // Schema enforcement mode - schemaEnforcementMode, err := settings.GetStringOrEmpty(ctx, stack.Name, "ledger", "schema-enforcement-mode") + schemaEnforcementMode, err := settings.PreferSpecString(ctx, stack.Name, ledger.Spec.SchemaEnforcementMode, + "Ledger.Spec.SchemaEnforcementMode", "ledger", "schema-enforcement-mode") if err != nil { return err } @@ -245,7 +254,7 @@ func installLedgerWorker(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1 } // Bucket cleanup settings - bucketCleanup, err := settings.GetAs[bucketCleanupConfiguration](ctx, stack.Name, "ledger", "worker", "bucket-cleanup") + bucketCleanup, err := resolveBucketCleanup(ctx, stack.Name, ledger) if err != nil { return err } @@ -261,7 +270,8 @@ func installLedgerWorker(ctx core.Context, stack *v1beta1.Stack, ledger *v1beta1 return err } - exportersEnabled, err := settings.GetBoolOrFalse(ctx, stack.Name, "ledger", "experimental-exporters") + exportersEnabled, err := settings.PreferSpecBool(ctx, stack.Name, ledger.Spec.ExperimentalExporters, + "Ledger.Spec.ExperimentalExporters", "ledger", "experimental-exporters") if err != nil { return fmt.Errorf("failed to get experimental exporters setting: %w", err) } @@ -386,3 +396,73 @@ func setCommonAPIContainerConfiguration(ctx core.Context, stack *v1beta1.Stack, return nil } + +// ledgerAPIField safely returns a field of Spec.API, or nil when API is unset. +func ledgerAPIField(ledger *v1beta1.Ledger, pick func(*v1beta1.LedgerAPIConfig) *int) *int { + if ledger.Spec.API == nil { + return nil + } + return pick(ledger.Spec.API) +} + +func resolveAsyncBlockHasher(ctx core.Context, stack string, ledger *v1beta1.Ledger) (asyncBlockHasherConfiguration, error) { + if ledger.Spec.Worker != nil && ledger.Spec.Worker.AsyncBlockHasher != nil { + return asyncBlockHasherConfiguration{ + MaxBlockSize: ledger.Spec.Worker.AsyncBlockHasher.MaxBlockSize, + Schedule: ledger.Spec.Worker.AsyncBlockHasher.Schedule, + }, nil + } + value, err := settings.GetAs[asyncBlockHasherConfiguration](ctx, stack, "ledger", "worker", "async-block-hasher") + if err != nil { + return asyncBlockHasherConfiguration{}, err + } + if value == nil { + return asyncBlockHasherConfiguration{}, nil + } + if value.MaxBlockSize != "" || value.Schedule != "" { + settings.LogDeprecation(ctx, stack, "Ledger.Spec.Worker.AsyncBlockHasher", "ledger", "worker", "async-block-hasher") + } + return *value, nil +} + +func resolvePipelines(ctx core.Context, stack string, ledger *v1beta1.Ledger) (pipelinesConfiguration, error) { + if ledger.Spec.Worker != nil && ledger.Spec.Worker.Pipelines != nil { + return pipelinesConfiguration{ + PullInterval: ledger.Spec.Worker.Pipelines.PullInterval, + PushRetryPeriod: ledger.Spec.Worker.Pipelines.PushRetryPeriod, + SyncPeriod: ledger.Spec.Worker.Pipelines.SyncPeriod, + LogsPageSize: ledger.Spec.Worker.Pipelines.LogsPageSize, + }, nil + } + value, err := settings.GetAs[pipelinesConfiguration](ctx, stack, "ledger", "worker", "pipelines") + if err != nil { + return pipelinesConfiguration{}, err + } + if value == nil { + return pipelinesConfiguration{}, nil + } + if value.PullInterval != "" || value.PushRetryPeriod != "" || value.SyncPeriod != "" || value.LogsPageSize != "" { + settings.LogDeprecation(ctx, stack, "Ledger.Spec.Worker.Pipelines", "ledger", "worker", "pipelines") + } + return *value, nil +} + +func resolveBucketCleanup(ctx core.Context, stack string, ledger *v1beta1.Ledger) (bucketCleanupConfiguration, error) { + if ledger.Spec.Worker != nil && ledger.Spec.Worker.BucketCleanup != nil { + return bucketCleanupConfiguration{ + RetentionPeriod: ledger.Spec.Worker.BucketCleanup.RetentionPeriod, + Schedule: ledger.Spec.Worker.BucketCleanup.Schedule, + }, nil + } + value, err := settings.GetAs[bucketCleanupConfiguration](ctx, stack, "ledger", "worker", "bucket-cleanup") + if err != nil { + return bucketCleanupConfiguration{}, err + } + if value == nil { + return bucketCleanupConfiguration{}, nil + } + if value.RetentionPeriod != "" || value.Schedule != "" { + settings.LogDeprecation(ctx, stack, "Ledger.Spec.Worker.BucketCleanup", "ledger", "worker", "bucket-cleanup") + } + return *value, nil +} diff --git a/internal/resources/orchestrations/deployments.go b/internal/resources/orchestrations/deployments.go index 633779ffe..e289b8a58 100644 --- a/internal/resources/orchestrations/deployments.go +++ b/internal/resources/orchestrations/deployments.go @@ -170,7 +170,8 @@ func createDeployment( annotations["database-secret-hash"] = temporalSecretResourceReference.Status.Hash } - maxParallelActivities, err := settings.GetIntOrDefault(ctx, stack.Name, 10, "orchestration", "max-parallel-activities") + maxParallelActivities, err := settings.PreferSpecIntOrDefault(ctx, stack.Name, orchestration.Spec.MaxParallelActivities, 10, + "Orchestration.Spec.MaxParallelActivities", "orchestration", "max-parallel-activities") if err != nil { return err } diff --git a/internal/resources/payments/deployments.go b/internal/resources/payments/deployments.go index 1cb54db65..283dc1ca2 100644 --- a/internal/resources/payments/deployments.go +++ b/internal/resources/payments/deployments.go @@ -26,11 +26,8 @@ import ( ) func getEncryptionKey(ctx core.Context, payments *v1beta1.Payments) (string, error) { - encryptionKey := payments.Spec.EncryptionKey - if encryptionKey == "" { - return settings.GetStringOrEmpty(ctx, payments.Spec.Stack, "payments", "encryption-key") - } - return "", nil + return settings.PreferSpecString(ctx, payments.Spec.Stack, payments.Spec.EncryptionKey, + "Payments.Spec.EncryptionKey", "payments", "encryption-key") } func temporalEnvVars(ctx core.Context, stack *v1beta1.Stack, payments *v1beta1.Payments) (hash map[string]string, env []corev1.EnvVar, err error) { @@ -113,7 +110,9 @@ func temporalEnvVars(ctx core.Context, stack *v1beta1.Stack, payments *v1beta1.P } var value int - value, err = settings.GetIntOrDefault(ctx, stack.Name, 4, "payments", "worker", "temporal-max-concurrent-workflow-task-pollers") + value, err = settings.PreferSpecIntOrDefault(ctx, stack.Name, paymentsWorkerField(payments, func(w *v1beta1.PaymentsWorkerConfig) *int { return w.TemporalMaxConcurrentWorkflowTaskPollers }), + 4, "Payments.Spec.Worker.TemporalMaxConcurrentWorkflowTaskPollers", + "payments", "worker", "temporal-max-concurrent-workflow-task-pollers") if err != nil { return } @@ -121,7 +120,9 @@ func temporalEnvVars(ctx core.Context, stack *v1beta1.Stack, payments *v1beta1.P core.Env("TEMPORAL_MAX_CONCURRENT_WORKFLOW_TASK_POLLERS", fmt.Sprintf("%d", value)), ) - value, err = settings.GetIntOrDefault(ctx, stack.Name, 4, "payments", "worker", "temporal-max-concurrent-activity-task-pollers") + value, err = settings.PreferSpecIntOrDefault(ctx, stack.Name, paymentsWorkerField(payments, func(w *v1beta1.PaymentsWorkerConfig) *int { return w.TemporalMaxConcurrentActivityTaskPollers }), + 4, "Payments.Spec.Worker.TemporalMaxConcurrentActivityTaskPollers", + "payments", "worker", "temporal-max-concurrent-activity-task-pollers") if err != nil { return } @@ -129,7 +130,9 @@ func temporalEnvVars(ctx core.Context, stack *v1beta1.Stack, payments *v1beta1.P core.Env("TEMPORAL_MAX_CONCURRENT_ACTIVITY_TASK_POLLERS", fmt.Sprintf("%d", value)), ) - value, err = settings.GetIntOrDefault(ctx, stack.Name, 10, "payments", "worker", "temporal-max-slots-per-poller") + value, err = settings.PreferSpecIntOrDefault(ctx, stack.Name, paymentsWorkerField(payments, func(w *v1beta1.PaymentsWorkerConfig) *int { return w.TemporalMaxSlotsPerPoller }), + 10, "Payments.Spec.Worker.TemporalMaxSlotsPerPoller", + "payments", "worker", "temporal-max-slots-per-poller") if err != nil { return } @@ -137,7 +140,9 @@ func temporalEnvVars(ctx core.Context, stack *v1beta1.Stack, payments *v1beta1.P core.Env("TEMPORAL_MAX_SLOTS_PER_POLLER", fmt.Sprintf("%d", value)), ) - value, err = settings.GetIntOrDefault(ctx, stack.Name, 50, "payments", "worker", "temporal-max-local-activity-slots") + value, err = settings.PreferSpecIntOrDefault(ctx, stack.Name, paymentsWorkerField(payments, func(w *v1beta1.PaymentsWorkerConfig) *int { return w.TemporalMaxLocalActivitySlots }), + 50, "Payments.Spec.Worker.TemporalMaxLocalActivitySlots", + "payments", "worker", "temporal-max-local-activity-slots") if err != nil { return } @@ -560,6 +565,14 @@ func createGateway(ctx core.Context, stack *v1beta1.Stack, p *v1beta1.Payments) Install(ctx) } +// paymentsWorkerField safely returns a field of Spec.Worker, or nil when Worker is unset. +func paymentsWorkerField(payments *v1beta1.Payments, pick func(*v1beta1.PaymentsWorkerConfig) *int) *int { + if payments.Spec.Worker == nil { + return nil + } + return pick(payments.Spec.Worker) +} + func validateTemporalURI(temporalURI *v1beta1.URI) error { if temporalURI.Scheme != "temporal" { return fmt.Errorf("invalid temporal uri: %s", temporalURI.String()) diff --git a/internal/resources/payments/finalizer.go b/internal/resources/payments/finalizer.go index e54b271d2..373db9e38 100644 --- a/internal/resources/payments/finalizer.go +++ b/internal/resources/payments/finalizer.go @@ -23,7 +23,8 @@ func Clean(ctx core.Context, t *v1beta1.Payments) error { return err } - clearTemporal, err := settings.GetBoolOrTrue(ctx, stack.Name, "payments", "clear-temporal") + clearTemporal, err := settings.PreferSpecBoolOrDefault(ctx, stack.Name, t.Spec.ClearTemporal, true, + "Payments.Spec.ClearTemporal", "payments", "clear-temporal") if err != nil { return err } diff --git a/internal/resources/settings/dual_read.go b/internal/resources/settings/dual_read.go new file mode 100644 index 000000000..0a9f9512f --- /dev/null +++ b/internal/resources/settings/dual_read.go @@ -0,0 +1,166 @@ +package settings + +import ( + "strings" + "time" + + "sigs.k8s.io/controller-runtime/pkg/log" + + "github.com/formancehq/operator/v3/internal/core" +) + +// Dual-read helpers preferring CRD spec values over Settings. +// +// The Settings system historically held module-specific tuning knobs (ledger +// experimental flags, payments worker tunings, gateway configuration, …). +// These have been moved to typed fields on the corresponding module CRDs. +// To allow a smooth migration, the PreferSpec* helpers below first inspect +// the spec value; only when it is zero do they fall back to a Settings +// lookup and emit a deprecation warning. + +func LogDeprecation(ctx core.Context, stack, replacement string, keys ...string) { + log.FromContext(ctx).Info( + "DEPRECATION: settings key is deprecated, move the value to the module spec", + "stack", stack, + "key", strings.Join(keys, "."), + "replacement", replacement, + ) +} + +// PreferSpecBool returns the dereferenced spec value when non-nil. Otherwise +// it falls back to the boolean setting at keys, returning false if unset. +// replacement is the CRD spec field path quoted in the deprecation log +// (e.g. "Ledger.Spec.ExperimentalFeatures"). +func PreferSpecBool(ctx core.Context, stack string, specVal *bool, replacement string, keys ...string) (bool, error) { + if specVal != nil { + return *specVal, nil + } + value, err := GetBool(ctx, stack, keys...) + if err != nil { + return false, err + } + if value == nil { + return false, nil + } + LogDeprecation(ctx, stack, replacement, keys...) + return *value, nil +} + +// PreferSpecBoolOrDefault is the variant returning a custom default when +// neither the spec nor the setting is set. +func PreferSpecBoolOrDefault(ctx core.Context, stack string, specVal *bool, defaultValue bool, replacement string, keys ...string) (bool, error) { + if specVal != nil { + return *specVal, nil + } + value, err := GetBool(ctx, stack, keys...) + if err != nil { + return false, err + } + if value == nil { + return defaultValue, nil + } + LogDeprecation(ctx, stack, replacement, keys...) + return *value, nil +} + +// PreferSpecInt returns the dereferenced spec value when non-nil. Otherwise +// it falls back to the int setting at keys (returns nil if unset). +func PreferSpecInt(ctx core.Context, stack string, specVal *int, replacement string, keys ...string) (*int, error) { + if specVal != nil { + return specVal, nil + } + value, err := GetInt(ctx, stack, keys...) + if err != nil { + return nil, err + } + if value == nil { + return nil, nil + } + LogDeprecation(ctx, stack, replacement, keys...) + return value, nil +} + +// PreferSpecIntOrDefault is the variant returning a custom default when +// neither the spec nor the setting is set. +func PreferSpecIntOrDefault(ctx core.Context, stack string, specVal *int, defaultValue int, replacement string, keys ...string) (int, error) { + if specVal != nil { + return *specVal, nil + } + value, err := GetInt(ctx, stack, keys...) + if err != nil { + return 0, err + } + if value == nil { + return defaultValue, nil + } + LogDeprecation(ctx, stack, replacement, keys...) + return *value, nil +} + +// PreferSpecString returns the spec value when non-empty. Otherwise it falls +// back to the string setting at keys, returning the empty string if unset. +func PreferSpecString(ctx core.Context, stack string, specVal string, replacement string, keys ...string) (string, error) { + if specVal != "" { + return specVal, nil + } + value, err := GetString(ctx, stack, keys...) + if err != nil { + return "", err + } + if value == nil { + return "", nil + } + LogDeprecation(ctx, stack, replacement, keys...) + return *value, nil +} + +// PreferSpecStringSlice returns the spec value when non-empty. Otherwise it +// falls back to the comma-separated string setting at keys. +func PreferSpecStringSlice(ctx core.Context, stack string, specVal []string, replacement string, keys ...string) ([]string, error) { + if len(specVal) > 0 { + return specVal, nil + } + value, err := GetStringSlice(ctx, stack, keys...) + if err != nil { + return nil, err + } + if value == nil { + return nil, nil + } + LogDeprecation(ctx, stack, replacement, keys...) + return value, nil +} + +// PreferSpecDuration returns the spec value when non-zero. Otherwise it falls +// back to the duration setting at keys, returning the default when unset. +func PreferSpecDuration(ctx core.Context, stack string, specVal time.Duration, defaultValue time.Duration, replacement string, keys ...string) (time.Duration, error) { + if specVal != 0 { + return specVal, nil + } + value, err := GetDuration(ctx, stack, keys...) + if err != nil { + return 0, err + } + if value == nil { + return defaultValue, nil + } + LogDeprecation(ctx, stack, replacement, keys...) + return *value, nil +} + +// PreferSpecMap returns the spec value when non-empty. Otherwise it falls +// back to the comma-separated key=value setting at keys. +func PreferSpecMap(ctx core.Context, stack string, specVal map[string]string, replacement string, keys ...string) (map[string]string, error) { + if len(specVal) > 0 { + return specVal, nil + } + value, err := GetMap(ctx, stack, keys...) + if err != nil { + return nil, err + } + if value == nil { + return nil, nil + } + LogDeprecation(ctx, stack, replacement, keys...) + return value, nil +} diff --git a/internal/resources/transactionplane/deployments.go b/internal/resources/transactionplane/deployments.go index c554a5ad4..266980c54 100644 --- a/internal/resources/transactionplane/deployments.go +++ b/internal/resources/transactionplane/deployments.go @@ -122,7 +122,8 @@ func createDeployments( return err } - workerEnabled, err := settings.GetBoolOrDefault(ctx, stack.Name, false, "transactionplane", "worker-enabled") + workerEnabled, err := settings.PreferSpecBoolOrDefault(ctx, stack.Name, t.Spec.WorkerEnabled, false, + "TransactionPlane.Spec.WorkerEnabled", "transactionplane", "worker-enabled") if err != nil { return err }