diff --git a/api/apps/v1alpha1/qdrant/types.go b/api/apps/v1alpha1/qdrant/types.go index 2b9fe0fe3f..8ee06b1fa1 100644 --- a/api/apps/v1alpha1/qdrant/types.go +++ b/api/apps/v1alpha1/qdrant/types.go @@ -35,6 +35,9 @@ type ConfigSpec struct { // Enable external access from outside the cluster. // +kubebuilder:default:=false External bool `json:"external"` + // TLS configuration. When omitted, the effective TLS state follows the value of `external`. + // +kubebuilder:default:={} + Tls TLS `json:"tls,omitempty"` } type Resources struct { @@ -44,5 +47,10 @@ type Resources struct { Memory resource.Quantity `json:"memory,omitempty"` } +type TLS struct { + // Enable TLS. When unset, inherits the value of `external` (TLS is on when external access is enabled). Set explicitly to `true` or `false` to override. + Enabled *bool `json:"enabled,omitempty"` +} + // +kubebuilder:validation:Enum="t1.nano";"t1.micro";"t1.small";"t1.medium";"t1.large";"t1.xlarge";"t1.2xlarge";"t1.4xlarge";"c1.nano";"c1.micro";"c1.small";"c1.medium";"c1.large";"c1.xlarge";"c1.2xlarge";"c1.4xlarge";"s1.nano";"s1.micro";"s1.small";"s1.medium";"s1.large";"s1.xlarge";"s1.2xlarge";"s1.4xlarge";"u1.nano";"u1.micro";"u1.small";"u1.medium";"u1.large";"u1.xlarge";"u1.2xlarge";"u1.4xlarge";"m1.nano";"m1.micro";"m1.small";"m1.medium";"m1.large";"m1.xlarge";"m1.2xlarge";"m1.4xlarge";"nano";"micro";"small";"medium";"large";"xlarge";"2xlarge" type ResourcesPreset string diff --git a/api/apps/v1alpha1/qdrant/zz_generated.deepcopy.go b/api/apps/v1alpha1/qdrant/zz_generated.deepcopy.go index 2abfd37e6f..8b9cbc6961 100644 --- a/api/apps/v1alpha1/qdrant/zz_generated.deepcopy.go +++ b/api/apps/v1alpha1/qdrant/zz_generated.deepcopy.go @@ -55,6 +55,7 @@ func (in *ConfigSpec) DeepCopyInto(out *ConfigSpec) { *out = *in in.Resources.DeepCopyInto(&out.Resources) out.Size = in.Size.DeepCopy() + in.Tls.DeepCopyInto(&out.Tls) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigSpec. @@ -83,3 +84,23 @@ func (in *Resources) DeepCopy() *Resources { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLS) DeepCopyInto(out *TLS) { + *out = *in + if in.Enabled != nil { + in, out := &in.Enabled, &out.Enabled + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLS. +func (in *TLS) DeepCopy() *TLS { + if in == nil { + return nil + } + out := new(TLS) + in.DeepCopyInto(out) + return out +} diff --git a/packages/apps/qdrant/Makefile b/packages/apps/qdrant/Makefile index 2110125f2f..a833e7e865 100644 --- a/packages/apps/qdrant/Makefile +++ b/packages/apps/qdrant/Makefile @@ -3,3 +3,6 @@ include ../../../hack/package.mk generate: cozyvalues-gen -m 'qdrant' -v values.yaml -s values.schema.json -r README.md -g ../../../api/apps/v1alpha1/qdrant/types.go ../../../hack/update-crd.sh + +test: + helm unittest . diff --git a/packages/apps/qdrant/README.md b/packages/apps/qdrant/README.md index 7ef48e05f5..7f6af687af 100644 --- a/packages/apps/qdrant/README.md +++ b/packages/apps/qdrant/README.md @@ -25,6 +25,14 @@ Service deploys Qdrant as a StatefulSet with automatic cluster mode when multipl | `external` | Enable external access from outside the cluster. | `bool` | `false` | +### TLS parameters + +| Name | Description | Type | Value | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------ | +| `tls` | TLS configuration. When omitted, the effective TLS state follows the value of `external`. | `object` | `{}` | +| `tls.enabled` | Enable TLS. When unset, inherits the value of `external` (TLS is on when external access is enabled). Set explicitly to `true` or `false` to override. | `*bool` | `null` | + + ## Parameter examples and reference ### resources and resourcesPreset diff --git a/packages/apps/qdrant/templates/certmanager.yaml b/packages/apps/qdrant/templates/certmanager.yaml new file mode 100644 index 0000000000..f46be84944 --- /dev/null +++ b/packages/apps/qdrant/templates/certmanager.yaml @@ -0,0 +1,78 @@ +{{- $clusterDomain := "cozy.local" }} +{{- if .Values._cluster }} +{{- $clusterDomain = (index .Values._cluster "cluster-domain") | default "cozy.local" }} +{{- end }} +{{- $tlsMap := default (dict) .Values.tls -}} +{{- $tlsEnabled := false -}} +{{- if hasKey $tlsMap "enabled" -}} + {{- $tlsEnabled = index $tlsMap "enabled" -}} +{{- else -}} + {{- $tlsEnabled = .Values.external | default false -}} +{{- end -}} +{{- if $tlsEnabled }} +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ .Release.Name }}-selfsigned + namespace: {{ .Release.Namespace }} +spec: + selfSigned: {} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ .Release.Name }}-ca + namespace: {{ .Release.Namespace }} +spec: + secretName: {{ .Release.Name }}-ca + duration: 43800h + commonName: {{ .Release.Name }}-ca + issuerRef: + name: {{ .Release.Name }}-selfsigned + isCA: true + privateKey: + rotationPolicy: Never +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ .Release.Name }}-ca + namespace: {{ .Release.Namespace }} +spec: + ca: + secretName: {{ .Release.Name }}-ca +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ .Release.Name }}-tls + namespace: {{ .Release.Namespace }} +spec: + secretName: {{ .Release.Name }}-tls + duration: 8760h + renewBefore: 720h + isCA: false + issuerRef: + name: {{ .Release.Name }}-ca + commonName: {{ .Release.Name }} + # server auth: required for REST (6333) and gRPC (6334) TLS endpoints. + # client auth: required for p2p mTLS — Qdrant uses ca_cert for peer + # verification when cluster.p2p.enable_tls is true (see qdrant.yaml). + usages: + - digital signature + - key encipherment + - server auth + - client auth + dnsNames: + - {{ .Release.Name }} + - {{ .Release.Name }}.{{ .Release.Namespace }}.svc + - {{ .Release.Name }}.{{ .Release.Namespace }}.svc.{{ $clusterDomain }} + - {{ .Release.Name }}-headless + - {{ .Release.Name }}-headless.{{ .Release.Namespace }}.svc + - {{ .Release.Name }}-headless.{{ .Release.Namespace }}.svc.{{ $clusterDomain }} + - "*.{{ .Release.Name }}-headless.{{ .Release.Namespace }}.svc.{{ $clusterDomain }}" + {{- if .Values.external }} + - {{ .Release.Name }}.{{ .Values._namespace.host }} + {{- end }} +{{- end }} diff --git a/packages/apps/qdrant/templates/qdrant.yaml b/packages/apps/qdrant/templates/qdrant.yaml index 888bd05e39..fd94e78f5a 100644 --- a/packages/apps/qdrant/templates/qdrant.yaml +++ b/packages/apps/qdrant/templates/qdrant.yaml @@ -1,3 +1,10 @@ +{{- $tlsMap := default (dict) .Values.tls -}} +{{- $tlsEnabled := false -}} +{{- if hasKey $tlsMap "enabled" -}} + {{- $tlsEnabled = index $tlsMap "enabled" -}} +{{- else -}} + {{- $tlsEnabled = .Values.external | default false -}} +{{- end -}} apiVersion: helm.toolkit.fluxcd.io/v2 kind: HelmRelease metadata: @@ -41,3 +48,28 @@ spec: service: type: LoadBalancer {{- end }} + config: + service: + enable_tls: {{ $tlsEnabled }} + cluster: + p2p: + enable_tls: {{ $tlsEnabled }} + {{- if $tlsEnabled }} + tls: + cert: /qdrant/tls/tls.crt + key: /qdrant/tls/tls.key + ca_cert: /qdrant/tls/ca.crt + {{- end }} + {{- if $tlsEnabled }} + additionalVolumes: + - name: tls + secret: + secretName: {{ .Release.Name }}-tls + additionalVolumeMounts: + - name: tls + mountPath: /qdrant/tls + readOnly: true + {{- else }} + additionalVolumes: [] + additionalVolumeMounts: [] + {{- end }} diff --git a/packages/apps/qdrant/tests/certmanager_test.yaml b/packages/apps/qdrant/tests/certmanager_test.yaml new file mode 100644 index 0000000000..293d876477 --- /dev/null +++ b/packages/apps/qdrant/tests/certmanager_test.yaml @@ -0,0 +1,467 @@ +suite: qdrant TLS cert-manager tests + +templates: + - templates/certmanager.yaml + +tests: + ##################### + # TLS disabled # + ##################### + + - it: renders no resources when tls.enabled is false + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: false + asserts: + - hasDocuments: + count: 0 + + ##################### + # TLS enabled # + ##################### + + - it: renders 4 cert-manager resources when tls.enabled is true + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - hasDocuments: + count: 4 + + - it: first document is a self-signed Issuer + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - isKind: + of: Issuer + documentIndex: 0 + - equal: + path: spec.selfSigned + value: {} + documentIndex: 0 + + - it: second document is a CA Certificate + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - isKind: + of: Certificate + documentIndex: 1 + - equal: + path: spec.isCA + value: true + documentIndex: 1 + + - it: third document is a CA-backed Issuer + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - isKind: + of: Issuer + documentIndex: 2 + - isNotNull: + path: spec.ca.secretName + documentIndex: 2 + + - it: fourth document is the TLS Certificate + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - isKind: + of: Certificate + documentIndex: 3 + - equal: + path: spec.isCA + value: false + documentIndex: 3 + + - it: leaf cert has server auth and client auth EKU + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - contains: + path: spec.usages + content: server auth + documentIndex: 3 + - contains: + path: spec.usages + content: client auth + documentIndex: 3 + - notContains: + path: spec.usages + content: cert sign + documentIndex: 3 + - notContains: + path: spec.usages + content: signing + documentIndex: 3 + + ####################################################### + # Canonical tri-state cases # + ####################################################### + + # (a) external: false, tls.enabled unset -> TLS OFF -> 0 documents + - it: "(a) renders no cert-manager resources when external is false and tls.enabled is unset" + release: + name: test-qdrant + namespace: tenant-test + set: + external: false + _cluster: + cluster-domain: cozy.local + asserts: + - hasDocuments: + count: 0 + + # (b) external: true, tls.enabled unset -> TLS ON -> 4 documents + external SAN + - it: "(b) renders 4 cert-manager resources when external is true and tls.enabled is unset" + release: + name: test-qdrant + namespace: tenant-test + set: + external: true + _namespace: + host: example.cozystack.io + _cluster: + cluster-domain: cozy.local + asserts: + - hasDocuments: + count: 4 + + - it: "(b) TLS Certificate contains external SAN when external is true and tls.enabled is unset" + release: + name: test-qdrant + namespace: tenant-test + set: + external: true + _namespace: + host: example.cozystack.io + _cluster: + cluster-domain: cozy.local + asserts: + - contains: + path: spec.dnsNames + content: test-qdrant.example.cozystack.io + documentIndex: 3 + + # (c) external: true, tls.enabled: false -> TLS OFF -> 0 documents + - it: "(c) renders no cert-manager resources when external is true but tls.enabled is explicitly false" + release: + name: test-qdrant + namespace: tenant-test + set: + external: true + tls: + enabled: false + _cluster: + cluster-domain: cozy.local + asserts: + - hasDocuments: + count: 0 + + # (d) external: false, tls.enabled: true -> TLS ON -> 4 documents, no external SAN + - it: "(d) renders 4 cert-manager resources when external is false but tls.enabled is explicitly true" + release: + name: test-qdrant + namespace: tenant-test + set: + external: false + tls: + enabled: true + _namespace: + host: example.cozystack.io + _cluster: + cluster-domain: cozy.local + asserts: + - hasDocuments: + count: 4 + - notContains: + path: spec.dnsNames + content: test-qdrant.example.cozystack.io + documentIndex: 3 + + ##################### + # Naming # + ##################### + + - it: names resources after release + release: + name: my-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: metadata.name + value: my-qdrant-selfsigned + documentIndex: 0 + - equal: + path: metadata.name + value: my-qdrant-ca + documentIndex: 1 + - equal: + path: metadata.name + value: my-qdrant-ca + documentIndex: 2 + - equal: + path: metadata.name + value: my-qdrant-tls + documentIndex: 3 + + - it: CA Certificate secretName matches CA Issuer secretName + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.secretName + value: test-qdrant-ca + documentIndex: 1 + - equal: + path: spec.ca.secretName + value: test-qdrant-ca + documentIndex: 2 + + - it: TLS Certificate secretName is release-tls + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - equal: + path: spec.secretName + value: test-qdrant-tls + documentIndex: 3 + + ##################### + # SAN — internal # + ##################### + + - it: TLS Certificate contains short service DNS name + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - contains: + path: spec.dnsNames + content: test-qdrant + documentIndex: 3 + + - it: TLS Certificate contains cluster-local service DNS name + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - contains: + path: spec.dnsNames + content: test-qdrant.tenant-test.svc + documentIndex: 3 + + - it: TLS Certificate contains FQDN service DNS name + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - contains: + path: spec.dnsNames + content: test-qdrant.tenant-test.svc.cozy.local + documentIndex: 3 + + - it: TLS Certificate contains headless service DNS name + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - contains: + path: spec.dnsNames + content: test-qdrant-headless + documentIndex: 3 + + - it: TLS Certificate contains headless cluster-local service DNS name + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - contains: + path: spec.dnsNames + content: test-qdrant-headless.tenant-test.svc + documentIndex: 3 + + - it: TLS Certificate contains headless FQDN service DNS name + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - contains: + path: spec.dnsNames + content: test-qdrant-headless.tenant-test.svc.cozy.local + documentIndex: 3 + + - it: TLS Certificate contains wildcard per-pod headless DNS name + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + _cluster: + cluster-domain: cozy.local + asserts: + - contains: + path: spec.dnsNames + content: "*.test-qdrant-headless.tenant-test.svc.cozy.local" + documentIndex: 3 + + - it: TLS Certificate has exactly 7 DNS names when external is false + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + external: false + _cluster: + cluster-domain: cozy.local + asserts: + - lengthEqual: + path: spec.dnsNames + count: 7 + documentIndex: 3 + + #################################### + # SAN — external # + #################################### + + - it: TLS Certificate has 8 DNS names when external is true + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + external: true + _namespace: + host: example.cozystack.io + _cluster: + cluster-domain: cozy.local + asserts: + - lengthEqual: + path: spec.dnsNames + count: 8 + documentIndex: 3 + + - it: TLS Certificate contains external DNS SAN when external is true + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + external: true + _namespace: + host: example.cozystack.io + _cluster: + cluster-domain: cozy.local + asserts: + - contains: + path: spec.dnsNames + content: test-qdrant.example.cozystack.io + documentIndex: 3 + + - it: does not add external SAN when external is false + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + external: false + _namespace: + host: example.cozystack.io + _cluster: + cluster-domain: cozy.local + asserts: + - notContains: + path: spec.dnsNames + content: test-qdrant.example.cozystack.io + documentIndex: 3 diff --git a/packages/apps/qdrant/tests/qdrant_test.yaml b/packages/apps/qdrant/tests/qdrant_test.yaml new file mode 100644 index 0000000000..599925bcb4 --- /dev/null +++ b/packages/apps/qdrant/tests/qdrant_test.yaml @@ -0,0 +1,291 @@ +suite: qdrant HelmRelease TLS tests + +templates: + - templates/qdrant.yaml + +tests: + ##################### + # Baseline # + ##################### + + - it: renders HelmRelease + release: + name: test-qdrant + namespace: tenant-test + asserts: + - hasDocuments: + count: 1 + - isKind: + of: HelmRelease + + ########################### + # TLS disabled # + ########################### + + - it: does not set service enable_tls when tls.enabled is false + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: false + asserts: + - equal: + path: spec.values.qdrant.config.service.enable_tls + value: false + + - it: does not set p2p enable_tls when tls.enabled is false + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: false + asserts: + - equal: + path: spec.values.qdrant.config.cluster.p2p.enable_tls + value: false + + - it: does not mount TLS volume when tls.enabled is false + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: false + asserts: + - isEmpty: + path: spec.values.qdrant.additionalVolumes + - isEmpty: + path: spec.values.qdrant.additionalVolumeMounts + + ########################### + # TLS enabled # + ########################### + + - it: sets service enable_tls to true when tls.enabled is true + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + asserts: + - equal: + path: spec.values.qdrant.config.service.enable_tls + value: true + + - it: sets p2p enable_tls to true when tls.enabled is true + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + asserts: + - equal: + path: spec.values.qdrant.config.cluster.p2p.enable_tls + value: true + + - it: sets tls.cert path when tls.enabled is true + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + asserts: + - equal: + path: spec.values.qdrant.config.tls.cert + value: /qdrant/tls/tls.crt + + - it: sets tls.key path when tls.enabled is true + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + asserts: + - equal: + path: spec.values.qdrant.config.tls.key + value: /qdrant/tls/tls.key + + - it: sets tls.ca_cert path when tls.enabled is true + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + asserts: + - equal: + path: spec.values.qdrant.config.tls.ca_cert + value: /qdrant/tls/ca.crt + + ########################### + # Volume mounts # + ########################### + + - it: mounts tls volume when tls.enabled is true + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + asserts: + - contains: + path: spec.values.qdrant.additionalVolumes + content: + name: tls + secret: + secretName: test-qdrant-tls + + - it: adds tls volumeMount when tls.enabled is true + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + asserts: + - contains: + path: spec.values.qdrant.additionalVolumeMounts + content: + name: tls + mountPath: /qdrant/tls + readOnly: true + + ####################################################### + # Canonical tri-state cases # + ####################################################### + + # (a) external: false, tls.enabled unset -> TLS OFF + - it: "(a) TLS is OFF when external is false and tls.enabled is unset" + release: + name: test-qdrant + namespace: tenant-test + set: + external: false + asserts: + - equal: + path: spec.values.qdrant.config.service.enable_tls + value: false + - equal: + path: spec.values.qdrant.config.cluster.p2p.enable_tls + value: false + - isEmpty: + path: spec.values.qdrant.additionalVolumes + - isEmpty: + path: spec.values.qdrant.additionalVolumeMounts + + # (b) external: true, tls.enabled unset -> TLS ON + - it: "(b) TLS is ON when external is true and tls.enabled is unset" + release: + name: test-qdrant + namespace: tenant-test + set: + external: true + asserts: + - equal: + path: spec.values.qdrant.config.service.enable_tls + value: true + - equal: + path: spec.values.qdrant.config.cluster.p2p.enable_tls + value: true + - contains: + path: spec.values.qdrant.additionalVolumes + content: + name: tls + secret: + secretName: test-qdrant-tls + + # (c) external: true, tls.enabled: false -> TLS OFF (explicit off wins) + - it: "(c) TLS is OFF when external is true but tls.enabled is explicitly false" + release: + name: test-qdrant + namespace: tenant-test + set: + external: true + tls: + enabled: false + asserts: + - equal: + path: spec.values.qdrant.config.service.enable_tls + value: false + - equal: + path: spec.values.qdrant.config.cluster.p2p.enable_tls + value: false + - isEmpty: + path: spec.values.qdrant.additionalVolumes + - isEmpty: + path: spec.values.qdrant.additionalVolumeMounts + + # (d) external: false, tls.enabled: true -> TLS ON (explicit on wins) + - it: "(d) TLS is ON when external is false but tls.enabled is explicitly true" + release: + name: test-qdrant + namespace: tenant-test + set: + external: false + tls: + enabled: true + asserts: + - equal: + path: spec.values.qdrant.config.service.enable_tls + value: true + - equal: + path: spec.values.qdrant.config.cluster.p2p.enable_tls + value: true + - contains: + path: spec.values.qdrant.additionalVolumes + content: + name: tls + secret: + secretName: test-qdrant-tls + + ########################### + # External service type # + ########################### + + - it: sets LoadBalancer service type when external is true + release: + name: test-qdrant + namespace: tenant-test + set: + external: true + asserts: + - equal: + path: spec.values.qdrant.service.type + value: LoadBalancer + + - it: does not set LoadBalancer when external is false + release: + name: test-qdrant + namespace: tenant-test + set: + external: false + asserts: + - notExists: + path: spec.values.qdrant.service.type + + ########################### + # Standalone mode (replicas=1) # + ########################### + + # Qdrant silently ignores cluster.p2p config in standalone mode, so + # emitting enable_tls: true with replicas=1 is harmless but intentional — + # the value is computed from tls.enabled alone, regardless of replica count. + - it: p2p enable_tls is emitted even for replicas=1 (cluster config ignored by Qdrant in standalone mode) + release: + name: test-qdrant + namespace: tenant-test + set: + tls: + enabled: true + replicas: 1 + asserts: + - equal: + path: spec.values.qdrant.config.cluster.p2p.enable_tls + value: true diff --git a/packages/apps/qdrant/values.schema.json b/packages/apps/qdrant/values.schema.json index 2c21514da8..c1784efd49 100644 --- a/packages/apps/qdrant/values.schema.json +++ b/packages/apps/qdrant/values.schema.json @@ -117,6 +117,17 @@ "description": "Enable external access from outside the cluster.", "type": "boolean", "default": false + }, + "tls": { + "description": "TLS configuration. When omitted, the effective TLS state follows the value of `external`.", + "type": "object", + "default": {}, + "properties": { + "enabled": { + "description": "Enable TLS. When unset, inherits the value of `external` (TLS is on when external access is enabled). Set explicitly to `true` or `false` to override.", + "type": "boolean" + } + } } } } diff --git a/packages/apps/qdrant/values.yaml b/packages/apps/qdrant/values.yaml index dc8b753a96..927050bcc3 100644 --- a/packages/apps/qdrant/values.yaml +++ b/packages/apps/qdrant/values.yaml @@ -72,3 +72,13 @@ storageClass: "" ## @param {bool} external - Enable external access from outside the cluster. external: false + +## +## @section TLS parameters +## + +## @typedef {struct} TLS - TLS configuration for Qdrant. +## @field {*bool} enabled - Enable TLS. When unset, inherits the value of `external` (TLS is on when external access is enabled). Set explicitly to `true` or `false` to override. + +## @param {TLS} [tls] - TLS configuration. When omitted, the effective TLS state follows the value of `external`. +tls: {} diff --git a/packages/system/qdrant-rd/cozyrds/qdrant.yaml b/packages/system/qdrant-rd/cozyrds/qdrant.yaml index 620c379c65..b266c0cead 100644 --- a/packages/system/qdrant-rd/cozyrds/qdrant.yaml +++ b/packages/system/qdrant-rd/cozyrds/qdrant.yaml @@ -8,7 +8,7 @@ spec: plural: qdrants singular: qdrant openAPISchema: |- - {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of Qdrant replicas. Cluster mode is automatically enabled when replicas > 1.","type":"integer","default":1},"resources":{"description":"Explicit CPU and memory configuration for each Qdrant replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"t1.small","enum":["t1.nano","t1.micro","t1.small","t1.medium","t1.large","t1.xlarge","t1.2xlarge","t1.4xlarge","c1.nano","c1.micro","c1.small","c1.medium","c1.large","c1.xlarge","c1.2xlarge","c1.4xlarge","s1.nano","s1.micro","s1.small","s1.medium","s1.large","s1.xlarge","s1.2xlarge","s1.4xlarge","u1.nano","u1.micro","u1.small","u1.medium","u1.large","u1.xlarge","u1.2xlarge","u1.4xlarge","m1.nano","m1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m1.2xlarge","m1.4xlarge","nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for vector data storage.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false}}} + {"title":"Chart Values","type":"object","properties":{"replicas":{"description":"Number of Qdrant replicas. Cluster mode is automatically enabled when replicas > 1.","type":"integer","default":1},"resources":{"description":"Explicit CPU and memory configuration for each Qdrant replica. When omitted, the preset defined in `resourcesPreset` is applied.","type":"object","default":{},"properties":{"cpu":{"description":"CPU available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"memory":{"description":"Memory (RAM) available to each replica.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true}}},"resourcesPreset":{"description":"Default sizing preset used when `resources` is omitted.","type":"string","default":"t1.small","enum":["t1.nano","t1.micro","t1.small","t1.medium","t1.large","t1.xlarge","t1.2xlarge","t1.4xlarge","c1.nano","c1.micro","c1.small","c1.medium","c1.large","c1.xlarge","c1.2xlarge","c1.4xlarge","s1.nano","s1.micro","s1.small","s1.medium","s1.large","s1.xlarge","s1.2xlarge","s1.4xlarge","u1.nano","u1.micro","u1.small","u1.medium","u1.large","u1.xlarge","u1.2xlarge","u1.4xlarge","m1.nano","m1.micro","m1.small","m1.medium","m1.large","m1.xlarge","m1.2xlarge","m1.4xlarge","nano","micro","small","medium","large","xlarge","2xlarge"]},"size":{"description":"Persistent Volume Claim size available for vector data storage.","default":"10Gi","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","anyOf":[{"type":"integer"},{"type":"string"}],"x-kubernetes-int-or-string":true},"storageClass":{"description":"StorageClass used to store the data.","type":"string","default":""},"external":{"description":"Enable external access from outside the cluster.","type":"boolean","default":false},"tls":{"description":"TLS configuration. When omitted, the effective TLS state follows the value of `external`.","type":"object","default":{},"properties":{"enabled":{"description":"Enable TLS. When unset, inherits the value of `external` (TLS is on when external access is enabled). Set explicitly to `true` or `false` to override.","type":"boolean"}}}}} release: prefix: qdrant- labels: @@ -27,7 +27,7 @@ spec: - vector-database - ai - ml - keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"]] + keysOrder: [["apiVersion"], ["appVersion"], ["kind"], ["metadata"], ["metadata", "name"], ["spec", "replicas"], ["spec", "resources"], ["spec", "resourcesPreset"], ["spec", "size"], ["spec", "storageClass"], ["spec", "external"], ["spec", "tls"]] secrets: exclude: [] include: