diff --git a/.github/workflows/example_test.yaml b/.github/workflows/example_test.yaml index 16d0ed0a1..20ce35a60 100644 --- a/.github/workflows/example_test.yaml +++ b/.github/workflows/example_test.yaml @@ -78,7 +78,7 @@ jobs: mkdir -p ${GITHUB_WORKSPACE}/bin cp /usr/local/bin/kustomize ${GITHUB_WORKSPACE}/bin/kustomize - name: Example test - run: config/samples/example-test.sh + run: tests/example-test.sh - name: Upload logs if test fail if: failure() uses: actions/upload-artifact@v3 diff --git a/.github/workflows/lint_test.yaml b/.github/workflows/lint_test.yaml index 3a41a9dfb..d50710368 100644 --- a/.github/workflows/lint_test.yaml +++ b/.github/workflows/lint_test.yaml @@ -22,7 +22,7 @@ jobs: check-latest: true - name: Set up chart-testing - uses: helm/chart-testing-action@v2.4.0 + uses: helm/chart-testing-action@v2.6.0 - name: Run chart-testing (list-changed) id: list-changed diff --git a/.kubeagi_repo.yaml b/.kubeagi_repo.yaml deleted file mode 100644 index 55d91dc77..000000000 --- a/.kubeagi_repo.yaml +++ /dev/null @@ -1,10 +0,0 @@ -apiVersion: core.kubebb.k8s.com.cn/v1alpha1 -kind: Repository -metadata: - name: kubeagi - namespace: kubebb-system -spec: - url: https://kubeagi.github.io/arcadia - pullStategy: - intervalSeconds: 120 - retry: 5 diff --git a/Dockerfile b/Dockerfile index 8b60d8629..d39c25a75 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,7 @@ COPY go.mod go.mod COPY go.sum go.sum # cache deps before building and copying source so that we don't need to re-download as much # and so that source changes don't invalidate our downloaded layer +RUN go env -w GOPROXY=https://goproxy.cn,direct RUN go mod download # Copy the go source diff --git a/PROJECT b/PROJECT index d06ede5eb..194360c00 100644 --- a/PROJECT +++ b/PROJECT @@ -1,7 +1,3 @@ -# Code generated by tool. DO NOT EDIT. -# This file is used to track the info used to scaffold your project -# and allow the plugins properly work. -# More info: https://book.kubebuilder.io/reference/project-config.html componentConfig: true domain: kubeagi.k8s.com.cn layout: @@ -58,4 +54,22 @@ resources: kind: Embedders path: github.com/kubeagi/arcadia/api/v1alpha1 version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: kubeagi.k8s.com.cn + group: arcadia + kind: Dataset + path: github.com/kubeagi/arcadia/api/v1alpha1 + version: v1alpha1 +- api: + crdVersion: v1 + namespaced: true + controller: true + domain: kubeagi.k8s.com.cn + group: arcadia + kind: VersionedDataset + path: github.com/kubeagi/arcadia/api/v1alpha1 + version: v1alpha1 version: "3" diff --git a/README.md b/README.md index e5366a9c1..2900e6a7a 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,13 @@ Our design and development in Arcadia design follows operator pattern which exte helm install --namespace arcadia --create-namespace arcadia arcadia/arcadia ``` +More conveniently,you can use [kubebb](https://github.com/kubebb) to install and upgrade arcadia automatically: +> Pre-requsities +> - [kubebb](https://kubebb.github.io/website/docs/quick-start/core_quickstart) +```shell +kubectl apply -f ./kubeagi.yaml +``` + ## CLI We provide a Command Line Tool `arctl` to interact with `arcadia`. See [here](./arctl/README.md) for more details. diff --git a/api/v1alpha1/condition.go b/api/v1alpha1/condition.go index ea9c51ff2..a4665ff4f 100644 --- a/api/v1alpha1/condition.go +++ b/api/v1alpha1/condition.go @@ -51,6 +51,32 @@ const ( ReasonReconcilePaused ConditionReason = "ReconcilePaused" ) +// Some Data related Condition Types +const ( + // Dataset have 3 phases: load -> process -> publish + // TypeLoaded resources are believed to be loaded + TypeLoaded ConditionType = "Loaded" + // TypeProcessed resources are believed to be processed + TypeProcessed ConditionType = "Processed" + // TypePublished resources are believed to be published + TypePublished ConditionType = "Published" +) + +// Some Dataset related Condition reasons +const ( + // Load data + ReasonDataLoading ConditionReason = "DataLoading" + ReasonDataLoadError ConditionReason = "DataLoadError" + ReasonDataLoadSuccess ConditionReason = "DataLoadSuccess" + // Process data + ReasonDataProcessing ConditionReason = "DataProcessing" + ReasonDataProcessError ConditionReason = "DataProcessError" + ReasonDataProcessSuccess ConditionReason = "DataProcessSuccess" + // Publish dataset + ReasonDatasetUnpublished ConditionReason = "DatasetUnpublished" + ReasonDatasetPublished ConditionReason = "DatasetPublished" +) + // A Condition that may apply to a resource. type Condition struct { // Type of this condition. At most one of each condition type may apply to diff --git a/api/v1alpha1/dataset.go b/api/v1alpha1/dataset.go new file mode 100644 index 000000000..f073fba11 --- /dev/null +++ b/api/v1alpha1/dataset.go @@ -0,0 +1,33 @@ +/* +Copyright 2023 KubeAGI. + +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 v1alpha1 + +type DatasetContentType string + +const ( + DatasetContentTypeText DatasetContentType = "text" + DatasetContentTypeImage DatasetContentType = "image" + DatasetContentTypeVoice DatasetContentType = "voice" + DatasetContentTypeVideo DatasetContentType = "video" +) + +var ( + // LabelDatasetScene defines the content type of this dataset + LabelDatasetContentType = Group + "/content-type" + // LabelDatasetBestCase defines the best case to use this dataset + LabelDatasetBestCase = Group + "/best-case" +) diff --git a/api/v1alpha1/dataset_types.go b/api/v1alpha1/dataset_types.go new file mode 100644 index 000000000..674130dbb --- /dev/null +++ b/api/v1alpha1/dataset_types.go @@ -0,0 +1,72 @@ +/* +Copyright 2023 KubeAGI. + +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 v1alpha1 + +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. + +// DatasetSpec defines the desired state of Dataset +type DatasetSpec struct { + // Creator defines dataset creator(AUTO-FILLED by webhook) + Creator string `json:"creator,omitempty"` + + // DisplayName defines dataset display name + DiplayName string `json:"displayName"` + + // ContentType defines dataset + ContentType string `json:"contentType"` + + // bestCase defines the best case to use this dataset + BestCase string `json:"bestCase,omitempty"` +} + +// DatasetStatus defines the observed state of Dataset +type DatasetStatus struct { + // ConditionedStatus is the current status + ConditionedStatus `json:",inline"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:printcolumn:name="display-name",type=string,JSONPath=`.spec.displayName` +//+kubebuilder:printcolumn:name="type",type=string,JSONPath=`.spec.contentType` + +// Dataset is the Schema for the datasets API +type Dataset struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec DatasetSpec `json:"spec,omitempty"` + Status DatasetStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// DatasetList contains a list of Dataset +type DatasetList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Dataset `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Dataset{}, &DatasetList{}) +} diff --git a/api/v1alpha1/datasource.go b/api/v1alpha1/datasource.go index 76b0f40fc..8ae60710d 100644 --- a/api/v1alpha1/datasource.go +++ b/api/v1alpha1/datasource.go @@ -23,11 +23,19 @@ const ( type DatasourceType string const ( + DatasourceTypeLocal DatasourceType = "local" DatasourceTypeOSS DatasourceType = "oss" DatasourceTypeUnknown DatasourceType = "unknown" ) func (ds DatasourceSpec) Type() DatasourceType { + // if endpoint is nil,this must be a `Local` datasource which utilize `SystemDatasource` by default to host its data + if ds.Enpoint == nil { + return DatasourceTypeLocal + } + + // For third party datasources + // Object storage service if ds.OSS != nil { return DatasourceTypeOSS diff --git a/api/v1alpha1/datasource_types.go b/api/v1alpha1/datasource_types.go index c9f07ade5..0fe805690 100644 --- a/api/v1alpha1/datasource_types.go +++ b/api/v1alpha1/datasource_types.go @@ -29,13 +29,13 @@ type DatasourceSpec struct { Creator string `json:"creator,omitempty"` // DisplayName defines datasource display name - DiplayName string `json:"displayName,omitempty"` + DiplayName string `json:"displayName"` // Description defines datasource description Description string `json:"description,omitempty"` // Enpoint defines connection info - Enpoint Endpoint `json:"endpoint"` + Enpoint *Endpoint `json:"endpoint,omitempty"` // OSS defines info for object storage service OSS *OSS `json:"oss,omitempty"` @@ -56,6 +56,8 @@ type DatasourceStatus struct { //+kubebuilder:object:root=true //+kubebuilder:subresource:status //+kubebuilder:resource:scope=Namespaced +//+kubebuilder:printcolumn:name="display-name",type=string,JSONPath=`.spec.displayName` +//+kubebuilder:printcolumn:name="type",type=string,JSONPath=`.metadata.labels.arcadia\.kubeagi\.k8s\.com\.cn/datasource-type` // Datasource is the Schema for the datasources API type Datasource struct { diff --git a/api/v1alpha1/versioneddataset.go b/api/v1alpha1/versioneddataset.go new file mode 100644 index 000000000..7520ecbb9 --- /dev/null +++ b/api/v1alpha1/versioneddataset.go @@ -0,0 +1,21 @@ +/* +Copyright 2023 KubeAGI. + +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 v1alpha1 + +var ( + LabelVersionedDatasetVersion = Group + "/version" +) diff --git a/api/v1alpha1/versioneddataset_types.go b/api/v1alpha1/versioneddataset_types.go new file mode 100644 index 000000000..834233b5a --- /dev/null +++ b/api/v1alpha1/versioneddataset_types.go @@ -0,0 +1,77 @@ +/* +Copyright 2023 KubeAGI. + +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 v1alpha1 + +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. + +type FileGroup struct { + // From defines the datasource which provides this `File` + Datasource *TypedObjectReference `json:"datasource"` + // Paths defines the detail paths to get objects from above datasource + Paths []string `json:"paths"` +} + +// VersionedDatasetSpec defines the desired state of VersionedDataset +type VersionedDatasetSpec struct { + // Dataset which this `VersionedDataset` belongs to + Dataset *TypedObjectReference `json:"dataset"` + + // Version + Version string `json:"version"` + + // FileGroups included in this `VersionedDataset` + // Grouped by Datasource + FileGroups []FileGroup `json:"fileGroups,omitempty"` +} + +// VersionedDatasetStatus defines the observed state of VersionedDataset +type VersionedDatasetStatus struct { + // ConditionedStatus is the current status + ConditionedStatus `json:",inline"` +} + +//+kubebuilder:object:root=true +//+kubebuilder:subresource:status +//+kubebuilder:printcolumn:name="dataset",type=string,JSONPath=`.spec.dataset.name` +//+kubebuilder:printcolumn:name="version",type=string,JSONPath=`.spec.version` + +// VersionedDataset is the Schema for the versioneddatasets API +type VersionedDataset struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec VersionedDatasetSpec `json:"spec,omitempty"` + Status VersionedDatasetStatus `json:"status,omitempty"` +} + +//+kubebuilder:object:root=true + +// VersionedDatasetList contains a list of VersionedDataset +type VersionedDatasetList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []VersionedDataset `json:"items"` +} + +func init() { + SchemeBuilder.Register(&VersionedDataset{}, &VersionedDatasetList{}) +} diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 4ce689017..d849be646 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -65,6 +65,96 @@ func (in *ConditionedStatus) DeepCopy() *ConditionedStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Dataset) DeepCopyInto(out *Dataset) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Dataset. +func (in *Dataset) DeepCopy() *Dataset { + if in == nil { + return nil + } + out := new(Dataset) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Dataset) 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 *DatasetList) DeepCopyInto(out *DatasetList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Dataset, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DatasetList. +func (in *DatasetList) DeepCopy() *DatasetList { + if in == nil { + return nil + } + out := new(DatasetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *DatasetList) 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 *DatasetSpec) DeepCopyInto(out *DatasetSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DatasetSpec. +func (in *DatasetSpec) DeepCopy() *DatasetSpec { + if in == nil { + return nil + } + out := new(DatasetSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DatasetStatus) DeepCopyInto(out *DatasetStatus) { + *out = *in + in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DatasetStatus. +func (in *DatasetStatus) DeepCopy() *DatasetStatus { + if in == nil { + return nil + } + out := new(DatasetStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Datasource) DeepCopyInto(out *Datasource) { *out = *in @@ -127,7 +217,11 @@ func (in *DatasourceList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DatasourceSpec) DeepCopyInto(out *DatasourceSpec) { *out = *in - in.Enpoint.DeepCopyInto(&out.Enpoint) + if in.Enpoint != nil { + in, out := &in.Enpoint, &out.Enpoint + *out = new(Endpoint) + (*in).DeepCopyInto(*out) + } if in.OSS != nil { in, out := &in.OSS, &out.OSS *out = new(OSS) @@ -276,6 +370,31 @@ func (in *Endpoint) DeepCopy() *Endpoint { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FileGroup) DeepCopyInto(out *FileGroup) { + *out = *in + if in.Datasource != nil { + in, out := &in.Datasource, &out.Datasource + *out = new(TypedObjectReference) + (*in).DeepCopyInto(*out) + } + if in.Paths != nil { + in, out := &in.Paths, &out.Paths + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FileGroup. +func (in *FileGroup) DeepCopy() *FileGroup { + if in == nil { + return nil + } + out := new(FileGroup) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LLM) DeepCopyInto(out *LLM) { *out = *in @@ -599,3 +718,105 @@ func (in *TypedObjectReference) DeepCopy() *TypedObjectReference { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VersionedDataset) DeepCopyInto(out *VersionedDataset) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VersionedDataset. +func (in *VersionedDataset) DeepCopy() *VersionedDataset { + if in == nil { + return nil + } + out := new(VersionedDataset) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VersionedDataset) 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 *VersionedDatasetList) DeepCopyInto(out *VersionedDatasetList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]VersionedDataset, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VersionedDatasetList. +func (in *VersionedDatasetList) DeepCopy() *VersionedDatasetList { + if in == nil { + return nil + } + out := new(VersionedDatasetList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VersionedDatasetList) 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 *VersionedDatasetSpec) DeepCopyInto(out *VersionedDatasetSpec) { + *out = *in + if in.Dataset != nil { + in, out := &in.Dataset, &out.Dataset + *out = new(TypedObjectReference) + (*in).DeepCopyInto(*out) + } + if in.FileGroups != nil { + in, out := &in.FileGroups, &out.FileGroups + *out = make([]FileGroup, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VersionedDatasetSpec. +func (in *VersionedDatasetSpec) DeepCopy() *VersionedDatasetSpec { + if in == nil { + return nil + } + out := new(VersionedDatasetSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VersionedDatasetStatus) DeepCopyInto(out *VersionedDatasetStatus) { + *out = *in + in.ConditionedStatus.DeepCopyInto(&out.ConditionedStatus) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VersionedDatasetStatus. +func (in *VersionedDatasetStatus) DeepCopy() *VersionedDatasetStatus { + if in == nil { + return nil + } + out := new(VersionedDatasetStatus) + in.DeepCopyInto(out) + return out +} diff --git a/assets/dataset_storage.drawio b/assets/dataset_storage.drawio new file mode 100644 index 000000000..7e2928f4e --- /dev/null +++ b/assets/dataset_storage.drawio @@ -0,0 +1 @@ +7Vxbc5s4FP41zOw+xCMBAvxo47g73e5Md9LJtn3ZwSDbtMTyYjlx9tdXAmEDOnbdmkvSJC9BBxDS952bjpQYln+3e5MG6+VfLKKJYaJoZ1gTwzQxxpb4JSWPucTFJBcs0jhSDx0EN/H/VAmRkm7jiG4qD3LGEh6vq8KQrVY05BVZkKbsofrYnCXVr66DBdUEN2GQ6NJ/4ogvlXRoosONP2i8WBafNpG6cxcUTyvBZhlE7KEksq4Ny08Z4/nV3c6niUSvACZ/b3rk7n5kKV3xc17wb9/dD/2J9TZ9+2UzJtPE+eBfOYqf+yDZqimr0fLHAoOUbVcRlb0gwxo/LGNOb9ZBKO8+CNaFbMnvEtHC4lIflRroPU053ZVEapRvKLujPH0Uj6i7NlGIKZ3BtjfAalgPBxKGBdLLEv6OhQeep/hX3C/2XzigIy4UQDBY/179+Zncf71x3vp/f/jsJdzyR1e2Bg2NhLaoJkv5ki3YKkiuD9JxFbzDM+8YWyvIvlDOH5XqB1vOqoAKHNPHj/L9ASman1R3WWOyq7Qe961oJA1ANFdsRXPJNJYzzu/vYv6x+Ia4/nT4hGgdOpWNos98/nLSR3VQiTZsm4b0lOIpQnmQLig/AboF60pKk4DH99WBQIyrV9+zWAxxr2OOV9Ux03MHBGHsOraLiOdZ1Q7z6ag+yjZW69Y19W5ti1Q7y6esdZap5H6GP6+lpGc1rSjpQWePqOmcrbjqFHtnqG0fKkgu1cFzvc7JYTbmoucCTZ8lLM3etWZB6EWWkG94yr7S0h3Tsm0S1Uiyi7b6+nECfsDjD2tmY5oDojl80wEcPkbewCVtQa8hP96GX6k0+NGWL397n7IvMusw0SzY0Oh3jRcxf14FvwqyUvEyI0oUJPFiJZqhQJUK+ViiGYvEZKRu3MVRlJkuxHZVH9qmj9S9XpG9lcmDonUR6BsnztVN5npojLAxHhrXrjEcG6Prq9UGa4RdYkgIEUTnCt+SfJ79QAaGEJ6M/S4YQjWGCGRgGOKoHr0a48jUrWuWWVfjxMy9kIYhRMDMIzLbbJ8Ap24ixNq7re8yYLXn4UxPIyFDfxoFXLg0Lq+y9n1LtvJjNgFZVQPseLX4Y9u6A8MmRE0DDgzOer3nmsTZ3SZx5lBP4sAHLaejJA7mc/jK50/zCSKK7T75LBzEK5+N8dmrfdp6eHvl8zI+vY74PDnMUl5ze2kGUwO9jbwDWDi1lnfAUZJouBmmk3A1f0NW2osUzPlvK2vXY5mMRfNwHpZFzkL+Pp5LTkdFv+I67zp/pY80s6W0EiOnnlcCKb8F8Gu2xq++6BJ+gl6NLoO9FbDMvsFyfs4YUPZTFpVwLYSyg6tN5k4E9gh7611uNzULmhS2g244S+VulbxKtyHfpvRcE9LLUCkV3w5m2QOSXxmbNsq5/VD1aS3L2BnwZGyQCVzMAoteeo2qZIbTydSf7leB+4W4Xi9uQPPcgudiv8kBylcEUDy7tfIV1hXvZdevcK18AlDUbfXK1avyv3D1ynpy8Ov71qoY/6LMol5VdPEAiprdUmNr1Ix/Xcuw6wx0WlgHV166ZwLT8EZNxAsQgk2BuAiI73vjOUUQOsIGwNnx4F6LHJaHBx7WGbKhxLKZrUW44GBpDLz4gsPx8x9n1HfzFX9v9aNne+iifzphJ0b6pFPPLiY3DZePgEjUrKOznbMdXUM7jHAdEDph2EpFafwsKkoXkawXSYYdFklO7MPoFaULYW8FLGjHvVuwOiuv+i/QGEiX5dUTm1i6MfhPzxhIl+VVGCzglNYFxjAYDF6izvcfAPQjRBkVT07he/f+ph4qOzlsFXkIueAJ3xFByD5WJ2lJheubnvviYm+HrYqw8bp4+87irQgZ31+9ubAKdLQYd175bJjPXosrpp4135oXekjwMEezfg317deAE9YtrDbkIIMuMq8zw1hXmdf+T8j6yyf0BDpbbQRPL/lyoB3DbsHS09SWjGH2Ao3BhZK4bvnVT/xlxjB7esbgQsf8OgWLmBpYukJfGmKf7R6h7TngNnrXe4QE2oZoOPFpexvCJvCRhOa2IUTz8E8U8j+iPvwvCuv6Gw== \ No newline at end of file diff --git a/assets/dataset_storage.drawio.png b/assets/dataset_storage.drawio.png new file mode 100644 index 000000000..5a210f221 Binary files /dev/null and b/assets/dataset_storage.drawio.png differ diff --git a/assets/system_datasource.drawio b/assets/system_datasource.drawio new file mode 100644 index 000000000..a9f29d8f1 --- /dev/null +++ b/assets/system_datasource.drawio @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/system_datasource.drawio.png b/assets/system_datasource.drawio.png new file mode 100644 index 000000000..e484b12b3 Binary files /dev/null and b/assets/system_datasource.drawio.png differ diff --git a/charts/arcadia/Chart.lock b/charts/arcadia/Chart.lock new file mode 100644 index 000000000..9d2fb1df0 --- /dev/null +++ b/charts/arcadia/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: minio + repository: "" + version: 5.0.10 +- name: fastchat + repository: "" + version: 0.0.2 +digest: sha256:54d12a585a3decd50f82eaffae0224f188f7d715565bd751ffda3435678c2619 +generated: "2023-11-02T06:00:49.531248052Z" diff --git a/charts/arcadia/Chart.yaml b/charts/arcadia/Chart.yaml index 46a6f4b0c..2f37000d7 100644 --- a/charts/arcadia/Chart.yaml +++ b/charts/arcadia/Chart.yaml @@ -2,14 +2,24 @@ apiVersion: v2 name: arcadia description: A Helm chart(KubeBB Component) for KubeAGI Arcadia type: application -version: 0.1.9 +version: 0.1.14 appVersion: "0.0.1" + keywords: - - kubeagi - - NativeAI - LLMOps + - Kubernetes + sources: - https://github.com/kubeagi/arcadia + maintainers: - name: bjwswang url: https://github.com/bjwswang + - name: lanture1064 + url: https://github.com/lanture1064 + +dependencies: + - name: minio + version: 5.0.10 + - name: fastchat + version: 0.0.2 diff --git a/charts/arcadia/charts/fastchat/.helmignore b/charts/arcadia/charts/fastchat/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/charts/arcadia/charts/fastchat/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/arcadia/charts/fastchat/Chart.yaml b/charts/arcadia/charts/fastchat/Chart.yaml new file mode 100644 index 000000000..c3d2bff8e --- /dev/null +++ b/charts/arcadia/charts/fastchat/Chart.yaml @@ -0,0 +1,33 @@ +apiVersion: v2 +name: fastchat +description: A Helm chart for fastchat server + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.0.2 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.2.32" + +sources: + - https://github.com/kubeagi/arcadia +keywords: + - kubeagi + - LLMOps +maintainers: + - name: lanture1064 + url: https://github.com/lanture1064 \ No newline at end of file diff --git a/charts/arcadia/charts/fastchat/templates/deployment.yaml b/charts/arcadia/charts/fastchat/templates/deployment.yaml new file mode 100644 index 000000000..8a2f1af71 --- /dev/null +++ b/charts/arcadia/charts/fastchat/templates/deployment.yaml @@ -0,0 +1,34 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }}-fastchat + namespace: {{ .Release.Namespace }} + labels: + control-plane: {{ .Release.Name }}-fastchat +spec: + selector: + matchLabels: + control-plane: {{ .Release.Name }}-fastchat + replicas: 1 + template: + metadata: + labels: + control-plane: {{ .Release.Name }}-fastchat + spec: + containers: + - name: {{ .Values.container.name.controller }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["/bin/bash","-c","python3 -m fastchat.serve.controller --host 0.0.0.0 --port 21001"] + ports: + - name: controller + containerPort: {{ .Values.service.controller.port }} + protocol: TCP + - name: {{ .Values.container.name.apiServer }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["/bin/bash","-c","python3 -m fastchat.serve.openai_api_server --controller-address http://localhost:21001 --host 0.0.0.0 --port 8000"] + ports: + - name: api + containerPort: {{ .Values.service.apiServer.port }} + protocol: TCP diff --git a/charts/arcadia/charts/fastchat/templates/ingress.yaml b/charts/arcadia/charts/fastchat/templates/ingress.yaml new file mode 100644 index 000000000..6b0431311 --- /dev/null +++ b/charts/arcadia/charts/fastchat/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := .Release.Name -}} +{{- $svcPort := .Values.service.apiServer.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }}-fastchat + labels: + control-plane: {{ .Release.Name }}-fastchat + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ .port }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ .port }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/arcadia/charts/fastchat/templates/service.yaml b/charts/arcadia/charts/fastchat/templates/service.yaml new file mode 100644 index 000000000..5c18a37b9 --- /dev/null +++ b/charts/arcadia/charts/fastchat/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }}-fastchat + labels: + control-plane: {{ .Release.Name }}-fastchat +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.apiServer.port }} + targetPort: {{ .Values.service.apiServer.port }} + protocol: TCP + name: api + - port: {{ .Values.service.controller.port }} + targetPort: {{ .Values.service.controller.port }} + protocol: TCP + name: controller + selector: + control-plane: {{ .Release.Name }}-fastchat \ No newline at end of file diff --git a/charts/arcadia/charts/fastchat/values.yaml b/charts/arcadia/charts/fastchat/values.yaml new file mode 100644 index 000000000..551f67e0b --- /dev/null +++ b/charts/arcadia/charts/fastchat/values.yaml @@ -0,0 +1,58 @@ +# Default values for fastchat. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. +image: + repository: kubebb/arcadia-fastchat + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "v0.0.1" + +container: + name: + controller: fastchat-controller + apiServer: fastchat-api-server + +service: + type: ClusterIP + controller: + port: 21001 + apiServer: + port: 8000 + +volumes: + # Replace with real path if you want to use local huggingface models + huggingface: + +ingress: + enabled: false + className: portal-ingress + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: api.fastchat.arcadia.com + paths: + - path: / + port: 8000 + pathType: ImplementationSpecific + - host: controller.fastchat.arcadia.com + paths: + - path: / + port: 21001 + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi \ No newline at end of file diff --git a/charts/arcadia/charts/minio/Chart.yaml b/charts/arcadia/charts/minio/Chart.yaml new file mode 100644 index 000000000..8cea2298f --- /dev/null +++ b/charts/arcadia/charts/minio/Chart.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +appVersion: RELEASE.2023-02-10T18-48-39Z +description: Multi-Cloud Object Storage +home: https://min.io +icon: https://min.io/resources/img/logo/MINIO_wordmark.png +keywords: +- minio +- storage +- object-storage +- s3 +- cluster +maintainers: +- email: dev@minio.io + name: MinIO, Inc +name: minio +sources: +- https://github.com/minio/minio +version: 5.0.10 diff --git a/charts/arcadia/charts/minio/README.md b/charts/arcadia/charts/minio/README.md new file mode 100644 index 000000000..6de4fb16b --- /dev/null +++ b/charts/arcadia/charts/minio/README.md @@ -0,0 +1,260 @@ +# MinIO Helm Chart + +[![Slack](https://slack.min.io/slack?type=svg)](https://slack.min.io) [![license](https://img.shields.io/badge/license-AGPL%20V3-blue)](https://github.com/minio/minio/blob/master/LICENSE) + +MinIO is a High Performance Object Storage released under GNU Affero General Public License v3.0. It is API compatible with Amazon S3 cloud storage service. Use MinIO to build high performance infrastructure for machine learning, analytics and application data workloads. + +For more detailed documentation please visit [here](https://min.io/docs/minio/linux/index.html) + +## Introduction + +This chart bootstraps MinIO Cluster on [Kubernetes](http://kubernetes.io) using the [Helm](https://helm.sh) package manager. + +## Prerequisites + +- Helm cli with Kubernetes cluster configured. +- PV provisioner support in the underlying infrastructure. (We recommend using ) +- Use Kubernetes version v1.19 and later for best experience. + +## Configure MinIO Helm repo + +```bash +helm repo add minio https://charts.min.io/ +``` + +### Installing the Chart + +Install this chart using: + +```bash +helm install --namespace minio --set rootUser=rootuser,rootPassword=rootpass123 --generate-name minio/minio +``` + +The command deploys MinIO on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation. + +### Installing the Chart (toy-setup) + +Minimal toy setup for testing purposes can be deployed using: + +```bash +helm install --set resources.requests.memory=512Mi --set replicas=1 --set persistence.enabled=false --set mode=standalone --set rootUser=rootuser,rootPassword=rootpass123 --generate-name minio/minio +``` + +### Upgrading the Chart + +You can use Helm to update MinIO version in a live release. Assuming your release is named as `my-release`, get the values using the command: + +```bash +helm get values my-release > old_values.yaml +``` + +Then change the field `image.tag` in `old_values.yaml` file with MinIO image tag you want to use. Now update the chart using + +```bash +helm upgrade -f old_values.yaml my-release minio/minio +``` + +Default upgrade strategies are specified in the `values.yaml` file. Update these fields if you'd like to use a different strategy. + +### Configuration + +Refer the [Values file](./values.yaml) for all the possible config fields. + +You can specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```bash +helm install --name my-release --set persistence.size=1Ti minio/minio +``` + +The above command deploys MinIO server with a 1Ti backing persistent volume. + +Alternately, you can provide a YAML file that specifies parameter values while installing the chart. For example, + +```bash +helm install --name my-release -f values.yaml minio/minio +``` + +### Persistence + +This chart provisions a PersistentVolumeClaim and mounts corresponding persistent volume to default location `/export`. You'll need physical storage available in the Kubernetes cluster for this to work. If you'd rather use `emptyDir`, disable PersistentVolumeClaim by: + +```bash +helm install --set persistence.enabled=false minio/minio +``` + +> *"An emptyDir volume is first created when a Pod is assigned to a Node, and exists as long as that Pod is running on that node. When a Pod is removed from a node for any reason, the data in the emptyDir is deleted forever."* + +### Existing PersistentVolumeClaim + +If a Persistent Volume Claim already exists, specify it during installation. + +1. Create the PersistentVolume +2. Create the PersistentVolumeClaim +3. Install the chart + +```bash +helm install --set persistence.existingClaim=PVC_NAME minio/minio +``` + +### NetworkPolicy + +To enable network policy for MinIO, +install [a networking plugin that implements the Kubernetes +NetworkPolicy spec](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy#before-you-begin), +and set `networkPolicy.enabled` to `true`. + +For Kubernetes v1.5 & v1.6, you must also turn on NetworkPolicy by setting +the DefaultDeny namespace annotation. Note: this will enforce policy for *all* pods in the namespace: + +``` +kubectl annotate namespace default "net.beta.kubernetes.io/network-policy={\"ingress\":{\"isolation\":\"DefaultDeny\"}}" +``` + +With NetworkPolicy enabled, traffic will be limited to just port 9000. + +For more precise policy, set `networkPolicy.allowExternal=true`. This will +only allow pods with the generated client label to connect to MinIO. +This label will be displayed in the output of a successful install. + +### Existing secret + +Instead of having this chart create the secret for you, you can supply a preexisting secret, much +like an existing PersistentVolumeClaim. + +First, create the secret: + +```bash +kubectl create secret generic my-minio-secret --from-literal=rootUser=foobarbaz --from-literal=rootPassword=foobarbazqux +``` + +Then install the chart, specifying that you want to use an existing secret: + +```bash +helm install --set existingSecret=my-minio-secret minio/minio +``` + +The following fields are expected in the secret: + +| .data.\ in Secret | Corresponding variable | Description | Required | +|:------------------------|:-----------------------|:---------------|:---------| +| `rootUser` | `rootUser` | Root user. | yes | +| `rootPassword` | `rootPassword` | Root password. | yes | + +All corresponding variables will be ignored in values file. + +### Configure TLS + +To enable TLS for MinIO containers, acquire TLS certificates from a CA or create self-signed certificates. While creating / acquiring certificates ensure the corresponding domain names are set as per the standard [DNS naming conventions](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-identity) in a Kubernetes StatefulSet (for a distributed MinIO setup). Then create a secret using + +```bash +kubectl create secret generic tls-ssl-minio --from-file=path/to/private.key --from-file=path/to/public.crt +``` + +Then install the chart, specifying that you want to use the TLS secret: + +```bash +helm install --set tls.enabled=true,tls.certSecret=tls-ssl-minio minio/minio +``` + +### Installing certificates from third party CAs + +MinIO can connect to other servers, including MinIO nodes or other server types such as NATs and Redis. If these servers use certificates that were not registered with a known CA, add trust for these certificates to MinIO Server by bundling these certificates into a Kubernetes secret and providing it to Helm via the `trustedCertsSecret` value. If `.Values.tls.enabled` is `true` and you're installing certificates for third party CAs, remember to include MinIO's own certificate with key `public.crt`, if it also needs to be trusted. + +For instance, given that TLS is enabled and you need to add trust for MinIO's own CA and for the CA of a Keycloak server, a Kubernetes secret can be created from the certificate files using `kubectl`: + +``` +kubectl -n minio create secret generic minio-trusted-certs --from-file=public.crt --from-file=keycloak.crt +``` + +If TLS is not enabled, you would need only the third party CA: + +``` +kubectl -n minio create secret generic minio-trusted-certs --from-file=keycloak.crt +``` + +The name of the generated secret can then be passed to Helm using a values file or the `--set` parameter: + +``` +trustedCertsSecret: "minio-trusted-certs" + +or + +--set trustedCertsSecret=minio-trusted-certs +``` + +### Create buckets after install + +Install the chart, specifying the buckets you want to create after install: + +```bash +helm install --set buckets[0].name=bucket1,buckets[0].policy=none,buckets[0].purge=false minio/minio +``` + +Description of the configuration parameters used above - + +- `buckets[].name` - name of the bucket to create, must be a string with length > 0 +- `buckets[].policy` - can be one of none|download|upload|public +- `buckets[].purge` - purge if bucket exists already + +### Create policies after install + +Install the chart, specifying the policies you want to create after install: + +```bash +helm install --set policies[0].name=mypolicy,policies[0].statements[0].resources[0]='arn:aws:s3:::bucket1',policies[0].statements[0].actions[0]='s3:ListBucket',policies[0].statements[0].actions[1]='s3:GetObject' minio/minio +``` + +Description of the configuration parameters used above - + +- `policies[].name` - name of the policy to create, must be a string with length > 0 +- `policies[].statements[]` - list of statements, includes actions and resources +- `policies[].statements[].resources[]` - list of resources that applies the statement +- `policies[].statements[].actions[]` - list of actions granted + +### Create user after install + +Install the chart, specifying the users you want to create after install: + +```bash +helm install --set users[0].accessKey=accessKey,users[0].secretKey=secretKey,users[0].policy=none,users[1].accessKey=accessKey2,users[1].secretRef=existingSecret,users[1].secretKey=password,users[1].policy=none minio/minio +``` + +Description of the configuration parameters used above - + +- `users[].accessKey` - accessKey of user +- `users[].secretKey` - secretKey of usersecretRef +- `users[].existingSecret` - secret name that contains the secretKey of user +- `users[].existingSecretKey` - data key in existingSecret secret containing the secretKey +- `users[].policy` - name of the policy to assign to user + +### Create service account after install + +Install the chart, specifying the service accounts you want to create after install: + +```bash +helm install --set svcaccts[0].accessKey=accessKey,svcaccts[0].secretKey=secretKey,svcaccts[0].user=parentUser,svcaccts[1].accessKey=accessKey2,svcaccts[1].secretRef=existingSecret,svcaccts[1].secretKey=password,svcaccts[1].user=parentUser2 minio/minio +``` + +Description of the configuration parameters used above - + +- `svcaccts[].accessKey` - accessKey of service account +- `svcaccts[].secretKey` - secretKey of svcacctsecretRef +- `svcaccts[].existingSecret` - secret name that contains the secretKey of service account +- `svcaccts[].existingSecretKey` - data key in existingSecret secret containing the secretKey +- `svcaccts[].user` - name of the parent user to assign to service account + +## Uninstalling the Chart + +Assuming your release is named as `my-release`, delete it using the command: + +```bash +helm delete my-release +``` + +or + +```bash +helm uninstall my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. diff --git a/charts/arcadia/charts/minio/templates/NOTES.txt b/charts/arcadia/charts/minio/templates/NOTES.txt new file mode 100644 index 000000000..7051b1e62 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/NOTES.txt @@ -0,0 +1,43 @@ +{{- if eq .Values.service.type "ClusterIP" "NodePort" }} +MinIO can be accessed via port {{ .Values.service.port }} on the following DNS name from within your cluster: +{{ template "minio.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local + +To access MinIO from localhost, run the below commands: + + 1. export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + + 2. kubectl port-forward $POD_NAME 9000 --namespace {{ .Release.Namespace }} + +Read more about port forwarding here: http://kubernetes.io/docs/user-guide/kubectl/kubectl_port-forward/ + +You can now access MinIO server on http://localhost:9000. Follow the below steps to connect to MinIO server with mc client: + + 1. Download the MinIO mc client - https://min.io/docs/minio/linux/reference/minio-mc.html#quickstart + + 2. export MC_HOST_{{ template "minio.fullname" . }}-local=http://$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "minio.secretName" . }} -o jsonpath="{.data.rootUser}" | base64 --decode):$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "minio.secretName" . }} -o jsonpath="{.data.rootPassword}" | base64 --decode)@localhost:{{ .Values.service.port }} + + 3. mc ls {{ template "minio.fullname" . }}-local + +{{- end }} +{{- if eq .Values.service.type "LoadBalancer" }} +MinIO can be accessed via port {{ .Values.service.port }} on an external IP address. Get the service external IP address by: +kubectl get svc --namespace {{ .Release.Namespace }} -l app={{ template "minio.fullname" . }} + +Note that the public IP may take a couple of minutes to be available. + +You can now access MinIO server on http://:9000. Follow the below steps to connect to MinIO server with mc client: + + 1. Download the MinIO mc client - https://min.io/docs/minio/linux/reference/minio-mc.html#quickstart + + 2. export MC_HOST_{{ template "minio.fullname" . }}-local=http://$(kubectl get secret {{ template "minio.secretName" . }} --namespace {{ .Release.Namespace }} -o jsonpath="{.data.rootUser}" | base64 --decode):$(kubectl get secret {{ template "minio.secretName" . }} -o jsonpath="{.data.rootPassword}" | base64 --decode)@:{{ .Values.service.port }} + + 3. mc ls {{ template "minio.fullname" . }} + +Alternately, you can use your browser or the MinIO SDK to access the server - https://min.io/docs/minio/linux/reference/minio-server/minio-server.html +{{- end }} + +{{ if and (.Values.networkPolicy.enabled) (not .Values.networkPolicy.allowExternal) }} +Note: Since NetworkPolicy is enabled, only pods with label +{{ template "minio.fullname" . }}-client=true" +will be able to connect to this minio cluster. +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/_helper_create_bucket.txt b/charts/arcadia/charts/minio/templates/_helper_create_bucket.txt new file mode 100644 index 000000000..f8d5cd833 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/_helper_create_bucket.txt @@ -0,0 +1,127 @@ +#!/bin/sh +set -e ; # Have script exit in the event of a failed command. + +{{- if .Values.configPathmc }} +MC_CONFIG_DIR="{{ .Values.configPathmc }}" +MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" +{{- else }} +MC="/usr/bin/mc --insecure" +{{- end }} + +# connectToMinio +# Use a check-sleep-check loop to wait for MinIO service to be available +connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 +} + +# checkBucketExists ($bucket) +# Check if the bucket exists, by using the exit code of `mc ls` +checkBucketExists() { + BUCKET=$1 + CMD=$(${MC} stat myminio/$BUCKET > /dev/null 2>&1) + return $? +} + +# createBucket ($bucket, $policy, $purge) +# Ensure bucket exists, purging if asked to +createBucket() { + BUCKET=$1 + POLICY=$2 + PURGE=$3 + VERSIONING=$4 + OBJECTLOCKING=$5 + + # Purge the bucket, if set & exists + # Since PURGE is user input, check explicitly for `true` + if [ $PURGE = true ]; then + if checkBucketExists $BUCKET ; then + echo "Purging bucket '$BUCKET'." + set +e ; # don't exit if this fails + ${MC} rm -r --force myminio/$BUCKET + set -e ; # reset `e` as active + else + echo "Bucket '$BUCKET' does not exist, skipping purge." + fi + fi + +# Create the bucket if it does not exist and set objectlocking if enabled (NOTE: versioning will be not changed if OBJECTLOCKING is set because it enables versioning to the Buckets created) +if ! checkBucketExists $BUCKET ; then + if [ ! -z $OBJECTLOCKING ] ; then + if [ $OBJECTLOCKING = true ] ; then + echo "Creating bucket with OBJECTLOCKING '$BUCKET'" + ${MC} mb --with-lock myminio/$BUCKET + elif [ $OBJECTLOCKING = false ] ; then + echo "Creating bucket '$BUCKET'" + ${MC} mb myminio/$BUCKET + fi + elif [ -z $OBJECTLOCKING ] ; then + echo "Creating bucket '$BUCKET'" + ${MC} mb myminio/$BUCKET + else + echo "Bucket '$BUCKET' already exists." + fi + fi + + + # set versioning for bucket if objectlocking is disabled or not set + if [ -z $OBJECTLOCKING ] ; then + if [ ! -z $VERSIONING ] ; then + if [ $VERSIONING = true ] ; then + echo "Enabling versioning for '$BUCKET'" + ${MC} version enable myminio/$BUCKET + elif [ $VERSIONING = false ] ; then + echo "Suspending versioning for '$BUCKET'" + ${MC} version suspend myminio/$BUCKET + fi + fi + else + echo "Bucket '$BUCKET' versioning unchanged." + fi + + + # At this point, the bucket should exist, skip checking for existence + # Set policy on the bucket + echo "Setting policy of bucket '$BUCKET' to '$POLICY'." + if [ $POLICY != "custom" ]; then + ${MC} anonymous set $POLICY myminio/$BUCKET + else + ${MC} anonymous set-json /config/bucket_policy_$BUCKET.json myminio/$BUCKET + fi +} + +# Try connecting to MinIO instance +{{- if .Values.tls.enabled }} +scheme=https +{{- else }} +scheme=http +{{- end }} +connectToMinio $scheme + +{{ if .Values.buckets }} +{{ $global := . }} +# Create the buckets +{{- range .Values.buckets }} +createBucket {{ tpl .name $global }} {{ .policy | default "none" | quote }} {{ .purge | default false }} {{ .versioning | default false }} {{ .objectlocking | default false }} +{{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/_helper_create_policy.txt b/charts/arcadia/charts/minio/templates/_helper_create_policy.txt new file mode 100644 index 000000000..d565b161e --- /dev/null +++ b/charts/arcadia/charts/minio/templates/_helper_create_policy.txt @@ -0,0 +1,75 @@ +#!/bin/sh +set -e ; # Have script exit in the event of a failed command. + +{{- if .Values.configPathmc }} +MC_CONFIG_DIR="{{ .Values.configPathmc }}" +MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" +{{- else }} +MC="/usr/bin/mc --insecure" +{{- end }} + +# connectToMinio +# Use a check-sleep-check loop to wait for MinIO service to be available +connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 +} + +# checkPolicyExists ($policy) +# Check if the policy exists, by using the exit code of `mc admin policy info` +checkPolicyExists() { + POLICY=$1 + CMD=$(${MC} admin policy info myminio $POLICY > /dev/null 2>&1) + return $? +} + +# createPolicy($name, $filename) +createPolicy () { + NAME=$1 + FILENAME=$2 + + # Create the name if it does not exist + echo "Checking policy: $NAME (in /config/$FILENAME.json)" + if ! checkPolicyExists $NAME ; then + echo "Creating policy '$NAME'" + else + echo "Policy '$NAME' already exists." + fi + ${MC} admin policy add myminio $NAME /config/$FILENAME.json + +} + +# Try connecting to MinIO instance +{{- if .Values.tls.enabled }} +scheme=https +{{- else }} +scheme=http +{{- end }} +connectToMinio $scheme + +{{ if .Values.policies }} +# Create the policies +{{- range $idx, $policy := .Values.policies }} +createPolicy {{ $policy.name }} policy_{{ $idx }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/arcadia/charts/minio/templates/_helper_create_svcacct.txt b/charts/arcadia/charts/minio/templates/_helper_create_svcacct.txt new file mode 100644 index 000000000..59f51b177 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/_helper_create_svcacct.txt @@ -0,0 +1,106 @@ +#!/bin/sh +set -e ; # Have script exit in the event of a failed command. + +{{- if .Values.configPathmc }} +MC_CONFIG_DIR="{{ .Values.configPathmc }}" +MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" +{{- else }} +MC="/usr/bin/mc --insecure" +{{- end }} + +# AccessKey and secretkey credentials file are added to prevent shell execution errors caused by special characters. +# Special characters for example : ',",<,>,{,} +MINIO_ACCESSKEY_SECRETKEY_TMP="/tmp/accessKey_and_secretKey_svcacct_tmp" + +# connectToMinio +# Use a check-sleep-check loop to wait for MinIO service to be available +connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 2 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 +} + +# checkSvcacctExists () +# Check if the svcacct exists, by using the exit code of `mc admin user svcacct info` +checkSvcacctExists() { + CMD=$(${MC} admin user svcacct info myminio $(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) > /dev/null 2>&1) + return $? +} + +# createSvcacct ($user) +createSvcacct () { + USER=$1 + FILENAME=$2 + #check accessKey_and_secretKey_tmp file + if [[ ! -f $MINIO_ACCESSKEY_SECRETKEY_TMP ]];then + echo "credentials file does not exist" + return 1 + fi + if [[ $(cat $MINIO_ACCESSKEY_SECRETKEY_TMP|wc -l) -ne 2 ]];then + echo "credentials file is invalid" + rm -f $MINIO_ACCESSKEY_SECRETKEY_TMP + return 1 + fi + SVCACCT=$(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) + # Create the svcacct if it does not exist + if ! checkSvcacctExists ; then + echo "Creating svcacct '$SVCACCT'" + # Check if policy file is define + if [ -z $FILENAME ]; then + ${MC} admin user svcacct add --access-key $(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) --secret-key $(tail -n1 $MINIO_ACCESSKEY_SECRETKEY_TMP) myminio $USER + else + ${MC} admin user svcacct add --access-key $(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) --secret-key $(tail -n1 $MINIO_ACCESSKEY_SECRETKEY_TMP) --policy /config/$FILENAME.json myminio $USER + fi + else + echo "Svcacct '$SVCACCT' already exists." + fi + #clean up credentials files. + rm -f $MINIO_ACCESSKEY_SECRETKEY_TMP +} + +# Try connecting to MinIO instance +{{- if .Values.tls.enabled }} +scheme=https +{{- else }} +scheme=http +{{- end }} +connectToMinio $scheme + +{{ if .Values.svcaccts }} +{{ $global := . }} +# Create the svcaccts +{{- range $idx, $svc := .Values.svcaccts }} +echo {{ tpl .accessKey $global }} > $MINIO_ACCESSKEY_SECRETKEY_TMP +{{- if .existingSecret }} +cat /config/secrets-svc/{{ tpl .existingSecret $global }}/{{ tpl .existingSecretKey $global }} >> $MINIO_ACCESSKEY_SECRETKEY_TMP +# Add a new line if it doesn't exist +sed -i '$a\' $MINIO_ACCESSKEY_SECRETKEY_TMP +{{ else }} +echo {{ .secretKey }} >> $MINIO_ACCESSKEY_SECRETKEY_TMP +{{- end }} +{{- if $svc.policy}} +createSvcacct {{ .user }} svc_policy_{{ $idx }} +{{ else }} +createSvcacct {{ .user }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/_helper_create_user.txt b/charts/arcadia/charts/minio/templates/_helper_create_user.txt new file mode 100644 index 000000000..324bc9d48 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/_helper_create_user.txt @@ -0,0 +1,105 @@ +#!/bin/sh +set -e ; # Have script exit in the event of a failed command. + +{{- if .Values.configPathmc }} +MC_CONFIG_DIR="{{ .Values.configPathmc }}" +MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" +{{- else }} +MC="/usr/bin/mc --insecure" +{{- end }} + +# AccessKey and secretkey credentials file are added to prevent shell execution errors caused by special characters. +# Special characters for example : ',",<,>,{,} +MINIO_ACCESSKEY_SECRETKEY_TMP="/tmp/accessKey_and_secretKey_tmp" + +# connectToMinio +# Use a check-sleep-check loop to wait for MinIO service to be available +connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 +} + +# checkUserExists () +# Check if the user exists, by using the exit code of `mc admin user info` +checkUserExists() { + CMD=$(${MC} admin user info myminio $(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) > /dev/null 2>&1) + return $? +} + +# createUser ($policy) +createUser() { + POLICY=$1 + #check accessKey_and_secretKey_tmp file + if [[ ! -f $MINIO_ACCESSKEY_SECRETKEY_TMP ]];then + echo "credentials file does not exist" + return 1 + fi + if [[ $(cat $MINIO_ACCESSKEY_SECRETKEY_TMP|wc -l) -ne 2 ]];then + echo "credentials file is invalid" + rm -f $MINIO_ACCESSKEY_SECRETKEY_TMP + return 1 + fi + USER=$(head -1 $MINIO_ACCESSKEY_SECRETKEY_TMP) + # Create the user if it does not exist + if ! checkUserExists ; then + echo "Creating user '$USER'" + cat $MINIO_ACCESSKEY_SECRETKEY_TMP | ${MC} admin user add myminio + else + echo "User '$USER' already exists." + fi + #clean up credentials files. + rm -f $MINIO_ACCESSKEY_SECRETKEY_TMP + + # set policy for user + if [ ! -z $POLICY -a $POLICY != " " ] ; then + echo "Adding policy '$POLICY' for '$USER'" + ${MC} admin policy set myminio $POLICY user=$USER + else + echo "User '$USER' has no policy attached." + fi +} + +# Try connecting to MinIO instance +{{- if .Values.tls.enabled }} +scheme=https +{{- else }} +scheme=http +{{- end }} +connectToMinio $scheme + +{{ if .Values.users }} +{{ $global := . }} +# Create the users +{{- range .Values.users }} +echo {{ tpl .accessKey $global }} > $MINIO_ACCESSKEY_SECRETKEY_TMP +{{- if .existingSecret }} +cat /config/secrets/{{ tpl .existingSecret $global }}/{{ tpl .existingSecretKey $global }} >> $MINIO_ACCESSKEY_SECRETKEY_TMP +# Add a new line if it doesn't exist +sed -i '$a\' $MINIO_ACCESSKEY_SECRETKEY_TMP +createUser {{ .policy }} +{{ else }} +echo {{ .secretKey }} >> $MINIO_ACCESSKEY_SECRETKEY_TMP +createUser {{ .policy }} +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/_helper_custom_command.txt b/charts/arcadia/charts/minio/templates/_helper_custom_command.txt new file mode 100644 index 000000000..b583a7782 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/_helper_custom_command.txt @@ -0,0 +1,58 @@ +#!/bin/sh +set -e ; # Have script exit in the event of a failed command. + +{{- if .Values.configPathmc }} +MC_CONFIG_DIR="{{ .Values.configPathmc }}" +MC="/usr/bin/mc --insecure --config-dir ${MC_CONFIG_DIR}" +{{- else }} +MC="/usr/bin/mc --insecure" +{{- end }} + +# connectToMinio +# Use a check-sleep-check loop to wait for MinIO service to be available +connectToMinio() { + SCHEME=$1 + ATTEMPTS=0 ; LIMIT=29 ; # Allow 30 attempts + set -e ; # fail if we can't read the keys. + ACCESS=$(cat /config/rootUser) ; SECRET=$(cat /config/rootPassword) ; + set +e ; # The connections to minio are allowed to fail. + echo "Connecting to MinIO server: $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT" ; + MC_COMMAND="${MC} alias set myminio $SCHEME://$MINIO_ENDPOINT:$MINIO_PORT $ACCESS $SECRET" ; + $MC_COMMAND ; + STATUS=$? ; + until [ $STATUS = 0 ] + do + ATTEMPTS=`expr $ATTEMPTS + 1` ; + echo \"Failed attempts: $ATTEMPTS\" ; + if [ $ATTEMPTS -gt $LIMIT ]; then + exit 1 ; + fi ; + sleep 2 ; # 1 second intervals between attempts + $MC_COMMAND ; + STATUS=$? ; + done ; + set -e ; # reset `e` as active + return 0 +} + +# runCommand ($@) +# Run custom mc command +runCommand() { + ${MC} "$@" + return $? +} + +# Try connecting to MinIO instance +{{- if .Values.tls.enabled }} +scheme=https +{{- else }} +scheme=http +{{- end }} +connectToMinio $scheme + +{{ if .Values.customCommands }} +# Run custom commands +{{- range .Values.customCommands }} +runCommand {{ .command }} +{{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/_helper_policy.tpl b/charts/arcadia/charts/minio/templates/_helper_policy.tpl new file mode 100644 index 000000000..f2150530b --- /dev/null +++ b/charts/arcadia/charts/minio/templates/_helper_policy.tpl @@ -0,0 +1,28 @@ +{{- $statements_length := len .statements -}} +{{- $statements_length := sub $statements_length 1 -}} +{ + "Version": "2012-10-17", + "Statement": [ +{{- range $i, $statement := .statements }} + { + "Effect": "Allow", + "Action": [ +"{{ $statement.actions | join "\",\n\"" }}" + ]{{ if $statement.resources }}, + "Resource": [ +"{{ $statement.resources | join "\",\n\"" }}" + ]{{ end }} +{{- if $statement.conditions }} +{{- $condition_len := len $statement.conditions }} +{{- $condition_len := sub $condition_len 1 }} + , + "Condition": { + {{- range $k,$v := $statement.conditions }} + {{- range $operator,$object := $v }} + "{{ $operator }}": { {{ $object }} }{{- if lt $k $condition_len }},{{- end }} + {{- end }}{{- end }} + }{{- end }} + }{{ if lt $i $statements_length }},{{end }} +{{- end }} + ] +} diff --git a/charts/arcadia/charts/minio/templates/_helpers.tpl b/charts/arcadia/charts/minio/templates/_helpers.tpl new file mode 100644 index 000000000..2fe061d34 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/_helpers.tpl @@ -0,0 +1,218 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "minio.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "minio.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "minio.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for networkpolicy. +*/}} +{{- define "minio.networkPolicy.apiVersion" -}} +{{- if semverCompare ">=1.4-0, <1.7-0" .Capabilities.KubeVersion.Version -}} +{{- print "extensions/v1beta1" -}} +{{- else if semverCompare ">=1.7-0, <1.16-0" .Capabilities.KubeVersion.Version -}} +{{- print "networking.k8s.io/v1beta1" -}} +{{- else if semverCompare "^1.16-0" .Capabilities.KubeVersion.Version -}} +{{- print "networking.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for deployment. +*/}} +{{- define "minio.deployment.apiVersion" -}} +{{- if semverCompare "<1.9-0" .Capabilities.KubeVersion.Version -}} +{{- print "apps/v1beta2" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for statefulset. +*/}} +{{- define "minio.statefulset.apiVersion" -}} +{{- if semverCompare "<1.16-0" .Capabilities.KubeVersion.Version -}} +{{- print "apps/v1beta2" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for ingress. +*/}} +{{- define "minio.ingress.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else if semverCompare "<1.19-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "networking.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for console ingress. +*/}} +{{- define "minio.consoleIngress.apiVersion" -}} +{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else if semverCompare "<1.19-0" .Capabilities.KubeVersion.GitVersion -}} +{{- print "networking.k8s.io/v1beta1" -}} +{{- else -}} +{{- print "networking.k8s.io/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Determine secret name. +*/}} +{{- define "minio.secretName" -}} +{{- if .Values.existingSecret -}} +{{- .Values.existingSecret }} +{{- else -}} +{{- include "minio.fullname" . -}} +{{- end -}} +{{- end -}} + +{{/* +Determine name for scc role and rolebinding +*/}} +{{- define "minio.sccRoleName" -}} +{{- printf "%s-%s" "scc" (include "minio.fullname" .) | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Properly format optional additional arguments to MinIO binary +*/}} +{{- define "minio.extraArgs" -}} +{{- range .Values.extraArgs -}} +{{ " " }}{{ . }} +{{- end -}} +{{- end -}} + +{{/* +Return the proper Docker Image Registry Secret Names +*/}} +{{- define "minio.imagePullSecrets" -}} +{{/* +Helm 2.11 supports the assignment of a value to a variable defined in a different scope, +but Helm 2.9 and 2.10 does not support it, so we need to implement this if-else logic. +Also, we can not use a single if because lazy evaluation is not an option +*/}} +{{- if .Values.global }} +{{- if .Values.global.imagePullSecrets }} +imagePullSecrets: +{{- range .Values.global.imagePullSecrets }} + - name: {{ . }} +{{- end }} +{{- else if .Values.imagePullSecrets }} +imagePullSecrets: + {{ toYaml .Values.imagePullSecrets }} +{{- end -}} +{{- else if .Values.imagePullSecrets }} +imagePullSecrets: + {{ toYaml .Values.imagePullSecrets }} +{{- end -}} +{{- end -}} + +{{/* +Formats volumeMount for MinIO TLS keys and trusted certs +*/}} +{{- define "minio.tlsKeysVolumeMount" -}} +{{- if .Values.tls.enabled }} +- name: cert-secret-volume + mountPath: {{ .Values.certsPath }} +{{- end }} +{{- if or .Values.tls.enabled (ne .Values.trustedCertsSecret "") }} +{{- $casPath := printf "%s/CAs" .Values.certsPath | clean }} +- name: trusted-cert-secret-volume + mountPath: {{ $casPath }} +{{- end }} +{{- end -}} + +{{/* +Formats volume for MinIO TLS keys and trusted certs +*/}} +{{- define "minio.tlsKeysVolume" -}} +{{- if .Values.tls.enabled }} +- name: cert-secret-volume + secret: + secretName: {{ tpl .Values.tls.certSecret $ }} + items: + - key: {{ .Values.tls.publicCrt }} + path: public.crt + - key: {{ .Values.tls.privateKey }} + path: private.key +{{- end }} +{{- if or .Values.tls.enabled (ne .Values.trustedCertsSecret "") }} +{{- $certSecret := eq .Values.trustedCertsSecret "" | ternary .Values.tls.certSecret .Values.trustedCertsSecret }} +{{- $publicCrt := eq .Values.trustedCertsSecret "" | ternary .Values.tls.publicCrt "" }} +- name: trusted-cert-secret-volume + secret: + secretName: {{ $certSecret }} + {{- if ne $publicCrt "" }} + items: + - key: {{ $publicCrt }} + path: public.crt + {{- end }} +{{- end }} +{{- end -}} + +{{/* +Returns the available value for certain key in an existing secret (if it exists), +otherwise it generates a random value. +*/}} +{{- define "minio.getValueFromSecret" }} + {{- $len := (default 16 .Length) | int -}} + {{- $obj := (lookup "v1" "Secret" .Namespace .Name).data -}} + {{- if $obj }} + {{- index $obj .Key | b64dec -}} + {{- else -}} + {{- randAlphaNum $len -}} + {{- end -}} +{{- end }} + +{{- define "minio.root.username" -}} + {{- if .Values.rootUser }} + {{- .Values.rootUser | toString }} + {{- else }} + {{- include "minio.getValueFromSecret" (dict "Namespace" .Release.Namespace "Name" (include "minio.fullname" .) "Length" 20 "Key" "rootUser") }} + {{- end }} +{{- end -}} + +{{- define "minio.root.password" -}} + {{- if .Values.rootPassword }} + {{- .Values.rootPassword | toString }} + {{- else }} + {{- include "minio.getValueFromSecret" (dict "Namespace" .Release.Namespace "Name" (include "minio.fullname" .) "Length" 40 "Key" "rootPassword") }} + {{- end }} +{{- end -}} diff --git a/charts/arcadia/charts/minio/templates/configmap.yaml b/charts/arcadia/charts/minio/templates/configmap.yaml new file mode 100644 index 000000000..0c70b290c --- /dev/null +++ b/charts/arcadia/charts/minio/templates/configmap.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "minio.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +data: + initialize: |- +{{ include (print $.Template.BasePath "/_helper_create_bucket.txt") . | indent 4 }} + add-user: |- +{{ include (print $.Template.BasePath "/_helper_create_user.txt") . | indent 4 }} + add-policy: |- +{{ include (print $.Template.BasePath "/_helper_create_policy.txt") . | indent 4 }} +{{- range $idx, $policy := .Values.policies }} + # Policy: {{ $policy.name }} + policy_{{ $idx }}.json: |- +{{ include (print $.Template.BasePath "/_helper_policy.tpl") . | indent 4 }} +{{ end }} +{{- range $idx, $policy := .Values.buckets }} + # BucketPolicy: {{ $policy.name }} + bucket_policy_{{ $policy.name }}.json: |- +{{ $policy.customPolicy | toJson | indent 4 }} +{{ end }} +{{- range $idx, $svc := .Values.svcaccts }} +{{- if $svc.policy }} + # SVC: {{ $svc.accessKey }} + svc_policy_{{ $idx }}.json: |- +{{ include (print $.Template.BasePath "/_helper_policy.tpl") .policy | indent 4 }} +{{- end }} +{{ end }} + add-svcacct: |- +{{ include (print $.Template.BasePath "/_helper_create_svcacct.txt") . | indent 4 }} + custom-command: |- +{{ include (print $.Template.BasePath "/_helper_custom_command.txt") . | indent 4 }} diff --git a/charts/arcadia/charts/minio/templates/console-ingress.yaml b/charts/arcadia/charts/minio/templates/console-ingress.yaml new file mode 100644 index 000000000..2ce9a93bf --- /dev/null +++ b/charts/arcadia/charts/minio/templates/console-ingress.yaml @@ -0,0 +1,58 @@ +{{- if .Values.consoleIngress.enabled -}} +{{- $fullName := printf "%s-console" (include "minio.fullname" .) -}} +{{- $servicePort := .Values.consoleService.port -}} +{{- $ingressPath := .Values.consoleIngress.path -}} +apiVersion: {{ template "minio.consoleIngress.apiVersion" . }} +kind: Ingress +metadata: + name: {{ $fullName }} + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.consoleIngress.labels }} +{{ toYaml . | indent 4 }} +{{- end }} + +{{- with .Values.consoleIngress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.consoleIngress.ingressClassName }} + ingressClassName: {{ .Values.consoleIngress.ingressClassName }} +{{- end }} +{{- if .Values.consoleIngress.tls }} + tls: + {{- range .Values.consoleIngress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.consoleIngress.hosts }} + - http: + paths: + - path: {{ $ingressPath }} + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + pathType: Prefix + backend: + service: + name: {{ $fullName }} + port: + number: {{ $servicePort }} + {{- else }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $servicePort }} + {{- end }} + {{- if . }} + host: {{ . | quote }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/console-service.yaml b/charts/arcadia/charts/minio/templates/console-service.yaml new file mode 100644 index 000000000..46da35974 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/console-service.yaml @@ -0,0 +1,48 @@ +{{ $scheme := "http" }} +{{- if .Values.tls.enabled }} +{{ $scheme = "https" }} +{{ end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "minio.fullname" . }}-console + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.consoleService.annotations }} + annotations: +{{ toYaml .Values.consoleService.annotations | indent 4 }} +{{- end }} +spec: +{{- if (or (eq .Values.consoleService.type "ClusterIP" "") (empty .Values.consoleService.type)) }} + type: ClusterIP + {{- if not (empty .Values.consoleService.clusterIP) }} + clusterIP: {{ .Values.consoleService.clusterIP }} + {{end}} +{{- else if eq .Values.consoleService.type "LoadBalancer" }} + type: {{ .Values.consoleService.type }} + loadBalancerIP: {{ default "" .Values.consoleService.loadBalancerIP }} +{{- else }} + type: {{ .Values.consoleService.type }} +{{- end }} + ports: + - name: {{ $scheme }} + port: {{ .Values.consoleService.port }} + protocol: TCP +{{- if (and (eq .Values.consoleService.type "NodePort") ( .Values.consoleService.nodePort)) }} + nodePort: {{ .Values.consoleService.nodePort }} +{{- else }} + targetPort: {{ .Values.minioConsolePort }} +{{- end}} +{{- if .Values.consoleService.externalIPs }} + externalIPs: +{{- range $i , $ip := .Values.consoleService.externalIPs }} + - {{ $ip }} +{{- end }} +{{- end }} + selector: + app: {{ template "minio.name" . }} + release: {{ .Release.Name }} diff --git a/charts/arcadia/charts/minio/templates/deployment.yaml b/charts/arcadia/charts/minio/templates/deployment.yaml new file mode 100644 index 000000000..ad92c892b --- /dev/null +++ b/charts/arcadia/charts/minio/templates/deployment.yaml @@ -0,0 +1,206 @@ +{{- if eq .Values.mode "standalone" }} +{{ $scheme := "http" }} +{{- if .Values.tls.enabled }} +{{ $scheme = "https" }} +{{ end }} +{{ $bucketRoot := or ($.Values.bucketRoot) ($.Values.mountPath) }} +apiVersion: {{ template "minio.deployment.apiVersion" . }} +kind: Deployment +metadata: + name: {{ template "minio.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.additionalLabels }} +{{ toYaml .Values.additionalLabels | trimSuffix "\n" | indent 4 }} +{{- end }} +{{- if .Values.additionalAnnotations }} + annotations: +{{ toYaml .Values.additionalAnnotations | trimSuffix "\n" | indent 4 }} +{{- end }} +spec: + strategy: + type: {{ .Values.DeploymentUpdate.type }} + {{- if eq .Values.DeploymentUpdate.type "RollingUpdate" }} + rollingUpdate: + maxSurge: {{ .Values.DeploymentUpdate.maxSurge }} + maxUnavailable: {{ .Values.DeploymentUpdate.maxUnavailable }} + {{- end}} + replicas: 1 + selector: + matchLabels: + app: {{ template "minio.name" . }} + release: {{ .Release.Name }} + template: + metadata: + name: {{ template "minio.fullname" . }} + labels: + app: {{ template "minio.name" . }} + release: {{ .Release.Name }} +{{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} +{{- end }} + annotations: +{{- if not .Values.ignoreChartChecksums }} + checksum/secrets: {{ include (print $.Template.BasePath "/secrets.yaml") . | sha256sum }} + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | trimSuffix "\n" | indent 8 }} +{{- end }} + spec: + {{- if .Values.priorityClassName }} + priorityClassName: "{{ .Values.priorityClassName }}" + {{- end }} + {{- if .Values.runtimeClassName }} + runtimeClassName: "{{ .Values.runtimeClassName }}" + {{- end }} +{{- if and .Values.securityContext.enabled .Values.persistence.enabled }} + securityContext: + runAsUser: {{ .Values.securityContext.runAsUser }} + runAsGroup: {{ .Values.securityContext.runAsGroup }} + fsGroup: {{ .Values.securityContext.fsGroup }} + {{- if and (ge .Capabilities.KubeVersion.Major "1") (ge .Capabilities.KubeVersion.Minor "20") }} + fsGroupChangePolicy: {{ .Values.securityContext.fsGroupChangePolicy }} + {{- end }} +{{- end }} +{{ if .Values.serviceAccount.create }} + serviceAccountName: {{ .Values.serviceAccount.name }} +{{- end }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - "/bin/sh" + - "-ce" + - "/usr/bin/docker-entrypoint.sh minio server {{ $bucketRoot }} -S {{ .Values.certsPath }} --address :{{ .Values.minioAPIPort }} --console-address :{{ .Values.minioConsolePort }} {{- template "minio.extraArgs" . }}" + volumeMounts: + - name: minio-user + mountPath: "/tmp/credentials" + readOnly: true + - name: export + mountPath: {{ .Values.mountPath }} + {{- if and .Values.persistence.enabled .Values.persistence.subPath }} + subPath: "{{ .Values.persistence.subPath }}" + {{- end }} + {{- if .Values.extraSecret }} + - name: extra-secret + mountPath: "/tmp/minio-config-env" + {{- end }} + {{- include "minio.tlsKeysVolumeMount" . | indent 12 }} + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} + ports: + - name: {{ $scheme }} + containerPort: {{ .Values.minioAPIPort }} + - name: {{ $scheme }}-console + containerPort: {{ .Values.minioConsolePort }} + env: + - name: MINIO_ROOT_USER + valueFrom: + secretKeyRef: + name: {{ template "minio.secretName" . }} + key: rootUser + - name: MINIO_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "minio.secretName" . }} + key: rootPassword + {{- if .Values.extraSecret }} + - name: MINIO_CONFIG_ENV_FILE + value: "/tmp/minio-config-env/config.env" + {{- end}} + {{- if .Values.metrics.serviceMonitor.public }} + - name: MINIO_PROMETHEUS_AUTH_TYPE + value: "public" + {{- end}} + {{- if .Values.oidc.enabled }} + - name: MINIO_IDENTITY_OPENID_CONFIG_URL + value: {{ .Values.oidc.configUrl }} + - name: MINIO_IDENTITY_OPENID_CLIENT_ID + value: {{ .Values.oidc.clientId }} + - name: MINIO_IDENTITY_OPENID_CLIENT_SECRET + value: {{ .Values.oidc.clientSecret }} + - name: MINIO_IDENTITY_OPENID_CLAIM_NAME + value: {{ .Values.oidc.claimName }} + - name: MINIO_IDENTITY_OPENID_CLAIM_PREFIX + value: {{ .Values.oidc.claimPrefix }} + - name: MINIO_IDENTITY_OPENID_SCOPES + value: {{ .Values.oidc.scopes }} + - name: MINIO_IDENTITY_OPENID_REDIRECT_URI + value: {{ .Values.oidc.redirectUri }} + - name: MINIO_IDENTITY_OPENID_COMMENT + value: {{ .Values.oidc.comment }} + {{- end}} + {{- if .Values.etcd.endpoints }} + - name: MINIO_ETCD_ENDPOINTS + value: {{ join "," .Values.etcd.endpoints | quote }} + {{- if .Values.etcd.clientCert }} + - name: MINIO_ETCD_CLIENT_CERT + value: "/tmp/credentials/etcd_client_cert.pem" + {{- end }} + {{- if .Values.etcd.clientCertKey }} + - name: MINIO_ETCD_CLIENT_CERT_KEY + value: "/tmp/credentials/etcd_client_cert_key.pem" + {{- end }} + {{- if .Values.etcd.pathPrefix }} + - name: MINIO_ETCD_PATH_PREFIX + value: {{ .Values.etcd.pathPrefix }} + {{- end }} + {{- if .Values.etcd.corednsPathPrefix }} + - name: MINIO_ETCD_COREDNS_PATH + value: {{ .Values.etcd.corednsPathPrefix }} + {{- end }} + {{- end }} + {{- range $key, $val := .Values.environment }} + - name: {{ $key }} + value: {{ $val | quote }} + {{- end}} + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.extraContainers }} + {{- if eq (typeOf .) "string" }} + {{- tpl . $ | nindent 8 }} + {{- else }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} +{{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} +{{- end }} +{{- include "minio.imagePullSecrets" . | indent 6 }} +{{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} +{{- end }} +{{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} +{{- end }} + volumes: + - name: export + {{- if .Values.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.persistence.existingClaim | default (include "minio.fullname" .) }} + {{- else }} + emptyDir: {} + {{- end }} + {{- if .Values.extraSecret }} + - name: extra-secret + secret: + secretName: {{ .Values.extraSecret }} + {{- end }} + - name: minio-user + secret: + secretName: {{ template "minio.secretName" . }} + {{- include "minio.tlsKeysVolume" . | indent 8 }} + {{- if .Values.extraVolumes }} + {{ toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/ingress.yaml b/charts/arcadia/charts/minio/templates/ingress.yaml new file mode 100644 index 000000000..8d9a837dc --- /dev/null +++ b/charts/arcadia/charts/minio/templates/ingress.yaml @@ -0,0 +1,58 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "minio.fullname" . -}} +{{- $servicePort := .Values.service.port -}} +{{- $ingressPath := .Values.ingress.path -}} +apiVersion: {{ template "minio.ingress.apiVersion" . }} +kind: Ingress +metadata: + name: {{ $fullName }} + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- with .Values.ingress.labels }} +{{ toYaml . | indent 4 }} +{{- end }} + +{{- with .Values.ingress.annotations }} + annotations: +{{ toYaml . | indent 4 }} +{{- end }} +spec: +{{- if .Values.ingress.ingressClassName }} + ingressClassName: {{ .Values.ingress.ingressClassName }} +{{- end }} +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.ingress.hosts }} + - http: + paths: + - path: {{ $ingressPath }} + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + pathType: Prefix + backend: + service: + name: {{ $fullName }} + port: + number: {{ $servicePort }} + {{- else }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $servicePort }} + {{- end }} + {{- if . }} + host: {{ . | quote }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/networkpolicy.yaml b/charts/arcadia/charts/minio/templates/networkpolicy.yaml new file mode 100644 index 000000000..ac219b937 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/networkpolicy.yaml @@ -0,0 +1,27 @@ +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: {{ template "minio.networkPolicy.apiVersion" . }} +metadata: + name: {{ template "minio.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + podSelector: + matchLabels: + app: {{ template "minio.name" . }} + release: {{ .Release.Name }} + ingress: + - ports: + - port: {{ .Values.minioAPIPort }} + - port: {{ .Values.minioConsolePort }} + {{- if not .Values.networkPolicy.allowExternal }} + from: + - podSelector: + matchLabels: + {{ template "minio.name" . }}-client: "true" + {{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/poddisruptionbudget.yaml b/charts/arcadia/charts/minio/templates/poddisruptionbudget.yaml new file mode 100644 index 000000000..41c649aa2 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/poddisruptionbudget.yaml @@ -0,0 +1,18 @@ +{{- if .Values.podDisruptionBudget.enabled }} +{{- if .Capabilities.APIVersions.Has "policy/v1beta1/PodDisruptionBudget" }} +apiVersion: policy/v1beta1 +{{- else }} +apiVersion: policy/v1 +{{- end }} +kind: PodDisruptionBudget +metadata: + name: minio + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }} +spec: + maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} + selector: + matchLabels: + app: {{ template "minio.name" . }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/post-job.yaml b/charts/arcadia/charts/minio/templates/post-job.yaml new file mode 100644 index 000000000..ebdc85276 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/post-job.yaml @@ -0,0 +1,273 @@ +{{- if or .Values.buckets .Values.users .Values.policies .Values.customCommands .Values.svcaccts }} +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ template "minio.fullname" . }}-post-job + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }}-post-job + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation + "helm.sh/hook-weight": "-1" + {{- with .Values.postJob.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + template: + metadata: + labels: + app: {{ template "minio.name" . }}-job + release: {{ .Release.Name }} + {{- if .Values.podLabels }} + {{- toYaml .Values.podLabels | nindent 8 }} + {{- end }} + {{- if .Values.postJob.podAnnotations }} + annotations: + {{- toYaml .Values.postJob.podAnnotations | nindent 8 }} + {{- end }} + spec: + restartPolicy: OnFailure + {{- include "minio.imagePullSecrets" . | nindent 6 }} + {{- if .Values.nodeSelector }} + nodeSelector: + {{- toYaml .Values.postJob.nodeSelector | nindent 8 }} + {{- end }} + {{- with .Values.postJob.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.postJob.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.postJob.securityContext.enabled }} + securityContext: + runAsUser: {{ .Values.postJob.securityContext.runAsUser }} + runAsGroup: {{ .Values.postJob.securityContext.runAsGroup }} + fsGroup: {{ .Values.postJob.securityContext.fsGroup }} + {{- end }} + volumes: + - name: minio-configuration + projected: + sources: + - configMap: + name: {{ template "minio.fullname" . }} + - secret: + name: {{ template "minio.secretName" . }} + {{- range (concat .Values.users (default (list) .Values.svcaccts)) }} + {{- if .existingSecret }} + - secret: + name: {{ tpl .existingSecret $ }} + items: + - key: {{ .existingSecretKey }} + path: secrets/{{ tpl .existingSecret $ }}/{{ tpl .existingSecretKey $ }} + {{- end }} + {{- end }} + {{- range ( default list .Values.svcaccts ) }} + {{- if .existingSecret }} + - secret: + name: {{ tpl .existingSecret $ }} + items: + - key: {{ .existingSecretKey }} + path: secrets-svc/{{ tpl .existingSecret $ }}/{{ tpl .existingSecretKey $ }} + {{- end }} + {{- end }} + {{- if .Values.tls.enabled }} + - name: cert-secret-volume-mc + secret: + secretName: {{ .Values.tls.certSecret }} + items: + - key: {{ .Values.tls.publicCrt }} + path: CAs/public.crt + {{ end }} + containers: + {{- if .Values.buckets }} + - name: minio-make-bucket + image: "{{ .Values.mcImage.repository }}:{{ .Values.mcImage.tag }}" + {{- if .Values.makeBucketJob.securityContext.enabled }} + securityContext: + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + capabilities: + drop: + - ALL + runAsUser: {{ .Values.makeBucketJob.securityContext.runAsUser }} + runAsGroup: {{ .Values.makeBucketJob.securityContext.runAsGroup }} + {{- end }} + imagePullPolicy: {{ .Values.mcImage.pullPolicy }} + {{- if .Values.makeBucketJob.exitCommand }} + command: [ "/bin/sh", "-c" ] + args: [ "/bin/sh /config/initialize; EV=$?; {{ .Values.makeBucketJob.exitCommand }} && exit $EV" ] + {{- else }} + command: [ "/bin/sh", "/config/initialize" ] + {{- end }} + env: + - name: MINIO_ENDPOINT + value: {{ template "minio.fullname" . }} + - name: MINIO_PORT + value: {{ .Values.service.port | quote }} + volumeMounts: + - name: minio-configuration + mountPath: /config + {{- if .Values.tls.enabled }} + - name: cert-secret-volume-mc + mountPath: {{ .Values.configPathmc }}certs + {{ end }} + resources: + {{- toYaml .Values.makeBucketJob.resources | nindent 12 }} + {{- end }} + {{- if .Values.users }} + - name: minio-make-user + image: "{{ .Values.mcImage.repository }}:{{ .Values.mcImage.tag }}" + {{- if .Values.makeUserJob.securityContext.enabled }} + securityContext: + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + capabilities: + drop: + - ALL + runAsUser: {{ .Values.makeUserJob.securityContext.runAsUser }} + runAsGroup: {{ .Values.makeUserJob.securityContext.runAsGroup }} + {{- end }} + imagePullPolicy: {{ .Values.mcImage.pullPolicy }} + {{- if .Values.makeUserJob.exitCommand }} + command: [ "/bin/sh", "-c" ] + args: [ "/bin/sh /config/add-user; EV=$?; {{ .Values.makeUserJob.exitCommand }} && exit $EV" ] + {{- else }} + command: [ "/bin/sh", "/config/add-user" ] + {{- end }} + env: + - name: MINIO_ENDPOINT + value: {{ template "minio.fullname" . }} + - name: MINIO_PORT + value: {{ .Values.service.port | quote }} + volumeMounts: + - name: minio-configuration + mountPath: /config + {{- if .Values.tls.enabled }} + - name: cert-secret-volume-mc + mountPath: {{ .Values.configPathmc }}certs + {{ end }} + resources: + {{- toYaml .Values.makeUserJob.resources | nindent 12 }} + {{- end }} + {{- if .Values.policies }} + - name: minio-make-policy + image: "{{ .Values.mcImage.repository }}:{{ .Values.mcImage.tag }}" + {{- if .Values.makePolicyJob.securityContext.enabled }} + securityContext: + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + capabilities: + drop: + - ALL + runAsUser: {{ .Values.makePolicyJob.securityContext.runAsUser }} + runAsGroup: {{ .Values.makePolicyJob.securityContext.runAsGroup }} + {{- end }} + imagePullPolicy: {{ .Values.mcImage.pullPolicy }} + {{- if .Values.makePolicyJob.exitCommand }} + command: [ "/bin/sh", "-c" ] + args: [ "/bin/sh /config/add-policy; EV=$?; {{ .Values.makePolicyJob.exitCommand }} && exit $EV" ] + {{- else }} + command: [ "/bin/sh", "/config/add-policy" ] + {{- end }} + env: + - name: MINIO_ENDPOINT + value: {{ template "minio.fullname" . }} + - name: MINIO_PORT + value: {{ .Values.service.port | quote }} + volumeMounts: + - name: minio-configuration + mountPath: /config + {{- if .Values.tls.enabled }} + - name: cert-secret-volume-mc + mountPath: {{ .Values.configPathmc }}certs + {{ end }} + resources: + {{- toYaml .Values.makePolicyJob.resources | nindent 12 }} + {{- end }} + {{- if .Values.customCommands }} + - name: minio-custom-command + image: "{{ .Values.mcImage.repository }}:{{ .Values.mcImage.tag }}" + {{- if .Values.customCommandJob.securityContext.enabled }} + securityContext: + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + capabilities: + drop: + - ALL + runAsUser: {{ .Values.customCommandJob.securityContext.runAsUser }} + runAsGroup: {{ .Values.customCommandJob.securityContext.runAsGroup }} + {{- end }} + imagePullPolicy: {{ .Values.mcImage.pullPolicy }} + {{- if .Values.customCommandJob.exitCommand }} + command: [ "/bin/sh", "-c" ] + args: [ "/bin/sh /config/custom-command; EV=$?; {{ .Values.customCommandJob.exitCommand }} && exit $EV" ] + {{- else }} + command: [ "/bin/sh", "/config/custom-command" ] + {{- end }} + env: + - name: MINIO_ENDPOINT + value: {{ template "minio.fullname" . }} + - name: MINIO_PORT + value: {{ .Values.service.port | quote }} + volumeMounts: + - name: minio-configuration + mountPath: /config + {{- if .Values.tls.enabled }} + - name: cert-secret-volume-mc + mountPath: {{ .Values.configPathmc }}certs + {{ end }} + resources: + {{- toYaml .Values.customCommandJob.resources | nindent 12 }} + {{- end }} + {{- if .Values.svcaccts }} + - name: minio-make-svcacct + image: "{{ .Values.mcImage.repository }}:{{ .Values.mcImage.tag }}" + {{- if .Values.makeServiceAccountJob.securityContext.enabled }} + securityContext: + allowPrivilegeEscalation: false + seccompProfile: + type: RuntimeDefault + runAsNonRoot: true + capabilities: + drop: + - ALL + runAsUser: {{ .Values.makeServiceAccountJob.securityContext.runAsUser }} + runAsGroup: {{ .Values.makeServiceAccountJob.securityContext.runAsGroup }} + {{- end }} + imagePullPolicy: {{ .Values.mcImage.pullPolicy }} + {{- if .Values.makeServiceAccountJob.exitCommand }} + command: [ "/bin/sh", "-c" ] + args: ["/bin/sh /config/add-svcacct; EV=$?; {{ .Values.makeServiceAccountJob.exitCommand }} && exit $EV" ] + {{- else }} + command: ["/bin/sh", "/config/add-svcacct"] + {{- end }} + env: + - name: MINIO_ENDPOINT + value: {{ template "minio.fullname" . }} + - name: MINIO_PORT + value: {{ .Values.service.port | quote }} + volumeMounts: + - name: minio-configuration + mountPath: /config + {{- if .Values.tls.enabled }} + - name: cert-secret-volume-mc + mountPath: {{ .Values.configPathmc }}certs + {{ end }} + resources: + {{- toYaml .Values.makeServiceAccountJob.resources | nindent 12 }} + {{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/pvc.yaml b/charts/arcadia/charts/minio/templates/pvc.yaml new file mode 100644 index 000000000..369aade41 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/pvc.yaml @@ -0,0 +1,35 @@ +{{- if eq .Values.mode "standalone" }} +{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ template "minio.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.persistence.annotations }} + annotations: +{{ toYaml .Values.persistence.annotations | trimSuffix "\n" | indent 4 }} +{{- end }} +spec: + accessModes: + - {{ .Values.persistence.accessMode | quote }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + +{{- if .Values.persistence.storageClass }} +{{- if (eq "-" .Values.persistence.storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: "{{ .Values.persistence.storageClass }}" +{{- end }} +{{- end }} +{{- if .Values.persistence.VolumeName }} + volumeName: "{{ .Values.persistence.VolumeName }}" +{{- end }} +{{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/secrets.yaml b/charts/arcadia/charts/minio/templates/secrets.yaml new file mode 100644 index 000000000..da2ecab4a --- /dev/null +++ b/charts/arcadia/charts/minio/templates/secrets.yaml @@ -0,0 +1,22 @@ +{{- if not .Values.existingSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "minio.secretName" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +type: Opaque +data: + rootUser: {{ include "minio.root.username" . | b64enc | quote }} + rootPassword: {{ include "minio.root.password" . | b64enc | quote }} + {{- if .Values.etcd.clientCert }} + etcd_client.crt: {{ .Values.etcd.clientCert | toString | b64enc | quote }} + {{- end }} + {{- if .Values.etcd.clientCertKey }} + etcd_client.key: {{ .Values.etcd.clientCertKey | toString | b64enc | quote }} + {{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/securitycontextconstraints.yaml b/charts/arcadia/charts/minio/templates/securitycontextconstraints.yaml new file mode 100644 index 000000000..4bac7e372 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/securitycontextconstraints.yaml @@ -0,0 +1,45 @@ +{{- if and .Values.securityContext.enabled .Values.persistence.enabled (.Capabilities.APIVersions.Has "security.openshift.io/v1") }} +apiVersion: security.openshift.io/v1 +kind: SecurityContextConstraints +metadata: + name: {{ template "minio.fullname" . }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +allowHostDirVolumePlugin: false +allowHostIPC: false +allowHostNetwork: false +allowHostPID: false +allowHostPorts: false +allowPrivilegeEscalation: true +allowPrivilegedContainer: false +allowedCapabilities: [] +readOnlyRootFilesystem: false +defaultAddCapabilities: [] +requiredDropCapabilities: +- KILL +- MKNOD +- SETUID +- SETGID +fsGroup: + type: MustRunAs + ranges: + - max: {{ .Values.securityContext.fsGroup }} + min: {{ .Values.securityContext.fsGroup }} +runAsUser: + type: MustRunAs + uid: {{ .Values.securityContext.runAsUser }} +seLinuxContext: + type: MustRunAs +supplementalGroups: + type: RunAsAny +volumes: +- configMap +- downwardAPI +- emptyDir +- persistentVolumeClaim +- projected +- secret +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/service.yaml b/charts/arcadia/charts/minio/templates/service.yaml new file mode 100644 index 000000000..741528df4 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/service.yaml @@ -0,0 +1,49 @@ +{{ $scheme := "http" }} +{{- if .Values.tls.enabled }} +{{ $scheme = "https" }} +{{ end }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "minio.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + monitoring: "true" +{{- if .Values.service.annotations }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end }} +spec: +{{- if (or (eq .Values.service.type "ClusterIP" "") (empty .Values.service.type)) }} + type: ClusterIP + {{- if not (empty .Values.service.clusterIP) }} + clusterIP: {{ .Values.service.clusterIP }} + {{end}} +{{- else if eq .Values.service.type "LoadBalancer" }} + type: {{ .Values.service.type }} + loadBalancerIP: {{ default "" .Values.service.loadBalancerIP }} +{{- else }} + type: {{ .Values.service.type }} +{{- end }} + ports: + - name: {{ $scheme }} + port: {{ .Values.service.port }} + protocol: TCP +{{- if (and (eq .Values.service.type "NodePort") ( .Values.service.nodePort)) }} + nodePort: {{ .Values.service.nodePort }} +{{- else }} + targetPort: {{ .Values.minioAPIPort }} +{{- end}} +{{- if .Values.service.externalIPs }} + externalIPs: +{{- range $i , $ip := .Values.service.externalIPs }} + - {{ $ip }} +{{- end }} +{{- end }} + selector: + app: {{ template "minio.name" . }} + release: {{ .Release.Name }} diff --git a/charts/arcadia/charts/minio/templates/serviceaccount.yaml b/charts/arcadia/charts/minio/templates/serviceaccount.yaml new file mode 100644 index 000000000..6a4bd94b3 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/serviceaccount.yaml @@ -0,0 +1,7 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ .Values.serviceAccount.name | quote }} + namespace: {{ .Release.Namespace | quote }} +{{- end -}} diff --git a/charts/arcadia/charts/minio/templates/servicemonitor.yaml b/charts/arcadia/charts/minio/templates/servicemonitor.yaml new file mode 100644 index 000000000..955273b52 --- /dev/null +++ b/charts/arcadia/charts/minio/templates/servicemonitor.yaml @@ -0,0 +1,117 @@ +{{- if and .Values.metrics.serviceMonitor.enabled .Values.metrics.serviceMonitor.includeNode}} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ template "minio.fullname" . }} + {{- if .Values.metrics.serviceMonitor.namespace }} + namespace: {{ .Values.metrics.serviceMonitor.namespace }} + {{ else }} + namespace: {{ .Release.Namespace | quote }} + {{- end }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + {{- if .Values.metrics.serviceMonitor.additionalLabels }} +{{ toYaml .Values.metrics.serviceMonitor.additionalLabels | indent 4 }} + {{- end }} +{{- if .Values.metrics.serviceMonitor.annotations }} + annotations: +{{ toYaml .Values.metrics.serviceMonitor.annotations | trimSuffix "\n" | indent 4 }} +{{- end }} +spec: + endpoints: + {{- if .Values.tls.enabled }} + - port: https + scheme: https + tlsConfig: + ca: + secret: + name: {{ .Values.tls.certSecret }} + key: {{ .Values.tls.publicCrt }} + serverName: {{ template "minio.fullname" . }} + {{ else }} + - port: http + scheme: http + {{- end }} + path: /minio/v2/metrics/node + {{- if .Values.metrics.serviceMonitor.interval }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.relabelConfigs }} +{{ toYaml .Values.metrics.serviceMonitor.relabelConfigs | indent 6 }} + {{- end }} + {{- if not .Values.metrics.serviceMonitor.public }} + bearerTokenSecret: + name: {{ template "minio.fullname" . }}-prometheus + key: token + {{- end }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace | quote }} + selector: + matchLabels: + app: {{ include "minio.name" . }} + release: {{ .Release.Name }} + monitoring: "true" +{{- end }} +{{- if .Values.metrics.serviceMonitor.enabled }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: Probe +metadata: + name: {{ template "minio.fullname" . }}-cluster + {{- if .Values.metrics.serviceMonitor.namespace }} + namespace: {{ .Values.metrics.serviceMonitor.namespace }} + {{ else }} + namespace: {{ .Release.Namespace | quote }} + {{- end }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + {{- if .Values.metrics.serviceMonitor.additionalLabels }} +{{ toYaml .Values.metrics.serviceMonitor.additionalLabels | indent 4 }} + {{- end }} +spec: + jobName: {{ template "minio.fullname" . }} + {{- if .Values.tls.enabled }} + tlsConfig: + ca: + secret: + name: {{ .Values.tls.certSecret }} + key: {{ .Values.tls.publicCrt }} + serverName: {{ template "minio.fullname" . }} + {{- end }} + prober: + url: {{ template "minio.fullname" . }}.{{ .Release.Namespace }}:{{ .Values.service.port }} + path: /minio/v2/metrics/cluster + {{- if .Values.tls.enabled }} + scheme: https + {{ else }} + scheme: http + {{- end }} + {{- if .Values.metrics.serviceMonitor.relabelConfigsCluster }} +{{ toYaml .Values.metrics.serviceMonitor.relabelConfigsCluster | indent 2 }} + {{- end }} + targets: + staticConfig: + static: + - {{ template "minio.fullname" . }}.{{ .Release.Namespace }} + {{- if not .Values.metrics.serviceMonitor.public }} + {{- if .Values.metrics.serviceMonitor.interval }} + interval: {{ .Values.metrics.serviceMonitor.interval }} + {{- end }} + {{- if .Values.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }} + {{- end }} + bearerTokenSecret: + name: {{ template "minio.fullname" . }}-prometheus + key: token + {{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/templates/statefulset.yaml b/charts/arcadia/charts/minio/templates/statefulset.yaml new file mode 100644 index 000000000..ba7c3021a --- /dev/null +++ b/charts/arcadia/charts/minio/templates/statefulset.yaml @@ -0,0 +1,259 @@ +{{- if eq .Values.mode "distributed" }} +{{ $poolCount := .Values.pools | int }} +{{ $nodeCount := .Values.replicas | int }} +{{ $replicas := mul $poolCount $nodeCount }} +{{ $drivesPerNode := .Values.drivesPerNode | int }} +{{ $scheme := "http" }} +{{- if .Values.tls.enabled }} +{{ $scheme = "https" }} +{{ end }} +{{ $mountPath := .Values.mountPath }} +{{ $bucketRoot := or ($.Values.bucketRoot) ($.Values.mountPath) }} +{{ $subPath := .Values.persistence.subPath }} +{{ $penabled := .Values.persistence.enabled }} +{{ $accessMode := .Values.persistence.accessMode }} +{{ $storageClass := .Values.persistence.storageClass }} +{{ $psize := .Values.persistence.size }} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "minio.fullname" . }}-svc + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +spec: + publishNotReadyAddresses: true + clusterIP: None + ports: + - name: {{ $scheme }} + port: {{ .Values.service.port }} + protocol: TCP + targetPort: {{ .Values.minioAPIPort }} + selector: + app: {{ template "minio.name" . }} + release: {{ .Release.Name }} +--- +apiVersion: {{ template "minio.statefulset.apiVersion" . }} +kind: StatefulSet +metadata: + name: {{ template "minio.fullname" . }} + namespace: {{ .Release.Namespace | quote }} + labels: + app: {{ template "minio.name" . }} + chart: {{ template "minio.chart" . }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.additionalLabels }} +{{ toYaml .Values.additionalLabels | trimSuffix "\n" | indent 4 }} +{{- end }} +{{- if .Values.additionalAnnotations }} + annotations: +{{ toYaml .Values.additionalAnnotations | trimSuffix "\n" | indent 4 }} +{{- end }} +spec: + updateStrategy: + type: {{ .Values.StatefulSetUpdate.updateStrategy }} + podManagementPolicy: "Parallel" + serviceName: {{ template "minio.fullname" . }}-svc + replicas: {{ $replicas }} + selector: + matchLabels: + app: {{ template "minio.name" . }} + release: {{ .Release.Name }} + template: + metadata: + name: {{ template "minio.fullname" . }} + labels: + app: {{ template "minio.name" . }} + release: {{ .Release.Name }} +{{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} +{{- end }} + annotations: +{{- if not .Values.ignoreChartChecksums }} + checksum/secrets: {{ include (print $.Template.BasePath "/secrets.yaml") . | sha256sum }} + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} +{{- end }} +{{- if .Values.podAnnotations }} +{{ toYaml .Values.podAnnotations | trimSuffix "\n" | indent 8 }} +{{- end }} + spec: + {{- if .Values.priorityClassName }} + priorityClassName: "{{ .Values.priorityClassName }}" + {{- end }} + {{- if .Values.runtimeClassName }} + runtimeClassName: "{{ .Values.runtimeClassName }}" + {{- end }} +{{- if and .Values.securityContext.enabled .Values.persistence.enabled }} + securityContext: + runAsUser: {{ .Values.securityContext.runAsUser }} + runAsGroup: {{ .Values.securityContext.runAsGroup }} + fsGroup: {{ .Values.securityContext.fsGroup }} + {{- if and (ge .Capabilities.KubeVersion.Major "1") (ge .Capabilities.KubeVersion.Minor "20") }} + fsGroupChangePolicy: {{ .Values.securityContext.fsGroupChangePolicy }} + {{- end }} +{{- end }} +{{ if .Values.serviceAccount.create }} + serviceAccountName: {{ .Values.serviceAccount.name }} +{{- end }} + containers: + - name: {{ .Chart.Name }} + image: {{ .Values.image.repository }}:{{ .Values.image.tag }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + + command: [ "/bin/sh", + "-ce", + "/usr/bin/docker-entrypoint.sh minio server {{- range $i := until $poolCount }}{{ $factor := mul $i $nodeCount }}{{ $endIndex := add $factor $nodeCount }}{{ $beginIndex := mul $i $nodeCount }} {{ $scheme }}://{{ template `minio.fullname` $ }}-{{ `{` }}{{ $beginIndex }}...{{ sub $endIndex 1 }}{{ `}`}}.{{ template `minio.fullname` $ }}-svc.{{ $.Release.Namespace }}.svc.{{ $.Values.clusterDomain }}{{if (gt $drivesPerNode 1)}}{{ $bucketRoot }}-{{ `{` }}0...{{ sub $drivesPerNode 1 }}{{ `}` }}{{else}}{{ $bucketRoot }}{{end}}{{- end}} -S {{ .Values.certsPath }} --address :{{ .Values.minioAPIPort }} --console-address :{{ .Values.minioConsolePort }} {{- template `minio.extraArgs` . }}" ] + volumeMounts: + {{- if $penabled }} + {{- if (gt $drivesPerNode 1) }} + {{- range $i := until $drivesPerNode }} + - name: export-{{ $i }} + mountPath: {{ $mountPath }}-{{ $i }} + {{- if and $penabled $subPath }} + subPath: {{ $subPath }} + {{- end }} + {{- end }} + {{- else }} + - name: export + mountPath: {{ $mountPath }} + {{- if and $penabled $subPath }} + subPath: {{ $subPath }} + {{- end }} + {{- end }} + {{- end }} + {{- if .Values.extraSecret }} + - name: extra-secret + mountPath: "/tmp/minio-config-env" + {{- end }} + {{- include "minio.tlsKeysVolumeMount" . | indent 12 }} + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} + ports: + - name: {{ $scheme }} + containerPort: {{ .Values.minioAPIPort }} + - name: {{ $scheme }}-console + containerPort: {{ .Values.minioConsolePort }} + env: + - name: MINIO_ROOT_USER + valueFrom: + secretKeyRef: + name: {{ template "minio.secretName" . }} + key: rootUser + - name: MINIO_ROOT_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "minio.secretName" . }} + key: rootPassword + {{- if .Values.extraSecret }} + - name: MINIO_CONFIG_ENV_FILE + value: "/tmp/minio-config-env/config.env" + {{- end}} + {{- if .Values.metrics.serviceMonitor.public }} + - name: MINIO_PROMETHEUS_AUTH_TYPE + value: "public" + {{- end}} + {{- if .Values.oidc.enabled }} + - name: MINIO_IDENTITY_OPENID_CONFIG_URL + value: {{ .Values.oidc.configUrl }} + - name: MINIO_IDENTITY_OPENID_CLIENT_ID + value: {{ .Values.oidc.clientId }} + - name: MINIO_IDENTITY_OPENID_CLIENT_SECRET + value: {{ .Values.oidc.clientSecret }} + - name: MINIO_IDENTITY_OPENID_CLAIM_NAME + value: {{ .Values.oidc.claimName }} + - name: MINIO_IDENTITY_OPENID_CLAIM_PREFIX + value: {{ .Values.oidc.claimPrefix }} + - name: MINIO_IDENTITY_OPENID_SCOPES + value: {{ .Values.oidc.scopes }} + - name: MINIO_IDENTITY_OPENID_REDIRECT_URI + value: {{ .Values.oidc.redirectUri }} + - name: MINIO_IDENTITY_OPENID_COMMENT + value: {{ .Values.oidc.comment }} + {{- end}} + {{- range $key, $val := .Values.environment }} + - name: {{ $key }} + value: {{ $val | quote }} + {{- end}} + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- with .Values.extraContainers }} + {{- if eq (typeOf .) "string" }} + {{- tpl . $ | nindent 8 }} + {{- else }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: +{{ toYaml . | indent 8 }} + {{- end }} +{{- include "minio.imagePullSecrets" . | indent 6 }} + {{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} + {{- end }} + {{- if and (gt $replicas 1) (ge .Capabilities.KubeVersion.Major "1") (ge .Capabilities.KubeVersion.Minor "19") }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml . | indent 8 }} + {{- end }} + {{- end }} + volumes: + - name: minio-user + secret: + secretName: {{ template "minio.secretName" . }} + {{- if .Values.extraSecret }} + - name: extra-secret + secret: + secretName: {{ .Values.extraSecret }} + {{- end }} + {{- include "minio.tlsKeysVolume" . | indent 8 }} + {{- if .Values.extraVolumes }} + {{ toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} +{{- if .Values.persistence.enabled }} + volumeClaimTemplates: + {{- if gt $drivesPerNode 1 }} + {{- range $diskId := until $drivesPerNode}} + - metadata: + name: export-{{ $diskId }} + {{- if $.Values.persistence.annotations }} + annotations: +{{ toYaml $.Values.persistence.annotations | trimSuffix "\n" | indent 10 }} + {{- end }} + spec: + accessModes: [ {{ $accessMode | quote }} ] + {{- if $storageClass }} + storageClassName: {{ $storageClass }} + {{- end }} + resources: + requests: + storage: {{ $psize }} + {{- end }} + {{- else }} + - metadata: + name: export + {{- if $.Values.persistence.annotations }} + annotations: +{{ toYaml $.Values.persistence.annotations | trimSuffix "\n" | indent 10 }} + {{- end }} + spec: + accessModes: [ {{ $accessMode | quote }} ] + {{- if $storageClass }} + storageClassName: {{ $storageClass }} + {{- end }} + resources: + requests: + storage: {{ $psize }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/arcadia/charts/minio/values.yaml b/charts/arcadia/charts/minio/values.yaml new file mode 100644 index 000000000..f6928418c --- /dev/null +++ b/charts/arcadia/charts/minio/values.yaml @@ -0,0 +1,557 @@ +## Provide a name in place of minio for `app:` labels +## +nameOverride: "" + +## Provide a name to substitute for the full names of resources +## +fullnameOverride: "" + +## set kubernetes cluster domain where minio is running +## +clusterDomain: cluster.local + +## Set default image, imageTag, and imagePullPolicy. mode is used to indicate the +## +image: + repository: hyperledgerk8s/minio-minio + tag: RELEASE.2023-02-10T18-48-39Z + pullPolicy: IfNotPresent + +imagePullSecrets: [] +# - name: "image-pull-secret" + +## Set default image, imageTag, and imagePullPolicy for the `mc` (the minio +## client used to create a default bucket). +## +mcImage: + repository: hyperledgerk8s/minio-mc + tag: RELEASE.2023-01-28T20-29-38Z + pullPolicy: IfNotPresent + +## minio mode, i.e. standalone or distributed +mode: standalone + +## Additional labels to include with deployment or statefulset +additionalLabels: {} + +## Additional annotations to include with deployment or statefulset +additionalAnnotations: {} + +## Typically the deployment/statefulset includes checksums of secrets/config, +## So that when these change on a subsequent helm install, the deployment/statefulset +## is restarted. This can result in unnecessary restarts under GitOps tooling such as +## flux, so set to "true" to disable this behaviour. +ignoreChartChecksums: false + +## Additional arguments to pass to minio binary +extraArgs: [] + +## Additional volumes to minio container +extraVolumes: [] + +## Additional volumeMounts to minio container +extraVolumeMounts: [] + +## Additional sidecar containers +extraContainers: [] + +## Internal port number for MinIO S3 API container +## Change service.port to change external port number +minioAPIPort: "9000" + +## Internal port number for MinIO Browser Console container +## Change consoleService.port to change external port number +minioConsolePort: "9001" + +## Update strategy for Deployments +DeploymentUpdate: + type: RollingUpdate + maxUnavailable: 0 + maxSurge: 100% + +## Update strategy for StatefulSets +StatefulSetUpdate: + updateStrategy: RollingUpdate + +## Pod priority settings +## ref: https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/ +## +priorityClassName: "" + +## Pod runtime class name +## ref https://kubernetes.io/docs/concepts/containers/runtime-class/ +## +runtimeClassName: "" + +## Set default rootUser, rootPassword +## AccessKey and secretKey is generated when not set +## Distributed MinIO ref: https://min.io/docs/minio/linux/operations/install-deploy-manage/deploy-minio-multi-node-multi-drive.html +## +rootUser: "" +rootPassword: "" + +## Use existing Secret that store following variables: +## +## | Chart var | .data. in Secret | +## |:----------------------|:-------------------------| +## | rootUser | rootUser | +## | rootPassword | rootPassword | +## +## All mentioned variables will be ignored in values file. +## .data.rootUser and .data.rootPassword are mandatory, +## others depend on enabled status of corresponding sections. +existingSecret: "" + +## Directory on the MinIO pof +certsPath: "/tmp/minio/certs/" +configPathmc: "/tmp/minio/mc/" + +## Path where PV would be mounted on the MinIO Pod +mountPath: "/export" +## Override the root directory which the minio server should serve from. +## If left empty, it defaults to the value of {{ .Values.mountPath }} +## If defined, it must be a sub-directory of the path specified in {{ .Values.mountPath }} +## +bucketRoot: "" + +# Number of drives attached to a node +drivesPerNode: 1 +# Number of MinIO containers running +replicas: 3 +# Number of expanded MinIO clusters +pools: 1 + +## TLS Settings for MinIO +tls: + enabled: false + ## Create a secret with private.key and public.crt files and pass that here. Ref: https://github.com/minio/minio/tree/master/docs/tls/kubernetes#2-create-kubernetes-secret + certSecret: "" + publicCrt: public.crt + privateKey: private.key + +## Trusted Certificates Settings for MinIO. Ref: https://min.io/docs/minio/linux/operations/network-encryption.html#third-party-certificate-authorities +## Bundle multiple trusted certificates into one secret and pass that here. Ref: https://github.com/minio/minio/tree/master/docs/tls/kubernetes#2-create-kubernetes-secret +## When using self-signed certificates, remember to include MinIO's own certificate in the bundle with key public.crt. +## If certSecret is left empty and tls is enabled, this chart installs the public certificate from .Values.tls.certSecret. +trustedCertsSecret: "" + +## Enable persistence using Persistent Volume Claims +## ref: http://kubernetes.io/docs/user-guide/persistent-volumes/ +## +persistence: + enabled: false + annotations: {} + + ## A manually managed Persistent Volume and Claim + ## Requires persistence.enabled: true + ## If defined, PVC must be created manually before volume will be bound + existingClaim: "" + + ## minio data Persistent Volume Storage Class + ## If defined, storageClassName: + ## If set to "-", storageClassName: "", which disables dynamic provisioning + ## If undefined (the default) or set to null, no storageClassName spec is + ## set, choosing the default provisioner. (gp2 on AWS, standard on + ## GKE, AWS & OpenStack) + ## + ## Storage class of PV to bind. By default it looks for standard storage class. + ## If the PV uses a different storage class, specify that here. + storageClass: "" + VolumeName: "" + accessMode: ReadWriteOnce + size: 5Gi + + ## If subPath is set mount a sub folder of a volume instead of the root of the volume. + ## This is especially handy for volume plugins that don't natively support sub mounting (like glusterfs). + ## + subPath: "" + +## Expose the MinIO service to be accessed from outside the cluster (LoadBalancer service). +## or access it from within the cluster (ClusterIP service). Set the service type and the port to serve it. +## ref: http://kubernetes.io/docs/user-guide/services/ +## +service: + type: ClusterIP + clusterIP: ~ + port: "9000" + nodePort: 32000 + +## Configure Ingress based on the documentation here: https://kubernetes.io/docs/concepts/services-networking/ingress/ +## + +ingress: + enabled: false + ingressClassName: "portal-ingress" + labels: + {} + # node-role.kubernetes.io/ingress: platform + + annotations: + {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # kubernetes.io/ingress.allow-http: "false" + # kubernetes.io/ingress.global-static-ip-name: "" + # nginx.ingress.kubernetes.io/secure-backends: "true" + # nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + # nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0 + path: / + hosts: + - minio-example.local + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +consoleService: + type: ClusterIP + clusterIP: ~ + port: "9001" + nodePort: 32001 + +consoleIngress: + enabled: true + ingressClassName: "portal-ingress" + labels: + {} + # node-role.kubernetes.io/ingress: platform + + annotations: + {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # kubernetes.io/ingress.allow-http: "false" + # kubernetes.io/ingress.global-static-ip-name: "" + # nginx.ingress.kubernetes.io/secure-backends: "true" + # nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" + # nginx.ingress.kubernetes.io/whitelist-source-range: 0.0.0.0/0 + path: / + hosts: + - console.minio.local + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +## Node labels for pod assignment +## Ref: https://kubernetes.io/docs/user-guide/node-selection/ +## +nodeSelector: {} +tolerations: [] +affinity: {} +topologySpreadConstraints: [] + +## Add stateful containers to have security context, if enabled MinIO will run as this +## user and group NOTE: securityContext is only enabled if persistence.enabled=true +securityContext: + enabled: true + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: "OnRootMismatch" + +# Additational pod annotations +podAnnotations: {} + +# Additional pod labels +podLabels: {} + +## Configure resource requests and limits +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +## +resources: + requests: + memory: 512Mi + +## List of policies to be created after minio install +## +## In addition to default policies [readonly|readwrite|writeonly|consoleAdmin|diagnostics] +## you can define additional policies with custom supported actions and resources +policies: +## writeexamplepolicy policy grants creation or deletion of buckets with name +## starting with example. In addition, grants objects write permissions on buckets starting with +## example. +# - name: custom +# statements: +# - resources: +# - 'arn:aws:s3:::kubeagi' +# actions: +# - "s3:ListBucket" +# - "s3:GetBucketLocation" +# effect: 'Allow' +# principal: +# AWS: +# - "*" +# - resources: +# - 'arn:aws:s3:::kubeagi/*' +# actions: +# - "s3:GetObject" +# effect: 'Allow' +# principal: +# AWS: +# - "*" +## readonlyexamplepolicy policy grants access to buckets with name starting with example. +## In addition, grants objects read permissions on buckets starting with example. +# - name: readonlyexamplepolicy +# statements: +# - resources: +# - 'arn:aws:s3:::example*/*' +# actions: +# - "s3:GetObject" +# - resources: +# - 'arn:aws:s3:::example*' +# actions: +# - "s3:GetBucketLocation" +# - "s3:ListBucket" +# - "s3:ListBucketMultipartUploads" +## conditionsexample policy creates all access to example bucket with aws:username="johndoe" and source ip range 10.0.0.0/8 and 192.168.0.0/24 only +# - name: conditionsexample +# statements: +# - resources: +# - 'arn:aws:s3:::example/*' +# actions: +# - 's3:*' +# conditions: +# - StringEquals: '"aws:username": "johndoe"' +# - IpAddress: | +# "aws:SourceIp": [ +# "10.0.0.0/8", +# "192.168.0.0/24" +# ] +# +## Additional Annotations for the Kubernetes Job makePolicyJob +makePolicyJob: + securityContext: + enabled: false + runAsUser: 1000 + runAsGroup: 1000 + resources: + requests: + memory: 128Mi + # Command to run after the main command on exit + exitCommand: "" + +## List of users to be created after minio install +## +users: + [] + ## Username, password and policy to be assigned to the user + ## Default policies are [readonly|readwrite|writeonly|consoleAdmin|diagnostics] + ## Add new policies as explained here https://min.io/docs/minio/kubernetes/upstream/administration/identity-access-management.html#access-management + ## NOTE: this will fail if LDAP is enabled in your MinIO deployment + ## make sure to disable this if you are using LDAP. + # - accessKey: q18aRFqWOAX7pEin + # secretKey: nCbZIP6q4s8KtQpL7n8CD2N88H6XABGf + # policy: readwrite + # Or you can refer to specific secret + # - accessKey: externalSecret + # existingSecret: my-secret + # existingSecretKey: password + # policy: readonly + +## Additional Annotations for the Kubernetes Job makeUserJob +makeUserJob: + securityContext: + enabled: true + runAsUser: 1000 + runAsGroup: 1000 + resources: + requests: + memory: 128Mi + # Command to run after the main command on exit + exitCommand: "" + +## List of service accounts to be created after minio install +## +# svcaccts: +## accessKey, secretKey and parent user to be assigned to the service accounts +## Add new service accounts as explained here https://min.io/docs/minio/kubernetes/upstream/administration/identity-access-management/minio-user-management.html#service-accounts +# - accessKey: console-svcacct +# secretKey: console123 +# user: console +## Or you can refer to specific secret +# - accessKey: externalSecret +# existingSecret: my-secret +# existingSecretKey: password +# user: console +## You also can pass custom policy +# - accessKey: console-svcacct +# secretKey: console123 +# user: console +# policy: +# statements: +# - resources: +# - 'arn:aws:s3:::example*/*' +# actions: +# - "s3:AbortMultipartUpload" +# - "s3:GetObject" +# - "s3:DeleteObject" +# - "s3:PutObject" +# - "s3:ListMultipartUploadParts" + +makeServiceAccountJob: + securityContext: + enabled: false + runAsUser: 1000 + runAsGroup: 1000 + resources: + requests: + memory: 128Mi + # Command to run after the main command on exit + exitCommand: "" + +## List of buckets to be created after minio install +## +buckets: + # Name of the bucket + - name: kubeagi + # Policy to be set on the + # bucket [none|download|upload|public|custom] + # if set to custom, customPolicy must be set. + policy: "custom" + # Purge if bucket exists already + purge: false + # set versioning for + # bucket [true|false] + versioning: false + # set objectlocking for + # bucket [true|false] NOTE: versioning is enabled by default if you use locking + objectlocking: false + # set custom policy + customPolicy: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + AWS: + - "*" + Action: + - s3:ListBucket + - s3:GetBucketLocation + Resource: + - arn:aws:s3:::kubeagi + - Effect: Allow + Principal: + AWS: + - "*" + Action: + - s3:GetObject + Resource: + - arn:aws:s3:::kubeagi/* + +## Additional Annotations for the Kubernetes Job makeBucketJob +makeBucketJob: + securityContext: + enabled: false + runAsUser: 1000 + runAsGroup: 1000 + resources: + requests: + memory: 128Mi + # Command to run after the main command on exit + exitCommand: "" + +## List of command to run after minio install +## NOTE: the mc command TARGET is always "myminio" +customCommands: + # - command: "admin policy set myminio consoleAdmin group='cn=ops,cn=groups,dc=example,dc=com'" + +## Additional Annotations for the Kubernetes Job customCommandJob +customCommandJob: + securityContext: + enabled: false + runAsUser: 1000 + runAsGroup: 1000 + resources: + requests: + memory: 128Mi + # Command to run after the main command on exit + exitCommand: "" + +## Merge jobs +postJob: + podAnnotations: {} + annotations: {} + securityContext: + enabled: false + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + nodeSelector: {} + tolerations: [] + affinity: {} + +## Use this field to add environment variables relevant to MinIO server. These fields will be passed on to MinIO container(s) +## when Chart is deployed +environment: + ## Please refer for comprehensive list https://min.io/docs/minio/linux/reference/minio-server/minio-server.html + ## MINIO_SUBNET_LICENSE: "License key obtained from https://subnet.min.io" + ## MINIO_BROWSER: "off" + +## The name of a secret in the same kubernetes namespace which contain secret values +## This can be useful for LDAP password, etc +## The key in the secret must be 'config.env' +## +# extraSecret: minio-extraenv + +## OpenID Identity Management +## The following section documents environment variables for enabling external identity management using an OpenID Connect (OIDC)-compatible provider. +## See https://min.io/docs/minio/linux/operations/external-iam/configure-openid-external-identity-management.html for a tutorial on using these variables. +oidc: + enabled: false + configUrl: "https://identity-provider-url/.well-known/openid-configuration" + clientId: "minio" + clientSecret: "" + claimName: "policy" + scopes: "openid,profile,email" + redirectUri: "https://console-endpoint-url/oauth_callback" + # Can leave empty + claimPrefix: "" + comment: "" + +networkPolicy: + enabled: false + allowExternal: true + +## PodDisruptionBudget settings +## ref: https://kubernetes.io/docs/concepts/workloads/pods/disruptions/ +## +podDisruptionBudget: + enabled: false + maxUnavailable: 1 + +## Specify the service account to use for the MinIO pods. If 'create' is set to 'false' +## and 'name' is left unspecified, the account 'default' will be used. +serviceAccount: + create: true + ## The name of the service account to use. If 'create' is 'true', a service account with that name + ## will be created. + name: "minio-sa" + +metrics: + serviceMonitor: + enabled: false + # scrape each node/pod individually for additional metrics + includeNode: false + public: true + additionalLabels: {} + # for node metrics + relabelConfigs: {} + # for cluster metrics + relabelConfigsCluster: + {} + # metricRelabelings: + # - regex: (server|pod) + # action: labeldrop + # namespace: monitoring + # interval: 30s + # scrapeTimeout: 10s + +## ETCD settings: https://github.com/minio/minio/blob/master/docs/sts/etcd.md +## Define endpoints to enable this section. +etcd: + endpoints: [] + pathPrefix: "" + corednsPathPrefix: "" + clientCert: "" + clientCertKey: "" diff --git a/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_datasets.yaml b/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_datasets.yaml new file mode 100644 index 000000000..912e593aa --- /dev/null +++ b/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_datasets.yaml @@ -0,0 +1,107 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: datasets.arcadia.kubeagi.k8s.com.cn +spec: + group: arcadia.kubeagi.k8s.com.cn + names: + kind: Dataset + listKind: DatasetList + plural: datasets + singular: dataset + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.displayName + name: display-name + type: string + - jsonPath: .spec.contentType + name: type + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Dataset is the Schema for the datasets 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: DatasetSpec defines the desired state of Dataset + properties: + bestCase: + description: bestCase defines the best case to use this dataset + type: string + contentType: + description: ContentType defines dataset + type: string + creator: + description: Creator defines dataset creator(AUTO-FILLED by webhook) + type: string + displayName: + description: DisplayName defines dataset display name + type: string + required: + - contentType + - displayName + type: object + status: + description: DatasetStatus defines the observed state of Dataset + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_datasources.yaml b/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_datasources.yaml index 1141776db..0f237d92e 100644 --- a/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_datasources.yaml +++ b/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_datasources.yaml @@ -15,7 +15,14 @@ spec: singular: datasource scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .spec.displayName + name: display-name + type: string + - jsonPath: .metadata.labels.arcadia\.kubeagi\.k8s\.com\.cn/datasource-type + name: type + type: string + name: v1alpha1 schema: openAPIV3Schema: description: Datasource is the Schema for the datasources API @@ -35,12 +42,58 @@ spec: spec: description: DatasourceSpec defines the desired state of Datasource properties: - authsecret: - description: AuthSecret defines datasource authsecret + creator: + description: Creator defines datasource creator(AUTO-FILLED by webhook) type: string - url: - description: URL defines datasource url + description: + description: Description defines datasource description type: string + displayName: + description: DisplayName defines datasource display name + type: string + endpoint: + description: Enpoint defines connection info + properties: + authSecret: + description: AuthSecret if the chart repository requires auth + authentication, set the username and password to secret, with + the field user and password respectively. + properties: + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: Namespace is the namespace of resource being + referenced + type: string + required: + - kind + - name + type: object + insecure: + description: Insecure if the endpoint needs a secure connection + type: boolean + url: + description: URL chart repository address + type: string + type: object + oss: + description: OSS defines info for object storage service + properties: + bucket: + type: string + object: + type: string + type: object type: object status: description: DatasourceStatus defines the observed state of Datasource diff --git a/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_embedders.yaml b/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_embedders.yaml index 9abe4115f..281c9d367 100644 --- a/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_embedders.yaml +++ b/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_embedders.yaml @@ -15,85 +15,112 @@ spec: singular: embedder scope: Namespaced versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: Embedder is the Schema for the embedders API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Embedder is the Schema for the embeddings 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 + 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: EmbedderSpec defines the desired state of embedder. - properties: - auth: - description: Auth keeps the authentication credentials when access - embedder, keeps in k8s secret. - type: string - displayName: - type: string - type: - description: Type defines the type of embedder. - type: string - url: - description: URL keeps the URL of the embedder service(Must required) - type: string - required: - - type - type: object - status: - description: EmbedderStatus defines the observed state of embedder. - properties: - conditions: - description: Conditions of the resource. - items: - description: A Condition that may apply to a resource. + type: string + metadata: + type: object + spec: + description: EmbedderSpec defines the desired state of Embedder + properties: + displayName: + description: Name of the Embedding service + type: string + endpoint: + description: Enpoint defines connection info + properties: + authSecret: + description: AuthSecret if the chart repository requires auth + authentication, set the username and password to secret, with + the field user and password respectively. properties: - lastSuccessfulTime: - description: LastSuccessfulTime is repository Last Successful - Update Time - format: date-time + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. type: string - lastTransitionTime: - description: LastTransitionTime is the last time this condition - transitioned from one status to another. - format: date-time + kind: + description: Kind is the type of resource being referenced type: string - message: - description: A Message containing details about this condition's - last transition from one status to another, if any. + name: + description: Name is the name of resource being referenced type: string - reason: - description: A Reason for this condition's last transition from - one status to another. - type: string - status: - description: Status of this condition; is it currently True, - False, or Unknown - type: string - type: - description: Type of this condition. At most one of each condition - type may apply to a resource at any point in time. + namespace: + description: Namespace is the namespace of resource being + referenced type: string required: - - lastTransitionTime - - reason - - status - - type + - kind + - name type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} + insecure: + description: Insecure if the endpoint needs a secure connection + type: boolean + url: + description: URL chart repository address + type: string + type: object + serviceType: + description: ServiceType indicates the source type of embedding service + type: string + type: object + status: + description: EmbeddingsStatus defines the observed state of Embedder + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_llms.yaml b/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_llms.yaml index 71be044a1..ad0e74be9 100644 --- a/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_llms.yaml +++ b/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_llms.yaml @@ -35,18 +35,46 @@ spec: spec: description: LLMSpec defines the desired state of LLM properties: - auth: - description: Auth keeps the authentication credentials when access - llm keeps in k8s secret - type: string displayName: type: string + endpoint: + description: Enpoint defines connection info + properties: + authSecret: + description: AuthSecret if the chart repository requires auth + authentication, set the username and password to secret, with + the field user and password respectively. + properties: + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: Namespace is the namespace of resource being + referenced + type: string + required: + - kind + - name + type: object + insecure: + description: Insecure if the endpoint needs a secure connection + type: boolean + url: + description: URL chart repository address + type: string + type: object type: description: Type defines the type of llm type: string - url: - description: URL keeps the URL of the llm service(Must required) - type: string required: - type type: object diff --git a/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_versioneddatasets.yaml b/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_versioneddatasets.yaml new file mode 100644 index 000000000..b2c83eb0d --- /dev/null +++ b/charts/arcadia/crds/arcadia.kubeagi.k8s.com.cn_versioneddatasets.yaml @@ -0,0 +1,234 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: versioneddatasets.arcadia.kubeagi.k8s.com.cn +spec: + group: arcadia.kubeagi.k8s.com.cn + names: + kind: VersionedDataset + listKind: VersionedDatasetList + plural: versioneddatasets + singular: versioneddataset + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.dataset.name + name: dataset + type: string + - jsonPath: .spec.version + name: version + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: VersionedDataset is the Schema for the versioneddatasets 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: VersionedDatasetSpec defines the desired state of VersionedDataset + properties: + dataset: + description: Dataset which this `VersionedDataset` belongs to + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: Namespace is the namespace of resource being referenced + type: string + required: + - kind + - name + type: object + files: + description: Files included in this `VersionedDataset` + items: + properties: + from: + description: From defines the datasource which provides this + `File` + properties: + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: Namespace is the namespace of resource being + referenced + type: string + required: + - kind + - name + type: object + path: + description: Path defines the detail path to get this `File` + type: string + required: + - from + - path + type: object + type: array + version: + description: Version + type: string + required: + - dataset + - version + type: object + status: + description: VersionedDatasetStatus defines the observed state of VersionedDataset + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + filesStatus: + description: FilesStatus contains the status to all files in VersionedDatasetSpec + items: + properties: + processCondition: + description: ProcessCondition records the status of data processing + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition + from one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each + condition type may apply to a resource at any point in + time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + uploadCondition: + description: UploadCondition records the status of file upload + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition + from one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each + condition type may apply to a resource at any point in + time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/charts/arcadia/templates/config.yaml b/charts/arcadia/templates/config.yaml new file mode 100644 index 000000000..c9685f817 --- /dev/null +++ b/charts/arcadia/templates/config.yaml @@ -0,0 +1,14 @@ +apiVersion: v1 +data: + config: | + systemDatasource: + apiGroup: arcadia.kubeagi.k8s.com.cn/v1alpha1 + kind: Datasource + name: '{{ .Release.Name }}-minio' + namespace: '{{ .Release.Namespace }}' +kind: ConfigMap +metadata: + labels: + control-plane: {{ .Release.Name }}-arcadia + name: {{ .Release.Name }}-config + namespace: {{ .Release.Namespace }} diff --git a/charts/arcadia/templates/deployment.yaml b/charts/arcadia/templates/deployment.yaml index cdfc12ce4..29a8f755c 100644 --- a/charts/arcadia/templates/deployment.yaml +++ b/charts/arcadia/templates/deployment.yaml @@ -27,6 +27,19 @@ spec: containers: - command: - /manager + env: + - name: POD_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: POD_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: DEFAULT_CONFIG + value: {{ .Release.Name }}-config image: {{ .Values.deployment.image }} imagePullPolicy: {{ .Values.deployment.imagePullPolicy }} name: manager diff --git a/charts/arcadia/templates/post-oss.yaml b/charts/arcadia/templates/post-oss.yaml new file mode 100644 index 000000000..bbdea332e --- /dev/null +++ b/charts/arcadia/templates/post-oss.yaml @@ -0,0 +1,20 @@ +apiVersion: arcadia.kubeagi.k8s.com.cn/v1alpha1 +kind: Datasource +metadata: + name: {{ .Release.Name }}-minio + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-weight": "1" +spec: + displayName: "内置系统数据源" + description: "Arcadia 内置系统数据源" + endpoint: + url: {{ .Release.Name }}-minio.{{ .Release.Namespace }}.svc.cluster.local:9000 + authSecret: + kind: Secret + name: {{ .Release.Name }}-minio + insecure: true + oss: + # pre-defined buckets for arcadia + bucket: {{ .Values.global.oss.bucket }} diff --git a/charts/arcadia/templates/rbac.yaml b/charts/arcadia/templates/rbac.yaml index cddaca4c9..8cf3b69a3 100644 --- a/charts/arcadia/templates/rbac.yaml +++ b/charts/arcadia/templates/rbac.yaml @@ -22,6 +22,14 @@ kind: ClusterRole metadata: name: {{ .Release.Name }} rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch - apiGroups: - "" resources: @@ -29,6 +37,33 @@ rules: verbs: - get - list + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - datasets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - datasets/finalizers + verbs: + - update +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - datasets/status + verbs: + - get + - patch + - update - apiGroups: - arcadia.kubeagi.k8s.com.cn resources: @@ -159,4 +194,29 @@ rules: - get - patch - update - +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - versioneddatasets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - versioneddatasets/finalizers + verbs: + - update +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - versioneddatasets/status + verbs: + - get + - patch + - update diff --git a/charts/arcadia/values.yaml b/charts/arcadia/values.yaml index edb9fc952..0f61243b4 100644 --- a/charts/arcadia/values.yaml +++ b/charts/arcadia/values.yaml @@ -1,3 +1,10 @@ +global: + oss: + bucket: &default-oss-bucket "arcadia" +# @section deployment is used as default deployment configurations for arcadia +# @param image Image to be used +# @param imagePullPolcy ImagePullPolicy +# @param resources Resources to be used deployment: image: kubebb/arcadia:v0.0.1 imagePullPolcy: IfNotPresent @@ -8,3 +15,53 @@ deployment: requests: cpu: 10m memory: 64Mi + +# @section fastchat is used as fastchat configurations for arcadia +fastchat: + ingress: + enabled: false + className: portal-ingress + hosts: + - host: fastchat-api.fastchat.arcadia.com + paths: + - path: / + port: 8000 + pathType: ImplementationSpecific + - host: fastchat-controller.fastchat.arcadia.com + paths: + - path: / + port: 21001 + pathType: ImplementationSpecific + + +# @section oss is used as default Object-Storage-Service for arcadia which provides the capability to +# - host user-uploaded data files as local datasource +# - host user-uploaded models +# The following params comes from kubebb/minio in repository https://kubebb.github.io/components +# @param oss.enabled Enable Object-Storage-Service in arcadia +# @param oss.buckets List of default buckets in arcadia +minio: + mode: standalone + rootUser: "admin" + rootPassword: "Passw0rd!" + persistence: + enabled: true + storageClass: "" + size: 30Gi + users: + - accessKey: q18aRFqWOAX7pEin + secretKey: nCbZIP6q4s8KtQpL7n8CD2N88H6XABGf + policy: readwrite + buckets: + # Name of the bucket + - name: *default-oss-bucket + # Policy to be set on the + # bucket [none|download|upload|public|custom] + # if set to custom, customPolicy must be set. + policy: "none" + # set versioning for + # bucket [true|false] + versioning: false + # set objectlocking for + # bucket [true|false] NOTE: versioning is enabled by default if you use locking + objectlocking: false diff --git a/config/crd/bases/arcadia.kubeagi.k8s.com.cn_datasets.yaml b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_datasets.yaml new file mode 100644 index 000000000..912e593aa --- /dev/null +++ b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_datasets.yaml @@ -0,0 +1,107 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: datasets.arcadia.kubeagi.k8s.com.cn +spec: + group: arcadia.kubeagi.k8s.com.cn + names: + kind: Dataset + listKind: DatasetList + plural: datasets + singular: dataset + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.displayName + name: display-name + type: string + - jsonPath: .spec.contentType + name: type + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Dataset is the Schema for the datasets 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: DatasetSpec defines the desired state of Dataset + properties: + bestCase: + description: bestCase defines the best case to use this dataset + type: string + contentType: + description: ContentType defines dataset + type: string + creator: + description: Creator defines dataset creator(AUTO-FILLED by webhook) + type: string + displayName: + description: DisplayName defines dataset display name + type: string + required: + - contentType + - displayName + type: object + status: + description: DatasetStatus defines the observed state of Dataset + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/bases/arcadia.kubeagi.k8s.com.cn_datasources.yaml b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_datasources.yaml index cca1aa855..590497c12 100644 --- a/config/crd/bases/arcadia.kubeagi.k8s.com.cn_datasources.yaml +++ b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_datasources.yaml @@ -15,7 +15,14 @@ spec: singular: datasource scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .spec.displayName + name: display-name + type: string + - jsonPath: .metadata.labels.arcadia\.kubeagi\.k8s\.com\.cn/datasource-type + name: type + type: string + name: v1alpha1 schema: openAPIV3Schema: description: Datasource is the Schema for the datasources API @@ -88,7 +95,7 @@ spec: type: string type: object required: - - endpoint + - displayName type: object status: description: DatasourceStatus defines the observed state of Datasource diff --git a/config/crd/bases/arcadia.kubeagi.k8s.com.cn_versioneddatasets.yaml b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_versioneddatasets.yaml new file mode 100644 index 000000000..9f06a7ea6 --- /dev/null +++ b/config/crd/bases/arcadia.kubeagi.k8s.com.cn_versioneddatasets.yaml @@ -0,0 +1,160 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: versioneddatasets.arcadia.kubeagi.k8s.com.cn +spec: + group: arcadia.kubeagi.k8s.com.cn + names: + kind: VersionedDataset + listKind: VersionedDatasetList + plural: versioneddatasets + singular: versioneddataset + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.dataset.name + name: dataset + type: string + - jsonPath: .spec.version + name: version + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: VersionedDataset is the Schema for the versioneddatasets 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: VersionedDatasetSpec defines the desired state of VersionedDataset + properties: + dataset: + description: Dataset which this `VersionedDataset` belongs to + properties: + apiGroup: + description: APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in + the core API group. For any other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: Namespace is the namespace of resource being referenced + type: string + required: + - kind + - name + type: object + fileGroups: + description: FileGroups included in this `VersionedDataset` Grouped + by Datasource + items: + properties: + datasource: + description: From defines the datasource which provides this + `File` + properties: + apiGroup: + description: APIGroup is the group for the resource being + referenced. If APIGroup is not specified, the specified + Kind must be in the core API group. For any other third-party + types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: Namespace is the namespace of resource being + referenced + type: string + required: + - kind + - name + type: object + paths: + description: Paths defines the detail paths to get objects from + above datasource + items: + type: string + type: array + required: + - datasource + - paths + type: object + type: array + version: + description: Version + type: string + required: + - dataset + - version + type: object + status: + description: VersionedDatasetStatus defines the observed state of VersionedDataset + properties: + conditions: + description: Conditions of the resource. + items: + description: A Condition that may apply to a resource. + properties: + lastSuccessfulTime: + description: LastSuccessfulTime is repository Last Successful + Update Time + format: date-time + type: string + lastTransitionTime: + description: LastTransitionTime is the last time this condition + transitioned from one status to another. + format: date-time + type: string + message: + description: A Message containing details about this condition's + last transition from one status to another, if any. + type: string + reason: + description: A Reason for this condition's last transition from + one status to another. + type: string + status: + description: Status of this condition; is it currently True, + False, or Unknown + type: string + type: + description: Type of this condition. At most one of each condition + type may apply to a resource at any point in time. + type: string + required: + - lastTransitionTime + - reason + - status + - type + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/config/crd/kustomization.yaml b/config/crd/kustomization.yaml index 1e3c33e33..df49548ff 100644 --- a/config/crd/kustomization.yaml +++ b/config/crd/kustomization.yaml @@ -7,6 +7,8 @@ resources: - bases/arcadia.kubeagi.k8s.com.cn_prompts.yaml - bases/arcadia.kubeagi.k8s.com.cn_datasources.yaml - bases/arcadia.kubeagi.k8s.com.cn_embedders.yaml +- bases/arcadia.kubeagi.k8s.com.cn_datasets.yaml +- bases/arcadia.kubeagi.k8s.com.cn_versioneddatasets.yaml #+kubebuilder:scaffold:crdkustomizeresource patchesStrategicMerge: @@ -17,6 +19,8 @@ patchesStrategicMerge: #- patches/webhook_in_prompts.yaml #- patches/webhook_in_datasources.yaml #- patches/webhook_in_embedders.yaml +#- patches/webhook_in_datasets.yaml +#- patches/webhook_in_versioneddatasets.yaml #+kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix. @@ -26,6 +30,8 @@ patchesStrategicMerge: #- patches/cainjection_in_prompts.yaml #- patches/cainjection_in_datasources.yaml #- patches/cainjection_in_embedders.yaml +#- patches/cainjection_in_datasets.yaml +#- patches/cainjection_in_versioneddatasets.yaml #+kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/config/crd/patches/cainjection_in_datasets.yaml b/config/crd/patches/cainjection_in_datasets.yaml new file mode 100644 index 000000000..064ae9c50 --- /dev/null +++ b/config/crd/patches/cainjection_in_datasets.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: datasets.arcadia.kubeagi.k8s.com.cn diff --git a/config/crd/patches/cainjection_in_versioneddatasets.yaml b/config/crd/patches/cainjection_in_versioneddatasets.yaml new file mode 100644 index 000000000..18ac8d467 --- /dev/null +++ b/config/crd/patches/cainjection_in_versioneddatasets.yaml @@ -0,0 +1,7 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: versioneddatasets.arcadia.kubeagi.k8s.com.cn diff --git a/config/crd/patches/webhook_in_datasets.yaml b/config/crd/patches/webhook_in_datasets.yaml new file mode 100644 index 000000000..e591e915d --- /dev/null +++ b/config/crd/patches/webhook_in_datasets.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: datasets.arcadia.kubeagi.k8s.com.cn +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/config/crd/patches/webhook_in_versioneddatasets.yaml b/config/crd/patches/webhook_in_versioneddatasets.yaml new file mode 100644 index 000000000..22ed62c5a --- /dev/null +++ b/config/crd/patches/webhook_in_versioneddatasets.yaml @@ -0,0 +1,16 @@ +# The following patch enables a conversion webhook for the CRD +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: versioneddatasets.arcadia.kubeagi.k8s.com.cn +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + namespace: system + name: webhook-service + path: /convert + conversionReviewVersions: + - v1 diff --git a/config/rbac/dataset_editor_role.yaml b/config/rbac/dataset_editor_role.yaml new file mode 100644 index 000000000..a0d73bbf1 --- /dev/null +++ b/config/rbac/dataset_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit datasets. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dataset-editor-role +rules: +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - datasets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - datasets/status + verbs: + - get diff --git a/config/rbac/dataset_viewer_role.yaml b/config/rbac/dataset_viewer_role.yaml new file mode 100644 index 000000000..deda05156 --- /dev/null +++ b/config/rbac/dataset_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view datasets. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: dataset-viewer-role +rules: +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - datasets + verbs: + - get + - list + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - datasets/status + verbs: + - get diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index f98ff14bf..16536a455 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -5,6 +5,14 @@ metadata: creationTimestamp: null name: manager-role rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch - apiGroups: - "" resources: @@ -12,6 +20,33 @@ rules: verbs: - get - list + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - datasets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - datasets/finalizers + verbs: + - update +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - datasets/status + verbs: + - get + - patch + - update - apiGroups: - arcadia.kubeagi.k8s.com.cn resources: @@ -142,3 +177,29 @@ rules: - get - patch - update +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - versioneddatasets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - versioneddatasets/finalizers + verbs: + - update +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - versioneddatasets/status + verbs: + - get + - patch + - update diff --git a/config/rbac/versioneddataset_editor_role.yaml b/config/rbac/versioneddataset_editor_role.yaml new file mode 100644 index 000000000..fec80806a --- /dev/null +++ b/config/rbac/versioneddataset_editor_role.yaml @@ -0,0 +1,24 @@ +# permissions for end users to edit versioneddatasets. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: versioneddataset-editor-role +rules: +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - versioneddatasets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - versioneddatasets/status + verbs: + - get diff --git a/config/rbac/versioneddataset_viewer_role.yaml b/config/rbac/versioneddataset_viewer_role.yaml new file mode 100644 index 000000000..4ef9f2647 --- /dev/null +++ b/config/rbac/versioneddataset_viewer_role.yaml @@ -0,0 +1,20 @@ +# permissions for end users to view versioneddatasets. +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: versioneddataset-viewer-role +rules: +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - versioneddatasets + verbs: + - get + - list + - watch +- apiGroups: + - arcadia.kubeagi.k8s.com.cn + resources: + - versioneddatasets/status + verbs: + - get diff --git a/config/samples/arcadia_v1alpha1_dataset.yaml b/config/samples/arcadia_v1alpha1_dataset.yaml new file mode 100644 index 000000000..6fa860886 --- /dev/null +++ b/config/samples/arcadia_v1alpha1_dataset.yaml @@ -0,0 +1,6 @@ +apiVersion: arcadia.kubeagi.k8s.com.cn/v1alpha1 +kind: Dataset +metadata: + name: dataset-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/arcadia_v1alpha1_datasource.yaml b/config/samples/arcadia_v1alpha1_datasource.yaml deleted file mode 100644 index 46635447f..000000000 --- a/config/samples/arcadia_v1alpha1_datasource.yaml +++ /dev/null @@ -1,17 +0,0 @@ -apiVersion: arcadia.kubeagi.k8s.com.cn/v1alpha1 -kind: Datasource -metadata: - name: arcadia-oss-minio - namespace: arcadia -spec: - displayName: "对象存储数据源" - description: "这是一个Minio的对象存储数据源" - endpoint: - url: arcadia-oss-minio.arcadia.svc.cluster.local:9000 - authSecret: - kind: secret - name: arcadia-oss-minio - insecure: true - oss: - bucket: "kubebb" - object: "" diff --git a/config/samples/arcadia_v1alpha1_local_datasource.yaml b/config/samples/arcadia_v1alpha1_local_datasource.yaml new file mode 100644 index 000000000..0e7005ea2 --- /dev/null +++ b/config/samples/arcadia_v1alpha1_local_datasource.yaml @@ -0,0 +1,8 @@ +apiVersion: arcadia.kubeagi.k8s.com.cn/v1alpha1 +kind: Datasource +metadata: + name: arcadia-local + namespace: arcadia +spec: + displayName: "本地存储数据源" + description: "这是一个使用系统数据源作为存储的本地数据源" \ No newline at end of file diff --git a/config/samples/arcadia_v1alpha1_versioneddataset.yaml b/config/samples/arcadia_v1alpha1_versioneddataset.yaml new file mode 100644 index 000000000..1324c257f --- /dev/null +++ b/config/samples/arcadia_v1alpha1_versioneddataset.yaml @@ -0,0 +1,6 @@ +apiVersion: arcadia.kubeagi.k8s.com.cn/v1alpha1 +kind: VersionedDataset +metadata: + name: versioneddataset-sample +spec: + # TODO(user): Add fields here diff --git a/config/samples/kustomization.yaml b/config/samples/kustomization.yaml index 6163e6797..eb170c0d6 100644 --- a/config/samples/kustomization.yaml +++ b/config/samples/kustomization.yaml @@ -5,4 +5,6 @@ resources: - arcadia_v1alpha1_prompt.yaml - arcadia_v1alpha1_datasource.yaml - arcadia_v1alpha1_embedders.yaml +- arcadia_v1alpha1_dataset.yaml +- arcadia_v1alpha1_versioneddataset.yaml #+kubebuilder:scaffold:manifestskustomizesamples diff --git a/controllers/dataset_controller.go b/controllers/dataset_controller.go new file mode 100644 index 000000000..e477eb459 --- /dev/null +++ b/controllers/dataset_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023 KubeAGI. + +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 controllers + +import ( + "context" + + "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" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" +) + +// DatasetReconciler reconciles a Dataset object +type DatasetReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=datasets,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=datasets/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=datasets/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 Dataset 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.12.2/pkg/reconcile +func (r *DatasetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *DatasetReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&arcadiav1alpha1.Dataset{}). + Complete(r) +} diff --git a/controllers/datasource_controller.go b/controllers/datasource_controller.go index be69f0e81..e98908dcd 100644 --- a/controllers/datasource_controller.go +++ b/controllers/datasource_controller.go @@ -19,6 +19,7 @@ package controllers import ( "context" "fmt" + "reflect" "github.com/go-logr/logr" corev1 "k8s.io/api/core/v1" @@ -26,11 +27,15 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/event" "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/predicate" "sigs.k8s.io/controller-runtime/pkg/reconcile" arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" + "github.com/kubeagi/arcadia/pkg/config" "github.com/kubeagi/arcadia/pkg/datasource" "github.com/kubeagi/arcadia/pkg/utils" ) @@ -44,7 +49,8 @@ type DatasourceReconciler struct { //+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=datasources,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=datasources/status,verbs=get;update;patch //+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=datasources/finalizers,verbs=update -//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list +//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch +//+kubebuilder:rbac:groups="",resources=configmaps,verbs=get;list;watch // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -80,14 +86,16 @@ func (r *DatasourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) } // initialize labels - err := r.Initialize(ctx, logger, instance) + requeue, err := r.Initialize(ctx, logger, instance) if err != nil { return reconcile.Result{}, fmt.Errorf("failed to initiali datasource: %w", err) } + if requeue { + return reconcile.Result{Requeue: true}, nil + } // check datasource if err := r.Checkdatasource(ctx, logger, instance); err != nil { - logger.Error(err, "Failed to check datasource") // Update conditioned status return reconcile.Result{}, err } @@ -97,11 +105,17 @@ func (r *DatasourceReconciler) Reconcile(ctx context.Context, req ctrl.Request) // SetupWithManager sets up the controller with the Manager. func (r *DatasourceReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&arcadiav1alpha1.Datasource{}). + For(&arcadiav1alpha1.Datasource{}, builder.WithPredicates(predicate.Funcs{ + UpdateFunc: func(ue event.UpdateEvent) bool { + oldDatsource := ue.ObjectOld.(*arcadiav1alpha1.Datasource) + newDatasource := ue.ObjectNew.(*arcadiav1alpha1.Datasource) + return !reflect.DeepEqual(oldDatsource.Spec, newDatasource.Spec) + }, + })). Complete(r) } -func (r *DatasourceReconciler) Initialize(ctx context.Context, logger logr.Logger, instance *arcadiav1alpha1.Datasource) error { +func (r *DatasourceReconciler) Initialize(ctx context.Context, logger logr.Logger, instance *arcadiav1alpha1.Datasource) (bool, error) { instanceDeepCopy := instance.DeepCopy() l := len(instanceDeepCopy.Finalizers) @@ -124,10 +138,10 @@ func (r *DatasourceReconciler) Initialize(ctx context.Context, logger logr.Logge } if update { - return r.Client.Update(ctx, instanceDeepCopy) + return true, r.Client.Update(ctx, instanceDeepCopy) } - return nil + return false, nil } // Checkdatasource to update status @@ -137,17 +151,33 @@ func (r *DatasourceReconciler) Checkdatasource(ctx context.Context, logger logr. // create datasource var ds datasource.Datasource + var info any switch instance.Spec.Type() { + case arcadiav1alpha1.DatasourceTypeLocal: + system, err := config.GetSystemDatasource(ctx, r.Client) + if err != nil { + return r.UpdateStatus(ctx, instance, err) + } + endpoint := system.Spec.Enpoint.DeepCopy() + if endpoint != nil && endpoint.AuthSecret != nil { + endpoint.AuthSecret.WithNameSpace(system.Namespace) + } + ds, err = datasource.NewLocal(ctx, r.Client, endpoint) + if err != nil { + return r.UpdateStatus(ctx, instance, err) + } + info = &arcadiav1alpha1.OSS{Bucket: instance.Namespace} case arcadiav1alpha1.DatasourceTypeOSS: - endpoiont := instance.Spec.Enpoint.DeepCopy() + endpoint := instance.Spec.Enpoint.DeepCopy() // set auth secret's namespace to the datasource's namespace - if endpoiont.AuthSecret != nil { - endpoiont.AuthSecret.WithNameSpace(instance.Namespace) + if endpoint.AuthSecret != nil { + endpoint.AuthSecret.WithNameSpace(instance.Namespace) } - ds, err = datasource.NewOSS(ctx, r.Client, endpoiont, instance.Spec.OSS.DeepCopy()) + ds, err = datasource.NewOSS(ctx, r.Client, endpoint) if err != nil { return r.UpdateStatus(ctx, instance, err) } + info = instance.Spec.OSS.DeepCopy() default: ds, err = datasource.NewUnknown(ctx, r.Client) if err != nil { @@ -156,7 +186,7 @@ func (r *DatasourceReconciler) Checkdatasource(ctx context.Context, logger logr. } // check datasource - if err := ds.Check(ctx, nil); err != nil { + if err := ds.Check(ctx, info); err != nil { return r.UpdateStatus(ctx, instance, err) } @@ -164,27 +194,30 @@ func (r *DatasourceReconciler) Checkdatasource(ctx context.Context, logger logr. return r.UpdateStatus(ctx, instance, nil) } +// UpdateStatus uppon error func (r *DatasourceReconciler) UpdateStatus(ctx context.Context, instance *arcadiav1alpha1.Datasource, err error) error { instanceCopy := instance.DeepCopy() + var newCondition arcadiav1alpha1.Condition if err != nil { - // Set status to unavailable - instanceCopy.Status.SetConditions(arcadiav1alpha1.Condition{ + // set condition to False + newCondition = arcadiav1alpha1.Condition{ Type: arcadiav1alpha1.TypeReady, Status: corev1.ConditionFalse, Reason: arcadiav1alpha1.ReasonUnavailable, Message: err.Error(), LastTransitionTime: metav1.Now(), - }) + } } else { - // Set status to available - instanceCopy.Status.SetConditions(arcadiav1alpha1.Condition{ + // set condition to True + newCondition = arcadiav1alpha1.Condition{ Type: arcadiav1alpha1.TypeReady, Status: corev1.ConditionTrue, Reason: arcadiav1alpha1.ReasonAvailable, - Message: "health check success", + Message: "Check Success", LastTransitionTime: metav1.Now(), LastSuccessfulTime: metav1.Now(), - }) + } } + instanceCopy.Status.SetConditions(newCondition) return r.Client.Status().Update(ctx, instanceCopy) } diff --git a/controllers/versioneddataset_controller.go b/controllers/versioneddataset_controller.go new file mode 100644 index 000000000..ffeebc2d8 --- /dev/null +++ b/controllers/versioneddataset_controller.go @@ -0,0 +1,62 @@ +/* +Copyright 2023 KubeAGI. + +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 controllers + +import ( + "context" + + "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" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" +) + +// VersionedDatasetReconciler reconciles a VersionedDataset object +type VersionedDatasetReconciler struct { + client.Client + Scheme *runtime.Scheme +} + +//+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=versioneddatasets,verbs=get;list;watch;create;update;patch;delete +//+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=versioneddatasets/status,verbs=get;update;patch +//+kubebuilder:rbac:groups=arcadia.kubeagi.k8s.com.cn,resources=versioneddatasets/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 VersionedDataset 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.12.2/pkg/reconcile +func (r *VersionedDatasetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { + _ = log.FromContext(ctx) + + // TODO(user): your logic here + + return ctrl.Result{}, nil +} + +// SetupWithManager sets up the controller with the Manager. +func (r *VersionedDatasetReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&arcadiav1alpha1.VersionedDataset{}). + Complete(r) +} diff --git a/go.mod b/go.mod index 7a6064fff..5c179fb59 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( github.com/99designs/gqlgen v0.17.40 github.com/amikos-tech/chroma-go v0.0.0-20230901221218-d0087270239e + github.com/coreos/go-oidc/v3 v3.7.0 github.com/go-logr/logr v1.2.0 github.com/gofiber/fiber/v2 v2.49.1 github.com/golang-jwt/jwt v3.2.2+incompatible @@ -26,6 +27,7 @@ require ( require ( github.com/agnivade/levenshtein v1.1.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/go-jose/go-jose/v3 v3.0.0 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.3 // indirect github.com/klauspost/cpuid/v2 v2.2.5 // indirect @@ -112,13 +114,13 @@ require ( golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea // indirect golang.org/x/net v0.17.0 // indirect - golang.org/x/oauth2 v0.10.0 // indirect + golang.org/x/oauth2 v0.13.0 // indirect golang.org/x/sys v0.13.0 // indirect golang.org/x/term v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect - google.golang.org/appengine v1.6.7 // indirect + google.golang.org/appengine v1.6.8 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -128,7 +130,7 @@ require ( k8s.io/apiextensions-apiserver v0.24.2 // indirect k8s.io/component-base v0.24.2 // indirect k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect - k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect + k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect sigs.k8s.io/yaml v1.3.0 // indirect diff --git a/go.sum b/go.sum index 49bf962a2..2e7c4a427 100644 --- a/go.sum +++ b/go.sum @@ -128,6 +128,8 @@ github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u9 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= +github.com/coreos/go-oidc/v3 v3.7.0 h1:FTdj0uexT4diYIPlF4yoFVI5MRO1r5+SEcIpEw9vC0o= +github.com/coreos/go-oidc/v3 v3.7.0/go.mod h1:yQzSCqBnK3e6Fs5l+f5i0F8Kwf0zpH9bPEsbY00KanM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= @@ -179,6 +181,8 @@ github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeME github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-jose/go-jose/v3 v3.0.0 h1:s6rrhirfEP/CGIoc6p+PZAeogN2SxKav6Wp7+dyMWVo= +github.com/go-jose/go-jose/v3 v3.0.0/go.mod h1:RNkWWRld676jZEYoV3+XK8L2ZnNSvIsxFMht0mSX+u8= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= @@ -633,6 +637,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -748,8 +753,8 @@ golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.10.0 h1:zHCpF2Khkwy4mMB4bv0U37YtJdTGW8jI0glAApi0Kh8= -golang.org/x/oauth2 v0.10.0/go.mod h1:kTpgurOux7LqtuxjuyZa4Gj2gdezIt/jQtGnNFfypQI= +golang.org/x/oauth2 v0.13.0 h1:jDDenyj+WgFtmV3zYVoi8aE2BwtXFLWOA67ZfNWftiY= +golang.org/x/oauth2 v0.13.0/go.mod h1:/JMhi4ZRXAf4HG9LiNmxvk+45+96RUlVThiH8FzNBn0= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -851,6 +856,7 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= @@ -953,8 +959,9 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= +google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= diff --git a/graphql-server/go-server/README.md b/graphql-server/go-server/README.md index 4a77b57a9..629e4e3c2 100644 --- a/graphql-server/go-server/README.md +++ b/graphql-server/go-server/README.md @@ -48,3 +48,37 @@ func (r *queryResolver) FindX(ctx context.Context, input string) (string, error) The file `model/model_gen.go` has a new structure x that we defined. All we have to do is just implement the `FindX` function. And the content of the function is up to you to play with. + + +## How to run + +in the root dir of the project + +```shell +# 1. build +make build-graphql-server + +# 2. run parameters +$ ./go-bff-server -h +Usage of ./main: + -client-id string + oidc client id + -client-secret string + oidc client secret + -enable-playgroud + whether to open the graphql playground (default true) + -host string + bind to the host, default is 0.0.0.0 + -issuer-url string + oidc issuer url + -kubeconfig string + Paths to a kubeconfig. Only required if out-of-cluster. + -master-url string + k8s master url + -port int + service listening port (default 8081) + +# 3. run +./go-bff-server --client-id=bff-client --client-secret=some-secret --master-url=https://k8s-adress --issuer-url=https://oidc-server +``` + diff --git a/graphql-server/go-server/graph/datasource.resolvers.go b/graphql-server/go-server/graph/datasource.resolvers.go index 5bc4ed788..56768fea9 100644 --- a/graphql-server/go-server/graph/datasource.resolvers.go +++ b/graphql-server/go-server/graph/datasource.resolvers.go @@ -8,11 +8,18 @@ import ( "context" "github.com/kubeagi/arcadia/graphql-server/go-server/graph/model" + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/auth" + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/client" "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/datasource" ) // CreateDatasource is the resolver for the createDatasource field. func (r *mutationResolver) CreateDatasource(ctx context.Context, input model.CreateDatasource) (*model.Datasource, error) { + token := auth.ForOIDCToken(ctx) + c, err := client.GetClientByIDToken(token) + if err != nil { + return nil, err + } url, authSecret := "", "" var insecure bool if input.URL != nil { @@ -24,11 +31,17 @@ func (r *mutationResolver) CreateDatasource(ctx context.Context, input model.Cre if input.Insecure != nil { insecure = *input.Insecure } - return datasource.CreateDatasource(ctx, input.Name, input.Namespace, url, authSecret, insecure) + return datasource.CreateDatasource(ctx, c, input.Name, input.Namespace, url, authSecret, insecure) } // Ds is the resolver for the ds field. func (r *queryResolver) Ds(ctx context.Context, input model.QueryDatasource) ([]*model.Datasource, error) { + token := auth.ForOIDCToken(ctx) + + c, err := client.GetClientByIDToken(token) + if err != nil { + return nil, err + } name := "" labelSelector, fieldSelector := "", "" if input.Name != nil { @@ -40,7 +53,7 @@ func (r *queryResolver) Ds(ctx context.Context, input model.QueryDatasource) ([] if input.LabelSelector != nil { labelSelector = *input.LabelSelector } - return datasource.DatasourceList(ctx, name, input.Namespace, labelSelector, fieldSelector) + return datasource.DatasourceList(ctx, c, name, input.Namespace, labelSelector, fieldSelector) } // Mutation returns MutationResolver implementation. diff --git a/graphql-server/go-server/graph/resolver.go b/graphql-server/go-server/graph/resolver.go index a25c09c61..06d0ca1f2 100644 --- a/graphql-server/go-server/graph/resolver.go +++ b/graphql-server/go-server/graph/resolver.go @@ -4,4 +4,5 @@ package graph // // It serves as dependency injection for your app, add any dependencies you require here. -type Resolver struct{} +type Resolver struct { +} diff --git a/graphql-server/go-server/main.go b/graphql-server/go-server/main.go index 1cdae09e4..5cec57ee2 100644 --- a/graphql-server/go-server/main.go +++ b/graphql-server/go-server/main.go @@ -27,21 +27,29 @@ import ( "github.com/99designs/gqlgen/graphql/handler" "github.com/99designs/gqlgen/graphql/playground" "k8s.io/klog/v2" - ctrl "sigs.k8s.io/controller-runtime" "github.com/kubeagi/arcadia/graphql-server/go-server/graph" - "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/client" + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/auth" + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/oidc" + + _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" ) var ( host = flag.String("host", "", "bind to the host, default is 0.0.0.0") port = flag.Int("port", 8081, "service listening port") enablePlayground = flag.Bool("enable-playgroud", true, "whether to open the graphql playground") + + issuerURL = flag.String("issuer-url", "", "oidc issuer url") + masterURL = flag.String("master-url", "", "k8s master url") + clientSecret = flag.String("client-secret", "", "oidc client secret") + clientID = flag.String("client-id", "", "oidc client id") ) func main() { - cfg := ctrl.GetConfigOrDie() - client.InitClient(cfg) + flag.Parse() + + oidc.InitOIDCArgs(*issuerURL, *masterURL, *clientSecret, *clientID) srv := handler.NewDefaultServer(graph.NewExecutableSchema(graph.Config{Resolvers: &graph.Resolver{}})) srv.AroundFields(func(ctx context.Context, next graphql.Resolver) (res interface{}, err error) { @@ -53,9 +61,10 @@ func main() { }) if *enablePlayground { - http.Handle("/", playground.Handler("Arcadia", "/query")) + http.Handle("/", auth.AuthInterceptor(oidc.Verifier, playground.Handler("Arcadia-BFF-Server", "/query"))) } - http.Handle("/query", srv) + http.Handle("/query", auth.AuthInterceptor(oidc.Verifier, srv.ServeHTTP)) + klog.Infof("listening server on port: %d", *port) log.Fatal(http.ListenAndServe(fmt.Sprintf("%s:%d", *host, *port), nil)) } diff --git a/graphql-server/go-server/pkg/auth/auth.go b/graphql-server/go-server/pkg/auth/auth.go new file mode 100644 index 000000000..750336a80 --- /dev/null +++ b/graphql-server/go-server/pkg/auth/auth.go @@ -0,0 +1,62 @@ +/* +Copyright 2023 KubeAGI. + +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 auth + +import ( + "context" + "net/http" + "strings" + + "github.com/coreos/go-oidc/v3/oidc" +) + +type idtokenKey struct{} + +func isBearerToken(token string) (bool, string) { + if len(token) < 6 { + return false, "" + } + head := strings.ToLower(token[:6]) + payload := strings.TrimSpace(token[6:]) + return head == "bearer" && len(payload) > 0, payload +} + +func AuthInterceptor(oidcVerifier *oidc.IDTokenVerifier, hf http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + idtoken := r.Header.Get("Authorization") + ok, rawToken := isBearerToken(idtoken) + if !ok { + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte("Unauthorized. Please provide an oidc token")) + return + } + _, err := oidcVerifier.Verify(context.TODO(), rawToken) + if err != nil { + w.WriteHeader(http.StatusUnauthorized) + _, _ = w.Write([]byte(err.Error())) + return + } + ctx := context.WithValue(r.Context(), idtokenKey{}, rawToken) + r = r.WithContext(ctx) + hf(w, r) + } +} + +func ForOIDCToken(ctx context.Context) string { + v, _ := ctx.Value(idtokenKey{}).(string) + return v +} diff --git a/graphql-server/go-server/pkg/client/client.go b/graphql-server/go-server/pkg/client/client.go index 5a18aceae..bae5f81c1 100644 --- a/graphql-server/go-server/pkg/client/client.go +++ b/graphql-server/go-server/pkg/client/client.go @@ -21,6 +21,9 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + + "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/oidc" ) var ( @@ -37,3 +40,11 @@ func InitClient(cfg *rest.Config) { func GetClient() dynamic.Interface { return c } + +func GetClientByIDToken(idtoken string) (dynamic.Interface, error) { + cfg, err := clientcmd.BuildConfigFromKubeconfigGetter("", oidc.OIDCKubeGetter(idtoken)) + if err != nil { + return nil, err + } + return dynamic.NewForConfig(cfg) +} diff --git a/graphql-server/go-server/pkg/datasource/datasource.go b/graphql-server/go-server/pkg/datasource/datasource.go index d7d850cc1..7a36150e3 100644 --- a/graphql-server/go-server/pkg/datasource/datasource.go +++ b/graphql-server/go-server/pkg/datasource/datasource.go @@ -23,10 +23,10 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/dynamic" "github.com/kubeagi/arcadia/api/v1alpha1" "github.com/kubeagi/arcadia/graphql-server/go-server/graph/model" - "github.com/kubeagi/arcadia/graphql-server/go-server/pkg/client" ) func datasource2model(obj *unstructured.Unstructured) *model.Datasource { @@ -58,8 +58,7 @@ func datasource2model(obj *unstructured.Unstructured) *model.Datasource { return &md } -func CreateDatasource(ctx context.Context, name, namespace, url, authsecret string, insecure bool) (*model.Datasource, error) { - c := client.GetClient() +func CreateDatasource(ctx context.Context, c dynamic.Interface, name, namespace, url, authsecret string, insecure bool) (*model.Datasource, error) { datasource := v1alpha1.Datasource{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -70,10 +69,10 @@ func CreateDatasource(ctx context.Context, name, namespace, url, authsecret stri APIVersion: v1alpha1.GroupVersion.String(), }, Spec: v1alpha1.DatasourceSpec{ - Enpoint: v1alpha1.Endpoint{ + Enpoint: &v1alpha1.Endpoint{ URL: url, AuthSecret: &v1alpha1.TypedObjectReference{ - Kind: "secret", + Kind: "Secret", Name: authsecret, }, Insecure: insecure, @@ -94,9 +93,8 @@ func CreateDatasource(ctx context.Context, name, namespace, url, authsecret stri return ds, nil } -func DatasourceList(ctx context.Context, name, namespace, labelSelector, fieldSelector string) ([]*model.Datasource, error) { +func DatasourceList(ctx context.Context, c dynamic.Interface, name, namespace, labelSelector, fieldSelector string) ([]*model.Datasource, error) { dsSchema := schema.GroupVersionResource{Group: v1alpha1.GroupVersion.Group, Version: v1alpha1.GroupVersion.Version, Resource: "datasources"} - c := client.GetClient() if name != "" { u, err := c.Resource(dsSchema).Namespace(namespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { diff --git a/graphql-server/go-server/pkg/oidc/oidc.go b/graphql-server/go-server/pkg/oidc/oidc.go new file mode 100644 index 000000000..38f3f576a --- /dev/null +++ b/graphql-server/go-server/pkg/oidc/oidc.go @@ -0,0 +1,93 @@ +/* +Copyright 2023 KubeAGI. + +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 oidc + +import ( + "context" + "crypto/tls" + "net/http" + "sync" + + "github.com/coreos/go-oidc/v3/oidc" + clientcmdapi "k8s.io/client-go/tools/clientcmd/api" + "k8s.io/klog/v2" +) + +var ( + once sync.Once + Verifier *oidc.IDTokenVerifier + + issuerURL1, masterURL1, clientSecret1, clientID1 string +) + +func InitOIDCArgs(issuerURL, masterURL, clientSecret, clientID string) { + once.Do(func() { + issuerURL1 = issuerURL + masterURL1 = masterURL + clientSecret1 = clientSecret + clientID1 = clientID + + ctx := oidc.ClientContext(context.TODO(), &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + }, + }) + provider, err := oidc.NewProvider(ctx, issuerURL) + if err != nil { + panic(err) + } + Verifier = provider.Verifier(&oidc.Config{ClientID: clientID}) + klog.V(5).Infof("oidc token validation was successful. issuerurl: %s, masterurl: %s, clientid: %s, clientsecret: %s", issuerURL1, masterURL1, clientID1, clientSecret1) + }) +} + +func OIDCKubeGetter(idtoken string) func() (*clientcmdapi.Config, error) { + return func() (*clientcmdapi.Config, error) { + return &clientcmdapi.Config{ + Kind: "Config", + APIVersion: "v1", + Clusters: map[string]*clientcmdapi.Cluster{ + "kube-oidc-proxy": { + Server: masterURL1, + InsecureSkipTLSVerify: true, + }, + }, + Contexts: map[string]*clientcmdapi.Context{ + "oidc@kube-oidc-proxy": { + Cluster: "kube-oidc-proxy", + AuthInfo: "oidc", + }, + }, + CurrentContext: "oidc@kube-oidc-proxy", + AuthInfos: map[string]*clientcmdapi.AuthInfo{ + "oidc": { + AuthProvider: &clientcmdapi.AuthProviderConfig{ + Name: "oidc", + Config: map[string]string{ + "client-id": clientID1, + "client-secret": clientID1, + "id-token": idtoken, + "idp-issuer-url": issuerURL1, + }, + }, + }, + }, + }, nil + } +} diff --git a/hack/install-operator-sdk.sh b/hack/install-operator-sdk.sh index e7abb7b8b..84e3d18b9 100755 --- a/hack/install-operator-sdk.sh +++ b/hack/install-operator-sdk.sh @@ -5,7 +5,9 @@ ARCH=$(go env GOARCH) OS=$(go env GOOS) URL="https://github.com/operator-framework/operator-sdk/releases/download/${OPERATOR_SDK_VERSION}/operator-sdk_${OS}_${ARCH}" -operator_sdk_version=$(operator-sdk version) +if command -v operator-sdk &> /dev/null; then + operator_sdk_version=$(operator-sdk version) +fi if echo $operator_sdk_version | grep -q "$OPERATOR_SDK_VERSION"; then echo "operator-sdk version ${OPERATOR_SDK_VERSION} found, exiting..." @@ -13,6 +15,7 @@ if echo $operator_sdk_version | grep -q "$OPERATOR_SDK_VERSION"; then fi echo "Installing operator-sdk version ${OPERATOR_SDK_VERSION} to /usr/local/bin/operator-sdk" +echo "$URL" curl -L $URL > operator-sdk chmod +x operator-sdk sudo mv operator-sdk /usr/local/bin diff --git a/kubeagi.yaml b/kubeagi.yaml new file mode 100644 index 000000000..20e4a9c3e --- /dev/null +++ b/kubeagi.yaml @@ -0,0 +1,30 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: arcadia +--- +apiVersion: core.kubebb.k8s.com.cn/v1alpha1 +kind: Repository +metadata: + name: kubeagi + namespace: arcadia +spec: + url: https://kubeagi.github.io/arcadia + pullStategy: + intervalSeconds: 120 + retry: 5 +--- +apiVersion: core.kubebb.k8s.com.cn/v1alpha1 +kind: Subscription +metadata: + name: arcadia + namespace: arcadia +spec: + name: arcadia # release name in helm + componentPlanInstallMethod: auto + component: + name: kubeagi.arcadia + namespace: arcadia + override: + set: + - deployment.imagePullPolcy=Always \ No newline at end of file diff --git a/llms/Dockerfile b/llms/Dockerfile deleted file mode 100644 index fa623c2f1..000000000 --- a/llms/Dockerfile +++ /dev/null @@ -1,15 +0,0 @@ -# FROM python:3.12.0b4-alpine3.18 -# FROM ubuntu:22.04 -FROM nvidia/cuda:11.7.1-runtime-ubuntu22.04 - -RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list -RUN sed -i 's/security.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list - -RUN apt update -y && apt upgrade -y && apt install -y python3 curl -RUN apt install python3-pip -y -# RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories -# RUN apk add curl py3-pip py3-setuptools -# RUN curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py -# RUN python3 get-pip.py -RUN pip3 install fschat -i https://pypi.mirrors.ustc.edu.cn/simple/ - diff --git a/llms/Dockerfile.server b/llms/Dockerfile.server new file mode 100644 index 000000000..7f29f6168 --- /dev/null +++ b/llms/Dockerfile.server @@ -0,0 +1,15 @@ +FROM python:3.9-slim + +ENV TZ=Asia/Shanghai + +RUN sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list +RUN sed -i 's/security.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list + +RUN export DEBIAN_FRONTEND=noninteractive \ + && apt-get update \ + && apt-get install -y tzdata \ + && ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && dpkg-reconfigure --frontend noninteractive tzdata + +RUN apt-get update -y && apt-get install -y python3.9-distutils curl python3-pip +RUN pip3 install fschat -i https://pypi.mirrors.ustc.edu.cn/simple/ \ No newline at end of file diff --git a/llms/docker-compose.yml b/llms/docker-compose.yml index 57b5d3198..11c25996b 100644 --- a/llms/docker-compose.yml +++ b/llms/docker-compose.yml @@ -4,7 +4,7 @@ services: fastchat-controller: build: context: . - dockerfile: Dockerfile + dockerfile: Dockerfile.server image: kubebb/arcadia-llms:latest ports: - "21001:21001" @@ -12,7 +12,7 @@ services: fastchat-api-server: build: context: . - dockerfile: Dockerfile + dockerfile: Dockerfile.server image: kubebb/arcadia-llms:latest ports: - "8000:8000" diff --git a/main.go b/main.go index ce83331e5..5655a6bfa 100644 --- a/main.go +++ b/main.go @@ -159,6 +159,20 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "Embedder") os.Exit(1) } + if err = (&controllers.DatasetReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Dataset") + os.Exit(1) + } + if err = (&controllers.VersionedDatasetReconciler{ + Client: mgr.GetClient(), + Scheme: mgr.GetScheme(), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "VersionedDataset") + os.Exit(1) + } //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { @@ -184,10 +198,3 @@ func main() { os.Exit(1) } } - -// TODO: Defines the configuration for the Arcadia controller and implement the config parser -// Config defines the configuration for the Arcadia controller -type Config struct { - // SystemDatasource specifies the built-in datasource for Arcadia to host data files and model files - SystemDatasource arcadiav1alpha1.TypedObjectReference -} diff --git a/pkg/config/config.go b/pkg/config/config.go new file mode 100644 index 000000000..9da09a7fd --- /dev/null +++ b/pkg/config/config.go @@ -0,0 +1,110 @@ +/* +Copyright 2023 KubeAGI. + +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 config + +import ( + "context" + "fmt" + "os" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/utils/env" + "sigs.k8s.io/controller-runtime/pkg/client" + + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" +) + +const ( + EnvConfigKey = "DEFAULT_CONFIG" + EnvConfigDefaultValue = "arcadia-config" + EnvNamespaceKey = "POD_NAMESPACE" + + InClusterNamespacePath = "/var/run/secrets/kubernetes.io/serviceaccount/namespace" +) + +var ( + ErrNoConfigEnv = fmt.Errorf("env:%s is not found", EnvConfigKey) + ErrNoConfig = fmt.Errorf("config in configmap is empty") + ErrNoNamespaceEnv = fmt.Errorf("not in cluster and env:%s is not found", EnvNamespaceKey) +) + +func GetSystemDatasource(ctx context.Context, c client.Client) (*arcadiav1alpha1.Datasource, error) { + config, err := GetConfig(ctx, c) + if err != nil { + return nil, err + } + name := config.SystemDatasource.Name + var namespace string + if config.SystemDatasource.Namespace != nil { + namespace = *config.SystemDatasource.Namespace + } else { + namespace, err = GetSelfNamespace() + if err != nil { + return nil, err + } + } + source := &arcadiav1alpha1.Datasource{} + if err = c.Get(ctx, client.ObjectKey{Name: name, Namespace: namespace}, source); err != nil { + return nil, err + } + return source, err +} + +func GetConfig(ctx context.Context, c client.Client) (config *Config, err error) { + cmName := env.GetString(EnvConfigKey, EnvConfigDefaultValue) + if cmName == "" { + return nil, ErrNoConfigEnv + } + cmNamespace, err := GetSelfNamespace() + if err != nil { + return nil, err + } + cm := &corev1.ConfigMap{} + if err = c.Get(ctx, client.ObjectKey{Name: cmName, Namespace: cmNamespace}, cm); err != nil { + return nil, err + } + value, ok := cm.Data["config"] + if !ok || len(value) == 0 { + return nil, ErrNoConfig + } + if err = yaml.Unmarshal([]byte(value), &config); err != nil { + return nil, err + } + return config, nil +} + +func GetSelfNamespace() (string, error) { + // Check whether the namespace file exists. + // If not, we are not running in cluster so can't guess the namespace. + if _, err := os.Stat(InClusterNamespacePath); os.IsNotExist(err) { + operatorNamespace := os.Getenv(EnvNamespaceKey) + if operatorNamespace == "" { + return "", ErrNoNamespaceEnv + } + return operatorNamespace, nil + } else if err != nil { + return "", fmt.Errorf("error checking namespace file: %w", err) + } + + // Load the namespace file and return its content + namespace, err := os.ReadFile(InClusterNamespacePath) + if err != nil { + return "", fmt.Errorf("error reading namespace file: %w", err) + } + return string(namespace), nil +} diff --git a/pkg/config/config_type.go b/pkg/config/config_type.go new file mode 100644 index 000000000..bc62710c9 --- /dev/null +++ b/pkg/config/config_type.go @@ -0,0 +1,27 @@ +/* +Copyright 2023 KubeAGI. + +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 config + +import ( + arcadiav1alpha1 "github.com/kubeagi/arcadia/api/v1alpha1" +) + +// Config defines the configuration for the Arcadia controller +type Config struct { + // SystemDatasource specifies the built-in datasource for Arcadia to host data files and model files + SystemDatasource arcadiav1alpha1.TypedObjectReference `json:"systemDatasource,omitempty"` +} diff --git a/pkg/datasource/datasource.go b/pkg/datasource/datasource.go index b62bc6c1d..b61f8002c 100644 --- a/pkg/datasource/datasource.go +++ b/pkg/datasource/datasource.go @@ -31,12 +31,15 @@ import ( var ( ErrUnknowDatasourceType = errors.New("unknow datasource type") + ErrOSSNoSuchBucket = errors.New("NoSuchBucket") ) type Datasource interface { - Check(ctx context.Context, options any) error + Check(ctx context.Context, info any) error } +var _ Datasource = (*Unknown)(nil) + type Unknown struct { } @@ -44,17 +47,48 @@ func NewUnknown(ctx context.Context, c client.Client) (*Unknown, error) { return &Unknown{}, nil } -func (u *Unknown) Check(ctx context.Context, options any) error { +func (u *Unknown) Check(ctx context.Context, info any) error { return ErrUnknowDatasourceType } +var _ Datasource = (*Local)(nil) + +// Local is a special datasource which use the system datasource as oss to store user-uploaded local files +// - `oss` in `Local` represents the system datasource oss client along with the `Local`'s oss info +type Local struct { + oss *OSS +} + +func NewLocal(ctx context.Context, c client.Client, endpoint *v1alpha1.Endpoint) (*Local, error) { + oss, err := NewOSS(ctx, c, endpoint) + if err != nil { + return nil, err + } + return &Local{oss: oss}, nil +} + +// Check `Local` with `OSS` +func (local *Local) Check(ctx context.Context, options any) (err error) { + err = local.oss.Check(ctx, options) + if err != nil && errors.Is(err, ErrOSSNoSuchBucket) { + ossInfo, ok := options.(*v1alpha1.OSS) + if !ok { + return errors.New("invalid check info for OSS") + } + defautlMakeBucketOptions := minio.MakeBucketOptions{} + err = local.oss.MakeBucket(ctx, ossInfo.Bucket, defautlMakeBucketOptions) + } + return err +} + var _ Datasource = (*OSS)(nil) +// OSS is a wrapper to object storage service type OSS struct { *minio.Client } -func NewOSS(ctx context.Context, c client.Client, endpoint *v1alpha1.Endpoint, ossInfo *v1alpha1.OSS) (*OSS, error) { +func NewOSS(ctx context.Context, c client.Client, endpoint *v1alpha1.Endpoint) (*OSS, error) { var accessKeyID, secretAccessKey string if endpoint.AuthSecret != nil { secret := corev1.Secret{} @@ -65,7 +99,7 @@ func NewOSS(ctx context.Context, c client.Client, endpoint *v1alpha1.Endpoint, o return nil, err } accessKeyID = string(secret.Data["rootUser"]) - secretAccessKey = string(secret.Data["rootUser"]) + secretAccessKey = string(secret.Data["rootPassword"]) // TODO: implement https(secure check) // if !endpoint.Insecure { @@ -83,7 +117,31 @@ func NewOSS(ctx context.Context, c client.Client, endpoint *v1alpha1.Endpoint, o return &OSS{Client: mc}, nil } -// TODO: implement Check with specific `options` -func (oss *OSS) Check(ctx context.Context, options any) error { +// Check oss agains info() +func (oss *OSS) Check(ctx context.Context, info any) error { + if info == nil { + return nil + } + ossInfo, ok := info.(*v1alpha1.OSS) + if !ok { + return errors.New("invalid check info for OSS") + } + + if ossInfo.Bucket != "" { + exist, err := oss.Client.BucketExists(ctx, ossInfo.Bucket) + if err != nil { + return err + } + if !exist { + return ErrOSSNoSuchBucket + } + + if ossInfo.Object != "" { + _, err := oss.Client.StatObject(ctx, ossInfo.Bucket, ossInfo.Object, minio.StatObjectOptions{}) + if err != nil { + return err + } + } + } return nil } diff --git a/config/samples/example-test.sh b/tests/example-test.sh similarity index 86% rename from config/samples/example-test.sh rename to tests/example-test.sh index 11b77df91..a23fb0a27 100755 --- a/config/samples/example-test.sh +++ b/tests/example-test.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright contributors to the Kubebb Core project +# Copyright contributors to the KubeAGI project # # SPDX-License-Identifier: Apache-2.0 # @@ -32,7 +32,7 @@ KindConfigPath=${TempFilePath}/kind-config.yaml InstallDirPath=${TempFilePath}/building-base DefaultPassWord=${DefaultPassWord:-'passw0rd'} LOG_DIR=${LOG_DIR:-"/tmp/kubeagi-example-test/logs"} -RootPath=$(dirname -- "$(readlink -f -- "$0")")/../.. +RootPath=$(dirname -- "$(readlink -f -- "$0")")/.. Timeout="${TimeoutSeconds}s" mkdir ${TempFilePath} || true @@ -169,26 +169,28 @@ function waitCRDStatusReady() { sleep 5 done } + info "1. create kind cluster" make kind -info "2. install minio as arcadia oss" -info "2.1 add repo kubebb" -helm repo add kubebb https://kubebb.github.io/components/ -helm repo update -info "2.2 install minio" -kubectl create namespace arcadia -helm install arcadia-oss -n arcadia kubebb/minio -waitPodReady "arcadia" "release=arcadia-oss" - -info "3. install arcadia" +info "2. load arcadia image to kind" docker tag controller:latest controller:example-e2e kind load docker-image controller:example-e2e --name=$KindName -make deploy IMG="controller:example-e2e" -kubectl wait deploy -n arcadia arcadia-controller-manager --for condition=Available=True --timeout=$Timeout -info "4. CRD datasource check" -kubectl apply -f config/samples/arcadia_v1alpha1_datasource.yaml -waitCRDStatusReady "Datasource" "arcadia" "arcadia-oss-minio" +info "3. install arcadia" +kubectl create namespace arcadia +helm install -narcadia arcadia charts/arcadia --set deployment.image=controller:example-e2e + +info "4. check system datasource arcadia-minio(system datasource)" +waitCRDStatusReady "Datasource" "arcadia" "arcadia-minio" + +info "5. create and verify local datasource" +kubectl apply -f config/samples/arcadia_v1alpha1_local_datasource.yaml +waitCRDStatusReady "Datasource" "arcadia" "arcadia-local" +datasourceType=$(kubectl get datasource -n arcadia arcadia-local -o=jsonpath='{.metadata.labels.arcadia\.kubeagi\.k8s\.com\.cn/datasource-type}') +if [[ $datasourceType != "local" ]]; then + error "Datasource should local but got $datasourceType" + exit 1 +fi info "all finished! ✅"