github.com/metaprov/modela-operator@v0.0.0-20240118193048-f378be8b74d2/api/v1alpha1/modela_types.go (about)

     1  /*
     2  Copyright 2022.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package v1alpha1
    18  
    19  import (
    20  	"encoding/json"
    21  	"errors"
    22  	v1 "k8s.io/api/core/v1"
    23  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    24  	"k8s.io/apimachinery/pkg/runtime"
    25  )
    26  
    27  // The current phase of a Modela installation
    28  type ModelaPhase string
    29  
    30  const (
    31  	ModelaPhaseInstallingVault         = "InstallingVault"
    32  	ModelaPhaseInstallingCertManager   = "InstallingCertManager"
    33  	ModelaPhaseInstallingObjectStorage = "InstallingObjectStorage"
    34  	ModelaPhaseInstallingOnlineStore   = "InstallingOnlineStore"
    35  	ModelaPhaseInstallingNginx         = "InstallingNginx"
    36  	ModelaPhaseInstallingPrometheus    = "InstallingPrometheus"
    37  	ModelaPhaseInstallingGrafana       = "InstallingGrafana"
    38  	ModelaPhaseInstallingLoki          = "InstallingLoki"
    39  	ModelaPhaseInstallingDatabase      = "InstallingSystemDatabase"
    40  	ModelaPhaseInstallingModela        = "InstallingModela"
    41  	ModelaPhaseInstallingTenant        = "InstallingTenant"
    42  	ModelaPhaseReady                   = "Ready"
    43  	ModelaPhaseUninstalling            = "UninstallingComponent"
    44  	ModelaPhaseFailed                  = "Failed"
    45  )
    46  
    47  var (
    48  	ComponentNotInstalledByModelaError = errors.New("component not installed by Modela Operator")
    49  	ComponentMissingResourcesError     = errors.New("component missing resources")
    50  )
    51  
    52  // ConditionStatus defines conditions of resources
    53  type ConditionStatus string
    54  
    55  // These are valid condition statuses. "ConditionTrue" means a resource is in the condition;
    56  // "ConditionFalse" means a resource is not in the condition; "ConditionUnknown" means kubernetes
    57  // can't decide if a resource is in the condition or not. In the future, we could add other
    58  // intermediate conditions, e.g. ConditionDegraded
    59  const (
    60  	ConditionTrue    ConditionStatus = "True"
    61  	ConditionFalse   ConditionStatus = "False"
    62  	ConditionUnknown ConditionStatus = "Unknown"
    63  )
    64  
    65  // ClusterConditionType is of string type
    66  type ModelaConditionType string
    67  
    68  // ClusterCondition describes the state of a cluster object at a certain point
    69  type ModelaCondition struct {
    70  	// Type of the condition.
    71  	Type ModelaConditionType `json:"type,omitempty"`
    72  	// Status of the condition, one of True, False, Unknown.
    73  	Status ConditionStatus `json:"status,omitempty"`
    74  	// Last time the condition transitioned from one status to another.
    75  	LastTransitionTime *metav1.Time `json:"lastTransitionTime,omitempty"`
    76  	// The reason for the condition's last transition.
    77  	Reason string `json:"reason,omitempty"`
    78  	// A human-readable message indicating details about the transition.
    79  	Message string `json:"message,omitempty"`
    80  }
    81  
    82  // Unstructured values for rendering Helm Charts
    83  // +k8s:deepcopy-gen=false
    84  type ChartValues struct {
    85  	// Object is a JSON compatible map with string, float, int, bool, []interface{}, or
    86  	// map[string]interface{} children.
    87  	Object map[string]interface{} `json:"-"`
    88  }
    89  
    90  // MarshalJSON ensures that the unstructured object produces proper
    91  // JSON when passed to Go's standard JSON library.
    92  func (u *ChartValues) MarshalJSON() ([]byte, error) {
    93  	return json.Marshal(u.Object)
    94  }
    95  
    96  // UnmarshalJSON ensures that the unstructured object properly decodes
    97  // JSON when passed to Go's standard JSON library.
    98  func (u *ChartValues) UnmarshalJSON(data []byte) error {
    99  	m := make(map[string]interface{})
   100  	if err := json.Unmarshal(data, &m); err != nil {
   101  		return err
   102  	}
   103  
   104  	u.Object = m
   105  
   106  	return nil
   107  }
   108  
   109  // Declaring this here prevents it from being generated.
   110  func (u *ChartValues) DeepCopyInto(out *ChartValues) {
   111  	out.Object = runtime.DeepCopyJSON(u.Object)
   112  }
   113  
   114  // IngressSpec defines the configuration for Modela to be exposed externally through Ingress resources.
   115  // The Kubernetes Ingress Class annotation (kubernetes.io/ingress.class) must be defined in the parent Modela resource
   116  // for Ingress resources to be created.
   117  type IngressSpec struct {
   118  	// Enabled indicates if Ingress resources will be created to expose the Modela API gateway and frontend.
   119  	// +kubebuilder:default:=false
   120  	Enabled bool `json:"enabled,omitempty"`
   121  	// Hostname specifies the host domain which will be used as the hostname for rules in Ingress resources managed
   122  	// by the Modela operator. By default, the hostname will default to a localhost alias.
   123  	// +kubebuilder:validation:Optional
   124  	// +kubebuilder:default:="localhost"
   125  	Hostname *string `json:"hostname,omitempty"`
   126  }
   127  
   128  // NginxSpec defines the configuration to install and configure the Nginx ingress controller
   129  type NginxSpec struct {
   130  	// Indicates if Nginx should be installed
   131  	// +kubebuilder:default:=true
   132  	// +kubebuilder:validation:Optional
   133  	Install bool `json:"install"`
   134  	// ChartValues is the set of Helm values that is used to render the Nginx Ingress Chart.
   135  	// Values are determined from https://artifacthub.io/packages/helm/ingress-nginx/ingress-nginx
   136  	// +kubebuilder:pruning:PreserveUnknownFields
   137  	// +kubebuilder:validation:Optional
   138  	Values ChartValues `json:"values,omitempty"`
   139  }
   140  
   141  // NodePortSpec defines the configuration to expose Modela through Node Port services
   142  type NodePortSpec struct {
   143  	// Indicates if Node Port services will be created
   144  	// +kubebuilder:default:=false
   145  	Enabled bool `json:"enabled,omitempty"`
   146  	// The port which Modela will be exposed through. The port, and the two ports above it, must be available.
   147  	// NodePort services will be allocated for the API Gateway, Proxy, and Frontend
   148  	// +kubebuilder:default:=30000
   149  	// +kubebuilder:validation:Minimum=30000
   150  	// +kubebuilder:validation:Maximum=32766
   151  	// +kubebuilder:validation:ExclusiveMaximum=true
   152  	Port int32 `json:"port,omitempty"`
   153  	// A map of labels that will select which Node to use when determining an external IP for the cluster.
   154  	// The external IP of the Node will be used to configure the frontend.
   155  	NodeSelector map[string]string `json:"nodeSelector,omitempty"`
   156  }
   157  
   158  // NetworkSpec defines the configuration for Modela to be exposed through Kubernetes networking features
   159  type NetworkSpec struct {
   160  	// The configuration to create NodePort services
   161  	// +kubebuilder:validation:Optional
   162  	NodePort *NodePortSpec `json:"nodePort,omitempty"`
   163  	// The configuration to create Ingress resources
   164  	// +kubebuilder:validation:Optional
   165  	Ingress *IngressSpec `json:"ingress,omitempty"`
   166  	// The configuration to install Nginx
   167  	// +kubebuilder:validation:Optional
   168  	Nginx *NginxSpec `json:"nginx,omitempty"`
   169  }
   170  
   171  type ApiGatewaySpec struct {
   172  	// Define the number of API Gateway replicas
   173  	// +kubebuilder:default:=0
   174  	// +kubebuilder:validation:Optional
   175  	Replicas *int32 `json:"replicas,omitempty"`
   176  
   177  	// +kubebuilder:validation:Optional
   178  	// Resources specifies resource requests and limits for the data plane deployment.
   179  	// Default values: 100m CPU request, 200m CPU limit, 128Mi memory request, 256Mi memory limit.
   180  	Resources *v1.ResourceRequirements `json:"resources,omitempty"`
   181  }
   182  
   183  type ControlPlaneSpec struct {
   184  	// The number of Control Plane replicas
   185  	// +kubebuilder:default:=0
   186  	// +kubebuilder:validation:Optional
   187  	Replicas *int32 `json:"replicas,omitempty"`
   188  
   189  	// Resources specifies resource requests and limits for the control plane deployment.
   190  	// Default values: 256m CPU request, 512m CPU limit, 256Mi memory request, 512Mi memory limit.
   191  	Resources *v1.ResourceRequirements `json:"resources,omitempty"`
   192  }
   193  
   194  type DataPlaneSpec struct {
   195  	// The number of Data Plane replicas
   196  	// +kubebuilder:default:=0
   197  	// +kubebuilder:validation:Optional
   198  	Replicas *int32 `json:"replicas,omitempty"`
   199  
   200  	// Resources specifies resource requests and limits for the data plane deployment.
   201  	// Default values: 100m CPU request, 200m CPU limit, 256Mi memory request, 512Mi memory limit.
   202  	Resources *v1.ResourceRequirements `json:"resources,omitempty"`
   203  }
   204  
   205  type CertManagerSpec struct {
   206  	// Indicates if cert-manager should be installed.
   207  	// +kubebuilder:default:=true
   208  	// +kubebuilder:validation:Optional
   209  	Install bool `json:"install"`
   210  
   211  	// ChartValues is the set of Helm values that is used to render the Cert Manager Chart.
   212  	// Values are determined from https://artifacthub.io/packages/helm/cert-manager/cert-manager.
   213  	// +kubebuilder:pruning:PreserveUnknownFields
   214  	// +kubebuilder:validation:Optional
   215  	Values ChartValues `json:"values,omitempty"`
   216  }
   217  
   218  type VaultSpec struct {
   219  	// Indicates if Vault should be installed. Enabling installation will initialize Vault on the modela-system
   220  	// namespace and configure it with the appropriate secret engine and policies. This option is not recommended
   221  	// for production environments as the root token and vault keys will be stored inside Kubernetes secrets.
   222  	// When installed this way, the Modela Operator will automatically unseal the Vault when necessary.
   223  	// +kubebuilder:default:=true
   224  	// +kubebuilder:validation:Optional
   225  	Install bool `json:"install"`
   226  
   227  	// MountPath specifies the path where secrets consumed by Modela will be stored.
   228  	// +kubebuilder:default:="modela/secrets"
   229  	MountPath string `json:"mountPath,omitempty"`
   230  
   231  	// VaultAddress specifies the address for an external Vault server. If specified, the Vault server
   232  	// must be configured with a KVv2 secret engine mounted at MountPath. It must also be configured to
   233  	// authorize the modela-operator-controller-manager ServiceAccount with read/write permissions
   234  	// +kubebuilder:validation:Optional
   235  	VaultAddress *string `json:"vaultAddress,omitempty"`
   236  
   237  	// ChartValues is the set of Helm values that are used to render the Vault Chart.
   238  	// +kubebuilder:pruning:PreserveUnknownFields
   239  	// +kubebuilder:validation:Optional
   240  	Values ChartValues `json:"values,omitempty"`
   241  }
   242  
   243  type ObjectStorageSpec struct {
   244  	// Indicates if Minio should be installed.
   245  	// +kubebuilder:default:=true
   246  	// +kubebuilder:validation:Optional
   247  	Install bool `json:"install"`
   248  
   249  	// ChartValues is the set of Helm values that is used to render the Minio Chart.
   250  	Values ChartValues `json:"values,omitempty"`
   251  }
   252  
   253  type DatabaseSpec struct {
   254  	// ChartValues is the set of Helm values that is used to render the Postgres Chart.
   255  	// +kubebuilder:pruning:PreserveUnknownFields
   256  	// +kubebuilder:validation:Optional
   257  	PostgresValues ChartValues `json:"postgresValues,omitempty"`
   258  
   259  	// InstallPgvector indicates if Postgres will be installed with the pgvector vector database extension.
   260  	// Pgvector is required to use Postgres as a vector database with the Modela LLM RAG engine.
   261  	// +kubebuilder:default:=true
   262  	// +kubebuilder:validation:Optional
   263  	InstallPgvector bool `json:"installPgvector"`
   264  
   265  	// InstallMongoDB indicates if MongoDB will be installed.
   266  	// MongoDB is a required component of the Modela LLM RAG engine.
   267  	// +kubebuilder:default:=true
   268  	// +kubebuilder:validation:Optional
   269  	InstallMongoDB bool `json:"installMongoDB,omitempty"`
   270  
   271  	// ChartValues is the set of Helm values that is used to render the MongoDB Chart.
   272  	// +kubebuilder:pruning:PreserveUnknownFields
   273  	// +kubebuilder:validation:Optional
   274  	MongoDBValues ChartValues `json:"mongoDBValues,omitempty"`
   275  }
   276  
   277  type OnlineStoreSpec struct {
   278  	// Indicates if Redis should be installed as part of the built-in online store.
   279  	// +kubebuilder:default:=true
   280  	// +kubebuilder:validation:Optional
   281  	Install bool `json:"install,omitempty"`
   282  
   283  	// ChartValues is the set of Helm values that is used to render the Redis Chart.
   284  	// +kubebuilder:pruning:PreserveUnknownFields
   285  	// +kubebuilder:validation:Optional
   286  	Values ChartValues `json:"values,omitempty"`
   287  }
   288  
   289  type ObservabilitySpec struct {
   290  	// Prometheus indicates if the Prometheus Helm Chart will be installed
   291  	//+kubebuilder:validation:Optional
   292  	Prometheus bool `json:"installPrometheus,omitempty"`
   293  	// ChartValues is the set of Helm values that is used to render the Prometheus Chart.
   294  	// Values are determined from https://artifacthub.io/packages/helm/prometheus-community/prometheus
   295  	// +kubebuilder:pruning:PreserveUnknownFields
   296  	// +kubebuilder:validation:Optional
   297  	PrometheusValues ChartValues `json:"prometheusValues,omitempty"`
   298  
   299  	// Loki indicates if the Loki Helm Chart will be installed
   300  	//+kubebuilder:validation:Optional
   301  	Loki bool `json:"installLoki,omitempty"`
   302  	// ChartValues is the set of Helm values that is used to render the Loki Chart.
   303  	// Values are determined from https://artifacthub.io/packages/helm/grafana/loki
   304  	// +kubebuilder:pruning:PreserveUnknownFields
   305  	// +kubebuilder:validation:Optional
   306  	LokiValues ChartValues `json:"lokiValues,omitempty"`
   307  
   308  	// Grafana indicates if the Grafana Helm Chart will be installed
   309  	//+kubebuilder:validation:Optional
   310  	Grafana bool `json:"installGrafana,omitempty"`
   311  	// ChartValues is the set of Helm values that is used to render the Grafana Chart.
   312  	// Values are determined from https://artifacthub.io/packages/helm/grafana/grafana
   313  	// +kubebuilder:pruning:PreserveUnknownFields
   314  	// +kubebuilder:validation:Optional
   315  	GrafanaValues ChartValues `json:"grafanaValues,omitempty"`
   316  }
   317  
   318  type ModelaLicenseSpec struct {
   319  	//+kubebuilder:validation:Optional
   320  	LicenseKey *string `json:"licenseKey,omitempty"`
   321  
   322  	// If LinkLicense is enabled, the Modela Operator will open a linking session through modela.ai which a
   323  	// system administrator can use to log in to their modela.ai account and link their license. The URL which
   324  	// must be opened by the administrator will be stored in the status of the Modela resource.
   325  	LinkLicense *bool `json:"linkLicense,omitempty"`
   326  }
   327  
   328  type TenantSpec struct {
   329  	// The name of the Tenant. This will determine the name of the namespace containing the Tenant's resources.
   330  	// +kubebuilder:validation:Required
   331  	Name string `json:"name,omitempty"`
   332  
   333  	// The password for the default admin account (with the username "admin"). If empty, then the
   334  	// Modela Operator will set the password to "default". Setting a secure password is highly recommended.
   335  	// +kubebuilder:validation:Optional
   336  	AdminPassword *string `json:"adminPassword,omitempty"`
   337  }
   338  
   339  // ModelaSpec defines the desired state of Modela
   340  type ModelaSpec struct {
   341  	// Distribution denotes the desired version of Modela. This version will determine the
   342  	// Docker image tags for all Modela images provided by Metaprov
   343  	// +kubebuilder:default:="develop"
   344  	// +kubebuilder:validation:Required
   345  	Distribution string `json:"distribution"`
   346  
   347  	// Observability specifies the configuration to install monitoring tools (Prometheus, Loki, Grafana)
   348  	Observability ObservabilitySpec `json:"observability,omitempty"`
   349  
   350  	// Network specifies the configuration to make Modela accessible through networking features
   351  	Network NetworkSpec `json:"network,omitempty"`
   352  
   353  	// License specifies the license information
   354  	// that will be applied to the installation of Modela
   355  	License ModelaLicenseSpec `json:"license,omitempty"`
   356  
   357  	// Tenants contains the collection of tenants that will be installed
   358  	//+kubebuilder:validation:Optional
   359  	Tenants []*TenantSpec `json:"tenants,omitempty"`
   360  
   361  	//+kubebuilder:validation:Optional
   362  	CertManager CertManagerSpec `json:"certManager,omitempty"`
   363  
   364  	//+kubebuilder:validation:Optional
   365  	ObjectStore ObjectStorageSpec `json:"objectStore,omitempty"`
   366  
   367  	//+kubebuilder:validation:Optional
   368  	Database DatabaseSpec `json:"database,omitempty"`
   369  
   370  	//+kubebuilder:validation:Optional
   371  	OnlineStore OnlineStoreSpec `json:"onlineStore,omitempty"`
   372  
   373  	//+kubebuilder:validation:Optional
   374  	ControlPlane ControlPlaneSpec `json:"controlPlane,omitempty"`
   375  
   376  	//+kubebuilder:validation:Optional
   377  	DataPlane DataPlaneSpec `json:"dataPlane,omitempty"`
   378  
   379  	//+kubebuilder:validation:Optional
   380  	ApiGateway ApiGatewaySpec `json:"apiGateway,omitempty"`
   381  
   382  	//+kubebuilder:validation:Optional
   383  	Vault VaultSpec `json:"vault,omitempty"`
   384  }
   385  
   386  // ModelaStatus defines the observed state of Modela
   387  type ModelaStatus struct {
   388  	// InstalledVersion denotes the live image tags of all Modela images
   389  	InstalledVersion string `json:"installedVersion,omitempty"`
   390  
   391  	// Tenants contains the names of installed Tenant
   392  	Tenants []string `json:"installedTenants,omitempty"`
   393  
   394  	// LicenseToken contains the reference to the license token generated by the license linking process, which
   395  	// can be used to fetch the active license of a modela.ai
   396  	LicenseToken *v1.ObjectReference `json:"licenseTokenRef,omitempty"`
   397  
   398  	// LinkLicenseUrl contains the URL which the system administrator must open in order to link their
   399  	// https://modela.ai account to the Modela Operator. Once linked, the Modela Operator will automatically
   400  	// fetch the license of their account in the case that will it will expire.
   401  	LinkLicenseUrl *string `json:"linkLicenseUrl,omitempty"`
   402  
   403  	Phase ModelaPhase `json:"phase,omitempty"`
   404  
   405  	// The Modela resource controller will update FailureMessage with an error message in the case of a failure
   406  	FailureMessage *string `json:"failureMessage,omitempty"`
   407  
   408  	// The last time the Modela resource was updated
   409  	//+kubebuilder:validation:Optional
   410  	LastUpdated *metav1.Time `json:"lastUpdated,omitempty"`
   411  
   412  	// +patchMergeKey=type
   413  	// +patchStrategy=merge
   414  	// +kubebuilder:validation:Optional
   415  	Conditions []ModelaCondition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,8,rep,name=conditions"`
   416  }
   417  
   418  // Modela defines the configuration of the Modela operator
   419  // +kubebuilder:object:root=true
   420  // +kubebuilder:subresource:status
   421  // +kubebuilder:resource:path=modelas,singular=modela,shortName="md",categories={data,modela,all}
   422  type Modela struct {
   423  	metav1.TypeMeta   `json:",inline"`
   424  	metav1.ObjectMeta `json:"metadata,omitempty"`
   425  
   426  	Spec   ModelaSpec   `json:"spec,omitempty"`
   427  	Status ModelaStatus `json:"status,omitempty"`
   428  }
   429  
   430  // ModelaList contains a list of Modela
   431  // +kubebuilder:object:root=true
   432  type ModelaList struct {
   433  	metav1.TypeMeta `json:",inline"`
   434  	metav1.ListMeta `json:"metadata,omitempty"`
   435  	Items           []Modela `json:"items"`
   436  }
   437  
   438  func init() {
   439  	SchemeBuilder.Register(&Modela{}, &ModelaList{})
   440  }