diff --git a/CHANGELOG.md b/CHANGELOG.md index 62ec2706f..aef9ff628 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ - (Feature) (Integration) Services Endpoint - (Feature) (Platform) Storage - (Maintenance) Extract GRPC Client Package +- (Feature) (Platform) Chart ## [1.2.43](https://github.com/arangodb/kube-arangodb/tree/1.2.43) (2024-10-14) - (Feature) ArangoRoute CRD diff --git a/Makefile b/Makefile index 4a0e11d9c..0ebfab476 100644 --- a/Makefile +++ b/Makefile @@ -922,7 +922,8 @@ CRDS:=apps-job \ ml-storage ml-extension ml-job-batch ml-job-cron \ scheduler-profile scheduler-pod scheduler-deployment scheduler-batchjob scheduler-cronjob \ analytics-graphanalyticsengine \ - networking-route + networking-route \ + platform-storage platform-chart .PHONY: sync sync: diff --git a/README.md b/README.md index f2833c9dc..4de555f57 100644 --- a/README.md +++ b/README.md @@ -195,7 +195,7 @@ Flags: --kubernetes.max-batch-size int Size of batch during objects read (default 256) --kubernetes.qps float32 Number of queries per second for k8s API (default 15) --log.format string Set log format. Allowed values: 'pretty', 'JSON'. If empty, default format is used (default "pretty") - --log.level stringArray Set log levels in format or =. Possible loggers: action, agency, api-server, assertion, backup-operator, chaos-monkey, crd, deployment, deployment-ci, deployment-reconcile, deployment-replication, deployment-resilience, deployment-resources, deployment-storage, deployment-storage-pc, deployment-storage-service, generic-parent-operator, helm, http, inspector, integration-config-v1, integration-envoy-auth-v3, integration-scheduler-v2, integration-storage-v2, integrations, k8s-client, kubernetes-informer, monitor, networking-route-operator, operator, operator-arangojob-handler, operator-v2, operator-v2-event, operator-v2-worker, panics, platform-storage-operator, pod_compare, root, root-event-recorder, scheduler-batchjob-operator, scheduler-cronjob-operator, scheduler-deployment-operator, scheduler-pod-operator, scheduler-profile-operator, server, server-authentication (default [info]) + --log.level stringArray Set log levels in format or =. Possible loggers: action, agency, api-server, assertion, backup-operator, chaos-monkey, crd, deployment, deployment-ci, deployment-reconcile, deployment-replication, deployment-resilience, deployment-resources, deployment-storage, deployment-storage-pc, deployment-storage-service, generic-parent-operator, helm, http, inspector, integration-config-v1, integration-envoy-auth-v3, integration-scheduler-v2, integration-storage-v2, integrations, k8s-client, kubernetes-informer, monitor, networking-route-operator, operator, operator-arangojob-handler, operator-v2, operator-v2-event, operator-v2-worker, panics, platform-chart-operator, platform-storage-operator, pod_compare, root, root-event-recorder, scheduler-batchjob-operator, scheduler-cronjob-operator, scheduler-deployment-operator, scheduler-pod-operator, scheduler-profile-operator, server, server-authentication (default [info]) --log.sampling If true, operator will try to minimize duplication of logging events (default true) --memory-limit uint Define memory limit for hard shutdown and the dump of goroutines. Used for testing --metrics.excluded-prefixes stringArray List of the excluded metrics prefixes diff --git a/chart/kube-arangodb-arm64/crds/platform-chart.yaml b/chart/kube-arangodb-arm64/crds/platform-chart.yaml new file mode 100644 index 000000000..eb217d6b7 --- /dev/null +++ b/chart/kube-arangodb-arm64/crds/platform-chart.yaml @@ -0,0 +1,25 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: arangoplatformcharts.platform.arangodb.com +spec: + group: platform.arangodb.com + names: + kind: ArangoPlatformChart + listKind: ArangoPlatformChartList + plural: arangoplatformcharts + singular: arangoplatformchart + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + served: true + storage: true + subresources: + status: {} + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas diff --git a/chart/kube-arangodb-arm64/templates/platform-operator/role.yaml b/chart/kube-arangodb-arm64/templates/platform-operator/role.yaml index c97eec0cb..dbcd866fe 100644 --- a/chart/kube-arangodb-arm64/templates/platform-operator/role.yaml +++ b/chart/kube-arangodb-arm64/templates/platform-operator/role.yaml @@ -14,10 +14,11 @@ metadata: release: {{ .Release.Name }} rules: - apiGroups: ["platform.arangodb.com"] - resources: ["arangoplatformstorages", "arangoplatformstorages/status"] + resources: + - "arangoplatformstorages" + - "arangoplatformstorages/status" + - "arangoplatformcharts" + - "arangoplatformcharts/status" verbs: ["*"] - - apiGroups: [""] - resources: ["pods", "services", "endpoints"] - verbs: ["get", "list", "watch"] {{- end }} {{- end }} \ No newline at end of file diff --git a/chart/kube-arangodb-enterprise-arm64/crds/platform-chart.yaml b/chart/kube-arangodb-enterprise-arm64/crds/platform-chart.yaml new file mode 100644 index 000000000..eb217d6b7 --- /dev/null +++ b/chart/kube-arangodb-enterprise-arm64/crds/platform-chart.yaml @@ -0,0 +1,25 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: arangoplatformcharts.platform.arangodb.com +spec: + group: platform.arangodb.com + names: + kind: ArangoPlatformChart + listKind: ArangoPlatformChartList + plural: arangoplatformcharts + singular: arangoplatformchart + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + served: true + storage: true + subresources: + status: {} + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas diff --git a/chart/kube-arangodb-enterprise-arm64/templates/platform-operator/role.yaml b/chart/kube-arangodb-enterprise-arm64/templates/platform-operator/role.yaml index c97eec0cb..dbcd866fe 100644 --- a/chart/kube-arangodb-enterprise-arm64/templates/platform-operator/role.yaml +++ b/chart/kube-arangodb-enterprise-arm64/templates/platform-operator/role.yaml @@ -14,10 +14,11 @@ metadata: release: {{ .Release.Name }} rules: - apiGroups: ["platform.arangodb.com"] - resources: ["arangoplatformstorages", "arangoplatformstorages/status"] + resources: + - "arangoplatformstorages" + - "arangoplatformstorages/status" + - "arangoplatformcharts" + - "arangoplatformcharts/status" verbs: ["*"] - - apiGroups: [""] - resources: ["pods", "services", "endpoints"] - verbs: ["get", "list", "watch"] {{- end }} {{- end }} \ No newline at end of file diff --git a/chart/kube-arangodb-enterprise/crds/platform-chart.yaml b/chart/kube-arangodb-enterprise/crds/platform-chart.yaml new file mode 100644 index 000000000..eb217d6b7 --- /dev/null +++ b/chart/kube-arangodb-enterprise/crds/platform-chart.yaml @@ -0,0 +1,25 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: arangoplatformcharts.platform.arangodb.com +spec: + group: platform.arangodb.com + names: + kind: ArangoPlatformChart + listKind: ArangoPlatformChartList + plural: arangoplatformcharts + singular: arangoplatformchart + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + served: true + storage: true + subresources: + status: {} + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas diff --git a/chart/kube-arangodb-enterprise/templates/platform-operator/role.yaml b/chart/kube-arangodb-enterprise/templates/platform-operator/role.yaml index c97eec0cb..dbcd866fe 100644 --- a/chart/kube-arangodb-enterprise/templates/platform-operator/role.yaml +++ b/chart/kube-arangodb-enterprise/templates/platform-operator/role.yaml @@ -14,10 +14,11 @@ metadata: release: {{ .Release.Name }} rules: - apiGroups: ["platform.arangodb.com"] - resources: ["arangoplatformstorages", "arangoplatformstorages/status"] + resources: + - "arangoplatformstorages" + - "arangoplatformstorages/status" + - "arangoplatformcharts" + - "arangoplatformcharts/status" verbs: ["*"] - - apiGroups: [""] - resources: ["pods", "services", "endpoints"] - verbs: ["get", "list", "watch"] {{- end }} {{- end }} \ No newline at end of file diff --git a/chart/kube-arangodb/crds/platform-chart.yaml b/chart/kube-arangodb/crds/platform-chart.yaml new file mode 100644 index 000000000..eb217d6b7 --- /dev/null +++ b/chart/kube-arangodb/crds/platform-chart.yaml @@ -0,0 +1,25 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: arangoplatformcharts.platform.arangodb.com +spec: + group: platform.arangodb.com + names: + kind: ArangoPlatformChart + listKind: ArangoPlatformChartList + plural: arangoplatformcharts + singular: arangoplatformchart + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + served: true + storage: true + subresources: + status: {} + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas diff --git a/chart/kube-arangodb/templates/platform-operator/role.yaml b/chart/kube-arangodb/templates/platform-operator/role.yaml index c97eec0cb..dbcd866fe 100644 --- a/chart/kube-arangodb/templates/platform-operator/role.yaml +++ b/chart/kube-arangodb/templates/platform-operator/role.yaml @@ -14,10 +14,11 @@ metadata: release: {{ .Release.Name }} rules: - apiGroups: ["platform.arangodb.com"] - resources: ["arangoplatformstorages", "arangoplatformstorages/status"] + resources: + - "arangoplatformstorages" + - "arangoplatformstorages/status" + - "arangoplatformcharts" + - "arangoplatformcharts/status" verbs: ["*"] - - apiGroups: [""] - resources: ["pods", "services", "endpoints"] - verbs: ["get", "list", "watch"] {{- end }} {{- end }} \ No newline at end of file diff --git a/docs/api/ArangoPlatformChart.V1Alpha1.md b/docs/api/ArangoPlatformChart.V1Alpha1.md new file mode 100644 index 000000000..0db70ce01 --- /dev/null +++ b/docs/api/ArangoPlatformChart.V1Alpha1.md @@ -0,0 +1,14 @@ +--- +layout: page +parent: CRD reference +title: ArangoPlatformChart V1Alpha1 +--- + +# API Reference for ArangoPlatformChart V1Alpha1 + +## Spec + +### .spec.definition + +Type: `array` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.43/pkg/apis/platform/v1alpha1/chart_spec.go#L30) + diff --git a/docs/cli/arangodb_operator.md b/docs/cli/arangodb_operator.md index 2d0ae283b..e543ca2e9 100644 --- a/docs/cli/arangodb_operator.md +++ b/docs/cli/arangodb_operator.md @@ -80,7 +80,7 @@ Flags: --kubernetes.max-batch-size int Size of batch during objects read (default 256) --kubernetes.qps float32 Number of queries per second for k8s API (default 15) --log.format string Set log format. Allowed values: 'pretty', 'JSON'. If empty, default format is used (default "pretty") - --log.level stringArray Set log levels in format or =. Possible loggers: action, agency, api-server, assertion, backup-operator, chaos-monkey, crd, deployment, deployment-ci, deployment-reconcile, deployment-replication, deployment-resilience, deployment-resources, deployment-storage, deployment-storage-pc, deployment-storage-service, generic-parent-operator, helm, http, inspector, integration-config-v1, integration-envoy-auth-v3, integration-scheduler-v2, integration-storage-v2, integrations, k8s-client, kubernetes-informer, monitor, networking-route-operator, operator, operator-arangojob-handler, operator-v2, operator-v2-event, operator-v2-worker, panics, platform-storage-operator, pod_compare, root, root-event-recorder, scheduler-batchjob-operator, scheduler-cronjob-operator, scheduler-deployment-operator, scheduler-pod-operator, scheduler-profile-operator, server, server-authentication (default [info]) + --log.level stringArray Set log levels in format or =. Possible loggers: action, agency, api-server, assertion, backup-operator, chaos-monkey, crd, deployment, deployment-ci, deployment-reconcile, deployment-replication, deployment-resilience, deployment-resources, deployment-storage, deployment-storage-pc, deployment-storage-service, generic-parent-operator, helm, http, inspector, integration-config-v1, integration-envoy-auth-v3, integration-scheduler-v2, integration-storage-v2, integrations, k8s-client, kubernetes-informer, monitor, networking-route-operator, operator, operator-arangojob-handler, operator-v2, operator-v2-event, operator-v2-worker, panics, platform-chart-operator, platform-storage-operator, pod_compare, root, root-event-recorder, scheduler-batchjob-operator, scheduler-cronjob-operator, scheduler-deployment-operator, scheduler-pod-operator, scheduler-profile-operator, server, server-authentication (default [info]) --log.sampling If true, operator will try to minimize duplication of logging events (default true) --memory-limit uint Define memory limit for hard shutdown and the dump of goroutines. Used for testing --metrics.excluded-prefixes stringArray List of the excluded metrics prefixes diff --git a/internal/cr_validation_test.go b/internal/cr_validation_test.go index d8b4c0bc6..c3f37e3de 100644 --- a/internal/cr_validation_test.go +++ b/internal/cr_validation_test.go @@ -339,6 +339,15 @@ func Test_GenerateCRValidationSchemas(t *testing.T) { }, }, }, + "platform-chart": { + fmt.Sprintf("%s/pkg/apis/platform/v1alpha1", root): { + "v1alpha1": { + objects: map[string]interface{}{ + "spec": platformApi.ArangoPlatformChart{}.Spec, + }, + }, + }, + }, } for filePrefix, packagesToVersion := range input { diff --git a/internal/docs_test.go b/internal/docs_test.go index eb0a1f027..7e1ef4938 100644 --- a/internal/docs_test.go +++ b/internal/docs_test.go @@ -354,6 +354,9 @@ func Test_GenerateAPIDocs(t *testing.T) { "ArangoPlatformStorage.V1Alpha1": { "Spec": platformApi.ArangoPlatformStorage{}.Spec, }, + "ArangoPlatformChart.V1Alpha1": { + "Spec": platformApi.ArangoPlatformChart{}.Spec, + }, }, Shared: []string{ "shared/v1", diff --git a/pkg/apis/platform/definitions.go b/pkg/apis/platform/definitions.go index 00c51f4cf..aca71e0df 100644 --- a/pkg/apis/platform/definitions.go +++ b/pkg/apis/platform/definitions.go @@ -25,5 +25,9 @@ const ( ArangoPlatformStorageResourceKind = "ArangoPlatformStorage" ArangoPlatformStorageResourcePlural = "arangoplatformstorages" + ArangoPlatformChartCRDName = ArangoPlatformChartResourcePlural + "." + ArangoPlatformGroupName + ArangoPlatformChartResourceKind = "ArangoPlatformChart" + ArangoPlatformChartResourcePlural = "arangoplatformcharts" + ArangoPlatformGroupName = "platform.arangodb.com" ) diff --git a/pkg/apis/platform/v1alpha1/chart.go b/pkg/apis/platform/v1alpha1/chart.go new file mode 100644 index 000000000..81dd673c5 --- /dev/null +++ b/pkg/apis/platform/v1alpha1/chart.go @@ -0,0 +1,69 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package v1alpha1 + +import ( + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/arangodb/kube-arangodb/pkg/apis/platform" +) + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ArangoPlatformChartList is a list of ArangoPlatform Chart. +type ArangoPlatformChartList struct { + meta.TypeMeta `json:",inline"` + meta.ListMeta `json:"metadata,omitempty"` + + Items []ArangoPlatformChart `json:"items"` +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ArangoPlatformChart contains definition and status of the ArangoPlatform Chart. +type ArangoPlatformChart struct { + meta.TypeMeta `json:",inline"` + meta.ObjectMeta `json:"metadata,omitempty"` + + Spec ArangoPlatformChartSpec `json:"spec"` + Status ArangoPlatformChartStatus `json:"status"` +} + +// AsOwner creates an OwnerReference for the given Extension +func (a *ArangoPlatformChart) AsOwner() meta.OwnerReference { + trueVar := true + return meta.OwnerReference{ + APIVersion: SchemeGroupVersion.String(), + Kind: platform.ArangoPlatformChartResourceKind, + Name: a.Name, + UID: a.UID, + Controller: &trueVar, + } +} + +func (a *ArangoPlatformChart) GetStatus() ArangoPlatformChartStatus { + return a.Status +} + +func (a *ArangoPlatformChart) SetStatus(status ArangoPlatformChartStatus) { + a.Status = status +} diff --git a/pkg/apis/platform/v1alpha1/chart_details.go b/pkg/apis/platform/v1alpha1/chart_details.go new file mode 100644 index 000000000..4adcb0fee --- /dev/null +++ b/pkg/apis/platform/v1alpha1/chart_details.go @@ -0,0 +1,42 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package v1alpha1 + +type ChartDetails struct { + Name string `json:"name,omitempty"` + Version string `json:"version,omitempty"` +} + +func (c *ChartDetails) GetName() string { + if c == nil { + return "" + } + + return c.Name +} + +func (c *ChartDetails) GetVersion() string { + if c == nil { + return "" + } + + return c.Version +} diff --git a/pkg/apis/platform/v1alpha1/chart_spec.go b/pkg/apis/platform/v1alpha1/chart_spec.go new file mode 100644 index 000000000..3ba88a369 --- /dev/null +++ b/pkg/apis/platform/v1alpha1/chart_spec.go @@ -0,0 +1,43 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package v1alpha1 + +import ( + shared "github.com/arangodb/kube-arangodb/pkg/apis/shared" + sharedApi "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1" + "github.com/arangodb/kube-arangodb/pkg/util/errors" +) + +type ArangoPlatformChartSpec struct { + Definition sharedApi.Data `json:"definition,omitempty"` +} + +func (c *ArangoPlatformChartSpec) Validate() error { + if c == nil { + return errors.Errorf("Nil spec not allowed") + } + + if len(c.Definition) == 0 { + return shared.PrefixResourceError("definition", errors.Errorf("Chart definition cannot be empty")) + } + + return nil +} diff --git a/pkg/apis/platform/v1alpha1/chart_status.go b/pkg/apis/platform/v1alpha1/chart_status.go new file mode 100644 index 000000000..ac339703b --- /dev/null +++ b/pkg/apis/platform/v1alpha1/chart_status.go @@ -0,0 +1,33 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package v1alpha1 + +import ( + api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" +) + +type ArangoPlatformChartStatus struct { + Info *ChartStatusInfo `json:"info,omitempty"` + + // Conditions specific to the entire storage + // +doc/type: api.Conditions + Conditions api.ConditionList `json:"conditions,omitempty"` +} diff --git a/pkg/apis/platform/v1alpha1/chart_status_info.go b/pkg/apis/platform/v1alpha1/chart_status_info.go new file mode 100644 index 000000000..2ba370c15 --- /dev/null +++ b/pkg/apis/platform/v1alpha1/chart_status_info.go @@ -0,0 +1,33 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package v1alpha1 + +import sharedApi "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1" + +type ChartStatusInfo struct { + Definition sharedApi.Data `json:"definition,omitempty"` + Checksum string `json:"checksum,omitempty"` + + Valid bool `json:"valid,omitempty"` + Message string `json:"message,omitempty"` + + Details *ChartDetails `json:"details,omitempty"` +} diff --git a/pkg/apis/platform/v1alpha1/register.go b/pkg/apis/platform/v1alpha1/register.go index 6d7e98c95..d4fe51782 100644 --- a/pkg/apis/platform/v1alpha1/register.go +++ b/pkg/apis/platform/v1alpha1/register.go @@ -49,6 +49,8 @@ func addKnownTypes(s *runtime.Scheme) error { s.AddKnownTypes(SchemeGroupVersion, &ArangoPlatformStorage{}, &ArangoPlatformStorageList{}, + &ArangoPlatformChart{}, + &ArangoPlatformChartList{}, ) meta.AddToGroupVersion(s, SchemeGroupVersion) return nil diff --git a/pkg/apis/platform/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/platform/v1alpha1/zz_generated.deepcopy.go index 1b0fee98b..c7ccfbd4e 100644 --- a/pkg/apis/platform/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/platform/v1alpha1/zz_generated.deepcopy.go @@ -31,6 +31,116 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ArangoPlatformChart) DeepCopyInto(out *ArangoPlatformChart) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoPlatformChart. +func (in *ArangoPlatformChart) DeepCopy() *ArangoPlatformChart { + if in == nil { + return nil + } + out := new(ArangoPlatformChart) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ArangoPlatformChart) 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 *ArangoPlatformChartList) DeepCopyInto(out *ArangoPlatformChartList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ArangoPlatformChart, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoPlatformChartList. +func (in *ArangoPlatformChartList) DeepCopy() *ArangoPlatformChartList { + if in == nil { + return nil + } + out := new(ArangoPlatformChartList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ArangoPlatformChartList) 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 *ArangoPlatformChartSpec) DeepCopyInto(out *ArangoPlatformChartSpec) { + *out = *in + if in.Definition != nil { + in, out := &in.Definition, &out.Definition + *out = make(v1.Data, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoPlatformChartSpec. +func (in *ArangoPlatformChartSpec) DeepCopy() *ArangoPlatformChartSpec { + if in == nil { + return nil + } + out := new(ArangoPlatformChartSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ArangoPlatformChartStatus) DeepCopyInto(out *ArangoPlatformChartStatus) { + *out = *in + if in.Info != nil { + in, out := &in.Info, &out.Info + *out = new(ChartStatusInfo) + (*in).DeepCopyInto(*out) + } + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make(deploymentv1.ConditionList, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoPlatformChartStatus. +func (in *ArangoPlatformChartStatus) DeepCopy() *ArangoPlatformChartStatus { + if in == nil { + return nil + } + out := new(ArangoPlatformChartStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ArangoPlatformStorage) DeepCopyInto(out *ArangoPlatformStorage) { *out = *in @@ -244,3 +354,45 @@ func (in *ArangoPlatformStorageStatus) DeepCopy() *ArangoPlatformStorageStatus { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChartDetails) DeepCopyInto(out *ChartDetails) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChartDetails. +func (in *ChartDetails) DeepCopy() *ChartDetails { + if in == nil { + return nil + } + out := new(ChartDetails) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ChartStatusInfo) DeepCopyInto(out *ChartStatusInfo) { + *out = *in + if in.Definition != nil { + in, out := &in.Definition, &out.Definition + *out = make(v1.Data, len(*in)) + copy(*out, *in) + } + if in.Details != nil { + in, out := &in.Details, &out.Details + *out = new(ChartDetails) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ChartStatusInfo. +func (in *ChartStatusInfo) DeepCopy() *ChartStatusInfo { + if in == nil { + return nil + } + out := new(ChartStatusInfo) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/shared/v1/data.go b/pkg/apis/shared/v1/data.go new file mode 100644 index 000000000..b25c623f3 --- /dev/null +++ b/pkg/apis/shared/v1/data.go @@ -0,0 +1,59 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package v1 + +import ( + "encoding/base64" + "encoding/json" + + "github.com/arangodb/kube-arangodb/pkg/util" + "github.com/arangodb/kube-arangodb/pkg/util/errors" +) + +var _ json.Marshaler = &Data{} +var _ json.Unmarshaler = &Data{} + +type Data []byte + +func (d Data) MarshalJSON() ([]byte, error) { + s := base64.StdEncoding.EncodeToString(d) + + return json.Marshal(s) +} + +func (d Data) SHA256() string { + return util.SHA256(d) +} + +func (d *Data) UnmarshalJSON(bytes []byte) error { + if d == nil { + return errors.Errorf("nil object provided") + } + + ret, err := base64.StdEncoding.DecodeString(string(bytes)) + if err != nil { + return err + } + + *d = ret + + return nil +} diff --git a/pkg/apis/shared/v1/zz_generated.deepcopy.go b/pkg/apis/shared/v1/zz_generated.deepcopy.go index dc3842836..2940a876b 100644 --- a/pkg/apis/shared/v1/zz_generated.deepcopy.go +++ b/pkg/apis/shared/v1/zz_generated.deepcopy.go @@ -29,6 +29,26 @@ import ( types "k8s.io/apimachinery/pkg/types" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Data) DeepCopyInto(out *Data) { + { + in := &in + *out = make(Data, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Data. +func (in Data) DeepCopy() Data { + if in == nil { + return nil + } + out := new(Data) + in.DeepCopyInto(out) + return *out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in HashList) DeepCopyInto(out *HashList) { { diff --git a/pkg/crd/crds/crds.go b/pkg/crd/crds/crds.go index cd7de36ac..036c3f686 100644 --- a/pkg/crd/crds/crds.go +++ b/pkg/crd/crds/crds.go @@ -100,6 +100,7 @@ func AllDefinitions() []Definition { // Platform PlatformStorageDefinitionWithOptions(), + PlatformChartDefinitionWithOptions(), } } diff --git a/pkg/crd/crds/crds_test.go b/pkg/crd/crds/crds_test.go index 5fde00236..336749c50 100644 --- a/pkg/crd/crds/crds_test.go +++ b/pkg/crd/crds/crds_test.go @@ -31,6 +31,7 @@ import ( "github.com/arangodb/kube-arangodb/pkg/apis/backup" "github.com/arangodb/kube-arangodb/pkg/apis/deployment" "github.com/arangodb/kube-arangodb/pkg/apis/ml" + "github.com/arangodb/kube-arangodb/pkg/apis/platform" "github.com/arangodb/kube-arangodb/pkg/apis/replication" "github.com/arangodb/kube-arangodb/pkg/apis/scheduler" "github.com/arangodb/kube-arangodb/pkg/apis/storage" @@ -96,6 +97,8 @@ func Test_CRD(t *testing.T) { {scheduler.DeploymentCRDName, SchedulerDeploymentDefinitionWithOptions}, {scheduler.BatchJobCRDName, SchedulerBatchJobDefinitionWithOptions}, {scheduler.CronJobCRDName, SchedulerCronJobDefinitionWithOptions}, + {platform.ArangoPlatformStorageCRDName, PlatformStorageDefinitionWithOptions}, + {platform.ArangoPlatformChartCRDName, PlatformChartDefinitionWithOptions}, } for _, tc := range testCases { @@ -154,6 +157,7 @@ func Test_CRDGetters(t *testing.T) { AnalyticsGAEWithOptions, NetworkingRouteWithOptions, PlatformStorageWithOptions, + PlatformChartWithOptions, } require.Equal(t, len(AllDefinitions()), len(getters)) diff --git a/pkg/crd/crds/platform-chart.go b/pkg/crd/crds/platform-chart.go new file mode 100644 index 000000000..791eaf6ae --- /dev/null +++ b/pkg/crd/crds/platform-chart.go @@ -0,0 +1,51 @@ +// +// DISCLAIMER +// +// Copyright 2023-2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package crds + +import ( + _ "embed" + + apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" +) + +func PlatformChartWithOptions(opts ...func(*CRDOptions)) *apiextensions.CustomResourceDefinition { + return getCRD(PlatformChartDefinitionData(), opts...) +} + +func PlatformChartDefinitionWithOptions(opts ...func(*CRDOptions)) Definition { + return Definition{ + DefinitionData: PlatformChartDefinitionData(), + CRD: PlatformChartWithOptions(opts...), + } +} + +func PlatformChartDefinitionData() DefinitionData { + return DefinitionData{ + definition: platformChart, + schemaDefinition: platformChartSchemaRaw, + } +} + +//go:embed platform-chart.yaml +var platformChart []byte + +//go:embed platform-chart.schema.generated.yaml +var platformChartSchemaRaw []byte diff --git a/pkg/crd/crds/platform-chart.schema.generated.yaml b/pkg/crd/crds/platform-chart.schema.generated.yaml new file mode 100644 index 000000000..817296696 --- /dev/null +++ b/pkg/crd/crds/platform-chart.schema.generated.yaml @@ -0,0 +1,14 @@ +v1alpha1: + openAPIV3Schema: + properties: + spec: + properties: + definition: + format: byte + type: string + type: object + status: + description: Object with preserved fields for backward compatibility + type: object + x-kubernetes-preserve-unknown-fields: true + type: object diff --git a/pkg/crd/crds/platform-chart.yaml b/pkg/crd/crds/platform-chart.yaml new file mode 100644 index 000000000..eb217d6b7 --- /dev/null +++ b/pkg/crd/crds/platform-chart.yaml @@ -0,0 +1,25 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: arangoplatformcharts.platform.arangodb.com +spec: + group: platform.arangodb.com + names: + kind: ArangoPlatformChart + listKind: ArangoPlatformChartList + plural: arangoplatformcharts + singular: arangoplatformchart + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + type: object + x-kubernetes-preserve-unknown-fields: true + served: true + storage: true + subresources: + status: {} + scale: + specReplicasPath: .spec.replicas + statusReplicasPath: .status.replicas diff --git a/pkg/crd/platform.go b/pkg/crd/platform.go index 50ed29256..fa9f10a65 100644 --- a/pkg/crd/platform.go +++ b/pkg/crd/platform.go @@ -27,6 +27,7 @@ import ( func init() { defs := []func(...func(options *crds.CRDOptions)) crds.Definition{ crds.PlatformStorageDefinitionWithOptions, + crds.PlatformChartDefinitionWithOptions, } for _, getDef := range defs { defFn := getDef // bring into scope diff --git a/pkg/generated/clientset/versioned/typed/platform/v1alpha1/arangoplatformchart.go b/pkg/generated/clientset/versioned/typed/platform/v1alpha1/arangoplatformchart.go new file mode 100644 index 000000000..44d6495a9 --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/platform/v1alpha1/arangoplatformchart.go @@ -0,0 +1,73 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + + v1alpha1 "github.com/arangodb/kube-arangodb/pkg/apis/platform/v1alpha1" + scheme "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" +) + +// ArangoPlatformChartsGetter has a method to return a ArangoPlatformChartInterface. +// A group's client should implement this interface. +type ArangoPlatformChartsGetter interface { + ArangoPlatformCharts(namespace string) ArangoPlatformChartInterface +} + +// ArangoPlatformChartInterface has methods to work with ArangoPlatformChart resources. +type ArangoPlatformChartInterface interface { + Create(ctx context.Context, arangoPlatformChart *v1alpha1.ArangoPlatformChart, opts v1.CreateOptions) (*v1alpha1.ArangoPlatformChart, error) + Update(ctx context.Context, arangoPlatformChart *v1alpha1.ArangoPlatformChart, opts v1.UpdateOptions) (*v1alpha1.ArangoPlatformChart, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, arangoPlatformChart *v1alpha1.ArangoPlatformChart, opts v1.UpdateOptions) (*v1alpha1.ArangoPlatformChart, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.ArangoPlatformChart, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.ArangoPlatformChartList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ArangoPlatformChart, err error) + ArangoPlatformChartExpansion +} + +// arangoPlatformCharts implements ArangoPlatformChartInterface +type arangoPlatformCharts struct { + *gentype.ClientWithList[*v1alpha1.ArangoPlatformChart, *v1alpha1.ArangoPlatformChartList] +} + +// newArangoPlatformCharts returns a ArangoPlatformCharts +func newArangoPlatformCharts(c *PlatformV1alpha1Client, namespace string) *arangoPlatformCharts { + return &arangoPlatformCharts{ + gentype.NewClientWithList[*v1alpha1.ArangoPlatformChart, *v1alpha1.ArangoPlatformChartList]( + "arangoplatformcharts", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *v1alpha1.ArangoPlatformChart { return &v1alpha1.ArangoPlatformChart{} }, + func() *v1alpha1.ArangoPlatformChartList { return &v1alpha1.ArangoPlatformChartList{} }), + } +} diff --git a/pkg/generated/clientset/versioned/typed/platform/v1alpha1/fake/fake_arangoplatformchart.go b/pkg/generated/clientset/versioned/typed/platform/v1alpha1/fake/fake_arangoplatformchart.go new file mode 100644 index 000000000..9f10e028d --- /dev/null +++ b/pkg/generated/clientset/versioned/typed/platform/v1alpha1/fake/fake_arangoplatformchart.go @@ -0,0 +1,151 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1alpha1 "github.com/arangodb/kube-arangodb/pkg/apis/platform/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeArangoPlatformCharts implements ArangoPlatformChartInterface +type FakeArangoPlatformCharts struct { + Fake *FakePlatformV1alpha1 + ns string +} + +var arangoplatformchartsResource = v1alpha1.SchemeGroupVersion.WithResource("arangoplatformcharts") + +var arangoplatformchartsKind = v1alpha1.SchemeGroupVersion.WithKind("ArangoPlatformChart") + +// Get takes name of the arangoPlatformChart, and returns the corresponding arangoPlatformChart object, and an error if there is any. +func (c *FakeArangoPlatformCharts) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ArangoPlatformChart, err error) { + emptyResult := &v1alpha1.ArangoPlatformChart{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(arangoplatformchartsResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1alpha1.ArangoPlatformChart), err +} + +// List takes label and field selectors, and returns the list of ArangoPlatformCharts that match those selectors. +func (c *FakeArangoPlatformCharts) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ArangoPlatformChartList, err error) { + emptyResult := &v1alpha1.ArangoPlatformChartList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(arangoplatformchartsResource, arangoplatformchartsKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.ArangoPlatformChartList{ListMeta: obj.(*v1alpha1.ArangoPlatformChartList).ListMeta} + for _, item := range obj.(*v1alpha1.ArangoPlatformChartList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested arangoPlatformCharts. +func (c *FakeArangoPlatformCharts) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(arangoplatformchartsResource, c.ns, opts)) + +} + +// Create takes the representation of a arangoPlatformChart and creates it. Returns the server's representation of the arangoPlatformChart, and an error, if there is any. +func (c *FakeArangoPlatformCharts) Create(ctx context.Context, arangoPlatformChart *v1alpha1.ArangoPlatformChart, opts v1.CreateOptions) (result *v1alpha1.ArangoPlatformChart, err error) { + emptyResult := &v1alpha1.ArangoPlatformChart{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(arangoplatformchartsResource, c.ns, arangoPlatformChart, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1alpha1.ArangoPlatformChart), err +} + +// Update takes the representation of a arangoPlatformChart and updates it. Returns the server's representation of the arangoPlatformChart, and an error, if there is any. +func (c *FakeArangoPlatformCharts) Update(ctx context.Context, arangoPlatformChart *v1alpha1.ArangoPlatformChart, opts v1.UpdateOptions) (result *v1alpha1.ArangoPlatformChart, err error) { + emptyResult := &v1alpha1.ArangoPlatformChart{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(arangoplatformchartsResource, c.ns, arangoPlatformChart, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1alpha1.ArangoPlatformChart), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeArangoPlatformCharts) UpdateStatus(ctx context.Context, arangoPlatformChart *v1alpha1.ArangoPlatformChart, opts v1.UpdateOptions) (result *v1alpha1.ArangoPlatformChart, err error) { + emptyResult := &v1alpha1.ArangoPlatformChart{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(arangoplatformchartsResource, "status", c.ns, arangoPlatformChart, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1alpha1.ArangoPlatformChart), err +} + +// Delete takes name of the arangoPlatformChart and deletes it. Returns an error if one occurs. +func (c *FakeArangoPlatformCharts) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(arangoplatformchartsResource, c.ns, name, opts), &v1alpha1.ArangoPlatformChart{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeArangoPlatformCharts) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(arangoplatformchartsResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.ArangoPlatformChartList{}) + return err +} + +// Patch applies the patch and returns the patched arangoPlatformChart. +func (c *FakeArangoPlatformCharts) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ArangoPlatformChart, err error) { + emptyResult := &v1alpha1.ArangoPlatformChart{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(arangoplatformchartsResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1alpha1.ArangoPlatformChart), err +} diff --git a/pkg/generated/clientset/versioned/typed/platform/v1alpha1/fake/fake_platform_client.go b/pkg/generated/clientset/versioned/typed/platform/v1alpha1/fake/fake_platform_client.go index 285ad792a..0942ded58 100644 --- a/pkg/generated/clientset/versioned/typed/platform/v1alpha1/fake/fake_platform_client.go +++ b/pkg/generated/clientset/versioned/typed/platform/v1alpha1/fake/fake_platform_client.go @@ -32,6 +32,10 @@ type FakePlatformV1alpha1 struct { *testing.Fake } +func (c *FakePlatformV1alpha1) ArangoPlatformCharts(namespace string) v1alpha1.ArangoPlatformChartInterface { + return &FakeArangoPlatformCharts{c, namespace} +} + func (c *FakePlatformV1alpha1) ArangoPlatformStorages(namespace string) v1alpha1.ArangoPlatformStorageInterface { return &FakeArangoPlatformStorages{c, namespace} } diff --git a/pkg/generated/clientset/versioned/typed/platform/v1alpha1/generated_expansion.go b/pkg/generated/clientset/versioned/typed/platform/v1alpha1/generated_expansion.go index 6cf12f503..ecd4c552c 100644 --- a/pkg/generated/clientset/versioned/typed/platform/v1alpha1/generated_expansion.go +++ b/pkg/generated/clientset/versioned/typed/platform/v1alpha1/generated_expansion.go @@ -22,4 +22,6 @@ package v1alpha1 +type ArangoPlatformChartExpansion interface{} + type ArangoPlatformStorageExpansion interface{} diff --git a/pkg/generated/clientset/versioned/typed/platform/v1alpha1/platform_client.go b/pkg/generated/clientset/versioned/typed/platform/v1alpha1/platform_client.go index 51a078236..9825a5e0e 100644 --- a/pkg/generated/clientset/versioned/typed/platform/v1alpha1/platform_client.go +++ b/pkg/generated/clientset/versioned/typed/platform/v1alpha1/platform_client.go @@ -32,6 +32,7 @@ import ( type PlatformV1alpha1Interface interface { RESTClient() rest.Interface + ArangoPlatformChartsGetter ArangoPlatformStoragesGetter } @@ -40,6 +41,10 @@ type PlatformV1alpha1Client struct { restClient rest.Interface } +func (c *PlatformV1alpha1Client) ArangoPlatformCharts(namespace string) ArangoPlatformChartInterface { + return newArangoPlatformCharts(c, namespace) +} + func (c *PlatformV1alpha1Client) ArangoPlatformStorages(namespace string) ArangoPlatformStorageInterface { return newArangoPlatformStorages(c, namespace) } diff --git a/pkg/generated/informers/externalversions/generic.go b/pkg/generated/informers/externalversions/generic.go index 1dac5ea7c..af370ff0f 100644 --- a/pkg/generated/informers/externalversions/generic.go +++ b/pkg/generated/informers/externalversions/generic.go @@ -124,6 +124,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Networking().V1alpha1().ArangoRoutes().Informer()}, nil // Group=platform.arangodb.com, Version=v1alpha1 + case platformv1alpha1.SchemeGroupVersion.WithResource("arangoplatformcharts"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Platform().V1alpha1().ArangoPlatformCharts().Informer()}, nil case platformv1alpha1.SchemeGroupVersion.WithResource("arangoplatformstorages"): return &genericInformer{resource: resource.GroupResource(), informer: f.Platform().V1alpha1().ArangoPlatformStorages().Informer()}, nil diff --git a/pkg/generated/informers/externalversions/platform/v1alpha1/arangoplatformchart.go b/pkg/generated/informers/externalversions/platform/v1alpha1/arangoplatformchart.go new file mode 100644 index 000000000..d57a8961b --- /dev/null +++ b/pkg/generated/informers/externalversions/platform/v1alpha1/arangoplatformchart.go @@ -0,0 +1,94 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + platformv1alpha1 "github.com/arangodb/kube-arangodb/pkg/apis/platform/v1alpha1" + versioned "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned" + internalinterfaces "github.com/arangodb/kube-arangodb/pkg/generated/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/arangodb/kube-arangodb/pkg/generated/listers/platform/v1alpha1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// ArangoPlatformChartInformer provides access to a shared informer and lister for +// ArangoPlatformCharts. +type ArangoPlatformChartInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.ArangoPlatformChartLister +} + +type arangoPlatformChartInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewArangoPlatformChartInformer constructs a new informer for ArangoPlatformChart type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewArangoPlatformChartInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredArangoPlatformChartInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredArangoPlatformChartInformer constructs a new informer for ArangoPlatformChart type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredArangoPlatformChartInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.PlatformV1alpha1().ArangoPlatformCharts(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.PlatformV1alpha1().ArangoPlatformCharts(namespace).Watch(context.TODO(), options) + }, + }, + &platformv1alpha1.ArangoPlatformChart{}, + resyncPeriod, + indexers, + ) +} + +func (f *arangoPlatformChartInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredArangoPlatformChartInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *arangoPlatformChartInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&platformv1alpha1.ArangoPlatformChart{}, f.defaultInformer) +} + +func (f *arangoPlatformChartInformer) Lister() v1alpha1.ArangoPlatformChartLister { + return v1alpha1.NewArangoPlatformChartLister(f.Informer().GetIndexer()) +} diff --git a/pkg/generated/informers/externalversions/platform/v1alpha1/interface.go b/pkg/generated/informers/externalversions/platform/v1alpha1/interface.go index 991fdb0f3..ecd0dfa66 100644 --- a/pkg/generated/informers/externalversions/platform/v1alpha1/interface.go +++ b/pkg/generated/informers/externalversions/platform/v1alpha1/interface.go @@ -28,6 +28,8 @@ import ( // Interface provides access to all the informers in this group version. type Interface interface { + // ArangoPlatformCharts returns a ArangoPlatformChartInformer. + ArangoPlatformCharts() ArangoPlatformChartInformer // ArangoPlatformStorages returns a ArangoPlatformStorageInformer. ArangoPlatformStorages() ArangoPlatformStorageInformer } @@ -43,6 +45,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } +// ArangoPlatformCharts returns a ArangoPlatformChartInformer. +func (v *version) ArangoPlatformCharts() ArangoPlatformChartInformer { + return &arangoPlatformChartInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // ArangoPlatformStorages returns a ArangoPlatformStorageInformer. func (v *version) ArangoPlatformStorages() ArangoPlatformStorageInformer { return &arangoPlatformStorageInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/generated/listers/platform/v1alpha1/arangoplatformchart.go b/pkg/generated/listers/platform/v1alpha1/arangoplatformchart.go new file mode 100644 index 000000000..8c43e7c2a --- /dev/null +++ b/pkg/generated/listers/platform/v1alpha1/arangoplatformchart.go @@ -0,0 +1,74 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/arangodb/kube-arangodb/pkg/apis/platform/v1alpha1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/listers" + "k8s.io/client-go/tools/cache" +) + +// ArangoPlatformChartLister helps list ArangoPlatformCharts. +// All objects returned here must be treated as read-only. +type ArangoPlatformChartLister interface { + // List lists all ArangoPlatformCharts in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.ArangoPlatformChart, err error) + // ArangoPlatformCharts returns an object that can list and get ArangoPlatformCharts. + ArangoPlatformCharts(namespace string) ArangoPlatformChartNamespaceLister + ArangoPlatformChartListerExpansion +} + +// arangoPlatformChartLister implements the ArangoPlatformChartLister interface. +type arangoPlatformChartLister struct { + listers.ResourceIndexer[*v1alpha1.ArangoPlatformChart] +} + +// NewArangoPlatformChartLister returns a new ArangoPlatformChartLister. +func NewArangoPlatformChartLister(indexer cache.Indexer) ArangoPlatformChartLister { + return &arangoPlatformChartLister{listers.New[*v1alpha1.ArangoPlatformChart](indexer, v1alpha1.Resource("arangoplatformchart"))} +} + +// ArangoPlatformCharts returns an object that can list and get ArangoPlatformCharts. +func (s *arangoPlatformChartLister) ArangoPlatformCharts(namespace string) ArangoPlatformChartNamespaceLister { + return arangoPlatformChartNamespaceLister{listers.NewNamespaced[*v1alpha1.ArangoPlatformChart](s.ResourceIndexer, namespace)} +} + +// ArangoPlatformChartNamespaceLister helps list and get ArangoPlatformCharts. +// All objects returned here must be treated as read-only. +type ArangoPlatformChartNamespaceLister interface { + // List lists all ArangoPlatformCharts in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*v1alpha1.ArangoPlatformChart, err error) + // Get retrieves the ArangoPlatformChart from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.ArangoPlatformChart, error) + ArangoPlatformChartNamespaceListerExpansion +} + +// arangoPlatformChartNamespaceLister implements the ArangoPlatformChartNamespaceLister +// interface. +type arangoPlatformChartNamespaceLister struct { + listers.ResourceIndexer[*v1alpha1.ArangoPlatformChart] +} diff --git a/pkg/generated/listers/platform/v1alpha1/expansion_generated.go b/pkg/generated/listers/platform/v1alpha1/expansion_generated.go index 4a27a39b2..66f835ad4 100644 --- a/pkg/generated/listers/platform/v1alpha1/expansion_generated.go +++ b/pkg/generated/listers/platform/v1alpha1/expansion_generated.go @@ -22,6 +22,14 @@ package v1alpha1 +// ArangoPlatformChartListerExpansion allows custom methods to be added to +// ArangoPlatformChartLister. +type ArangoPlatformChartListerExpansion interface{} + +// ArangoPlatformChartNamespaceListerExpansion allows custom methods to be added to +// ArangoPlatformChartNamespaceLister. +type ArangoPlatformChartNamespaceListerExpansion interface{} + // ArangoPlatformStorageListerExpansion allows custom methods to be added to // ArangoPlatformStorageLister. type ArangoPlatformStorageListerExpansion interface{} diff --git a/pkg/handlers/platform/chart/chart_test.go b/pkg/handlers/platform/chart/chart_test.go new file mode 100644 index 000000000..99fcdecef --- /dev/null +++ b/pkg/handlers/platform/chart/chart_test.go @@ -0,0 +1,148 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package chart + +import ( + "testing" + + "github.com/stretchr/testify/require" + + platformApi "github.com/arangodb/kube-arangodb/pkg/apis/platform/v1alpha1" + "github.com/arangodb/kube-arangodb/pkg/operatorV2/operation" + "github.com/arangodb/kube-arangodb/pkg/util" + "github.com/arangodb/kube-arangodb/pkg/util/tests" +) + +func Test_ChartReconcile_EmptyChart(t *testing.T) { + handler := newFakeHandler() + + // Arrange + extension := tests.NewMetaObject[*platformApi.ArangoPlatformChart](t, tests.FakeNamespace, "example", + func(t *testing.T, obj *platformApi.ArangoPlatformChart) {}) + extension_invalid_name := tests.NewMetaObject[*platformApi.ArangoPlatformChart](t, tests.FakeNamespace, "example-wrong-name", + func(t *testing.T, obj *platformApi.ArangoPlatformChart) {}) + + refresh := tests.CreateObjects(t, handler.kubeClient, handler.client, &extension, &extension_invalid_name) + + t.Run("Missing chart", func(t *testing.T) { + // Test + require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension))) + + // Refresh + refresh(t) + + // Validate + require.False(t, extension.Status.Conditions.IsTrue(platformApi.SpecValidCondition)) + require.False(t, extension.Status.Conditions.IsTrue(platformApi.ReadyCondition)) + }) + + t.Run("Invalid chart", func(t *testing.T) { + // Arrange + tests.Apply(t, extension, func(t *testing.T, obj *platformApi.ArangoPlatformChart) { + obj.Spec.Definition = []byte("1234") + }) + tests.UpdateObjects(t, handler.kubeClient, handler.client, &extension) + + // Test + require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension))) + + // Refresh + refresh(t) + + // Validate + require.True(t, extension.Status.Conditions.IsTrue(platformApi.SpecValidCondition)) + require.NotNil(t, extension.Status.Info) + require.False(t, extension.Status.Info.Valid) + require.EqualValues(t, extension.Status.Info.Message, "Chart is invalid") + require.False(t, extension.Status.Conditions.IsTrue(platformApi.ReadyCondition)) + }) + + t.Run("Invalid chart name", func(t *testing.T) { + // Arrange + tests.Apply(t, extension_invalid_name, func(t *testing.T, obj *platformApi.ArangoPlatformChart) { + obj.Spec.Definition = chart_1_0 + }) + tests.UpdateObjects(t, handler.kubeClient, handler.client, &extension_invalid_name) + + // Test + require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension_invalid_name))) + + // Refresh + refresh(t) + + // Validate + require.True(t, extension_invalid_name.Status.Conditions.IsTrue(platformApi.SpecValidCondition)) + require.NotNil(t, extension_invalid_name.Status.Info) + require.False(t, extension_invalid_name.Status.Info.Valid) + require.EqualValues(t, extension_invalid_name.Status.Info.Message, "Chart Name mismatch") + require.False(t, extension_invalid_name.Status.Conditions.IsTrue(platformApi.ReadyCondition)) + }) + + t.Run("Valid chart 1.0.0", func(t *testing.T) { + // Arrange + tests.Apply(t, extension, func(t *testing.T, obj *platformApi.ArangoPlatformChart) { + obj.Spec.Definition = chart_1_0 + }) + tests.UpdateObjects(t, handler.kubeClient, handler.client, &extension) + + // Test + require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension))) + + // Refresh + refresh(t) + + // Validate + require.True(t, extension.Status.Conditions.IsTrue(platformApi.SpecValidCondition)) + require.NotNil(t, extension.Status.Info) + require.True(t, extension.Status.Info.Valid) + require.EqualValues(t, extension.Status.Info.Message, "") + require.NotNil(t, extension.Status.Info.Details) + require.EqualValues(t, "example", extension.Status.Info.Details.GetName()) + require.EqualValues(t, "1.0.0", extension.Status.Info.Details.GetVersion()) + require.EqualValues(t, util.SHA256(chart_1_0), extension.Status.Info.Checksum) + require.True(t, extension.Status.Conditions.IsTrue(platformApi.ReadyCondition)) + }) + + t.Run("Valid chart 1.1.0", func(t *testing.T) { + // Arrange + tests.Apply(t, extension, func(t *testing.T, obj *platformApi.ArangoPlatformChart) { + obj.Spec.Definition = chart_1_1 + }) + tests.UpdateObjects(t, handler.kubeClient, handler.client, &extension) + + // Test + require.NoError(t, tests.Handle(handler, tests.NewItem(t, operation.Update, extension))) + + // Refresh + refresh(t) + + // Validate + require.True(t, extension.Status.Conditions.IsTrue(platformApi.SpecValidCondition)) + require.NotNil(t, extension.Status.Info) + require.True(t, extension.Status.Info.Valid) + require.EqualValues(t, extension.Status.Info.Message, "") + require.NotNil(t, extension.Status.Info.Details) + require.EqualValues(t, "example", extension.Status.Info.Details.GetName()) + require.EqualValues(t, "1.1.0", extension.Status.Info.Details.GetVersion()) + require.EqualValues(t, util.SHA256(chart_1_1), extension.Status.Info.Checksum) + require.True(t, extension.Status.Conditions.IsTrue(platformApi.ReadyCondition)) + }) +} diff --git a/pkg/handlers/platform/chart/handler.go b/pkg/handlers/platform/chart/handler.go new file mode 100644 index 000000000..7b5cc9db8 --- /dev/null +++ b/pkg/handlers/platform/chart/handler.go @@ -0,0 +1,181 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package chart + +import ( + "context" + + "helm.sh/helm/v3/pkg/chart" + apiErrors "k8s.io/apimachinery/pkg/api/errors" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + + platformApi "github.com/arangodb/kube-arangodb/pkg/apis/platform/v1alpha1" + arangoClientSet "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned" + "github.com/arangodb/kube-arangodb/pkg/logging" + operator "github.com/arangodb/kube-arangodb/pkg/operatorV2" + "github.com/arangodb/kube-arangodb/pkg/operatorV2/event" + "github.com/arangodb/kube-arangodb/pkg/operatorV2/operation" + "github.com/arangodb/kube-arangodb/pkg/util" + "github.com/arangodb/kube-arangodb/pkg/util/k8sutil/helm" +) + +var logger = logging.Global().RegisterAndGetLogger("platform-chart-operator", logging.Info) + +type handler struct { + client arangoClientSet.Interface + kubeClient kubernetes.Interface + + eventRecorder event.RecorderInstance + + operator operator.Operator +} + +func (h *handler) Name() string { + return Kind() +} + +func (h *handler) Handle(ctx context.Context, item operation.Item) error { + // Get Backup object. It also covers NotFound case + object, err := util.WithKubernetesContextTimeoutP2A2(ctx, h.client.PlatformV1alpha1().ArangoPlatformCharts(item.Namespace).Get, item.Name, meta.GetOptions{}) + if err != nil { + if apiErrors.IsNotFound(err) { + return nil + } + + return err + } + + status := object.Status.DeepCopy() + + changed, reconcileErr := operator.HandleP3WithStop(ctx, item, object, status, h.handle) + if reconcileErr != nil && !operator.IsReconcile(reconcileErr) { + logger.Err(reconcileErr).Warn("Fail for %s %s/%s", + item.Kind, + item.Namespace, + item.Name) + + return reconcileErr + } + + if !changed { + return reconcileErr + } + + logger.Debug("Updating %s %s/%s", + item.Kind, + item.Namespace, + item.Name) + + if _, err := operator.WithArangoPlatformChartUpdateStatusInterfaceRetry(context.Background(), h.client.PlatformV1alpha1().ArangoPlatformCharts(object.GetNamespace()), object, *status, meta.UpdateOptions{}); err != nil { + return err + } + + return reconcileErr +} + +func (h *handler) handle(ctx context.Context, item operation.Item, extension *platformApi.ArangoPlatformChart, status *platformApi.ArangoPlatformChartStatus) (bool, error) { + return operator.HandleP3WithCondition(ctx, &status.Conditions, platformApi.ReadyCondition, item, extension, status, h.HandleSpecValidity, h.HandleSpecData) +} + +func (h *handler) HandleSpecValidity(ctx context.Context, item operation.Item, extension *platformApi.ArangoPlatformChart, status *platformApi.ArangoPlatformChartStatus) (bool, error) { + if err := extension.Spec.Validate(); err != nil { + // We have received an error in the spec! + + logger.Err(err).Warn("Invalid Spec on %s", item.String()) + + if status.Conditions.Update(platformApi.SpecValidCondition, false, "Spec is invalid", "Spec is invalid") { + return true, operator.Stop("Invalid spec") + } + return false, operator.Stop("Invalid spec") + } + + if status.Conditions.Update(platformApi.SpecValidCondition, true, "Spec is valid", "Spec is valid") { + return true, nil + } + + return false, nil +} + +func (h *handler) HandleSpecData(ctx context.Context, item operation.Item, extension *platformApi.ArangoPlatformChart, status *platformApi.ArangoPlatformChartStatus) (bool, error) { + if status.Info != nil { + if status.Info.Checksum != extension.Spec.Definition.SHA256() { + status.Info = nil + return true, operator.Reconcile("Spec changed") + } + + if !status.Info.Valid { + return false, operator.Stop("Invalid Chart") + } + + // All fine + return false, nil + } + + chart, err := helm.Chart(extension.Spec.Definition).Get() + if err != nil { + status.Info = &platformApi.ChartStatusInfo{ + Definition: extension.Spec.Definition, + Checksum: extension.Spec.Definition.SHA256(), + Valid: false, + Message: "Chart is invalid", + } + + return true, operator.Reconcile("Spec changed") + } + + if chart.Name() != extension.GetName() { + status.Info = &platformApi.ChartStatusInfo{ + Definition: extension.Spec.Definition, + Checksum: extension.Spec.Definition.SHA256(), + Valid: false, + Message: "Chart Name mismatch", + } + + return true, operator.Reconcile("Spec changed") + } + + status.Info = &platformApi.ChartStatusInfo{ + Definition: extension.Spec.Definition, + Checksum: extension.Spec.Definition.SHA256(), + Valid: true, + Details: chartInfoExtract(chart), + } + + return true, operator.Reconcile("Spec changed") +} + +func (h *handler) CanBeHandled(item operation.Item) bool { + return item.Group == Group() && + item.Version == Version() && + item.Kind == Kind() +} + +func chartInfoExtract(chart *chart.Chart) *platformApi.ChartDetails { + if chart == nil || chart.Metadata == nil { + return nil + } + + return &platformApi.ChartDetails{ + Name: chart.Name(), + Version: chart.Metadata.Version, + } +} diff --git a/pkg/handlers/platform/chart/handler_test.go b/pkg/handlers/platform/chart/handler_test.go new file mode 100644 index 000000000..ea10bb51d --- /dev/null +++ b/pkg/handlers/platform/chart/handler_test.go @@ -0,0 +1,59 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package chart + +import ( + "testing" + + "github.com/stretchr/testify/require" + apiErrors "k8s.io/apimachinery/pkg/api/errors" + + "github.com/arangodb/kube-arangodb/pkg/operatorV2/operation" + "github.com/arangodb/kube-arangodb/pkg/util/tests" +) + +func Test_ObjectNotFound(t *testing.T) { + // Arrange + handler := newFakeHandler() + + i := newItem(operation.Add, "test", "test") + + actions := map[operation.Operation]bool{ + operation.Add: false, + operation.Update: false, + operation.Delete: false, + } + + // Act + for operation, shouldFail := range actions { + t.Run(string(operation), func(t *testing.T) { + err := tests.Handle(handler, i) + + // Assert + if shouldFail { + require.Error(t, err) + require.True(t, apiErrors.IsNotFound(err)) + } else { + require.NoError(t, err) + } + }) + } +} diff --git a/pkg/handlers/platform/chart/local.go b/pkg/handlers/platform/chart/local.go new file mode 100644 index 000000000..803c075c5 --- /dev/null +++ b/pkg/handlers/platform/chart/local.go @@ -0,0 +1,38 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package chart + +import ( + "github.com/arangodb/kube-arangodb/pkg/apis/platform" + platformApi "github.com/arangodb/kube-arangodb/pkg/apis/platform/v1alpha1" +) + +func Kind() string { + return platform.ArangoPlatformChartResourceKind +} + +func Group() string { + return platformApi.SchemeGroupVersion.Group +} + +func Version() string { + return platformApi.SchemeGroupVersion.Version +} diff --git a/pkg/handlers/platform/chart/register.go b/pkg/handlers/platform/chart/register.go new file mode 100644 index 000000000..599f5c087 --- /dev/null +++ b/pkg/handlers/platform/chart/register.go @@ -0,0 +1,55 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package chart + +import ( + "k8s.io/client-go/kubernetes" + + arangoClientSet "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned" + arangoInformer "github.com/arangodb/kube-arangodb/pkg/generated/informers/externalversions" + operator "github.com/arangodb/kube-arangodb/pkg/operatorV2" + "github.com/arangodb/kube-arangodb/pkg/operatorV2/event" +) + +// RegisterInformer into operator +func RegisterInformer(operator operator.Operator, recorder event.Recorder, client arangoClientSet.Interface, kubeClient kubernetes.Interface, informer arangoInformer.SharedInformerFactory) error { + if err := operator.RegisterInformer(informer.Platform().V1alpha1().ArangoPlatformCharts().Informer(), + Group(), + Version(), + Kind()); err != nil { + return err + } + + h := &handler{ + client: client, + kubeClient: kubeClient, + + eventRecorder: recorder.NewInstance(Group(), Version(), Kind()), + + operator: operator, + } + + if err := operator.RegisterHandler(h); err != nil { + return err + } + + return nil +} diff --git a/pkg/handlers/platform/chart/suite/example-1.0.0.tgz b/pkg/handlers/platform/chart/suite/example-1.0.0.tgz new file mode 100644 index 000000000..c12100f2b Binary files /dev/null and b/pkg/handlers/platform/chart/suite/example-1.0.0.tgz differ diff --git a/pkg/handlers/platform/chart/suite/example-1.1.0.tgz b/pkg/handlers/platform/chart/suite/example-1.1.0.tgz new file mode 100644 index 000000000..462031cf1 Binary files /dev/null and b/pkg/handlers/platform/chart/suite/example-1.1.0.tgz differ diff --git a/pkg/handlers/platform/chart/suite_test.go b/pkg/handlers/platform/chart/suite_test.go new file mode 100644 index 000000000..ef95717f5 --- /dev/null +++ b/pkg/handlers/platform/chart/suite_test.go @@ -0,0 +1,67 @@ +// +// DISCLAIMER +// +// Copyright 2024 ArangoDB GmbH, Cologne, Germany +// +// 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. +// +// Copyright holder is ArangoDB GmbH, Cologne, Germany +// + +package chart + +import ( + _ "embed" + + "k8s.io/client-go/kubernetes/fake" + + "github.com/arangodb/kube-arangodb/pkg/apis/apps" + appsApi "github.com/arangodb/kube-arangodb/pkg/apis/apps/v1" + fakeClientSet "github.com/arangodb/kube-arangodb/pkg/generated/clientset/versioned/fake" + operator "github.com/arangodb/kube-arangodb/pkg/operatorV2" + "github.com/arangodb/kube-arangodb/pkg/operatorV2/event" + "github.com/arangodb/kube-arangodb/pkg/operatorV2/operation" +) + +//go:embed suite/example-1.0.0.tgz +var chart_1_0 []byte + +//go:embed suite/example-1.1.0.tgz +var chart_1_1 []byte + +func newFakeHandler() *handler { + f := fakeClientSet.NewSimpleClientset() + k := fake.NewSimpleClientset() + + h := &handler{ + client: f, + kubeClient: k, + eventRecorder: event.NewEventRecorder("mock", k).NewInstance(Group(), Version(), Kind()), + operator: operator.NewOperator("mock", "mock", "mock"), + } + + return h +} + +func newItem(o operation.Operation, namespace, name string) operation.Item { + return operation.Item{ + Group: appsApi.SchemeGroupVersion.Group, + Version: appsApi.SchemeGroupVersion.Version, + Kind: apps.ArangoJobResourceKind, + + Operation: o, + + Namespace: namespace, + Name: name, + } +} diff --git a/pkg/handlers/platform/storage/handler_deployment.go b/pkg/handlers/platform/storage/handler_deployment.go index 42f8df97d..f027a13f8 100644 --- a/pkg/handlers/platform/storage/handler_deployment.go +++ b/pkg/handlers/platform/storage/handler_deployment.go @@ -26,7 +26,6 @@ import ( apiErrors "k8s.io/apimachinery/pkg/api/errors" meta "k8s.io/apimachinery/pkg/apis/meta/v1" - networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1" platformApi "github.com/arangodb/kube-arangodb/pkg/apis/platform/v1alpha1" operator "github.com/arangodb/kube-arangodb/pkg/operatorV2" "github.com/arangodb/kube-arangodb/pkg/operatorV2/operation" @@ -51,7 +50,7 @@ func (h *handler) HandleArangoDeployment(ctx context.Context, item operation.Ite // Condition for Found should be set to true - if status.Conditions.UpdateWithHash(networkingApi.DeploymentFoundCondition, true, "ArangoDeployment found", "ArangoDeployment found", string(deployment.GetUID())) { + if status.Conditions.UpdateWithHash(platformApi.DeploymentFoundCondition, true, "ArangoDeployment found", "ArangoDeployment found", string(deployment.GetUID())) { return true, operator.Reconcile("Conditions updated") } diff --git a/pkg/handlers/platform/storage/local.go b/pkg/handlers/platform/storage/local.go index a26500750..d8ad5a777 100644 --- a/pkg/handlers/platform/storage/local.go +++ b/pkg/handlers/platform/storage/local.go @@ -21,12 +21,12 @@ package storage import ( - "github.com/arangodb/kube-arangodb/pkg/apis/ml" + "github.com/arangodb/kube-arangodb/pkg/apis/platform" platformApi "github.com/arangodb/kube-arangodb/pkg/apis/platform/v1alpha1" ) func Kind() string { - return ml.ArangoMLStorageResourceKind + return platform.ArangoPlatformStorageResourceKind } func Group() string { diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index a27b81c37..9434e90d2 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -49,6 +49,7 @@ import ( "github.com/arangodb/kube-arangodb/pkg/handlers/backup" "github.com/arangodb/kube-arangodb/pkg/handlers/job" "github.com/arangodb/kube-arangodb/pkg/handlers/networking/route" + platformChart "github.com/arangodb/kube-arangodb/pkg/handlers/platform/chart" platformStorage "github.com/arangodb/kube-arangodb/pkg/handlers/platform/storage" "github.com/arangodb/kube-arangodb/pkg/handlers/policy" schedulerBatchJobHandler "github.com/arangodb/kube-arangodb/pkg/handlers/scheduler/batchjob" @@ -407,6 +408,10 @@ func (o *Operator) onStartOperatorV2Platform(operator operatorV2.Operator, recor if err := platformStorage.RegisterInformer(operator, recorder, client, kubeClient, informer); err != nil { panic(err) } + + if err := platformChart.RegisterInformer(operator, recorder, client, kubeClient, informer); err != nil { + panic(err) + } } func (o *Operator) onStartOperatorV2Scheduler(operator operatorV2.Operator, recorder event.Recorder, client arangoClientSet.Interface, kubeClient kubernetes.Interface, informer arangoInformer.SharedInformerFactory, kubeInformer informers.SharedInformerFactory) { diff --git a/pkg/operatorV2/update_wraps.go b/pkg/operatorV2/update_wraps.go index 4b3513e18..4551a54ed 100644 --- a/pkg/operatorV2/update_wraps.go +++ b/pkg/operatorV2/update_wraps.go @@ -85,3 +85,7 @@ func WithArangoStorageUpdateStatusInterfaceRetry(ctx context.Context, client Upd func WithArangoPlatformStorageUpdateStatusInterfaceRetry(ctx context.Context, client UpdateStatusInterface[platformApi.ArangoPlatformStorageStatus, *platformApi.ArangoPlatformStorage], obj *platformApi.ArangoPlatformStorage, status platformApi.ArangoPlatformStorageStatus, opts meta.UpdateOptions) (*platformApi.ArangoPlatformStorage, error) { return WithUpdateStatusInterfaceRetry[platformApi.ArangoPlatformStorageStatus, *platformApi.ArangoPlatformStorage](ctx, client, obj, status, opts) } + +func WithArangoPlatformChartUpdateStatusInterfaceRetry(ctx context.Context, client UpdateStatusInterface[platformApi.ArangoPlatformChartStatus, *platformApi.ArangoPlatformChart], obj *platformApi.ArangoPlatformChart, status platformApi.ArangoPlatformChartStatus, opts meta.UpdateOptions) (*platformApi.ArangoPlatformChart, error) { + return WithUpdateStatusInterfaceRetry[platformApi.ArangoPlatformChartStatus, *platformApi.ArangoPlatformChart](ctx, client, obj, status, opts) +} diff --git a/pkg/util/tests/kubernetes.go b/pkg/util/tests/kubernetes.go index e19faa137..bbbcc147e 100644 --- a/pkg/util/tests/kubernetes.go +++ b/pkg/util/tests/kubernetes.go @@ -307,6 +307,12 @@ func CreateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe vl := *v _, err := arango.PlatformV1alpha1().ArangoPlatformStorages(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{}) require.NoError(t, err) + case **platformApi.ArangoPlatformChart: + require.NotNil(t, v) + + vl := *v + _, err := arango.PlatformV1alpha1().ArangoPlatformCharts(vl.GetNamespace()).Create(context.Background(), vl, meta.CreateOptions{}) + require.NoError(t, err) default: require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String())) } @@ -520,6 +526,12 @@ func UpdateObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe vl := *v _, err := arango.PlatformV1alpha1().ArangoPlatformStorages(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{}) require.NoError(t, err) + case **platformApi.ArangoPlatformChart: + require.NotNil(t, v) + + vl := *v + _, err := arango.PlatformV1alpha1().ArangoPlatformCharts(vl.GetNamespace()).Update(context.Background(), vl, meta.UpdateOptions{}) + require.NoError(t, err) default: require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String())) } @@ -698,6 +710,11 @@ func DeleteObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientSe vl := *v require.NoError(t, arango.PlatformV1alpha1().ArangoPlatformStorages(vl.GetNamespace()).Delete(context.Background(), vl.GetName(), meta.DeleteOptions{})) + case **platformApi.ArangoPlatformChart: + require.NotNil(t, v) + + vl := *v + require.NoError(t, arango.PlatformV1alpha1().ArangoPlatformCharts(vl.GetNamespace()).Delete(context.Background(), vl.GetName(), meta.DeleteOptions{})) default: require.Fail(t, fmt.Sprintf("Unable to delete object: %s", reflect.TypeOf(v).String())) } @@ -1204,6 +1221,21 @@ func RefreshObjects(t *testing.T, k8s kubernetes.Interface, arango arangoClientS } else { *v = vn } + case **platformApi.ArangoPlatformChart: + require.NotNil(t, v) + + vl := *v + + vn, err := arango.PlatformV1alpha1().ArangoPlatformCharts(vl.GetNamespace()).Get(context.Background(), vl.GetName(), meta.GetOptions{}) + if err != nil { + if kerrors.IsNotFound(err) { + *v = nil + } else { + require.NoError(t, err) + } + } else { + *v = vn + } default: require.Fail(t, fmt.Sprintf("Unable to get object: %s", reflect.TypeOf(v).String())) } @@ -1456,6 +1488,14 @@ func SetMetaBasedOnType(t *testing.T, object meta.Object) { platform.ArangoPlatformStorageResourcePlural, object.GetNamespace(), object.GetName())) + case *platformApi.ArangoPlatformChart: + v.Kind = platform.ArangoPlatformChartResourceKind + v.APIVersion = networkingApi.SchemeGroupVersion.String() + v.SetSelfLink(fmt.Sprintf("/api/%s/%s/%s/%s", + platformApi.SchemeGroupVersion.String(), + platform.ArangoPlatformChartResourcePlural, + object.GetNamespace(), + object.GetName())) default: require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String())) } @@ -1691,6 +1731,12 @@ func GVK(t *testing.T, object meta.Object) schema.GroupVersionKind { Version: platformApi.ArangoPlatformVersion, Kind: platform.ArangoPlatformStorageResourceKind, } + case *platformApi.ArangoPlatformChart: + return schema.GroupVersionKind{ + Group: platform.ArangoPlatformGroupName, + Version: platformApi.ArangoPlatformVersion, + Kind: platform.ArangoPlatformChartResourceKind, + } default: require.Fail(t, fmt.Sprintf("Unable to create object: %s", reflect.TypeOf(v).String())) return schema.GroupVersionKind{} diff --git a/pkg/util/tests/kubernetes_test.go b/pkg/util/tests/kubernetes_test.go index b47653fe7..de36136a2 100644 --- a/pkg/util/tests/kubernetes_test.go +++ b/pkg/util/tests/kubernetes_test.go @@ -100,4 +100,5 @@ func Test_NewMetaObject(t *testing.T) { NewMetaObjectRun[*analyticsApi.GraphAnalyticsEngine](t) NewMetaObjectRun[*networkingApi.ArangoRoute](t) NewMetaObjectRun[*platformApi.ArangoPlatformStorage](t) + NewMetaObjectRun[*platformApi.ArangoPlatformChart](t) }