Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ spec:
storage:
format: "PVC"
folder: "/inputs"
size: "1Gi"
size: "1Gi" # Optional, defaults to "5Gi" if not specified when using PVC mode
data:
filename: "data.csv"
format: "CSV"
Expand Down
28 changes: 26 additions & 2 deletions api/tas/v1alpha1/trustyaiservice_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

const (
// DefaultPVCSize is the default size for PVC when missing from the spec
DefaultPVCSize = "5Gi"
)

// TrustyAIService is the Schema for the trustyaiservices API
// +kubebuilder:object:root=true
// +kubebuilder:storageversion
Expand All @@ -36,8 +41,11 @@ type TrustyAIService struct {
type StorageSpec struct {
// Format only supports "PVC" or "DATABASE" values
// +kubebuilder:validation:Enum=PVC;DATABASE
Format string `json:"format"`
Folder string `json:"folder,omitempty"`
Format string `json:"format"`
Folder string `json:"folder,omitempty"`
// Size specifies the storage size when using PVC format
// If not specified, a default size of DefaultPVCSize will be used (when in PVC mode)
// Size is ignored when in database mode and for migration, the existing PVC will be used if found
Size string `json:"size,omitempty"`
DatabaseConfigurations string `json:"databaseConfigurations,omitempty"`
}
Expand Down Expand Up @@ -108,6 +116,22 @@ func (s *StorageSpec) IsStorageDatabase() bool {
return s.Format == "DATABASE"
}

// GetSize returns the specified storage size or a default value if not set (only relevant for PVC mode)
func (s *StorageSpec) GetSize() string {
// For database mode, always ignore size (even in migration cases)
if s.IsStorageDatabase() {
return ""
}

// For PVC mode
if s.Size != "" {
return s.Size
}

// Default size for PVC mode, when missing
return DefaultPVCSize
}

// IsMigration returns true if the migration fields are set.
func (t *TrustyAIService) IsMigration() bool {
if t.Spec.Storage.Format == "DATABASE" && t.Spec.Storage.Folder != "" && t.Spec.Data.Filename != "" {
Expand Down
62 changes: 62 additions & 0 deletions api/tas/v1alpha1/trustyaiservice_types_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package v1alpha1

import (
"testing"
)

func TestStorageSpecGetSize(t *testing.T) {
tests := []struct {
name string
storage StorageSpec
expected string
}{
{
name: "PVC with specified size",
storage: StorageSpec{
Format: "PVC",
Size: "10Gi",
},
expected: "10Gi",
},
{
name: "PVC with missing size",
storage: StorageSpec{
Format: "PVC",
},
expected: DefaultPVCSize,
},
{
name: "Database mode with specified size (should be ignored)",
storage: StorageSpec{
Format: "DATABASE",
Size: "10Gi",
},
expected: "",
},
{
name: "Database mode with no size specified",
storage: StorageSpec{
Format: "DATABASE",
},
expected: "",
},
{
name: "Migration case with size (should still be ignored)",
storage: StorageSpec{
Format: "DATABASE",
Folder: "/data",
Size: "5Gi",
},
expected: "",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := tt.storage.GetSize()
if result != tt.expected {
t.Errorf("GetSize() = %v, expected %v", result, tt.expected)
}
})
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ spec:
- DATABASE
type: string
size:
description: |-
Size specifies the storage size when using PVC format
If not specified, a default size of DefaultPVCSize will be used (when in PVC mode)
Size is ignored when in database mode and for migration, the existing PVC will be used if found
type: string
required:
- format
Expand Down
21 changes: 11 additions & 10 deletions controllers/tas/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package tas

import (
"context"
"fmt"
"reflect"
"strconv"

Expand Down Expand Up @@ -99,17 +100,18 @@ func (r *TrustyAIServiceReconciler) createDeploymentObject(ctx context.Context,

// reconcileDeployment returns a Deployment object with the same name/namespace as the cr
func (r *TrustyAIServiceReconciler) createDeployment(ctx context.Context, cr *trustyaiopendatahubiov1alpha1.TrustyAIService, imageName string, caBundle CustomCertificatesBundle) error {

if !cr.Spec.Storage.IsDatabaseConfigurationsSet() {

// For PVC mode or migration mode, check that the PVC exists
if cr.Spec.Storage.IsStoragePVC() || cr.IsMigration() {
pvcName := generatePVCName(cr)

pvc := &corev1.PersistentVolumeClaim{}
pvcerr := r.Get(ctx, types.NamespacedName{Name: pvcName, Namespace: cr.Namespace}, pvc)
if pvcerr != nil {
log.FromContext(ctx).Error(pvcerr, "PVC not found")
return pvcerr
}
} else if !cr.Spec.Storage.IsDatabaseConfigurationsSet() {
// database mode without configurations set
return fmt.Errorf("database configurations must be set for database storage mode")
}

// We can now create the Deployment.
Expand All @@ -131,22 +133,22 @@ func (r *TrustyAIServiceReconciler) createDeployment(ctx context.Context, cr *tr
}
// Created successfully
return nil

}

// updateDeployment returns a Deployment object with the same name/namespace as the cr
func (r *TrustyAIServiceReconciler) updateDeployment(ctx context.Context, cr *trustyaiopendatahubiov1alpha1.TrustyAIService, imageName string, caBundle CustomCertificatesBundle) error {

if !cr.Spec.Storage.IsDatabaseConfigurationsSet() {

// For PVC mode or migration mode, check that the PVC exists
if cr.Spec.Storage.IsStoragePVC() || cr.IsMigration() {
pvcName := generatePVCName(cr)

pvc := &corev1.PersistentVolumeClaim{}
pvcerr := r.Get(ctx, types.NamespacedName{Name: pvcName, Namespace: cr.Namespace}, pvc)
if pvcerr != nil {
log.FromContext(ctx).Error(pvcerr, "PVC not found")
return pvcerr
}
} else if !cr.Spec.Storage.IsDatabaseConfigurationsSet() {
// Pure database mode without configurations set
return fmt.Errorf("database configurations must be set for database storage mode")
}

// We can now create the Deployment object.
Expand All @@ -168,7 +170,6 @@ func (r *TrustyAIServiceReconciler) updateDeployment(ctx context.Context, cr *tr
}
// Created successfully
return nil

}

func (r *TrustyAIServiceReconciler) ensureDeployment(ctx context.Context, instance *trustyaiopendatahubiov1alpha1.TrustyAIService, caBundle CustomCertificatesBundle, migration bool) error {
Expand Down
3 changes: 2 additions & 1 deletion controllers/tas/deployment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ func setupAndTestDeploymentServiceAccount(instance *trustyaiopendatahubiov1alpha

caBundle := reconciler.GetCustomCertificatesBundle(ctx, instance)

if mode == "PVC" {
// Create a PVC for PVC mode or migration mode
if mode == "PVC" || instance.IsMigration() {
Expect(createTestPVC(ctx, k8sClient, instance)).To(Succeed())
}
Expect(reconciler.createServiceAccount(ctx, instance)).To(Succeed())
Expand Down
39 changes: 35 additions & 4 deletions controllers/tas/storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,21 @@ func generatePVCName(instance *trustyaiopendatahubiov1alpha1.TrustyAIService) st
}

func (r *TrustyAIServiceReconciler) ensurePVC(ctx context.Context, instance *trustyaiopendatahubiov1alpha1.TrustyAIService) error {
pvcName := generatePVCName(instance)
// Skip PVC creation for database mode, unless it's a migration
if instance.Spec.Storage.IsStorageDatabase() && !instance.IsMigration() {
log.FromContext(ctx).Info("Skipping PVC check for database mode")
return nil
}

pvcName := generatePVCName(instance)
pvc := &corev1.PersistentVolumeClaim{}

// Check if PVC already exists
err := r.Get(ctx, types.NamespacedName{Name: pvcName, Namespace: instance.Namespace}, pvc)
if err != nil {
if apierrors.IsNotFound(err) {
// PVC doesn't exist, create it
log.FromContext(ctx).Info("PVC not found. Creating.")
// The PVC doesn't exist, so we need to create it

creationErr := r.createPVC(ctx, instance)
if creationErr == nil {
// Creation successful, emit Event
Expand All @@ -39,10 +44,36 @@ func (r *TrustyAIServiceReconciler) ensurePVC(ctx context.Context, instance *tru
return err
}

// For migration case, we've found an existing PVC and will use it
if instance.IsMigration() {
log.FromContext(ctx).Info("Found existing PVC for migration case. Using it.")
}

return nil
}

func (r *TrustyAIServiceReconciler) createPVC(ctx context.Context, instance *trustyaiopendatahubiov1alpha1.TrustyAIService) error {
// Skip PVC creation for database storage, unless it's a migration
if instance.Spec.Storage.IsStorageDatabase() && !instance.IsMigration() {
log.FromContext(ctx).Info("Skipping PVC creation for database mode")
return nil
}

// For migration, use DefaultPVCSize regardless of what's in the CR
var size string
if instance.IsMigration() {
size = trustyaiopendatahubiov1alpha1.DefaultPVCSize
log.FromContext(ctx).Info("Using size of " + size + " for migration PVC")
} else {
// For regular PVC mode, get the size from the CR or use default
size = instance.Spec.Storage.GetSize()
}

if size == "" {
log.FromContext(ctx).Info("Skipping PVC creation because size is empty")
return nil
}

pvcName := generatePVCName(instance)

pvc := &corev1.PersistentVolumeClaim{
Expand All @@ -56,7 +87,7 @@ func (r *TrustyAIServiceReconciler) createPVC(ctx context.Context, instance *tru
},
Resources: corev1.VolumeResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceStorage: resource.MustParse(instance.Spec.Storage.Size),
corev1.ResourceStorage: resource.MustParse(size),
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion controllers/tas/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func createDefaultMigrationCustomResource(namespaceCurrent string) *trustyaiopen
Format: STORAGE_DATABASE,
DatabaseConfigurations: defaultDatabaseConfigurationName,
Folder: "/data",
Size: "1Gi",
// Size not set as it's ignored in database mode
},
Data: trustyaiopendatahubiov1alpha1.DataSpec{
Filename: "data.csv",
Expand Down
Loading