github.com/metaprov/modela-operator@v0.0.0-20240118193048-f378be8b74d2/controllers/components/online_store.go (about)

     1  package components
     2  
     3  import (
     4  	"context"
     5  	managementv1 "github.com/metaprov/modela-operator/api/v1alpha1"
     6  	"github.com/metaprov/modela-operator/pkg/helm"
     7  	"github.com/metaprov/modela-operator/pkg/kube"
     8  	k8serr "k8s.io/apimachinery/pkg/api/errors"
     9  	"sigs.k8s.io/controller-runtime/pkg/log"
    10  	"sigs.k8s.io/kustomize/kyaml/kio"
    11  )
    12  
    13  // Modela system represent the model core system
    14  type OnlineStore struct {
    15  	Namespace     string
    16  	Version       string
    17  	ReleaseName   string
    18  	Name          string
    19  	PodNamePrefix string
    20  	ManifestPath  string
    21  	Dryrun        bool
    22  }
    23  
    24  func NewOnlineStore() *OnlineStore {
    25  	return &OnlineStore{
    26  		Namespace:     "modela-system",
    27  		ManifestPath:  "online-store",
    28  		PodNamePrefix: "modela-online-store",
    29  		ReleaseName:   "modela-redis",
    30  		Name:          "redis",
    31  	}
    32  }
    33  
    34  func (os OnlineStore) GetInstallPhase() managementv1.ModelaPhase {
    35  	return managementv1.ModelaPhaseInstallingOnlineStore
    36  }
    37  
    38  func (os OnlineStore) IsEnabled(modela managementv1.Modela) bool {
    39  	return modela.Spec.OnlineStore.Install
    40  }
    41  
    42  // Check if the database installed
    43  func (os OnlineStore) Installed(ctx context.Context) (bool, error) {
    44  	if created, err := kube.IsNamespaceCreated("modela-system"); !created || err != nil {
    45  		return created, err
    46  	}
    47  	if _, missing, err := kube.LoadResources(os.ManifestPath, nil, false); missing > 0 {
    48  		log.FromContext(ctx).Info("Resources detected as missing from the modela-system namespace", "count", missing)
    49  		return false, managementv1.ComponentMissingResourcesError
    50  	} else if err != nil {
    51  		return false, err
    52  	}
    53  
    54  	if installed, err := helm.IsChartInstalled(ctx, os.Name, os.Namespace, os.ReleaseName); !installed {
    55  		return false, err
    56  	}
    57  
    58  	return true, nil
    59  }
    60  
    61  func (os OnlineStore) Install(ctx context.Context, modela *managementv1.Modela) error {
    62  	logger := log.FromContext(ctx)
    63  
    64  	if err := kube.CreateNamespace(os.Namespace, modela.Name); err != nil && !k8serr.IsAlreadyExists(err) {
    65  		logger.Error(err, "failed to create namespace")
    66  		return err
    67  	}
    68  
    69  	logger.Info("Applying Helm Chart", "version", os.Version)
    70  	if installed, err := helm.IsChartInstalled(ctx, os.Name, os.Namespace, os.ReleaseName); !installed {
    71  		if err = helm.InstallChart(ctx, os.Name, os.Namespace, os.ReleaseName, modela.Spec.OnlineStore.Values.Object); err != nil {
    72  			return err
    73  		}
    74  	}
    75  
    76  	var password string
    77  	if values, err := kube.GetSecretValuesAsString("modela-system", "redis"); err == nil {
    78  		password, _ = values["redis-password"]
    79  	}
    80  
    81  	yaml, _, err := kube.LoadResources(os.ManifestPath, []kio.Filter{
    82  		kube.LabelFilter{Labels: map[string]string{"management.modela.ai/operator": modela.Name}},
    83  		kube.NamespaceFilter{Namespace: os.Namespace},
    84  		kube.RedisSecretFilter{Password: password},
    85  		kube.ContainerVersionFilter{Version: modela.Spec.Distribution},
    86  		kube.OwnerReferenceFilter{Owner: modela.GetName(), OwnerNamespace: modela.GetNamespace(), UID: string(modela.GetUID())},
    87  	}, false)
    88  	if err != nil {
    89  		return err
    90  	}
    91  
    92  	logger.Info("Applying online store resources", "length", len(yaml))
    93  	if err := kube.ApplyYaml(string(yaml)); err != nil {
    94  		return err
    95  	}
    96  
    97  	return nil
    98  }
    99  
   100  func (os OnlineStore) InstallNewVersion(ctx context.Context, modela *managementv1.Modela) error {
   101  	logger := log.FromContext(ctx)
   102  
   103  	var password string
   104  	if values, err := kube.GetSecretValuesAsString("modela-system", "redis"); err == nil {
   105  		password, _ = values["redis-password"]
   106  	}
   107  
   108  	yaml, _, err := kube.LoadResources(os.ManifestPath, []kio.Filter{
   109  		kube.LabelFilter{Labels: map[string]string{"management.modela.ai/operator": modela.Name}},
   110  		kube.NamespaceFilter{Namespace: os.Namespace},
   111  		kube.RedisSecretFilter{Password: password},
   112  		kube.ContainerVersionFilter{Version: modela.Spec.Distribution},
   113  		kube.OwnerReferenceFilter{Owner: modela.GetName(), OwnerNamespace: modela.GetNamespace(), UID: string(modela.GetUID())},
   114  	}, false)
   115  	if err != nil {
   116  		return err
   117  	}
   118  
   119  	logger.Info("Applying online store resources", "length", len(yaml), "ns", os.Namespace)
   120  	if err := kube.ApplyYaml(string(yaml)); err != nil {
   121  		return err
   122  	}
   123  
   124  	return nil
   125  }
   126  
   127  func (os OnlineStore) Installing(ctx context.Context) (bool, error) {
   128  	installed, err := os.Installed(ctx)
   129  	if !installed {
   130  		return installed, err
   131  	}
   132  
   133  	running, err := kube.IsPodRunning(os.Namespace, os.PodNamePrefix)
   134  	if err != nil {
   135  		return false, err
   136  	}
   137  	return !running, nil
   138  }
   139  
   140  func (os OnlineStore) Ready(ctx context.Context) (bool, error) {
   141  	installing, err := os.Installing(ctx)
   142  	if err != nil && err != managementv1.ComponentNotInstalledByModelaError {
   143  		return false, err
   144  	}
   145  	return !installing, nil
   146  }
   147  
   148  func (os OnlineStore) Uninstall(ctx context.Context, modela *managementv1.Modela) error {
   149  	return helm.UninstallChart(ctx, os.Name, os.Namespace, os.ReleaseName, map[string]interface{}{})
   150  }