From 56e63854b4f9bc038972f5fbf8c636724d2ef7f5 Mon Sep 17 00:00:00 2001 From: Apoorva Appadoo Srinivas Date: Sun, 20 Oct 2024 18:34:19 +0200 Subject: [PATCH] feat: add custom model support --- PROJECT | 9 + api/v1/custommodel_types.go | 64 +++++++ api/v1/zz_generated.deepcopy.go | 89 +++++++++ cmd/main.go | 7 + ...ama.ollama.startupnation_custommodels.yaml | 57 ++++++ config/crd/kustomization.yaml | 2 + config/rbac/custommodel_editor_role.yaml | 27 +++ config/rbac/custommodel_viewer_role.yaml | 23 +++ config/rbac/kustomization.yaml | 2 + config/rbac/role.yaml | 3 + config/samples/kustomization.yaml | 1 + config/samples/ollama_v1_custommodel.yaml | 18 ++ go.mod | 5 + go.sum | 84 +++++++++ internal/controller/custommodel_controller.go | 172 ++++++++++++++++++ .../controller/custommodel_controller_test.go | 84 +++++++++ internal/controller/helper.go | 21 +++ internal/controller/model_controller.go | 20 -- internal/ollama_client/api.gen.go | 47 +++-- openapi.yaml | 6 + 20 files changed, 701 insertions(+), 40 deletions(-) create mode 100644 api/v1/custommodel_types.go create mode 100644 config/crd/bases/ollama.ollama.startupnation_custommodels.yaml create mode 100644 config/rbac/custommodel_editor_role.yaml create mode 100644 config/rbac/custommodel_viewer_role.yaml create mode 100644 config/samples/ollama_v1_custommodel.yaml create mode 100644 internal/controller/custommodel_controller.go create mode 100644 internal/controller/custommodel_controller_test.go create mode 100644 internal/controller/helper.go diff --git a/PROJECT b/PROJECT index 79c5fbd..dfe0c0f 100644 --- a/PROJECT +++ b/PROJECT @@ -17,4 +17,13 @@ resources: kind: Model path: github.com/StartUpNationLabs/simple-ollama-operator/api/v1 version: v1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: ollama.startupnation + group: ollama + kind: CustomModel + path: github.com/StartUpNationLabs/simple-ollama-operator/api/v1 + version: v1 version: "3" diff --git a/api/v1/custommodel_types.go b/api/v1/custommodel_types.go new file mode 100644 index 0000000..0b99c2e --- /dev/null +++ b/api/v1/custommodel_types.go @@ -0,0 +1,64 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// CustomModelSpec defines the desired state of CustomModel +type CustomModelSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file + + ModelName string `json:"modelName"` + ModelFile string `json:"modelFile"` +} + +// CustomModelStatus defines the observed state of CustomModel +type CustomModelStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status + +// CustomModel is the Schema for the custommodels API +type CustomModel struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec CustomModelSpec `json:"spec,omitempty"` + Status CustomModelStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// CustomModelList contains a list of CustomModel +type CustomModelList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []CustomModel `json:"items"` +} + +func init() { + SchemeBuilder.Register(&CustomModel{}, &CustomModelList{}) +} diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 4c96b9d..a223b46 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -24,6 +24,95 @@ 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 *CustomModel) DeepCopyInto(out *CustomModel) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomModel. +func (in *CustomModel) DeepCopy() *CustomModel { + if in == nil { + return nil + } + out := new(CustomModel) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CustomModel) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomModelList) DeepCopyInto(out *CustomModelList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]CustomModel, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomModelList. +func (in *CustomModelList) DeepCopy() *CustomModelList { + if in == nil { + return nil + } + out := new(CustomModelList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *CustomModelList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomModelSpec) DeepCopyInto(out *CustomModelSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomModelSpec. +func (in *CustomModelSpec) DeepCopy() *CustomModelSpec { + if in == nil { + return nil + } + out := new(CustomModelSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CustomModelStatus) DeepCopyInto(out *CustomModelStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomModelStatus. +func (in *CustomModelStatus) DeepCopy() *CustomModelStatus { + if in == nil { + return nil + } + out := new(CustomModelStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Model) DeepCopyInto(out *Model) { *out = *in diff --git a/cmd/main.go b/cmd/main.go index 83ffa1a..10aeff2 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -152,6 +152,13 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "Model") os.Exit(1) } + if err = (&controller.CustomModelReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "CustomModel") + os.Exit(1) + } // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { diff --git a/config/crd/bases/ollama.ollama.startupnation_custommodels.yaml b/config/crd/bases/ollama.ollama.startupnation_custommodels.yaml new file mode 100644 index 0000000..7aee2c4 --- /dev/null +++ b/config/crd/bases/ollama.ollama.startupnation_custommodels.yaml @@ -0,0 +1,57 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.1 + name: custommodels.ollama.ollama.startupnation +spec: + group: ollama.ollama.startupnation + names: + kind: CustomModel + listKind: CustomModelList + plural: custommodels + singular: custommodel + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: CustomModel is the Schema for the custommodels API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: CustomModelSpec defines the desired state of CustomModel + properties: + modelFile: + type: string + modelName: + type: string + required: + - modelFile + - modelName + type: object + status: + description: CustomModelStatus defines the observed state of CustomModel + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 834e0ca..d3a6936 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -3,6 +3,7 @@ # It should be run by config/default resources: - bases/ollama.ollama.startupnation_models.yaml +- bases/ollama.ollama.startupnation_custommodels.yaml # +kubebuilder:scaffold:crdkustomizeresource patches: @@ -13,6 +14,7 @@ patches: # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. # patches here are for enabling the CA injection for each CRD #- path: patches/cainjection_in_models.yaml +#- path: patches/cainjection_in_custommodels.yaml # +kubebuilder:scaffold:crdkustomizecainjectionpatch # [WEBHOOK] To enable webhook, uncomment the following section diff --git a/config/rbac/custommodel_editor_role.yaml b/config/rbac/custommodel_editor_role.yaml new file mode 100644 index 0000000..334299b --- /dev/null +++ b/config/rbac/custommodel_editor_role.yaml @@ -0,0 +1,27 @@ +# permissions for end users to edit custommodels. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: simple-ollama-operator + app.kubernetes.io/managed-by: kustomize + name: custommodel-editor-role +rules: +- apiGroups: + - ollama.ollama.startupnation + resources: + - custommodels + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - ollama.ollama.startupnation + resources: + - custommodels/status + verbs: + - get diff --git a/config/rbac/custommodel_viewer_role.yaml b/config/rbac/custommodel_viewer_role.yaml new file mode 100644 index 0000000..1f1a2de --- /dev/null +++ b/config/rbac/custommodel_viewer_role.yaml @@ -0,0 +1,23 @@ +# permissions for end users to view custommodels. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + app.kubernetes.io/name: simple-ollama-operator + app.kubernetes.io/managed-by: kustomize + name: custommodel-viewer-role +rules: +- apiGroups: + - ollama.ollama.startupnation + resources: + - custommodels + verbs: + - get + - list + - watch +- apiGroups: + - ollama.ollama.startupnation + resources: + - custommodels/status + verbs: + - get diff --git a/config/rbac/kustomization.yaml b/config/rbac/kustomization.yaml index 3ec631c..31f1c9f 100644 --- a/config/rbac/kustomization.yaml +++ b/config/rbac/kustomization.yaml @@ -22,6 +22,8 @@ resources: # default, aiding admins in cluster management. Those roles are # not used by the Project itself. You can comment the following lines # if you do not want those helpers be installed with your Project. +- custommodel_editor_role.yaml +- custommodel_viewer_role.yaml - model_editor_role.yaml - model_viewer_role.yaml diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 50dac14..2da6566 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -7,6 +7,7 @@ rules: - apiGroups: - ollama.ollama.startupnation resources: + - custommodels - models verbs: - create @@ -19,12 +20,14 @@ rules: - apiGroups: - ollama.ollama.startupnation resources: + - custommodels/finalizers - models/finalizers verbs: - update - apiGroups: - ollama.ollama.startupnation resources: + - custommodels/status - models/status verbs: - get diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index ef8e14f..4d24248 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -1,4 +1,5 @@ ## Append samples of your project ## resources: - ollama_v1_model.yaml +- ollama_v1_custommodel.yaml # +kubebuilder:scaffold:manifestskustomizesamples diff --git a/config/samples/ollama_v1_custommodel.yaml b/config/samples/ollama_v1_custommodel.yaml new file mode 100644 index 0000000..edd64e8 --- /dev/null +++ b/config/samples/ollama_v1_custommodel.yaml @@ -0,0 +1,18 @@ +apiVersion: ollama.ollama.startupnation/v1 +kind: CustomModel +metadata: + labels: + app.kubernetes.io/name: simple-ollama-operator + app.kubernetes.io/managed-by: kustomize + name: mario-custommodel-sample +spec: + modelName: mario-custommodel-sample + modelFile: >- + FROM llama3.2 + # sets the temperature to 1 [higher is more creative, lower is more coherent] + PARAMETER temperature 1 + # sets the context window size to 4096, this controls how many tokens the LLM can use as context to generate the next token + PARAMETER num_ctx 4096 + + # sets a custom system message to specify the behavior of the chat assistant + SYSTEM You are Mario from super mario bros, acting as an assistant. You are in a conversation with Luigi, who is asking you for help. You are in a hurry to save Princess Peach from Bowser, so you are trying to be as helpful as possible while also being brief. You are in a good mood and are excited to help Luigi. diff --git a/go.mod b/go.mod index 681df0a..7d65ee8 100644 --- a/go.mod +++ b/go.mod @@ -21,6 +21,7 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -53,15 +54,18 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/prometheus/client_golang v1.19.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect + github.com/speakeasy-api/openapi-overlay v0.9.0 // indirect github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/stoewer/go-strcase v1.2.0 // indirect + github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect go.opentelemetry.io/otel v1.28.0 // indirect @@ -74,6 +78,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.26.0 // indirect golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.26.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect golang.org/x/sync v0.8.0 // indirect diff --git a/go.sum b/go.sum index 91ad197..deb6b4b 100644 --- a/go.sum +++ b/go.sum @@ -14,12 +14,18 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58= +github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w= +github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q= github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v0.5.2 h1:xVCHIVMUu1wtM/VkR9jVZ45N3FhZfYMMYGorLCR8P3k= @@ -28,6 +34,8 @@ github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0 github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= @@ -49,6 +57,7 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= @@ -57,24 +66,40 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/cel-go v0.20.1 h1:nDx9r8S3L4pE61eDdt8igGj8rf5kjYR3ILxWIpWNi84= github.com/google/cel-go v0.20.1/go.mod h1:kWcIzTsPX0zmQ+H3TirHstLLf9ep5QTsZBN9u4dOYLg= github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28= github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= @@ -88,6 +113,7 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -106,10 +132,24 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oapi-codegen/oapi-codegen/v2 v2.4.1 h1:ykgG34472DWey7TSjd8vIfNykXgjOgYJZoQbKfEeY/Q= +github.com/oapi-codegen/oapi-codegen/v2 v2.4.1/go.mod h1:N5+lY1tiTDV3V1BeHtOxeWXHoPVeApvsvjJqegfoaz8= github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro= github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= @@ -130,6 +170,9 @@ github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoG github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/speakeasy-api/openapi-overlay v0.9.0 h1:Wrz6NO02cNlLzx1fB093lBlYxSI54VRhy1aSutx0PQg= +github.com/speakeasy-api/openapi-overlay v0.9.0/go.mod h1:f5FloQrHA7MsxYg9djzMD5h6dxrHjVVByWKh7an8TRc= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -141,6 +184,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -149,6 +193,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= +github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk= +github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -182,28 +228,50 @@ golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8Cj golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= @@ -211,6 +279,7 @@ golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= @@ -226,19 +295,34 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1: google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/controller/custommodel_controller.go b/internal/controller/custommodel_controller.go new file mode 100644 index 0000000..9aa43c3 --- /dev/null +++ b/internal/controller/custommodel_controller.go @@ -0,0 +1,172 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + "github.com/StartUpNationLabs/simple-ollama-operator/internal/ollama_client" + "os" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + "k8s.io/apimachinery/pkg/runtime" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/log" + + ollamav1 "github.com/StartUpNationLabs/simple-ollama-operator/api/v1" +) + +// CustomModelReconciler reconciles a CustomModel object +type CustomModelReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +// +kubebuilder:rbac:groups=ollama.ollama.startupnation,resources=custommodels,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=ollama.ollama.startupnation,resources=custommodels/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=ollama.ollama.startupnation,resources=custommodels/finalizers,verbs=update + +// Reconcile is part of the main kubernetes reconciliation loop which aims to +// move the current state of the cluster closer to the desired state. +// TODO(user): Modify the Reconcile function to compare the state specified by +// the CustomModel object against the actual cluster state, and then +// perform operations to make the cluster state reflect the state specified by +// the user. +// +// For more details, check Reconcile and its Result here: +// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.0/pkg/reconcile +func (r *CustomModelReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + logger := log.FromContext(ctx) + + // Fetch the Model instance + CustomModel := &ollamav1.CustomModel{} + err := r.Get(ctx, req.NamespacedName, CustomModel) + if err != nil { + return ctrl.Result{}, client.IgnoreNotFound(err) + } + // Read url from the CustomModel instance + ollamaUrl := os.Getenv("OLLAMA_URL") + if ollamaUrl == "" { + logger.Error(err, "unable to fetch Ollama URL") + panic("OLLAMA_URL not set") + } + + // create a new Ollama Client + ollamaClient, err := ollama_client.NewClientWithResponses(ollamaUrl) + if err != nil { + logger.Error(err, "unable to create Ollama Client") + return ctrl.Result{}, err + } + logger.Info("Ollama Client created") + // If the CustomModel is being deleted, delete it from the Ollama Client + CustomModelFinalizer := "CustomModel.finalizer.ollama.ollama.startupnation" + + if CustomModel.ObjectMeta.DeletionTimestamp.IsZero() { + // The object is not being deleted, so if it does not have our finalizer, + // then lets add the finalizer and update the object. + if !containsString(CustomModel.ObjectMeta.Finalizers, CustomModelFinalizer) { + CustomModel.ObjectMeta.Finalizers = append(CustomModel.ObjectMeta.Finalizers, CustomModelFinalizer) + if err := r.Update(context.Background(), CustomModel); err != nil { + return reconcile.Result{}, err + } + } + } else { + // The object is being deleted + if containsString(CustomModel.ObjectMeta.Finalizers, CustomModelFinalizer) { + // our finalizer is present, so lets handle our external dependency + // first, we delete the external dependency + logger.Info("Deleting CustomModel", "CustomModel Name", CustomModel.Spec.ModelName, "Ollama URL", ollamaUrl) + _, err := ollamaClient.DeleteApiDelete(ctx, &ollama_client.DeleteApiDeleteParams{ + Model: CustomModel.Spec.ModelName, + }) + if err != nil { + logger.Error(err, "unable to delete CustomModel") + } + + // remove our finalizer from the list and update it. + CustomModel.ObjectMeta.Finalizers = removeString(CustomModel.ObjectMeta.Finalizers, CustomModelFinalizer) + if err := r.Update(context.Background(), CustomModel); err != nil { + return reconcile.Result{}, err + } + } + + // Our finalizer has finished, so the reconciler can do nothing. + return reconcile.Result{}, nil + } + // if the CustomModel is not being deleted, start reconciliation + + // get the CustomModel from the Ollama Client + logger.Info("Checking if CustomModel exists", "CustomModel Name", CustomModel.Spec.ModelName, "Ollama URL", ollamaUrl) + res, err := ollamaClient.PostApiShowWithResponse(ctx, ollama_client.PostApiShowJSONRequestBody{ + Name: &CustomModel.Spec.ModelName, + }) + logger.Info("Checking if CustomModel exists", "CustomModel Name", CustomModel.Spec.ModelName, "Ollama URL", ollamaUrl, "status", res.Status()) + if err == nil && res.Status() == "200" { + logger.Info("CustomModel exists", "CustomModel Name", CustomModel.Spec.ModelName, "Ollama URL", ollamaUrl) + if res.JSON200 != nil { + logger.Info("Checking if the ModelFile is the same", "CustomModel Name", CustomModel.Spec.ModelName, "Ollama URL", ollamaUrl) + if *res.JSON200.Parameters == CustomModel.Spec.ModelFile { + logger.Info("ModelFile is the same", "CustomModel Name", CustomModel.Spec.ModelName, "Ollama URL", ollamaUrl) + return ctrl.Result{}, nil + } + logger.Info("ModelFile is not the same", "CustomModel Name", CustomModel.Spec.ModelName, "Ollama URL", ollamaUrl) + // delete the CustomModel and create a new one + logger.Info("Deleting CustomModel", "CustomModel Name", CustomModel.Spec.ModelName, "Ollama URL", ollamaUrl) + _, err := ollamaClient.DeleteApiDelete(ctx, &ollama_client.DeleteApiDeleteParams{ + Model: CustomModel.Spec.ModelName, + }) + if err != nil { + logger.Error(err, "unable to delete CustomModel") + } + // Create the CustomModel + logger.Info("Creating CustomModel", "CustomModel Name", CustomModel.Spec.ModelName, "Ollama URL", ollamaUrl) + stream := false + _, err = ollamaClient.PostApiCreate(ctx, ollama_client.PostApiCreateJSONRequestBody{ + Name: &CustomModel.Spec.ModelName, + Modelfile: &CustomModel.Spec.ModelFile, + Stream: &stream, + }) + if err != nil { + logger.Error(err, "unable to create CustomModel") + return ctrl.Result{}, err + } + } + return ctrl.Result{}, err + } + // if the CustomModel does not exist, create it + logger.Info("CustomModel does not exist, creating CustomModel", "CustomModel Name", CustomModel.Spec.ModelName, "Ollama URL", ollamaUrl) + stream := false + _, err = ollamaClient.PostApiCreate(ctx, ollama_client.PostApiCreateJSONRequestBody{ + Name: &CustomModel.Spec.ModelName, + Modelfile: &CustomModel.Spec.ModelFile, + Stream: &stream, + }) + if err != nil { + logger.Error(err, "unable to create CustomModel") + return ctrl.Result{}, err + } + logger.Info("CustomModel created", "CustomModel Name", CustomModel.Spec.ModelName, "Ollama URL", ollamaUrl) + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *CustomModelReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&ollamav1.CustomModel{}). + Complete(r) +} diff --git a/internal/controller/custommodel_controller_test.go b/internal/controller/custommodel_controller_test.go new file mode 100644 index 0000000..eed4382 --- /dev/null +++ b/internal/controller/custommodel_controller_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2024. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package controller + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + ollamav1 "github.com/StartUpNationLabs/simple-ollama-operator/api/v1" +) + +var _ = Describe("CustomModel Controller", func() { + Context("When reconciling a resource", func() { + const resourceName = "test-resource" + + ctx := context.Background() + + typeNamespacedName := types.NamespacedName{ + Name: resourceName, + Namespace: "default", // TODO(user):Modify as needed + } + custommodel := &ollamav1.CustomModel{} + + BeforeEach(func() { + By("creating the custom resource for the Kind CustomModel") + err := k8sClient.Get(ctx, typeNamespacedName, custommodel) + if err != nil && errors.IsNotFound(err) { + resource := &ollamav1.CustomModel{ + ObjectMeta: metav1.ObjectMeta{ + Name: resourceName, + Namespace: "default", + }, + // TODO(user): Specify other spec details if needed. + } + Expect(k8sClient.Create(ctx, resource)).To(Succeed()) + } + }) + + AfterEach(func() { + // TODO(user): Cleanup logic after each test, like removing the resource instance. + resource := &ollamav1.CustomModel{} + err := k8sClient.Get(ctx, typeNamespacedName, resource) + Expect(err).NotTo(HaveOccurred()) + + By("Cleanup the specific resource instance CustomModel") + Expect(k8sClient.Delete(ctx, resource)).To(Succeed()) + }) + It("should successfully reconcile the resource", func() { + By("Reconciling the created resource") + controllerReconciler := &CustomModelReconciler{ + Client: k8sClient, + Scheme: k8sClient.Scheme(), + } + + _, err := controllerReconciler.Reconcile(ctx, reconcile.Request{ + NamespacedName: typeNamespacedName, + }) + Expect(err).NotTo(HaveOccurred()) + // TODO(user): Add more specific assertions depending on your controller's reconciliation logic. + // Example: If you expect a certain status condition after reconciliation, verify it here. + }) + }) +}) diff --git a/internal/controller/helper.go b/internal/controller/helper.go new file mode 100644 index 0000000..74a1137 --- /dev/null +++ b/internal/controller/helper.go @@ -0,0 +1,21 @@ +package controller + +// Helper functions to check and remove string from a slice of strings. +func containsString(slice []string, s string) bool { + for _, item := range slice { + if item == s { + return true + } + } + return false +} + +func removeString(slice []string, s string) (result []string) { + for _, item := range slice { + if item == s { + continue + } + result = append(result, item) + } + return +} diff --git a/internal/controller/model_controller.go b/internal/controller/model_controller.go index 8ad2c00..d1e0555 100644 --- a/internal/controller/model_controller.go +++ b/internal/controller/model_controller.go @@ -143,23 +143,3 @@ func (r *ModelReconciler) SetupWithManager(mgr ctrl.Manager) error { For(&ollamav1.Model{}). Complete(r) } - -// Helper functions to check and remove string from a slice of strings. -func containsString(slice []string, s string) bool { - for _, item := range slice { - if item == s { - return true - } - } - return false -} - -func removeString(slice []string, s string) (result []string) { - for _, item := range slice { - if item == s { - continue - } - result = append(result, item) - } - return -} diff --git a/internal/ollama_client/api.gen.go b/internal/ollama_client/api.gen.go index fbfd902..ae8a55a 100644 --- a/internal/ollama_client/api.gen.go +++ b/internal/ollama_client/api.gen.go @@ -32,11 +32,17 @@ type PostApiCopyJSONBody struct { // PostApiCreateJSONBody defines parameters for PostApiCreate. type PostApiCreateJSONBody struct { + // Modelfile The Modelfile contents + Modelfile *string `json:"modelfile,omitempty"` + // Name Name of the model to create (required) Name *string `json:"name,omitempty"` // Path Path to the Modelfile Path *string `json:"path,omitempty"` + + // Stream Stream the Modelfile + Stream *bool `json:"stream,omitempty"` } // DeleteApiDeleteParams defines parameters for DeleteApiDelete. @@ -1517,26 +1523,27 @@ func ParseGetApiTagsResponse(rsp *http.Response) (*GetApiTagsResponse, error) { // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "H4sIAAAAAAAC/+yY32/ctg/A/xVBL9/vAC/JfjzdW9oORYamC5bsaR0CnkWfVciSK9KX3IL874Mk2+c7", - "+340Ddqh3ZtPokge+RFF6UFqWzg5e5AKKfe6Zu2snMnzqwtROC+0ZfSQs7YLcae5FM4YqEBUTqEhmUnW", - "bFDOZDt+fnUhM7lET0nPDydnJ2fyMZOuRgu1ljP5UxzKZA1cUrB8CrU+zV29Cj9qRzx256WrV6K1eiJe", - "egRG6gaSY2Adl+iFhQpF4V0lwAq81xR9j4IyuuEhKL1QciavHPF5rYN2mUmPHxokfuFU9CR3ltFGZ6Cu", - "jc7jutP3FDx6kJSXWEF02QetrJFax1lbSI5v/4+bEsVAoPU/uvz/YF57VN+FqK7qEFRir+0ihI9c43Oc", - "VpjmjtX12I+4+XvMWT6GoW6BnLFvMA5Q7Syl//Tj2dknRIQYuIlfR7myBaIg9giVcIX49fq3tyKJUkp6", - "Ui3eSWryHIneyaiVmqoCv1qDcxnTH6YSbBGgPbjF+Z6vRFNSUmiDOzlKap+LpJDKsW9vQ4JdIbjsUs5O", - "pD90gKGw4cb6roDLoCLoG/7DbxubDoAtcBQa5DYp66+h4VdxvEcHrBKaSShgGGGTZM9rnT5iTfRQIaMn", - "OfvzqMwnPzYzr4P0hwZ9qGqJItkVwM2MZYPob0f5r68mm31OtrKJ1RyV0nZBu0vBa7QhZSjWwl092Hum", - "/LLW/Vz1INmbPAKOPkdcXEUTB75SOnyCaZUNUBxlKAueVfVEuG7wngOWi6mwOf9vqCubWdeM1RBL21Rz", - "9HLtFngPq+MwHeR8E8Aeoi2JSGEXqiMYBNHFITZnIBZ6iVakZLRtUPi11ApV1y3dlJqEDt1S2kShHUKr", - "aqctn+zCtzP5bcFbYhfLIcKbUZ/szlbEWI0VXsfxgU63RO+1wnUN/x8JhYW20f8p3YxVbYB39H5FY0yn", - "3/neUrvmSSY//46My+55ajuG+8diaj9mMvU86hbiwsL5KnxJBYzfs65wKpjKWRxonztnEGyYwSWY29w1", - "yfux9TivGt839mMR40AdEOl3wbg5i5m7PeTGUGy/qS4/k9YIqtrgPkOtxH4b7PiAH59yugcLPyewNhe8", - "ACV+T1VpV6EFkbvwB+KKvtTWjTG7y+wrd2dDDjf7/rBt2sut0XMPsamarJlXQftz1UttCfPGT2z7c2Pc", - "nejmRe6sxTwWxq6NX/s55vwjLhUhWoeupTFxE4UvJTSoU21UJ7z5/JVG6QUST2+JXQ1qi/lT6e6pag1s", - "AhuYGTemdUPlbk7/qDcoZdd/HgSUyq8LUCr/e+sYsETlmCUq3d1ulq5LdycUMmhDAuau4R4mbXPTqP7x", - "rNAGs76zyAYtViaMztESZvG6S8OmZxeKwe6XeCihZPeLc9JGbLLc9OGebhQGTwQP+9vFJyB42aY+tVPd", - "4blmLPKShC62hCJtDOlatcAJ2N5o4vblWHAJLMCjgCVoA3ODwrgcjBlXr9cYiLmB9ir9bDlo37CHXedI", - "QBf6I1vMDsbxAaP/xuMOkafcPWNsXZGC2D3Pb+YuiryJ85fd/OPjPwEAAP//GUfMvAIYAAA=", + "H4sIAAAAAAAC/+yZX2/cNgzAv4qgl22Al2Z/nu4tbYciQ9MFS/a0DgHPos8qZMkV6UtuQb77IMn2+c6+", + "P0mDrWj35sgUySN/okjnXmpbODm7lwop97pm7aycybPLc1E4L7Rl9JCztgtxq7kUzhioQFROoSGZSdZs", + "UM5ku352eS4zuURPSc8PJ6cnp/Ihk65GC7WWM/lTXMpkDVxSsPwCav0id/Uq/FE74rE7r1y9Eq3VE/HK", + "IzBSt5AcA+u4RC8sVCgK7yoBVuCdpuh7FJTRDQ9B6bmSM3npiM9qHbTLTHr82CDxS6eiJ7mzjDY6A3Vt", + "dB73vfhAwaN7SXmJFUSXfdDKGql1nLWF5Pj277guUQwEWv+jy98G89qj+i5EdVWHoBJ7bRchfOQan+O0", + "wvTuWF0P/Yqbf8Cc5UNY6jbIGfsG4wLVzlL6TT+enn5CRIiBm/h0lCtbIApij1AJV4hfr357J5IopaQn", + "1eK9pCbPkei9jFqpqSrwqzU4FzH94VWCLQK0B7f4vucr0ZSUFNrgTo6S2uciqertTaa9d0e0+mkKnMDD", + "eP+7QIkrBJcdN+xEisoBEMOpHeu7BC6DCh76NclxTOZYwVVK8o79c+cMgv3q4O0w3MJXoUFus7p+Ghp+", + "Hdd7gMEqoZmEAoYRvEn2rNbpIVZmDxUyepKzP49CJ/mxiY4O0h8b9KG2JgxlV4Y3M5YNor8d5b++mGz2", + "OdnKJlZzVErbBe0uSG/QhpShWAt3VWnvzfbLWvezVqXpinT0bebiLppoO5TS4RFMq2yA4ihDWfCsqifC", + "dY13HLBcTIXN+c/hUtzMumashljappqjl2u3wHtYHYfpIOebAPYQbUlECrtQHcEgiC4OsUUEsdBLtCIl", + "o23Gwl9LrVB1Pdt1qUno0LOlQxSaMrSqdtryyS58O5NfF7wldrEcIrwZ9cm7dUWMU3drXB/odEv0Xitc", + "1/BvSCgstI3+T+lmrGoDvKMVKRpjOv3O95baPU8y+e+fyLjtjqeOY5iCFlPnMZOpaVI3EDcWzlfhSSpg", + "/J51NdkEKWdxoL3vbjKJSzA3uWuS92Pr8b1qfD9ejEWMA3VApD8F4+4uZu7mkBtDsf2muvxMWiOoaoP7", + "DLUS+22w4wN+fMrtHiz8nMDa3PASlPg9VaVdhRZE7sIPiDv6Uls3xuwus6/drQ053Jw+wrFpR2yj5x5i", + "UzVZMy+D9ueql9oS5o2fOPZnxrhb0b0PI4jFPBbGbg5Y+znm/BFTSYjWoeH48FCh2qh+FjOF0gsknj4S", + "uxrUFvOn0t1T1RrYBDYwM25M64bK3Zz+UW9Qyq5/PAgolV8WoFT+/8VlwBKVY5aodLe7Wboq3a1QyKAN", + "CZi7hnuYtM1No/pPeIU2mPWdRTZosTJhdI6WMIvjLg2bnl0oBrvPhuIjkKFk9z/npI3YZLnZ+Po08Rlo", + "/Yngfn+7+AQEL9rUp3aquzzXjEVektD5llCkjSGNVQucgO2tJm6/XwsugQV4FLAEbWBuUBiXgzHj6vUG", + "AzHX0I7Sz5aD9kv6sOscCehCP7LF7GAcXzD6bzzuEnnK7Blj64oUxO6fBJu5iyJv4/uL7v3Dwz8BAAD/", + "/3TlKXmIGAAA", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/openapi.yaml b/openapi.yaml index d14a693..e7e41ac 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -86,6 +86,12 @@ paths: path: type: string description: Path to the Modelfile + modelfile: + type: string + description: The Modelfile contents + stream: + type: boolean + description: Stream the Modelfile responses: '200': description: A stream of JSON objects with status "success"