From 5b8e848f2a842a1c97f37434d501668ca77dda02 Mon Sep 17 00:00:00 2001 From: Lucas Alvares Gomes Date: Wed, 27 May 2026 09:57:01 +0100 Subject: [PATCH] Add PVC for persistent PostgreSQL storage Introduce a "database" field on the OpenStackLightspeed CR spec that allows configuring a PersistentVolumeClaim for the PostgreSQL data directory. A few details about the implementation: * Reuse existing PVC if one already exists with matching size * Block reconciliation with a clear error if existing PVC size does not match the requested size * If database is omitted from the CR, create a persistent storage with the default values * If no database.class is specified uses the cluster default * Default PVC size is "1Gi" The PVC is created without an owner reference so that data survives CR deletion and is reused on re-creation. Signed-off-by: Lucas Alvares Gomes --- api/v1beta1/openstacklightspeed_types.go | 20 ++++++ api/v1beta1/zz_generated.deepcopy.go | 23 ++++++- ...ed.openstack.org_openstacklightspeeds.yaml | 20 ++++++ ...tspeed-operator.clusterserviceversion.yaml | 18 +++-- ...ed.openstack.org_openstacklightspeeds.yaml | 20 ++++++ ...tspeed-operator.clusterserviceversion.yaml | 3 + config/rbac/role.yaml | 13 ++-- .../api_v1beta1_openstacklightspeed.yaml | 4 ++ internal/controller/constants.go | 2 + internal/controller/errors.go | 3 + .../openstacklightspeed_controller.go | 6 ++ internal/controller/postgres_deployment.go | 7 +- internal/controller/postgres_reconciler.go | 65 ++++++++++++++++++- .../assert-openstack-lightspeed-instance.yaml | 14 ++++ .../00-mock-resources.yaml | 1 + .../01-assert-mock-objects-created.yaml | 1 + .../02-cleanup-leftover-pvc.yaml | 8 +++ ...-create-openstack-lightspeed-instance.yaml | 18 +++++ ...-assert-openstack-lightspeed-instance.yaml | 54 +++++++++++++++ ...cleanup-openstack-lightspeed-instance.yaml | 1 + ...-errors-openstack-lightspeed-instance.yaml | 1 + .../07-cleanup-mock-objects.yaml | 1 + .../08-errors-mock-objects.yaml | 1 + 23 files changed, 285 insertions(+), 19 deletions(-) create mode 120000 test/kuttl/tests/persistent-database/00-mock-resources.yaml create mode 120000 test/kuttl/tests/persistent-database/01-assert-mock-objects-created.yaml create mode 100644 test/kuttl/tests/persistent-database/02-cleanup-leftover-pvc.yaml create mode 100644 test/kuttl/tests/persistent-database/03-create-openstack-lightspeed-instance.yaml create mode 100644 test/kuttl/tests/persistent-database/04-assert-openstack-lightspeed-instance.yaml create mode 120000 test/kuttl/tests/persistent-database/05-cleanup-openstack-lightspeed-instance.yaml create mode 120000 test/kuttl/tests/persistent-database/06-errors-openstack-lightspeed-instance.yaml create mode 120000 test/kuttl/tests/persistent-database/07-cleanup-mock-objects.yaml create mode 120000 test/kuttl/tests/persistent-database/08-errors-mock-objects.yaml diff --git a/api/v1beta1/openstacklightspeed_types.go b/api/v1beta1/openstacklightspeed_types.go index 4cdf0cd6..f5862e88 100644 --- a/api/v1beta1/openstacklightspeed_types.go +++ b/api/v1beta1/openstacklightspeed_types.go @@ -19,6 +19,7 @@ package v1beta1 import ( "github.com/openstack-k8s-operators/lib-common/modules/common/condition" "github.com/openstack-k8s-operators/lib-common/modules/common/util" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -48,6 +49,18 @@ const ( MaxTokensForResponseDefault = 2048 ) +// DatabaseSpec defines configuration for persistent PostgreSQL storage. +type DatabaseSpec struct { + // +kubebuilder:validation:Optional + // Size of the PersistentVolumeClaim for PostgreSQL data. Defaults to 1Gi. + Size resource.Quantity `json:"size,omitempty"` + + // +kubebuilder:validation:Optional + // StorageClass name for the PersistentVolumeClaim. If omitted, the cluster's + // default StorageClass is used. + Class string `json:"class,omitempty"` +} + // OpenStackLightspeedSpec defines the desired state of OpenStackLightspeed type OpenStackLightspeedSpec struct { OpenStackLightspeedCore `json:",inline"` @@ -65,6 +78,12 @@ type OpenStackLightspeedSpec struct { // Allows forcing a specific OCP version instead of auto-detection. // Format should be like "4.15", "4.16", etc. OCPRAGVersionOverride string `json:"ocpVersionOverride,omitempty"` + + // +kubebuilder:validation:Optional + // Database configures persistent storage for PostgreSQL data. + // When omitted, an emptyDir volume is used (data is lost on pod reschedule). + // When set, a PersistentVolumeClaim is created and mounted. + Database *DatabaseSpec `json:"database,omitempty"` } // OpenStackLightspeedCore defines the desired state of OpenStackLightspeed @@ -154,6 +173,7 @@ type OpenStackLightspeedStatus struct { // +operator-sdk:csv:customresourcedefinitions:resources={{ServiceAccount,v1,lightspeed-app-server}} // +operator-sdk:csv:customresourcedefinitions:resources={{NetworkPolicy,v1,lightspeed-app-server}} // +operator-sdk:csv:customresourcedefinitions:resources={{NetworkPolicy,v1,lightspeed-postgres-server}} +// +operator-sdk:csv:customresourcedefinitions:resources={{PersistentVolumeClaim,v1,openstack-lightspeed-data}} // +operator-sdk:csv:customresourcedefinitions:resources={{ClusterRole,v1,lightspeed-app-server-sar-role}} // +operator-sdk:csv:customresourcedefinitions:resources={{ClusterRoleBinding,v1,lightspeed-app-server-sar-role-binding}} // +operator-sdk:csv:customresourcedefinitions:resources={{Subscription,v1alpha1}} diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 266dec11..80eefb2e 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -25,12 +25,28 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DatabaseSpec) DeepCopyInto(out *DatabaseSpec) { + *out = *in + out.Size = in.Size.DeepCopy() +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DatabaseSpec. +func (in *DatabaseSpec) DeepCopy() *DatabaseSpec { + if in == nil { + return nil + } + out := new(DatabaseSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *OpenStackLightspeed) DeepCopyInto(out *OpenStackLightspeed) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) } @@ -118,6 +134,11 @@ func (in *OpenStackLightspeedList) DeepCopyObject() runtime.Object { func (in *OpenStackLightspeedSpec) DeepCopyInto(out *OpenStackLightspeedSpec) { *out = *in out.OpenStackLightspeedCore = in.OpenStackLightspeedCore + if in.Database != nil { + in, out := &in.Database, &out.Database + *out = new(DatabaseSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenStackLightspeedSpec. diff --git a/bundle/manifests/lightspeed.openstack.org_openstacklightspeeds.yaml b/bundle/manifests/lightspeed.openstack.org_openstacklightspeeds.yaml index a9fa4a71..fc6dbfbb 100644 --- a/bundle/manifests/lightspeed.openstack.org_openstacklightspeeds.yaml +++ b/bundle/manifests/lightspeed.openstack.org_openstacklightspeeds.yaml @@ -49,6 +49,26 @@ spec: spec: description: OpenStackLightspeedSpec defines the desired state of OpenStackLightspeed properties: + database: + description: |- + Database configures persistent storage for PostgreSQL data. + When omitted, an emptyDir volume is used (data is lost on pod reschedule). + When set, a PersistentVolumeClaim is created and mounted. + properties: + class: + description: |- + StorageClass name for the PersistentVolumeClaim. If omitted, the cluster's + default StorageClass is used. + type: string + size: + anyOf: + - type: integer + - type: string + description: Size of the PersistentVolumeClaim for PostgreSQL + data. Defaults to 1Gi. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object enableOCPRAG: default: false description: Enables automatic OCP documentation based on cluster diff --git a/bundle/manifests/openstack-lightspeed-operator.clusterserviceversion.yaml b/bundle/manifests/openstack-lightspeed-operator.clusterserviceversion.yaml index 1ad8c239..f401cf6b 100644 --- a/bundle/manifests/openstack-lightspeed-operator.clusterserviceversion.yaml +++ b/bundle/manifests/openstack-lightspeed-operator.clusterserviceversion.yaml @@ -25,7 +25,7 @@ metadata: ] capabilities: Basic Install categories: AI/Machine Learning - createdAt: "2026-05-17T15:20:36Z" + createdAt: "2026-05-27T08:37:10Z" description: AI-powered virtual assistant for Red Hat OpenStack Services on OpenShift features.operators.openshift.io/cnf: "false" features.operators.openshift.io/cni: "false" @@ -113,6 +113,9 @@ spec: - kind: Secret name: metrics-reader-token version: v1 + - kind: PersistentVolumeClaim + name: openstack-lightspeed-data + version: v1 specDescriptors: - description: |- Secret name containing API token for the LLMEndpoint. The secret must contain @@ -361,11 +364,10 @@ spec: - apiGroups: - "" resources: - - secrets + - persistentvolumeclaims + - services verbs: - create - - delete - - deletecollection - get - list - patch @@ -374,23 +376,25 @@ spec: - apiGroups: - "" resources: - - serviceaccounts + - secrets verbs: - create + - delete + - deletecollection - get - list - patch + - update - watch - apiGroups: - "" resources: - - services + - serviceaccounts verbs: - create - get - list - patch - - update - watch - apiGroups: - apps diff --git a/config/crd/bases/lightspeed.openstack.org_openstacklightspeeds.yaml b/config/crd/bases/lightspeed.openstack.org_openstacklightspeeds.yaml index 5f5b9071..b88cbcba 100644 --- a/config/crd/bases/lightspeed.openstack.org_openstacklightspeeds.yaml +++ b/config/crd/bases/lightspeed.openstack.org_openstacklightspeeds.yaml @@ -49,6 +49,26 @@ spec: spec: description: OpenStackLightspeedSpec defines the desired state of OpenStackLightspeed properties: + database: + description: |- + Database configures persistent storage for PostgreSQL data. + When omitted, an emptyDir volume is used (data is lost on pod reschedule). + When set, a PersistentVolumeClaim is created and mounted. + properties: + class: + description: |- + StorageClass name for the PersistentVolumeClaim. If omitted, the cluster's + default StorageClass is used. + type: string + size: + anyOf: + - type: integer + - type: string + description: Size of the PersistentVolumeClaim for PostgreSQL + data. Defaults to 1Gi. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object enableOCPRAG: default: false description: Enables automatic OCP documentation based on cluster diff --git a/config/manifests/bases/openstack-lightspeed-operator.clusterserviceversion.yaml b/config/manifests/bases/openstack-lightspeed-operator.clusterserviceversion.yaml index a14cccfe..449fc48e 100644 --- a/config/manifests/bases/openstack-lightspeed-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/openstack-lightspeed-operator.clusterserviceversion.yaml @@ -90,6 +90,9 @@ spec: - kind: Secret name: metrics-reader-token version: v1 + - kind: PersistentVolumeClaim + name: openstack-lightspeed-data + version: v1 specDescriptors: - description: |- Secret name containing API token for the LLMEndpoint. The secret must contain diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index a39fe276..66d5febc 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -111,11 +111,10 @@ rules: - apiGroups: - "" resources: - - secrets + - persistentvolumeclaims + - services verbs: - create - - delete - - deletecollection - get - list - patch @@ -124,23 +123,25 @@ rules: - apiGroups: - "" resources: - - serviceaccounts + - secrets verbs: - create + - delete + - deletecollection - get - list - patch + - update - watch - apiGroups: - "" resources: - - services + - serviceaccounts verbs: - create - get - list - patch - - update - watch - apiGroups: - apps diff --git a/config/samples/api_v1beta1_openstacklightspeed.yaml b/config/samples/api_v1beta1_openstacklightspeed.yaml index 2c0b9519..35e3224c 100644 --- a/config/samples/api_v1beta1_openstacklightspeed.yaml +++ b/config/samples/api_v1beta1_openstacklightspeed.yaml @@ -11,3 +11,7 @@ spec: llmCredentials: openstack-lightspeed-apitoken modelName: llama3.1:8b tlsCACertBundle: openstack-lightspeed-certs + # Uncomment to customize persistent PostgreSQL storage: + # database: + # size: "5Gi" + # class: "my-storage-class" diff --git a/internal/controller/constants.go b/internal/controller/constants.go index 1ee82b48..19d55e8f 100644 --- a/internal/controller/constants.go +++ b/internal/controller/constants.go @@ -72,6 +72,8 @@ const ( PostgresConfigVolumeMountPath = "/usr/share/pgsql/postgresql.conf.sample" PostgresDataVolume = "postgres-data" PostgresDataVolumeMountPath = "/var/lib/pgsql" + PostgresDataPVCName = "openstack-lightspeed-data" + PostgresDataPVCDefaultSize = "1Gi" PostgresVarRunVolumeName = "lightspeed-postgres-var-run" PostgresVarRunVolumeMountPath = "/var/run/postgresql" TmpVolumeName = "tmp-writable-volume" diff --git a/internal/controller/errors.go b/internal/controller/errors.go index 9640f76f..630468c5 100644 --- a/internal/controller/errors.go +++ b/internal/controller/errors.go @@ -59,4 +59,7 @@ var ( ErrCreatePostgresConfigMap = errors.New("failed to create Postgres configmap") ErrGetPostgresConfigMap = errors.New("failed to get Postgres configmap") ErrCreatePostgresNetworkPolicy = errors.New("failed to create Postgres network policy") + ErrCreatePostgresPVC = errors.New("failed to create Postgres PVC") + ErrGetPostgresPVC = errors.New("failed to get Postgres PVC") + ErrPostgresPVCSizeMismatch = errors.New("existing Postgres PVC size does not match requested size") ) diff --git a/internal/controller/openstacklightspeed_controller.go b/internal/controller/openstacklightspeed_controller.go index 5ae2e8a9..b369c3a0 100644 --- a/internal/controller/openstacklightspeed_controller.go +++ b/internal/controller/openstacklightspeed_controller.go @@ -73,6 +73,7 @@ func (r *OpenStackLightspeedReconciler) GetLogger(ctx context.Context) logr.Logg // +kubebuilder:rbac:groups="",resources=serviceaccounts,namespace=openstack-lightspeed,verbs=get;list;watch;create;patch // +kubebuilder:rbac:groups=console.openshift.io,resources=consoleplugins,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=operator.openshift.io,resources=consoles,verbs=watch;list;get;update +// +kubebuilder:rbac:groups="",resources=persistentvolumeclaims,namespace=openstack-lightspeed,verbs=get;list;watch;create;patch;update func (r *OpenStackLightspeedReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { Log := r.GetLogger(ctx) @@ -284,6 +285,11 @@ func (r *OpenStackLightspeedReconciler) SetupWithManager(mgr ctrl.Manager) error Owns(&corev1.ConfigMap{}). Owns(&corev1.Secret{}). Owns(&consolev1.ConsolePlugin{}). + Watches( + &corev1.PersistentVolumeClaim{}, + handler.EnqueueRequestsFromMapFunc(r.NotifyAllOpenStackLightspeeds), + builder.WithPredicates(predicate.ResourceVersionChangedPredicate{}), + ). Watches( clusterVersion, handler.EnqueueRequestsFromMapFunc(r.NotifyAllOpenStackLightspeeds), diff --git a/internal/controller/postgres_deployment.go b/internal/controller/postgres_deployment.go index f89f71e0..3988d0e9 100644 --- a/internal/controller/postgres_deployment.go +++ b/internal/controller/postgres_deployment.go @@ -27,7 +27,6 @@ import ( ) // buildPostgresPodTemplateSpec builds the pod template spec for the Postgres deployment. -// If configMapChanged is true, it adds a force-reload timestamp to trigger pod restart. func buildPostgresPodTemplateSpec() corev1.PodTemplateSpec { // Build volumes and volume mounts volumes := []corev1.Volume{} @@ -85,12 +84,12 @@ func buildPostgresPodTemplateSpec() corev1.PodTemplateSpec { SubPath: PostgresConfigKey, }) - // TODO: CRITICAL - Replace EmptyDir with a PVC. With EmptyDir all conversation - // history is lost if the pod is rescheduled or the OCP control plane goes down. volumes = append(volumes, corev1.Volume{ Name: PostgresDataVolume, VolumeSource: corev1.VolumeSource{ - EmptyDir: &corev1.EmptyDirVolumeSource{}, + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ + ClaimName: PostgresDataPVCName, + }, }, }) volumeMounts = append(volumeMounts, corev1.VolumeMount{ diff --git a/internal/controller/postgres_reconciler.go b/internal/controller/postgres_reconciler.go index 70d4549a..fa1a8dad 100644 --- a/internal/controller/postgres_reconciler.go +++ b/internal/controller/postgres_reconciler.go @@ -28,6 +28,7 @@ import ( corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/intstr" @@ -53,6 +54,7 @@ func ReconcilePostgresResources(h *common_helper.Helper, ctx context.Context, in // Uses fail-fast pattern where the first error stops execution. func ReconcilePostgresDeployment(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { tasks := []ReconcileTask{ + {Name: "PostgresPVC", Task: reconcilePostgresPVC}, {Name: "PostgresDeployment", Task: reconcilePostgresDeploymentTask}, {Name: "PostgresService", Task: reconcilePostgresServiceTask}, } @@ -222,7 +224,68 @@ func reconcilePostgresNetworkPolicy(h *common_helper.Helper, ctx context.Context return nil } -func reconcilePostgresDeploymentTask(h *common_helper.Helper, ctx context.Context, _ *apiv1beta1.OpenStackLightspeed) error { +func reconcilePostgresPVC(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { + requestedQty := resource.MustParse(PostgresDataPVCDefaultSize) + var storageClass string + if instance.Spec.Database != nil { + if !instance.Spec.Database.Size.IsZero() { + requestedQty = instance.Spec.Database.Size + } + storageClass = instance.Spec.Database.Class + } + + pvc := &corev1.PersistentVolumeClaim{} + pvcKey := client.ObjectKey{ + Name: PostgresDataPVCName, + Namespace: h.GetBeforeObject().GetNamespace(), + } + + err := h.GetClient().Get(ctx, pvcKey, pvc) + if err != nil && !errors.IsNotFound(err) { + return fmt.Errorf("%w: %v", ErrGetPostgresPVC, err) + } + + if err == nil { + // PVC already exists, validate if the size matches + existingQty := pvc.Spec.Resources.Requests[corev1.ResourceStorage] + if requestedQty.Cmp(existingQty) != 0 { + return fmt.Errorf("%w: requested size %s but existing PVC has %s", + ErrPostgresPVCSizeMismatch, requestedQty.String(), existingQty.String()) + } + h.GetLogger().Info("Postgres PVC already exists with matching size", "name", pvc.Name) + return nil + } + + // PVC does not exist, create it + pvc = &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: PostgresDataPVCName, + Namespace: h.GetBeforeObject().GetNamespace(), + }, + } + + result, err := controllerutil.CreateOrPatch(ctx, h.GetClient(), pvc, func() error { + pvc.Spec.AccessModes = []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce} + pvc.Spec.Resources = corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: requestedQty, + }, + } + if storageClass != "" { + pvc.Spec.StorageClassName = &storageClass + } + return nil + }) + + if err != nil { + return fmt.Errorf("%w: %v", ErrCreatePostgresPVC, err) + } + + h.GetLogger().Info("Postgres PVC reconciled", "name", pvc.Name, "result", result) + return nil +} + +func reconcilePostgresDeploymentTask(h *common_helper.Helper, ctx context.Context, instance *apiv1beta1.OpenStackLightspeed) error { deployment := &appsv1.Deployment{ ObjectMeta: metav1.ObjectMeta{ Name: PostgresDeploymentName, diff --git a/test/kuttl/common/openstack-lightspeed-instance/assert-openstack-lightspeed-instance.yaml b/test/kuttl/common/openstack-lightspeed-instance/assert-openstack-lightspeed-instance.yaml index bf2ce836..9449e2ee 100644 --- a/test/kuttl/common/openstack-lightspeed-instance/assert-openstack-lightspeed-instance.yaml +++ b/test/kuttl/common/openstack-lightspeed-instance/assert-openstack-lightspeed-instance.yaml @@ -2,6 +2,20 @@ # Assert that the operator created all expected resources # ############################################################################## +# Postgres PVC (persistent storage is always enabled) +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: openstack-lightspeed-data + namespace: openstack-lightspeed +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + # Postgres resources --- apiVersion: v1 diff --git a/test/kuttl/tests/persistent-database/00-mock-resources.yaml b/test/kuttl/tests/persistent-database/00-mock-resources.yaml new file mode 120000 index 00000000..8235a1fd --- /dev/null +++ b/test/kuttl/tests/persistent-database/00-mock-resources.yaml @@ -0,0 +1 @@ +../../common/mock-objects/mock-resources.yaml \ No newline at end of file diff --git a/test/kuttl/tests/persistent-database/01-assert-mock-objects-created.yaml b/test/kuttl/tests/persistent-database/01-assert-mock-objects-created.yaml new file mode 120000 index 00000000..07f977a1 --- /dev/null +++ b/test/kuttl/tests/persistent-database/01-assert-mock-objects-created.yaml @@ -0,0 +1 @@ +../../common/mock-objects/assert-mock-objects-created.yaml \ No newline at end of file diff --git a/test/kuttl/tests/persistent-database/02-cleanup-leftover-pvc.yaml b/test/kuttl/tests/persistent-database/02-cleanup-leftover-pvc.yaml new file mode 100644 index 00000000..2dd8f7aa --- /dev/null +++ b/test/kuttl/tests/persistent-database/02-cleanup-leftover-pvc.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: kuttl.dev/v1beta1 +kind: TestStep +delete: + - apiVersion: v1 + kind: PersistentVolumeClaim + name: openstack-lightspeed-data + namespace: openstack-lightspeed diff --git a/test/kuttl/tests/persistent-database/03-create-openstack-lightspeed-instance.yaml b/test/kuttl/tests/persistent-database/03-create-openstack-lightspeed-instance.yaml new file mode 100644 index 00000000..338f7ef0 --- /dev/null +++ b/test/kuttl/tests/persistent-database/03-create-openstack-lightspeed-instance.yaml @@ -0,0 +1,18 @@ +--- +apiVersion: lightspeed.openstack.org/v1beta1 +kind: OpenStackLightspeed +metadata: + name: openstack-lightspeed + namespace: openstack-lightspeed +spec: + llmEndpoint: http://mock-llm-api-server-pod:8000/v1 + llmEndpointType: openai + llmCredentials: openstack-lightspeed-apitoken + modelName: ibm-granite/granite-3.1-8b-instruct + tlsCACertBundle: openstack-lightspeed-cert + llmProjectID: test-project-id + llmDeploymentName: test-deployment-name + llmAPIVersion: v1 + enableOCPRAG: false + database: + size: "2Gi" diff --git a/test/kuttl/tests/persistent-database/04-assert-openstack-lightspeed-instance.yaml b/test/kuttl/tests/persistent-database/04-assert-openstack-lightspeed-instance.yaml new file mode 100644 index 00000000..12564ff1 --- /dev/null +++ b/test/kuttl/tests/persistent-database/04-assert-openstack-lightspeed-instance.yaml @@ -0,0 +1,54 @@ +############################################################################## +# Assert that the PVC was created with the custom size # +############################################################################## + +# Postgres PVC with custom size from CR +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: openstack-lightspeed-data + namespace: openstack-lightspeed +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 2Gi + +# Postgres Deployment should be running +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: lightspeed-postgres-server + namespace: openstack-lightspeed +status: + replicas: 1 + readyReplicas: 1 + availableReplicas: 1 + +# OpenStackLightspeed CR status +--- +apiVersion: lightspeed.openstack.org/v1beta1 +kind: OpenStackLightspeed +metadata: + name: openstack-lightspeed + namespace: openstack-lightspeed +spec: + database: + size: "2Gi" +status: + conditions: + - type: Ready + status: "True" + reason: Ready + message: Setup complete + - type: OCPRAGReady + status: "True" + reason: Ready + message: OCP RAG is disabled + - type: OpenStackLightspeedReady + status: "True" + reason: Ready + message: OpenStack Lightspeed created diff --git a/test/kuttl/tests/persistent-database/05-cleanup-openstack-lightspeed-instance.yaml b/test/kuttl/tests/persistent-database/05-cleanup-openstack-lightspeed-instance.yaml new file mode 120000 index 00000000..6b2075b0 --- /dev/null +++ b/test/kuttl/tests/persistent-database/05-cleanup-openstack-lightspeed-instance.yaml @@ -0,0 +1 @@ +../../common/openstack-lightspeed-instance/cleanup-openstack-lightspeed-instance.yaml \ No newline at end of file diff --git a/test/kuttl/tests/persistent-database/06-errors-openstack-lightspeed-instance.yaml b/test/kuttl/tests/persistent-database/06-errors-openstack-lightspeed-instance.yaml new file mode 120000 index 00000000..81472440 --- /dev/null +++ b/test/kuttl/tests/persistent-database/06-errors-openstack-lightspeed-instance.yaml @@ -0,0 +1 @@ +../../common/openstack-lightspeed-instance/errors-openstack-lightspeed-instance.yaml \ No newline at end of file diff --git a/test/kuttl/tests/persistent-database/07-cleanup-mock-objects.yaml b/test/kuttl/tests/persistent-database/07-cleanup-mock-objects.yaml new file mode 120000 index 00000000..410c9278 --- /dev/null +++ b/test/kuttl/tests/persistent-database/07-cleanup-mock-objects.yaml @@ -0,0 +1 @@ +../../common/mock-objects/cleanup-mock-objects.yaml \ No newline at end of file diff --git a/test/kuttl/tests/persistent-database/08-errors-mock-objects.yaml b/test/kuttl/tests/persistent-database/08-errors-mock-objects.yaml new file mode 120000 index 00000000..696a5e26 --- /dev/null +++ b/test/kuttl/tests/persistent-database/08-errors-mock-objects.yaml @@ -0,0 +1 @@ +../../common/mock-objects/errors-mock-objects.yaml \ No newline at end of file