diff --git a/apis/installer/v1alpha1/ace_ace_types.go b/apis/installer/v1alpha1/ace_ace_types.go
index 7f9999fa2..f1ca2cca6 100644
--- a/apis/installer/v1alpha1/ace_ace_types.go
+++ b/apis/installer/v1alpha1/ace_ace_types.go
@@ -55,6 +55,7 @@ type AceSpec struct {
PlatformUi AcePlatformUi `json:"platform-ui"`
ClusterUi AceClusterUi `json:"cluster-ui"`
Grafana AceGrafana `json:"grafana"`
+ Perses AcePerses `json:"perses"`
KubedbUi AceKubedbUi `json:"kubedb-ui"`
PlatformApi AcePlatformApi `json:"platform-api"`
IngressNginx AceIngressNginx `json:"ingress-nginx"`
@@ -123,6 +124,11 @@ type AceGrafana struct {
*GrafanaSpec `json:",inline,omitempty"`
}
+type AcePerses struct {
+ Enabled bool `json:"enabled"`
+ *PersesSpec `json:",inline,omitempty"`
+}
+
type AceKubedbUi struct {
Enabled bool `json:"enabled"`
*KubedbUiSpec `json:",inline,omitempty"`
@@ -245,6 +251,54 @@ type KubeStashSpec struct {
StorageSecret wizardsapi.OptionalResource `json:"storageSecret"`
}
+type PersesSpec struct {
+ Config PersesConfig `json:"config"`
+ Env []core.EnvVar `json:"env"`
+ PodAnnotations map[string]string `json:"podAnnotations"`
+}
+
+type PersesConfig struct {
+ APIPrefix string `json:"api_prefix,omitempty"`
+ Security SecurityConfig `json:"security,omitempty"`
+ Database DatabaseConfig `json:"database,omitempty"`
+}
+
+type SecurityConfig struct {
+ EnableAuth bool `json:"enable_auth,omitempty"`
+ EncryptionKey string `json:"encryption_key,omitempty"`
+ Authentication AuthenticationConfig `json:"authentication,omitempty"`
+ Authorization AuthorizationConfig `json:"authorization,omitempty"`
+}
+
+type AuthenticationConfig struct {
+ Providers AuthProviders `json:"providers,omitempty"`
+}
+
+type AuthProviders struct {
+ EnableNative bool `json:"enable_native,omitempty"`
+}
+
+type AuthorizationConfig struct {
+ GuestPermissions []Permission `json:"guest_permissions,omitempty"`
+}
+
+type Permission struct {
+ Actions []string `json:"actions,omitempty"`
+ Scopes []string `json:"scopes,omitempty"`
+}
+
+type DatabaseConfig struct {
+ SQL SQLConfig `json:"sql,omitempty"`
+}
+
+type SQLConfig struct {
+ User string `json:"user,omitempty"`
+ Password string `json:"password,omitempty"`
+ Address string `json:"addr,omitempty"`
+ DBName string `json:"db_name,omitempty"`
+ AllowNativePasswords bool `json:"allow_native_passwords,omitempty"`
+}
+
type InfraDns struct {
catgwapi.GatewayDns `json:",inline,omitempty"`
// +optional
@@ -310,6 +364,7 @@ type Settings struct {
Platform PlatformSettings `json:"platform"`
Security SecuritySettings `json:"security"`
Grafana GrafanaSettings `json:"grafana"`
+ Perses PersesSettings `json:"perses"`
InboxServer InboxServerSettings `json:"inboxServer"`
Contract ContractStorage `json:"contract"`
Firebase FirebaseSettings `json:"firebase"`
@@ -420,6 +475,10 @@ type GrafanaSettings struct {
SecretKey string `json:"secretKey"`
}
+type PersesSettings struct {
+ EncryptionKey string `json:"encryptionKey"`
+}
+
type InboxServerSettings struct {
JmapURL string `json:"jmapURL"`
WebAdminURL string `json:"webAdminURL"`
diff --git a/apis/installer/v1alpha1/ace_options_types.go b/apis/installer/v1alpha1/ace_options_types.go
index ea7ec7130..1dd68c268 100644
--- a/apis/installer/v1alpha1/ace_options_types.go
+++ b/apis/installer/v1alpha1/ace_options_types.go
@@ -64,6 +64,7 @@ type AceOptionsSpec struct {
PlatformUi AceOptionsComponentSpec `json:"platform-ui"`
ClusterUi AceOptionsComponentSpec `json:"cluster-ui"`
Grafana AceOptionsComponentSpec `json:"grafana"`
+ Perses AceOptionsComponentSpec `json:"perses"`
KubedbUi AceOptionsComponentSpec `json:"kubedb-ui"`
PlatformApi AceOptionsComponentSpec `json:"platform-api"`
Ingress AceOptionsIngressNginx `json:"ingress"`
@@ -514,9 +515,11 @@ type GeneratedValues struct {
// +optional
JKSPassword string `json:"jksPassword"`
// +optional
- GrafanaSecretKey string `json:"grafanaSecretKey"`
- InboxServer InboxServerValues `json:"inboxServer"`
- OpenFGAServer OpenFGAServerValues `json:"openfga"`
+ GrafanaSecretKey string `json:"grafanaSecretKey"`
+ // +optional
+ PersesEncryptionKey string `json:"persesEncryptionKey"`
+ InboxServer InboxServerValues `json:"inboxServer"`
+ OpenFGAServer OpenFGAServerValues `json:"openfga"`
// InstallerSecret used by hosted mode (prod and ninja)
// to generate and validate marketplace self-hosted installer options
// +optional
diff --git a/apis/installer/v1alpha1/zz_generated.deepcopy.go b/apis/installer/v1alpha1/zz_generated.deepcopy.go
index 0d829ae2e..74f536be2 100644
--- a/apis/installer/v1alpha1/zz_generated.deepcopy.go
+++ b/apis/installer/v1alpha1/zz_generated.deepcopy.go
@@ -1468,6 +1468,7 @@ func (in *AceOptionsSpec) DeepCopyInto(out *AceOptionsSpec) {
in.PlatformUi.DeepCopyInto(&out.PlatformUi)
in.ClusterUi.DeepCopyInto(&out.ClusterUi)
in.Grafana.DeepCopyInto(&out.Grafana)
+ in.Perses.DeepCopyInto(&out.Perses)
in.KubedbUi.DeepCopyInto(&out.KubedbUi)
in.PlatformApi.DeepCopyInto(&out.PlatformApi)
in.Ingress.DeepCopyInto(&out.Ingress)
@@ -1545,6 +1546,26 @@ func (in *AceOutboxSyncerSettingsSecretName) DeepCopy() *AceOutboxSyncerSettings
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AcePerses) DeepCopyInto(out *AcePerses) {
+ *out = *in
+ if in.PersesSpec != nil {
+ in, out := &in.PersesSpec, &out.PersesSpec
+ *out = new(PersesSpec)
+ (*in).DeepCopyInto(*out)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AcePerses.
+func (in *AcePerses) DeepCopy() *AcePerses {
+ if in == nil {
+ return nil
+ }
+ out := new(AcePerses)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AcePgOutbox) DeepCopyInto(out *AcePgOutbox) {
*out = *in
@@ -1793,6 +1814,7 @@ func (in *AceSpec) DeepCopyInto(out *AceSpec) {
in.PlatformUi.DeepCopyInto(&out.PlatformUi)
in.ClusterUi.DeepCopyInto(&out.ClusterUi)
in.Grafana.DeepCopyInto(&out.Grafana)
+ in.Perses.DeepCopyInto(&out.Perses)
in.KubedbUi.DeepCopyInto(&out.KubedbUi)
in.PlatformApi.DeepCopyInto(&out.PlatformApi)
in.IngressNginx.DeepCopyInto(&out.IngressNginx)
@@ -2284,6 +2306,59 @@ func (in *AppIngressDns) DeepCopy() *AppIngressDns {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AuthProviders) DeepCopyInto(out *AuthProviders) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthProviders.
+func (in *AuthProviders) DeepCopy() *AuthProviders {
+ if in == nil {
+ return nil
+ }
+ out := new(AuthProviders)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AuthenticationConfig) DeepCopyInto(out *AuthenticationConfig) {
+ *out = *in
+ out.Providers = in.Providers
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthenticationConfig.
+func (in *AuthenticationConfig) DeepCopy() *AuthenticationConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(AuthenticationConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AuthorizationConfig) DeepCopyInto(out *AuthorizationConfig) {
+ *out = *in
+ if in.GuestPermissions != nil {
+ in, out := &in.GuestPermissions, &out.GuestPermissions
+ *out = make([]Permission, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthorizationConfig.
+func (in *AuthorizationConfig) DeepCopy() *AuthorizationConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(AuthorizationConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AutoscalingSpec) DeepCopyInto(out *AutoscalingSpec) {
*out = *in
@@ -3452,6 +3527,22 @@ func (in *DNSProxyAuth) DeepCopy() *DNSProxyAuth {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *DatabaseConfig) DeepCopyInto(out *DatabaseConfig) {
+ *out = *in
+ out.SQL = in.SQL
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DatabaseConfig.
+func (in *DatabaseConfig) DeepCopy() *DatabaseConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(DatabaseConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeployUi) DeepCopyInto(out *DeployUi) {
*out = *in
@@ -8965,6 +9056,93 @@ func (in *OutboxSyncerSpec) DeepCopy() *OutboxSyncerSpec {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *Permission) DeepCopyInto(out *Permission) {
+ *out = *in
+ if in.Actions != nil {
+ in, out := &in.Actions, &out.Actions
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+ if in.Scopes != nil {
+ in, out := &in.Scopes, &out.Scopes
+ *out = make([]string, len(*in))
+ copy(*out, *in)
+ }
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Permission.
+func (in *Permission) DeepCopy() *Permission {
+ if in == nil {
+ return nil
+ }
+ out := new(Permission)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PersesConfig) DeepCopyInto(out *PersesConfig) {
+ *out = *in
+ in.Security.DeepCopyInto(&out.Security)
+ out.Database = in.Database
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersesConfig.
+func (in *PersesConfig) DeepCopy() *PersesConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(PersesConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PersesSettings) DeepCopyInto(out *PersesSettings) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersesSettings.
+func (in *PersesSettings) DeepCopy() *PersesSettings {
+ if in == nil {
+ return nil
+ }
+ out := new(PersesSettings)
+ in.DeepCopyInto(out)
+ return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *PersesSpec) DeepCopyInto(out *PersesSpec) {
+ *out = *in
+ in.Config.DeepCopyInto(&out.Config)
+ if in.Env != nil {
+ in, out := &in.Env, &out.Env
+ *out = make([]v1.EnvVar, len(*in))
+ for i := range *in {
+ (*in)[i].DeepCopyInto(&(*out)[i])
+ }
+ }
+ if in.PodAnnotations != nil {
+ in, out := &in.PodAnnotations, &out.PodAnnotations
+ *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 PersesSpec.
+func (in *PersesSpec) DeepCopy() *PersesSpec {
+ if in == nil {
+ return nil
+ }
+ out := new(PersesSpec)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PersistenceSpec) DeepCopyInto(out *PersistenceSpec) {
*out = *in
@@ -10667,6 +10845,21 @@ func (in *SMTPConfig) DeepCopy() *SMTPConfig {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SQLConfig) DeepCopyInto(out *SQLConfig) {
+ *out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SQLConfig.
+func (in *SQLConfig) DeepCopy() *SQLConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(SQLConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecretKeySelector) DeepCopyInto(out *SecretKeySelector) {
*out = *in
@@ -10683,6 +10876,23 @@ func (in *SecretKeySelector) DeepCopy() *SecretKeySelector {
return out
}
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *SecurityConfig) DeepCopyInto(out *SecurityConfig) {
+ *out = *in
+ out.Authentication = in.Authentication
+ in.Authorization.DeepCopyInto(&out.Authorization)
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecurityConfig.
+func (in *SecurityConfig) DeepCopy() *SecurityConfig {
+ if in == nil {
+ return nil
+ }
+ out := new(SecurityConfig)
+ in.DeepCopyInto(out)
+ return out
+}
+
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *SecuritySettings) DeepCopyInto(out *SecuritySettings) {
*out = *in
@@ -11303,6 +11513,7 @@ func (in *Settings) DeepCopyInto(out *Settings) {
in.Platform.DeepCopyInto(&out.Platform)
out.Security = in.Security
out.Grafana = in.Grafana
+ out.Perses = in.Perses
out.InboxServer = in.InboxServer
out.Contract = in.Contract
out.Firebase = in.Firebase
diff --git a/charts/ace-installer/README.md b/charts/ace-installer/README.md
index c09808bcd..7a308b353 100644
--- a/charts/ace-installer/README.md
+++ b/charts/ace-installer/README.md
@@ -102,6 +102,8 @@ The following table lists the configurable parameters of the `ace-installer` cha
| helm.releases.panopticon.enabled | | true |
| helm.releases.panopticon.version | | "v2026.1.15" |
| helm.releases.panopticon.values | | {"monitoring":{"agent":"prometheus.io/operator","enabled":true,"serviceMonitor":{"labels":{"release":"kube-prometheus-stack"}}}} |
+| helm.releases.prom-label-proxy.enabled | | false |
+| helm.releases.prom-label-proxy.version | | "v2026.4.30" |
| helm.releases.reloader.enabled | | true |
| helm.releases.reloader.version | | "2.2.9" |
| helm.releases.service-gateway-presets.enabled | | false |
diff --git a/charts/ace-installer/templates/presets/bootstrap-presets.yaml b/charts/ace-installer/templates/presets/bootstrap-presets.yaml
index e8f6de29a..c93113393 100644
--- a/charts/ace-installer/templates/presets/bootstrap-presets.yaml
+++ b/charts/ace-installer/templates/presets/bootstrap-presets.yaml
@@ -33,6 +33,8 @@ opscenter-features:
values: %s
license-proxyserver:
values: %s
+ prom-label-proxy:
+ values: %s
service-gateway-presets:
values: %s
stash-presets:
@@ -49,6 +51,7 @@ opscenter-features:
((dig "opscenter-features" "values" "helm" "releases" "kubedb" "values" (dict) $.Values.helm.releases) | toJson)
((dig "opscenter-features" "values" "helm" "releases" "kubestash" "values" (dict) $.Values.helm.releases) | toJson)
((dig "opscenter-features" "values" "helm" "releases" "license-proxyserver" "values" (dict) $.Values.helm.releases) | toJson)
+ ((dig "opscenter-features" "values" "helm" "releases" "prom-label-proxy" "values" (dict) $.Values.helm.releases) | toJson)
((dig "opscenter-features" "values" "helm" "releases" "service-gateway-presets" "values" (dict) $.Values.helm.releases) | toJson)
((dig "opscenter-features" "values" "helm" "releases" "stash-presets" "values" (dict) $.Values.helm.releases) | toJson)
| fromYaml }}
diff --git a/charts/ace-installer/values.yaml b/charts/ace-installer/values.yaml
index b488ef476..cefa305af 100644
--- a/charts/ace-installer/values.yaml
+++ b/charts/ace-installer/values.yaml
@@ -123,6 +123,9 @@ helm:
serviceMonitor:
labels:
release: kube-prometheus-stack
+ prom-label-proxy:
+ enabled: false
+ version: "v2026.4.30"
reloader:
enabled: true
version: "2.2.9"
diff --git a/charts/ace/Chart.yaml b/charts/ace/Chart.yaml
index c39627c9a..36b4e2e46 100644
--- a/charts/ace/Chart.yaml
+++ b/charts/ace/Chart.yaml
@@ -64,3 +64,7 @@ dependencies:
repository: file://../platform-opscenter
condition: platform-opscenter.enabled
version: v2026.5.22
+- name: perses
+ repository: oci://ghcr.io/appscode-charts
+ condition: perses.enabled
+ version: v2026.4.30
\ No newline at end of file
diff --git a/charts/ace/README.md b/charts/ace/README.md
index 8fdd7fc54..b49edd91b 100644
--- a/charts/ace/README.md
+++ b/charts/ace/README.md
@@ -50,6 +50,7 @@ The following table lists the configurable parameters of the `ace` chart and the
| platform-ui.enabled | | false |
| cluster-ui.enabled | | false |
| grafana.enabled | | false |
+| perses.enabled | | false |
| kubedb-ui.enabled | | false |
| platform-api.enabled | | false |
| gateway.annotations | | {} |
@@ -188,6 +189,7 @@ The following table lists the configurable parameters of the `ace` chart and the
| settings.platform.logoutURL | redirect url after logout | "" |
| settings.grafana.appMode | possible values : production, development | production |
| settings.grafana.secretKey | | 4nHrUDNw00AjlhAq8hCGYPxBt6I1UCbmdC5ReY19IPWdy8qFDzTZzXkdCr5d6qwP |
+| settings.perses.encryptionKey | | "" |
| settings.inboxServer.jmapURL | | "" |
| settings.inboxServer.webAdminURL | | "" |
| settings.inboxServer.emailDomain | | "" |
diff --git a/charts/ace/templates/gateway/route-main.yaml b/charts/ace/templates/gateway/route-main.yaml
index 58c3c0d9c..4fe5fb8b0 100644
--- a/charts/ace/templates/gateway/route-main.yaml
+++ b/charts/ace/templates/gateway/route-main.yaml
@@ -85,6 +85,7 @@ spec:
namespace: {{ .Release.Namespace }}
port: 80
weight: 1
+ {{- if (index .Values "grafana" "enabled") }}
- matches:
- path:
type: PathPrefix
@@ -99,6 +100,23 @@ spec:
timeouts:
backendRequest: 2m
request: 2m
+ {{- end }}
+ {{- if (index .Values "perses" "enabled") }}
+ - matches:
+ - path:
+ type: PathPrefix
+ value: /observe
+ backendRefs:
+ - group: ""
+ kind: Service
+ name: {{ include "ace.fullname" . }}-perses
+ namespace: {{ .Release.Namespace }}
+ port: 8080
+ weight: 1
+ timeouts:
+ backendRequest: 2m
+ request: 2m
+ {{- end }}
- matches:
- path:
type: PathPrefix
diff --git a/charts/ace/templates/platform/setup-config.yaml b/charts/ace/templates/platform/setup-config.yaml
index ba49053d7..3a4b87ad4 100644
--- a/charts/ace/templates/platform/setup-config.yaml
+++ b/charts/ace/templates/platform/setup-config.yaml
@@ -18,6 +18,7 @@ stringData:
reloadPlatformAccounts: true
{{- end }}
importerServiceAccount: {{ include "appscode.serviceAccountName" . }}-importer
+ syncPersesAccounts: true
{{- with .Values.setupJob.config }}
{{- . | toYaml | nindent 4 }}
{{- end }}
diff --git a/charts/ace/values.openapiv3_schema.yaml b/charts/ace/values.openapiv3_schema.yaml
index 9abb223f2..e3cf2435d 100644
--- a/charts/ace/values.openapiv3_schema.yaml
+++ b/charts/ace/values.openapiv3_schema.yaml
@@ -18680,6 +18680,155 @@ properties:
- volumeMounts
- volumes
type: object
+ perses:
+ properties:
+ config:
+ properties:
+ api_prefix:
+ type: string
+ database:
+ properties:
+ sql:
+ properties:
+ addr:
+ type: string
+ allow_native_passwords:
+ type: boolean
+ db_name:
+ type: string
+ password:
+ type: string
+ user:
+ type: string
+ type: object
+ type: object
+ security:
+ properties:
+ authentication:
+ properties:
+ providers:
+ properties:
+ enable_native:
+ type: boolean
+ type: object
+ type: object
+ authorization:
+ properties:
+ guest_permissions:
+ items:
+ properties:
+ actions:
+ items:
+ type: string
+ type: array
+ scopes:
+ items:
+ type: string
+ type: array
+ type: object
+ type: array
+ type: object
+ enable_auth:
+ type: boolean
+ encryption_key:
+ type: string
+ type: object
+ type: object
+ enabled:
+ type: boolean
+ env:
+ items:
+ properties:
+ name:
+ type: string
+ value:
+ type: string
+ valueFrom:
+ properties:
+ configMapKeyRef:
+ properties:
+ key:
+ type: string
+ name:
+ default: ''
+ type: string
+ optional:
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ fieldRef:
+ properties:
+ apiVersion:
+ type: string
+ fieldPath:
+ type: string
+ required:
+ - fieldPath
+ type: object
+ x-kubernetes-map-type: atomic
+ fileKeyRef:
+ properties:
+ key:
+ type: string
+ optional:
+ default: false
+ type: boolean
+ path:
+ type: string
+ volumeName:
+ type: string
+ required:
+ - key
+ - path
+ - volumeName
+ type: object
+ x-kubernetes-map-type: atomic
+ resourceFieldRef:
+ properties:
+ containerName:
+ type: string
+ divisor:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ resource:
+ type: string
+ required:
+ - resource
+ type: object
+ x-kubernetes-map-type: atomic
+ secretKeyRef:
+ properties:
+ key:
+ type: string
+ name:
+ default: ''
+ type: string
+ optional:
+ type: boolean
+ required:
+ - key
+ type: object
+ x-kubernetes-map-type: atomic
+ type: object
+ required:
+ - name
+ type: object
+ type: array
+ podAnnotations:
+ additionalProperties:
+ type: string
+ type: object
+ required:
+ - config
+ - enabled
+ - env
+ - podAnnotations
+ type: object
pgoutbox:
properties:
affinity:
@@ -24481,6 +24630,13 @@ properties:
- apiURL
- preSharedKey
type: object
+ perses:
+ properties:
+ encryptionKey:
+ type: string
+ required:
+ - encryptionKey
+ type: object
platform:
properties:
appName:
@@ -24617,6 +24773,7 @@ properties:
- inboxServer
- nats
- openfga
+ - perses
- platform
- security
- smtp
@@ -27403,6 +27560,7 @@ required:
- nats-dns
- openfga
- outbox-syncer
+- perses
- pgoutbox
- platform-api
- platform-ui
diff --git a/charts/ace/values.yaml b/charts/ace/values.yaml
index a1399098a..1fd3ac45f 100644
--- a/charts/ace/values.yaml
+++ b/charts/ace/values.yaml
@@ -11,6 +11,9 @@ cluster-ui:
grafana:
enabled: false
+perses:
+ enabled: false
+
kubedb-ui:
enabled: false
@@ -419,6 +422,9 @@ settings:
appMode: production
secretKey: 4nHrUDNw00AjlhAq8hCGYPxBt6I1UCbmdC5ReY19IPWdy8qFDzTZzXkdCr5d6qwP
+ perses:
+ encryptionKey: ""
+
inboxServer:
jmapURL: ""
webAdminURL: ""
diff --git a/charts/opscenter-features/README.md b/charts/opscenter-features/README.md
index 35f6f3b4c..0941e8b8c 100644
--- a/charts/opscenter-features/README.md
+++ b/charts/opscenter-features/README.md
@@ -71,7 +71,7 @@ The following table lists the configurable parameters of the `opscenter-features
| helm.createNamespace | | true |
| helm.repositories.appscode-charts-oci.url | | oci://ghcr.io/appscode-charts |
| helm.releases.aceshifter.version | | "v2026.5.22" |
-| helm.releases.appscode-otel-stack.version | | "v2025.2.28" |
+| helm.releases.appscode-otel-stack.version | | "v2026.5.22" |
| helm.releases.aws-credential-manager.version | | "v2026.1.20" |
| helm.releases.azure-credential-manager.version | | "v2026.4.16" |
| helm.releases.gcp-credential-manager.version | | "v2026.3.11" |
@@ -96,7 +96,7 @@ The following table lists the configurable parameters of the `opscenter-features
| helm.releases.gatekeeper-grafana-dashboards.version | | "v2023.10.1" |
| helm.releases.gatekeeper-library.version | | "v2023.10.1" |
| helm.releases.gateway-api.version | | "v2025.3.14" |
-| helm.releases.grafana-operator.version | | "v2026.3.30" |
+| helm.releases.grafana-operator.version | | "v2026.5.22" |
| helm.releases.keda.version | | "2.19.0" |
| helm.releases.keda-add-ons-http.version | | "0.12.0" |
| helm.releases.kube-grafana-dashboards.version | | "v2023.10.1" |
@@ -116,7 +116,7 @@ The following table lists the configurable parameters of the `opscenter-features
| helm.releases.license-proxyserver.version | | "v2026.2.16" |
| helm.releases.longhorn.version | | "1.7.2" |
| helm.releases.metrics-server.version | | "3.11.0" |
-| helm.releases.monitoring-operator.version | | "v2026.3.30" |
+| helm.releases.monitoring-operator.version | | "v2026.5.22" |
| helm.releases.monitoring-operator.values.alertmanager.email.enabled | | false |
| helm.releases.monitoring-operator.values.alertmanager.email.to | | "" |
| helm.releases.monitoring-operator.values.alertmanager.email.from | | "" |
@@ -135,6 +135,7 @@ The following table lists the configurable parameters of the `opscenter-features
| helm.releases.panopticon.version | | "v2026.1.15" |
| helm.releases.prepare-cluster.version | | "v2023.12.21" |
| helm.releases.prometheus-adapter.version | | "4.9.0" |
+| helm.releases.prom-label-proxy.version | | "v2026.5.22" |
| helm.releases.reloader.version | | "2.2.9" |
| helm.releases.scanner.version | | "v2026.1.15" |
| helm.releases.service-backend.version | | "v2026.5.22" |
@@ -147,6 +148,8 @@ The following table lists the configurable parameters of the `opscenter-features
| helm.releases.stash-opscenter.version | | "v2025.7.31" |
| helm.releases.stash-presets.version | | "v2026.5.22" |
| helm.releases.supervisor.version | | "v2026.1.15" |
+| helm.releases.tenant-operator.version | | "v2026.5.22" |
+| helm.releases.thanos-operator.version | | "v2026.5.22" |
| helm.releases.topolvm.version | | "15.0.0" |
| helm.releases.voyager.version | | "v2026.3.23" |
| helm.releases.voyager-gateway.version | | "v2026.1.15" |
diff --git a/charts/opscenter-features/templates/featuresets/opscenter-observability/telemetry-stack/appscode-otel-stack.yaml b/charts/opscenter-features/templates/featuresets/opscenter-observability/telemetry-stack/appscode-otel-stack.yaml
new file mode 100644
index 000000000..c3eb68b75
--- /dev/null
+++ b/charts/opscenter-features/templates/featuresets/opscenter-observability/telemetry-stack/appscode-otel-stack.yaml
@@ -0,0 +1,50 @@
+{{ $defaults := dict "registryFQDN" (include "registry.ghcr" $) }}
+
+{{ $vals := dig "appscode-otel-stack" "values" (dict) .Values.helm.releases }}
+{{ $vals = mergeOverwrite $defaults $vals }}
+
+{{- if eq (include "distro.openshift" $) "true" }}
+{{ $vals = mergeOverwrite $vals (dict "distro" .Values.distro) }}
+{{- end }}
+
+apiVersion: ui.k8s.appscode.com/v1alpha1
+kind: Feature
+metadata:
+ name: appscode-otel-stack
+ labels:
+ app.kubernetes.io/part-of: opscenter-observability
+spec:
+ title: AppsCode OTEL Stack
+ description: |
+ Deploy and manage OpenTelemetry collectors and pipelines for traces, metrics, and logs in Kubernetes.
+ icons:
+ - src: https://cdn.appscode.com/k8s/icons/menu/cluster.svg
+ type: image/svg+xml
+ featureSet: opscenter-observability
+ featureBlock: appscode-otel-stack
+ recommended: true
+ requirements:
+ features:
+ - monitoring-operator
+ readinessChecks:
+ workloads:
+ - group: apps
+ version: v1
+ kind: Deployment
+ selector:
+ app.kubernetes.io/component: opentelemetry-collector
+ app.kubernetes.io/instance: monitoring.appscode-otel-stack-gateway
+ app.kubernetes.io/managed-by: opentelemetry-operator
+ app.kubernetes.io/name: appscode-otel-stack-gateway-collector
+ chart:
+ name: appscode-otel-stack
+ namespace: monitoring
+ createNamespace: {{ $.Values.helm.createNamespace }}
+ version: {{ dig "appscode-otel-stack" "version" "" $.Values.helm.releases }}
+ sourceRef:
+ kind: HelmRepository
+ name: appscode-charts-oci
+ namespace: {{ .Release.Namespace }}
+{{- with $vals }}
+ {{- dict "values" . | toYaml | nindent 2 }}
+{{- end }}
diff --git a/charts/opscenter-features/templates/featuresets/opscenter-observability/telemetry-stack/prom-label-proxy.yaml b/charts/opscenter-features/templates/featuresets/opscenter-observability/telemetry-stack/prom-label-proxy.yaml
new file mode 100644
index 000000000..72dcd7dec
--- /dev/null
+++ b/charts/opscenter-features/templates/featuresets/opscenter-observability/telemetry-stack/prom-label-proxy.yaml
@@ -0,0 +1,49 @@
+{{ $defaults := dict "registryFQDN" (include "registry.ghcr" $) }}
+
+{{ $vals := dig "prom-label-proxy" "values" (dict) .Values.helm.releases }}
+{{ $vals = mergeOverwrite $defaults $vals }}
+
+{{- if eq (include "distro.openshift" $) "true" }}
+{{ $vals = mergeOverwrite $vals (dict "distro" .Values.distro) }}
+{{- end }}
+
+apiVersion: ui.k8s.appscode.com/v1alpha1
+kind: Feature
+metadata:
+ name: prom-label-proxy
+ labels:
+ app.kubernetes.io/part-of: opscenter-observability
+spec:
+ title: Prometheus Label Proxy
+ description: |
+ Enforce label-based tenant isolation for Prometheus queries, restricting data access per namespace or team.
+ icons:
+ - src: https://cdn.appscode.com/k8s/icons/menu/cluster.svg
+ type: image/svg+xml
+ featureSet: opscenter-observability
+ featureBlock: tenant-operator
+ recommended: true
+ requirements:
+ features:
+ - thanos-operator
+ - gateway-api
+ - catalog-manager
+ readinessChecks:
+ workloads:
+ - group: apps
+ version: v1
+ kind: Deployment
+ selector:
+ app.kubernetes.io/name: prom-label-proxy
+ chart:
+ name: prom-label-proxy
+ namespace: monitoring
+ createNamespace: {{ $.Values.helm.createNamespace }}
+ version: {{ dig "appscode-otel-stack" "version" "" $.Values.helm.releases }}
+ sourceRef:
+ kind: HelmRepository
+ name: appscode-charts-oci
+ namespace: {{ .Release.Namespace }}
+{{- with $vals }}
+ {{- dict "values" . | toYaml | nindent 2 }}
+{{- end }}
diff --git a/charts/opscenter-features/templates/featuresets/opscenter-observability/telemetry-stack/tenant-operator.yaml b/charts/opscenter-features/templates/featuresets/opscenter-observability/telemetry-stack/tenant-operator.yaml
new file mode 100644
index 000000000..a1b1010e8
--- /dev/null
+++ b/charts/opscenter-features/templates/featuresets/opscenter-observability/telemetry-stack/tenant-operator.yaml
@@ -0,0 +1,48 @@
+{{ $defaults := dict "registryFQDN" (include "registry.ghcr" $) }}
+
+{{ $vals := dig "tenant-operator" "values" (dict) .Values.helm.releases }}
+{{ $vals = mergeOverwrite $defaults $vals }}
+
+{{- if eq (include "distro.openshift" $) "true" }}
+{{ $vals = mergeOverwrite $vals (dict "distro" .Values.distro) }}
+{{- end }}
+
+apiVersion: ui.k8s.appscode.com/v1alpha1
+kind: Feature
+metadata:
+ name: tenant-operator
+ labels:
+ app.kubernetes.io/part-of: opscenter-observability
+spec:
+ title: Tenant Operator
+ description: |
+ Manage multi-tenant observability by isolating monitoring resources and access per tenant in Kubernetes.
+ icons:
+ - src: https://cdn.appscode.com/k8s/icons/menu/cluster.svg
+ type: image/svg+xml
+ featureSet: opscenter-observability
+ featureBlock: tenant-operator
+ recommended: true
+ requirements:
+ features:
+ - prom-label-proxy
+ - thanos-operator
+ readinessChecks:
+ workloads:
+ - group: apps
+ version: v1
+ kind: Deployment
+ selector:
+ app.kubernetes.io/name: tenant-operator
+ chart:
+ name: tenant-operator
+ namespace: monitoring
+ createNamespace: {{ $.Values.helm.createNamespace }}
+ version: {{ dig "tenant-operator" "version" "" $.Values.helm.releases }}
+ sourceRef:
+ kind: HelmRepository
+ name: appscode-charts-oci
+ namespace: {{ .Release.Namespace }}
+{{- with $vals }}
+ {{- dict "values" . | toYaml | nindent 2 }}
+{{- end }}
diff --git a/charts/opscenter-features/templates/featuresets/opscenter-observability/telemetry-stack/thanos-operator.yaml b/charts/opscenter-features/templates/featuresets/opscenter-observability/telemetry-stack/thanos-operator.yaml
new file mode 100644
index 000000000..d3dd3c82e
--- /dev/null
+++ b/charts/opscenter-features/templates/featuresets/opscenter-observability/telemetry-stack/thanos-operator.yaml
@@ -0,0 +1,47 @@
+{{ $defaults := dict "registryFQDN" (include "registry.ghcr" $) }}
+
+{{ $vals := dig "thanos-operator" "values" (dict) .Values.helm.releases }}
+{{ $vals = mergeOverwrite $defaults $vals }}
+
+{{- if eq (include "distro.openshift" $) "true" }}
+{{ $vals = mergeOverwrite $vals (dict "distro" .Values.distro) }}
+{{- end }}
+
+apiVersion: ui.k8s.appscode.com/v1alpha1
+kind: Feature
+metadata:
+ name: thanos-operator
+ labels:
+ app.kubernetes.io/part-of: opscenter-observability
+spec:
+ title: Thanos Operator
+ description: |
+ Manage Thanos components for highly available, long-term Prometheus metrics storage and global querying.
+ icons:
+ - src: https://cdn.appscode.com/k8s/icons/menu/cluster.svg
+ type: image/svg+xml
+ featureSet: opscenter-observability
+ featureBlock: tenant-operator
+ recommended: true
+ readinessChecks:
+ workloads:
+ - group: apps
+ version: v1
+ kind: Deployment
+ selector:
+ app.kubernetes.io/component: manager
+ app.kubernetes.io/created-by: thanos-operator
+ app.kubernetes.io/part-of: thanos-operator
+ control-plane: controller-manager
+ chart:
+ name: thanos-operator
+ namespace: monitoring
+ createNamespace: {{ $.Values.helm.createNamespace }}
+ version: {{ dig "appscode-otel-stack" "version" "" $.Values.helm.releases }}
+ sourceRef:
+ kind: HelmRepository
+ name: appscode-charts-oci
+ namespace: {{ .Release.Namespace }}
+{{- with $vals }}
+ {{- dict "values" . | toYaml | nindent 2 }}
+{{- end }}
diff --git a/charts/opscenter-features/values.yaml b/charts/opscenter-features/values.yaml
index 8d35f59ee..80b92ba26 100644
--- a/charts/opscenter-features/values.yaml
+++ b/charts/opscenter-features/values.yaml
@@ -57,7 +57,7 @@ helm:
aceshifter:
version: "v2026.5.22"
appscode-otel-stack:
- version: "v2025.2.28"
+ version: "v2026.5.22"
aws-credential-manager:
version: "v2026.1.20"
azure-credential-manager:
@@ -107,7 +107,7 @@ helm:
gateway-api:
version: "v2025.3.14"
grafana-operator:
- version: "v2026.3.30"
+ version: "v2026.5.22"
keda:
version: "2.19.0"
keda-add-ons-http:
@@ -147,7 +147,7 @@ helm:
metrics-server:
version: "3.11.0"
monitoring-operator:
- version: "v2026.3.30"
+ version: "v2026.5.22"
values:
alertmanager:
email:
@@ -177,6 +177,8 @@ helm:
version: "v2023.12.21"
prometheus-adapter:
version: "4.9.0"
+ prom-label-proxy:
+ version: "v2026.5.22"
reloader:
version: "2.2.9"
scanner:
@@ -201,6 +203,10 @@ helm:
version: "v2026.5.22"
supervisor:
version: "v2026.1.15"
+ tenant-operator:
+ version: "v2026.5.22"
+ thanos-operator:
+ version: "v2026.5.22"
topolvm:
version: "15.0.0"
voyager:
diff --git a/features.md b/features.md
index bb3ad7660..29a803e7c 100644
--- a/features.md
+++ b/features.md
@@ -41,6 +41,12 @@ graph TD;
kube-prometheus-stack-->monitoring-operator;
panopticon-->license-proxyserver;
prometheus-adapter-->kube-prometheus-stack;
+ appscode-otel-stack-->monitoring-operator;
+ prom-label-proxy-->thanos-operator;
+ prom-label-proxy-->gateway-api;
+ prom-label-proxy-->catalog-manager;
+ tenant-operator-->prom-label-proxy;
+ tenant-operator-->thanos-operator;
gatekeeper-constraints-->gatekeeper;
gatekeeper-constraints-->gatekeeper-templates;
gatekeeper-grafana-dashboards-->gatekeeper;
diff --git a/schema/ace-options/values.openapiv3_schema.yaml b/schema/ace-options/values.openapiv3_schema.yaml
index e2049bc28..710e6f90f 100644
--- a/schema/ace-options/values.openapiv3_schema.yaml
+++ b/schema/ace-options/values.openapiv3_schema.yaml
@@ -231,6 +231,8 @@ properties:
required:
- preSharedKeys
type: object
+ persesEncryptionKey:
+ type: string
postgresPassword:
type: string
promotedToProduction:
@@ -1746,6 +1748,89 @@ properties:
DynamicResourceAllocation feature gate.
+ This field is immutable. It can only be set for containers.'
+ items:
+ description: ResourceClaim references one entry in PodSpec.ResourceClaims.
+ properties:
+ name:
+ description: 'Name must match the name of one entry in pod.spec.resourceClaims
+ of
+
+ the Pod where this field is used. It makes that resource available
+
+ inside a container.'
+ type: string
+ request:
+ description: 'Request is the name chosen for a request in the referenced
+ claim.
+
+ If empty, everything from the claim is made available, otherwise
+
+ only the result of this request.'
+ type: string
+ required:
+ - name
+ type: object
+ type: array
+ x-kubernetes-list-map-keys:
+ - name
+ x-kubernetes-list-type: map
+ limits:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Limits describes the maximum amount of compute resources
+ allowed.
+
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ requests:
+ additionalProperties:
+ anyOf:
+ - type: integer
+ - type: string
+ pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$
+ x-kubernetes-int-or-string: true
+ description: 'Requests describes the minimum amount of compute resources
+ required.
+
+ If Requests is omitted for a container, it defaults to Limits if that
+ is explicitly specified,
+
+ otherwise to an implementation-defined value. Requests cannot exceed
+ Limits.
+
+ More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/'
+ type: object
+ type: object
+ required:
+ - enabled
+ type: object
+ perses:
+ properties:
+ enabled:
+ type: boolean
+ nodeSelector:
+ additionalProperties:
+ type: string
+ type: object
+ resources:
+ description: ResourceRequirements describes the compute resource requirements.
+ properties:
+ claims:
+ description: 'Claims lists the names of resources, defined in spec.resourceClaims,
+
+ that are used by this container.
+
+
+ This field depends on the
+
+ DynamicResourceAllocation feature gate.
+
+
This field is immutable. It can only be set for containers.'
items:
description: ResourceClaim references one entry in PodSpec.ResourceClaims.
@@ -2616,6 +2701,7 @@ required:
- nats
- openfga
- outbox-syncer
+ - perses
- pgoutbox
- platform-api
- platform-ui