From 713714938d4ba20fac0a495c3456e4b22baf387e Mon Sep 17 00:00:00 2001 From: Luca Sepe Date: Mon, 4 Mar 2024 16:03:00 +0100 Subject: [PATCH] feat: refactoring routes, formtemplates, schema definitions etc. (#18) --- README.md | 301 ++++++------------ apis/apis.go | 2 - .../v1alpha1/group_version_info.go | 37 --- apis/core/formdefinitions/v1alpha1/managed.go | 25 -- .../formdefinitions/v1alpha1/managed_list.go | 12 - apis/core/formdefinitions/v1alpha1/types.go | 72 ----- .../v1alpha1/zz_generated.deepcopy.go | 137 -------- apis/ui/formtemplates/v1alpha1/types.go | 14 +- .../v1alpha1/zz_generated.deepcopy.go | 31 +- crds/widgets.ui.krateo.io_formtemplates.yaml | 71 +---- go.mod | 2 - go.sum | 12 - internal/kubernetes/dynamic/dynamic.go | 16 + .../formdefinitions/formdefinitions.go | 185 ----------- .../formdefinitions/formdefinitions_test.go | 76 ----- .../kubernetes/formdefinitions/util/util.go | 77 ----- .../formdefinitions/util/util_test.go | 46 --- .../schemadefinitions/schemadefinitions.go | 107 +++++++ .../schemadefinitions_test.go | 147 +++++++++ .../{evaluator.go => evaluator.go.txt} | 0 ...valuator_test.go => evaluator_test.go.txt} | 0 .../merger/{merger.go => merger.go.txt} | 0 .../{merger_test.go => merger_test.go.txt} | 0 .../server/routes/layout/columns/getter.go | 31 +- .../server/routes/layout/columns/lister.go | 25 +- .../server/routes/layout/columns/register.go | 3 +- internal/server/routes/layout/rows/getter.go | 26 +- internal/server/routes/layout/rows/lister.go | 25 +- .../server/routes/layout/rows/register.go | 3 +- .../routes/widgets/cardtemplates/getter.go | 14 +- .../routes/widgets/cardtemplates/lister.go | 25 +- .../routes/widgets/cardtemplates/register.go | 2 + .../widgets/formtemplates/definition.go | 21 -- .../routes/widgets/formtemplates/getter.go | 147 +++++---- .../routes/widgets/formtemplates/register.go | 2 + .../routes/widgets/formtemplates/resource.go | 64 ---- scripts/server-run.sh | 16 +- testdata/clusterrole-apps-viewer.yaml | 26 ++ testdata/fireworksapp.crd.yaml | 10 +- testdata/fireworksapp.sample.yaml | 2 +- testdata/formtemplate.api.sample.yaml | 39 --- testdata/formtemplate.sample.yaml | 12 +- .../schemadefinition.crd.yaml | 63 ++-- ...mple.yaml => schemadefinition.sample.yaml} | 5 +- 44 files changed, 615 insertions(+), 1316 deletions(-) delete mode 100644 apis/core/formdefinitions/v1alpha1/group_version_info.go delete mode 100644 apis/core/formdefinitions/v1alpha1/managed.go delete mode 100644 apis/core/formdefinitions/v1alpha1/managed_list.go delete mode 100644 apis/core/formdefinitions/v1alpha1/types.go delete mode 100644 apis/core/formdefinitions/v1alpha1/zz_generated.deepcopy.go delete mode 100644 internal/kubernetes/formdefinitions/formdefinitions.go delete mode 100644 internal/kubernetes/formdefinitions/formdefinitions_test.go delete mode 100644 internal/kubernetes/formdefinitions/util/util.go delete mode 100644 internal/kubernetes/formdefinitions/util/util_test.go create mode 100644 internal/kubernetes/schemadefinitions/schemadefinitions.go create mode 100644 internal/kubernetes/schemadefinitions/schemadefinitions_test.go rename internal/kubernetes/widgets/formtemplates/evaluator/{evaluator.go => evaluator.go.txt} (100%) rename internal/kubernetes/widgets/formtemplates/evaluator/{evaluator_test.go => evaluator_test.go.txt} (100%) rename internal/kubernetes/widgets/formtemplates/merger/{merger.go => merger.go.txt} (100%) rename internal/kubernetes/widgets/formtemplates/merger/{merger_test.go => merger_test.go.txt} (100%) delete mode 100644 internal/server/routes/widgets/formtemplates/definition.go delete mode 100644 internal/server/routes/widgets/formtemplates/resource.go create mode 100644 testdata/clusterrole-apps-viewer.yaml delete mode 100644 testdata/formtemplate.api.sample.yaml rename crds/core.krateo.io_formdefinitions.yaml => testdata/schemadefinition.crd.yaml (60%) rename testdata/{formdefinition.sample.yaml => schemadefinition.sample.yaml} (80%) diff --git a/README.md b/README.md index 8654ae0..efc5ce6 100644 --- a/README.md +++ b/README.md @@ -9,228 +9,127 @@ Krateo **B**ackend **F**or **F**rontend. | | | |:------------------|:------------------------------------------------------------------------------------| | **Verb** | `GET` | -| **Path** | `/apis/widgets.ui.krateo.io/v1alpha1/cardtemplates` | -| **Query Params** | `eval`: if _"false"_ do not evaluate expressions (default: true) | -| | `sub`: username (subject) | +| **Path** | `/apis/widgets.ui.krateo.io/cardtemplates` | +| **Query Params** | `sub`: username (subject) | | | `orgs`: comma separated organizations | | | `namespace`: namespace where to list cardtemplates (optional) | +| | `version`: cardtemplates schema version (optional) | **Example** ```sh -curl "http://localhost:8080/apis/widgets.ui.krateo.io/v1alpha1/cardtemplates?sub=cyberjoker&orgs=devs&namespace=dev-system" +curl "http://localhost:8090/apis/widgets.ui.krateo.io/cardtemplates?sub=cyberjoker&orgs=devs&namespace=demo-system" ``` -**Response On Failure** - -```json -{ - "kind": "Status", - "apiVersion": "v1", - "status": "Failure", - "message": "forbidden: User \"cyberjoker\" cannot list resource \"cardtemplates\" in API group \"widgets.ui.krateo.io\" in namespace dev-system", - "reason": "Forbidden", - "code": 403 -} +### Get one card template + +| | | +|:------------------|:------------------------------------------------------------------------------------| +| **Method** | `GET` | +| **Path** | `/apis/widgets.ui.krateo.io/cardtemplates/${NAME}` | +| **Path Params** | `${NAME}` is your `CardTemplate` object name | +| **Query Params** | `sub`: username (subject) | +| | `orgs`: comma separated organizations | +| | `namespace`: namespace where to list cardtemplates | +| | `version`: cardtemplates schema version (optional) | + +**Example**: + +```sh +curl "http://localhost:8090/apis/widgets.ui.krateo.io/cardtemplates/one?sub=cyberjoker&orgs=devs&namespace=demo-system" ``` -**Response On Success** - -```json -{ - "kind": "CardTemplateList", - "apiVersion": "widgets.ui.krateo.io/v1alpha1", - "metadata": { - "resourceVersion": "2618" - }, - "items": [ - { - "kind": "CardTemplate", - "apiVersion": "widgets.ui.krateo.io/v1alpha1", - "metadata": { - "name": "card-dev", - "namespace": "dev-system", - "uid": "2f05f33c-f3c8-4ed1-b39e-f398524bb33d", - "resourceVersion": "275", - "generation": 1, - "creationTimestamp": "2023-12-01T15:37:18Z", - "annotations": { - "krateo.io/allowed-verbs": "get,list", - "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"widgets.ui.krateo.io/v1alpha1\",\"kind\":\"CardTemplate\",\"metadata\":{\"annotations\":{},\"name\":\"card-dev\",\"namespace\":\"dev-system\"},\"spec\":{\"api\":[{\"endpointRef\":{\"name\":\"httpbin-endpoint\",\"namespace\":\"dev-system\"},\"headers\":[\"Accept: application/json\"],\"name\":\"httpbin\",\"path\":\"/anything\",\"payload\":\"{\\n \\\"firstName\\\": \\\"Charles\\\",\\n \\\"lastName\\\": \\\"Doe\\\",\\n \\\"age\\\": 41,\\n \\\"location\\\": {\\n \\\"city\\\": \\\"San Fracisco\\\",\\n \\\"postalCode\\\": \\\"94103\\\"\\n },\\n \\\"hobbies\\\": [\\n \\\"chess\\\",\\n \\\"netflix\\\"\\n ]\\n}\\n\",\"verb\":\"GET\"}],\"app\":{\"actions\":[{\"enabled\":true,\"endpointRef\":{\"name\":\"krateogateway-endpoint\",\"namespace\":\"krateo-system\"},\"name\":\"crd\",\"path\":\"/apis/apiextensions.k8s.io/v1/customresourcedefinitions/postgresqls.composition.krateo.io\",\"verb\":\"DELETE\"}],\"color\":\"GREEN\",\"content\":\"${ .httpbin.json.location.city }\",\"icon\":\"ApartmentOutlined\",\"tags\":\"${ .httpbin.json.hobbies | join(\\\",\\\") }\",\"title\":\"${ (.httpbin.json.firstName + \\\" \\\" + .httpbin.json.lastName) }\"}}}\n" - }, - "managedFields": [ - { - "manager": "kubectl-client-side-apply", - "operation": "Update", - "apiVersion": "widgets.ui.krateo.io/v1alpha1", - "time": "2023-12-01T15:37:18Z", - "fieldsType": "FieldsV1", - "fieldsV1": { - "f:metadata": { - "f:annotations": { - ".": {}, - "f:kubectl.kubernetes.io/last-applied-configuration": {} - } - }, - "f:spec": { - ".": {}, - "f:api": {}, - "f:app": { - ".": {}, - "f:actions": {}, - "f:color": {}, - "f:content": {}, - "f:icon": {}, - "f:tags": {}, - "f:title": {} - } - } - } - } - ] - }, - "spec": { - "app": { - "title": "Charles Doe", - "content": "San Fracisco", - "icon": "ApartmentOutlined", - "color": "GREEN", - "tags": "chess,netflix", - "actions": [ - { - "name": "crd", - "path": "/apis/apiextensions.k8s.io/v1/customresourcedefinitions/postgresqls.composition.krateo.io", - "verb": "DELETE", - "endpointRef": { - "name": "krateogateway-endpoint", - "namespace": "krateo-system" - }, - "enabled": false - } - ] - }, - "api": [ - { - "name": "httpbin", - "path": "/anything", - "verb": "GET", - "headers": [ - "Accept: application/json" - ], - "payload": "{\n \"firstName\": \"Charles\",\n \"lastName\": \"Doe\",\n \"age\": 41,\n \"location\": {\n \"city\": \"San Fracisco\",\n \"postalCode\": \"94103\"\n },\n \"hobbies\": [\n \"chess\",\n \"netflix\"\n ]\n}\n", - "endpointRef": { - "name": "httpbin-endpoint", - "namespace": "dev-system" - }, - "enabled": true - } - ] - } - } - ] -} +## Column API + +### List all columns + +| | | +|:------------------|:------------------------------------------------------------------------------------| +| **Verb** | `GET` | +| **Path** | `/apis/layout.ui.krateo.io/columns` | +| **Query Params** | `sub`: username (subject) | +| | `orgs`: comma separated organizations | +| | `namespace`: namespace where to list cardtemplates (optional) | +| | `version`: cardtemplates schema version (optional) | + +**Example**: + +```sh +curl "http://localhost:8090/apis/layout.ui.krateo.io/columns?sub=cyberjoker&orgs=devs&namespace=demo-system" ``` -### Get one card template +### Get one column | | | |:------------------|:------------------------------------------------------------------------------------| | **Method** | `GET` | -| **Path** | `/apis/widgets.ui.krateo.io/v1alpha1/cardtemplates/${NAME}` | -| **Path Params** | `${NAME}` is your `CardTemplate` object name | -| **Query Params** | `eval`: if _"false"_ do not evaluate expressions (default: true) | -| | `sub`: username (subject) | +| **Path** | `/apis/layout.ui.krateo.io/columns/${NAME}` | +| **Path Params** | `${NAME}` is your `Column` object name | +| **Query Params** | `sub`: username (subject) | | | `orgs`: comma separated organizations | | | `namespace`: namespace where to list cardtemplates | +| | `version`: cardtemplates schema version (optional) | **Example**: ```sh -curl "http://localhost:8080/apis/widgets.ui.krateo.io/v1alpha1/cardtemplates/card-dev?sub=cyberjoker&orgs=devs&namespace=dev-system" +curl "http://localhost:8090/apis/layout.ui.krateo.io/columns/three?sub=cyberjoker&orgs=devs&namespace=demo-system" ``` -```json -{ - "kind": "CardTemplate", - "apiVersion": "widgets.ui.krateo.io/v1alpha1", - "metadata": { - "name": "card-dev", - "namespace": "dev-system", - "uid": "2f05f33c-f3c8-4ed1-b39e-f398524bb33d", - "resourceVersion": "275", - "generation": 1, - "creationTimestamp": "2023-12-01T15:37:18Z", - "annotations": { - "krateo.io/allowed-verbs": "get,list", - "kubectl.kubernetes.io/last-applied-configuration": "{\"apiVersion\":\"widgets.ui.krateo.io/v1alpha1\",\"kind\":\"CardTemplate\",\"metadata\":{\"annotations\":{},\"name\":\"card-dev\",\"namespace\":\"dev-system\"},\"spec\":{\"api\":[{\"endpointRef\":{\"name\":\"httpbin-endpoint\",\"namespace\":\"dev-system\"},\"headers\":[\"Accept: application/json\"],\"name\":\"httpbin\",\"path\":\"/anything\",\"payload\":\"{\\n \\\"firstName\\\": \\\"Charles\\\",\\n \\\"lastName\\\": \\\"Doe\\\",\\n \\\"age\\\": 41,\\n \\\"location\\\": {\\n \\\"city\\\": \\\"San Fracisco\\\",\\n \\\"postalCode\\\": \\\"94103\\\"\\n },\\n \\\"hobbies\\\": [\\n \\\"chess\\\",\\n \\\"netflix\\\"\\n ]\\n}\\n\",\"verb\":\"GET\"}],\"app\":{\"actions\":[{\"enabled\":true,\"endpointRef\":{\"name\":\"krateogateway-endpoint\",\"namespace\":\"krateo-system\"},\"name\":\"crd\",\"path\":\"/apis/apiextensions.k8s.io/v1/customresourcedefinitions/postgresqls.composition.krateo.io\",\"verb\":\"DELETE\"}],\"color\":\"GREEN\",\"content\":\"${ .httpbin.json.location.city }\",\"icon\":\"ApartmentOutlined\",\"tags\":\"${ .httpbin.json.hobbies | join(\\\",\\\") }\",\"title\":\"${ (.httpbin.json.firstName + \\\" \\\" + .httpbin.json.lastName) }\"}}}\n" - }, - "managedFields": [ - { - "manager": "kubectl-client-side-apply", - "operation": "Update", - "apiVersion": "widgets.ui.krateo.io/v1alpha1", - "time": "2023-12-01T15:37:18Z", - "fieldsType": "FieldsV1", - "fieldsV1": { - "f:metadata": { - "f:annotations": { - ".": {}, - "f:kubectl.kubernetes.io/last-applied-configuration": {} - } - }, - "f:spec": { - ".": {}, - "f:api": {}, - "f:app": { - ".": {}, - "f:actions": {}, - "f:color": {}, - "f:content": {}, - "f:icon": {}, - "f:tags": {}, - "f:title": {} - } - } - } - } - ] - }, - "spec": { - "app": { - "title": "Charles Doe", - "content": "San Fracisco", - "icon": "ApartmentOutlined", - "color": "GREEN", - "tags": "chess,netflix", - "actions": [ - { - "name": "crd", - "path": "/apis/apiextensions.k8s.io/v1/customresourcedefinitions/postgresqls.composition.krateo.io", - "verb": "DELETE", - "endpointRef": { - "name": "krateogateway-endpoint", - "namespace": "krateo-system" - }, - "enabled": false - } - ] - }, - "api": [ - { - "name": "httpbin", - "path": "/anything", - "verb": "GET", - "headers": [ - "Accept: application/json" - ], - "payload": "{\n \"firstName\": \"Charles\",\n \"lastName\": \"Doe\",\n \"age\": 41,\n \"location\": {\n \"city\": \"San Fracisco\",\n \"postalCode\": \"94103\"\n },\n \"hobbies\": [\n \"chess\",\n \"netflix\"\n ]\n}\n", - "endpointRef": { - "name": "httpbin-endpoint", - "namespace": "dev-system" - }, - "enabled": true - } - ] - } -} -``` \ No newline at end of file +## Rows API + +### List all rows + +| | | +|:------------------|:------------------------------------------------------------------------------------| +| **Verb** | `GET` | +| **Path** | `/apis/layout.ui.krateo.io/rows` | +| **Query Params** | `sub`: username (subject) | +| | `orgs`: comma separated organizations | +| | `namespace`: namespace where to list cardtemplates (optional) | +| | `version`: cardtemplates schema version (optional) | + +**Example**: + +```sh +curl "http://localhost:8090/apis/layout.ui.krateo.io/rows?sub=cyberjoker&orgs=devs&namespace=demo-system" +``` + +### Get one row + +| | | +|:------------------|:------------------------------------------------------------------------------------| +| **Method** | `GET` | +| **Path** | `/apis/layout.ui.krateo.io/rows/${NAME}` | +| **Path Params** | `${NAME}` is your `Row` object name | +| **Query Params** | `sub`: username (subject) | +| | `orgs`: comma separated organizations | +| | `namespace`: namespace where to list cardtemplates | +| | `version`: cardtemplates schema version (optional) | + +**Example**: + +```sh +curl "http://localhost:8090/apis/layout.ui.krateo.io/rows/two?sub=cyberjoker&orgs=devs&namespace=demo-system" +``` + +## FormTemplate API + + +### Get one formtemplate + +| | | +|:------------------|:------------------------------------------------------------------------------------| +| **Method** | `GET` | +| **Path** | `/apis/widgets.ui.krateo.io/formtemplates/${NAME}` | +| **Path Params** | `${NAME}` is your `Row` object name | +| **Query Params** | `sub`: username (subject) | +| | `orgs`: comma separated organizations | +| | `namespace`: namespace where to list cardtemplates | +| | `version`: cardtemplates schema version (optional) | + +**Example**: + +```sh +curl "http://localhost:8090/apis/widgets.ui.krateo.io/formtemplates/fireworksapp?sub=cyberjoker&orgs=devs&namespace=demo-system" +``` diff --git a/apis/apis.go b/apis/apis.go index d68acb0..15d25b5 100644 --- a/apis/apis.go +++ b/apis/apis.go @@ -1,7 +1,6 @@ package apis import ( - formdefinitionsv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/core/formdefinitions/v1alpha1" cardtemplatesv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/cardtemplates/v1alpha1" columnsv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/columns/v1alpha1" formtemplatesv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/formtemplates/v1alpha1" @@ -23,6 +22,5 @@ func init() { columnsv1alpha1.SchemeBuilder.AddToScheme, rowsv1alpha1.SchemeBuilder.AddToScheme, formtemplatesv1alpha1.SchemeBuilder.AddToScheme, - formdefinitionsv1alpha1.SchemeBuilder.AddToScheme, ) } diff --git a/apis/core/formdefinitions/v1alpha1/group_version_info.go b/apis/core/formdefinitions/v1alpha1/group_version_info.go deleted file mode 100644 index 9a41bee..0000000 --- a/apis/core/formdefinitions/v1alpha1/group_version_info.go +++ /dev/null @@ -1,37 +0,0 @@ -// Package v1alpha1 contains API Schema definitions v1alpha1 API group -// +kubebuilder:object:generate=true -// +groupName=core.krateo.io -// +versionName=v1alpha1 -package v1alpha1 - -import ( - "reflect" - - "k8s.io/apimachinery/pkg/runtime/schema" - "sigs.k8s.io/controller-runtime/pkg/scheme" -) - -// Package type metadata. -const ( - Group = "core.krateo.io" - Version = "v1alpha1" -) - -var ( - // SchemeGroupVersion is group version used to register these objects - SchemeGroupVersion = schema.GroupVersion{Group: Group, Version: Version} - - // SchemeBuilder is used to add go types to the GroupVersionKind scheme - SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} -) - -var ( - FormDefinitionKind = reflect.TypeOf(FormDefinition{}).Name() - FormDefinitionGroupKind = schema.GroupKind{Group: Group, Kind: FormDefinitionKind}.String() - FormDefinitionKindAPIVersion = FormDefinitionKind + "." + SchemeGroupVersion.String() - FormDefinitionGroupVersionKind = SchemeGroupVersion.WithKind(FormDefinitionKind) -) - -func init() { - SchemeBuilder.Register(&FormDefinition{}, &FormDefinitionList{}) -} diff --git a/apis/core/formdefinitions/v1alpha1/managed.go b/apis/core/formdefinitions/v1alpha1/managed.go deleted file mode 100644 index fc08ea2..0000000 --- a/apis/core/formdefinitions/v1alpha1/managed.go +++ /dev/null @@ -1,25 +0,0 @@ -package v1alpha1 - -import ( - rtv1 "github.com/krateoplatformops/provider-runtime/apis/common/v1" -) - -// GetCondition of this Definition. -func (mg *FormDefinition) GetCondition(ct rtv1.ConditionType) rtv1.Condition { - return mg.Status.GetCondition(ct) -} - -// GetDeletionPolicy of this Definition. -func (mg *FormDefinition) GetDeletionPolicy() rtv1.DeletionPolicy { - return mg.Spec.DeletionPolicy -} - -// SetConditions of this Definition. -func (mg *FormDefinition) SetConditions(c ...rtv1.Condition) { - mg.Status.SetConditions(c...) -} - -// SetDeletionPolicy of this Definition. -func (mg *FormDefinition) SetDeletionPolicy(r rtv1.DeletionPolicy) { - mg.Spec.DeletionPolicy = r -} diff --git a/apis/core/formdefinitions/v1alpha1/managed_list.go b/apis/core/formdefinitions/v1alpha1/managed_list.go deleted file mode 100644 index 67b7e1a..0000000 --- a/apis/core/formdefinitions/v1alpha1/managed_list.go +++ /dev/null @@ -1,12 +0,0 @@ -package v1alpha1 - -import "github.com/krateoplatformops/provider-runtime/pkg/resource" - -// GetItems of this DefinitionList. -func (l *FormDefinitionList) GetItems() []resource.Managed { - items := make([]resource.Managed, len(l.Items)) - for i := range l.Items { - items[i] = &l.Items[i] - } - return items -} diff --git a/apis/core/formdefinitions/v1alpha1/types.go b/apis/core/formdefinitions/v1alpha1/types.go deleted file mode 100644 index 41d7340..0000000 --- a/apis/core/formdefinitions/v1alpha1/types.go +++ /dev/null @@ -1,72 +0,0 @@ -package v1alpha1 - -import ( - rtv1 "github.com/krateoplatformops/provider-runtime/apis/common/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type SchemaInfo struct { - // Url of the values.schema.json file - // +kubebuilder:validation:Required - Url string `json:"url"` - - // Group: collection of kinds. - // +kubebuilder:validation:Required - Group string `json:"group"` - - // Version: allow Kubernetes to release groups as tagged versions. - // +kubebuilder:validation:Required - Version string `json:"version"` - - // Kind: the name of the object you are trying to generate - // +kubebuilder:validation:Required - Kind string `json:"kind"` -} - -// FormDefinitionSpec is the specification of a Definition. -type FormDefinitionSpec struct { - rtv1.ManagedSpec `json:",inline"` - - // Schema: the schema info - // +immutable - Schema SchemaInfo `json:"schema"` -} - -// FormDefinitionStatus is the status of a Definition. -type FormDefinitionStatus struct { - rtv1.ManagedStatus `json:",inline"` - - // Resource: the generated custom resource - // +optional - Resource string `json:"resource,omitempty"` - - // Digest: schema digest - // +optional - Digest *string `json:"digest,omitempty"` -} - -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status -//+kubebuilder:resource:scope=Namespaced,categories={krateo,definition,frontend,forms} -//+kubebuilder:printcolumn:name="RESOURCE",type="string",JSONPath=".status.resource" -//+kubebuilder:printcolumn:name="READY",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status" -//+kubebuilder:printcolumn:name="AGE",type="date",JSONPath=".metadata.creationTimestamp",priority=10 - -// FormDefinition is a definition type with a spec and a status. -type FormDefinition struct { - metav1.TypeMeta `json:",inline"` - metav1.ObjectMeta `json:"metadata,omitempty"` - - Spec FormDefinitionSpec `json:"spec,omitempty"` - Status FormDefinitionStatus `json:"status,omitempty"` -} - -//+kubebuilder:object:root=true - -// FormDefinitionList is a list of Definition objects. -type FormDefinitionList struct { - metav1.TypeMeta `json:",inline"` - metav1.ListMeta `json:"metadata,omitempty"` - - Items []FormDefinition `json:"items"` -} diff --git a/apis/core/formdefinitions/v1alpha1/zz_generated.deepcopy.go b/apis/core/formdefinitions/v1alpha1/zz_generated.deepcopy.go deleted file mode 100644 index 2b0b4be..0000000 --- a/apis/core/formdefinitions/v1alpha1/zz_generated.deepcopy.go +++ /dev/null @@ -1,137 +0,0 @@ -//go:build !ignore_autogenerated - -/* -Copyright 2023 Krateo SRL. - -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. -*/ - -// Code generated by controller-gen. DO NOT EDIT. - -package v1alpha1 - -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 *FormDefinition) DeepCopyInto(out *FormDefinition) { - *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 FormDefinition. -func (in *FormDefinition) DeepCopy() *FormDefinition { - if in == nil { - return nil - } - out := new(FormDefinition) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FormDefinition) 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 *FormDefinitionList) DeepCopyInto(out *FormDefinitionList) { - *out = *in - out.TypeMeta = in.TypeMeta - in.ListMeta.DeepCopyInto(&out.ListMeta) - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]FormDefinition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FormDefinitionList. -func (in *FormDefinitionList) DeepCopy() *FormDefinitionList { - if in == nil { - return nil - } - out := new(FormDefinitionList) - in.DeepCopyInto(out) - return out -} - -// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FormDefinitionList) 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 *FormDefinitionSpec) DeepCopyInto(out *FormDefinitionSpec) { - *out = *in - out.ManagedSpec = in.ManagedSpec - out.Schema = in.Schema -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FormDefinitionSpec. -func (in *FormDefinitionSpec) DeepCopy() *FormDefinitionSpec { - if in == nil { - return nil - } - out := new(FormDefinitionSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FormDefinitionStatus) DeepCopyInto(out *FormDefinitionStatus) { - *out = *in - in.ManagedStatus.DeepCopyInto(&out.ManagedStatus) - if in.Digest != nil { - in, out := &in.Digest, &out.Digest - *out = new(string) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FormDefinitionStatus. -func (in *FormDefinitionStatus) DeepCopy() *FormDefinitionStatus { - if in == nil { - return nil - } - out := new(FormDefinitionStatus) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *SchemaInfo) DeepCopyInto(out *SchemaInfo) { - *out = *in -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SchemaInfo. -func (in *SchemaInfo) DeepCopy() *SchemaInfo { - if in == nil { - return nil - } - out := new(SchemaInfo) - in.DeepCopyInto(out) - return out -} diff --git a/apis/ui/formtemplates/v1alpha1/types.go b/apis/ui/formtemplates/v1alpha1/types.go index 2e50cf3..c36894d 100644 --- a/apis/ui/formtemplates/v1alpha1/types.go +++ b/apis/ui/formtemplates/v1alpha1/types.go @@ -20,18 +20,7 @@ func (di *DataItem) String() string { } type FormTemplateSpec struct { - // DefinitionRef: reference to FormDefintion - DefinitionRef *core.Reference `json:"definitionRef"` - - // ResourceRef: reference to resource instance - ResourceRef *core.Reference `json:"resourceRef"` - - // +optional - Data []*DataItem `json:"data,omitempty"` - - // APIList list of api calls. - // +optional - APIList []*core.API `json:"api,omitempty"` + SchemaDefinitionRef *core.Reference `json:"schemaDefinitionRef"` } type FormTemplateStatusContent struct { @@ -61,7 +50,6 @@ type FormTemplate struct { // +kubebuilder:object:root=true -// FormTemplateList contains a list of FormTemplate type FormTemplateList struct { metav1.TypeMeta `json:",inline"` metav1.ListMeta `json:"metadata,omitempty"` diff --git a/apis/ui/formtemplates/v1alpha1/zz_generated.deepcopy.go b/apis/ui/formtemplates/v1alpha1/zz_generated.deepcopy.go index eddaf04..0c4a317 100644 --- a/apis/ui/formtemplates/v1alpha1/zz_generated.deepcopy.go +++ b/apis/ui/formtemplates/v1alpha1/zz_generated.deepcopy.go @@ -102,38 +102,11 @@ func (in *FormTemplateList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FormTemplateSpec) DeepCopyInto(out *FormTemplateSpec) { *out = *in - if in.DefinitionRef != nil { - in, out := &in.DefinitionRef, &out.DefinitionRef + if in.SchemaDefinitionRef != nil { + in, out := &in.SchemaDefinitionRef, &out.SchemaDefinitionRef *out = new(core.Reference) **out = **in } - if in.ResourceRef != nil { - in, out := &in.ResourceRef, &out.ResourceRef - *out = new(core.Reference) - **out = **in - } - if in.Data != nil { - in, out := &in.Data, &out.Data - *out = make([]*DataItem, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(DataItem) - **out = **in - } - } - } - if in.APIList != nil { - in, out := &in.APIList, &out.APIList - *out = make([]*core.API, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = new(core.API) - (*in).DeepCopyInto(*out) - } - } - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FormTemplateSpec. diff --git a/crds/widgets.ui.krateo.io_formtemplates.yaml b/crds/widgets.ui.krateo.io_formtemplates.yaml index 7a6afd8..cdd9c9f 100644 --- a/crds/widgets.ui.krateo.io_formtemplates.yaml +++ b/crds/widgets.ui.krateo.io_formtemplates.yaml @@ -36,72 +36,8 @@ spec: type: object spec: properties: - api: - description: APIList list of api calls. - items: - description: API contains external api call info. - properties: - dependOn: - type: string - endpointRef: - description: A Reference to a named object. - properties: - name: - description: Name of the referenced object. - type: string - namespace: - description: Namespace of the referenced object. - type: string - required: - - name - - namespace - type: object - headers: - items: - type: string - type: array - krateoGateway: - type: boolean - name: - type: string - path: - type: string - payload: - type: string - verb: - default: GET - type: string - required: - - name - type: object - type: array - data: - items: - properties: - path: - type: string - value: - type: string - required: - - path - - value - type: object - type: array - definitionRef: - description: 'DefinitionRef: reference to FormDefintion' - properties: - name: - description: Name of the referenced object. - type: string - namespace: - description: Namespace of the referenced object. - type: string - required: - - name - - namespace - type: object - resourceRef: - description: 'ResourceRef: reference to resource instance' + schemaDefinitionRef: + description: A Reference to a named object. properties: name: description: Name of the referenced object. @@ -114,8 +50,7 @@ spec: - namespace type: object required: - - definitionRef - - resourceRef + - schemaDefinitionRef type: object status: properties: diff --git a/go.mod b/go.mod index 773f171..81ff691 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/go-chi/chi/v5 v5.0.10 github.com/google/go-cmp v0.6.0 github.com/itchyny/gojq v0.12.13 - github.com/krateoplatformops/provider-runtime v0.7.0 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.31.0 k8s.io/api v0.29.2 @@ -22,7 +21,6 @@ require ( require ( github.com/emicklei/go-restful/v3 v3.11.2 // indirect - github.com/evanphx/json-patch/v5 v5.9.0 // indirect github.com/fatih/color v1.15.0 // indirect github.com/go-logr/logr v1.4.1 // indirect github.com/go-openapi/jsonpointer v0.20.2 // indirect diff --git a/go.sum b/go.sum index 0132021..add9e56 100644 --- a/go.sum +++ b/go.sum @@ -7,8 +7,6 @@ github.com/emicklei/go-restful/v3 v3.11.2 h1:1onLa9DcsMYO9P+CXaL0dStDqQ2EHHXLiz+ github.com/emicklei/go-restful/v3 v3.11.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg= -github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ= github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs= github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -18,8 +16,6 @@ github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNIT github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= -github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q= github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs= github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= @@ -73,8 +69,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/krateoplatformops/provider-runtime v0.7.0 h1:Dg2qW3FfRnuR8H/ueX83+fjSW4Gayydhakc10hBJhfY= -github.com/krateoplatformops/provider-runtime v0.7.0/go.mod h1:pUhNcIkQMpsa/b0pD0QpJhBg5wBryTfg+jhC9mFHbkA= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -123,16 +117,10 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo= -go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a h1:Q8/wZp0KX97QFTc2ywcOE0YRjZPVIx+MXInMzdvQqcA= -golang.org/x/exp v0.0.0-20240119083558-1b970713d09a/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= diff --git a/internal/kubernetes/dynamic/dynamic.go b/internal/kubernetes/dynamic/dynamic.go index ad447a2..4db75e6 100644 --- a/internal/kubernetes/dynamic/dynamic.go +++ b/internal/kubernetes/dynamic/dynamic.go @@ -16,6 +16,8 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/rest" "k8s.io/client-go/restmapper" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" ) func NewGetter(rc *rest.Config) (*Getter, error) { @@ -101,3 +103,17 @@ func Extract(ctx context.Context, obj *unstructured.Unstructured, filter string) err = json.NewDecoder(buf).Decode(&xxx) return xxx, err } + +func InferGroupResource(g, k string) schema.GroupResource { + gk := schema.GroupKind{ + Group: g, + Kind: k, + } + + kind := types.Type{Name: types.Name{Name: gk.Kind}} + namer := namer.NewPrivatePluralNamer(nil) + return schema.GroupResource{ + Group: gk.Group, + Resource: strings.ToLower(namer.Name(&kind)), + } +} diff --git a/internal/kubernetes/formdefinitions/formdefinitions.go b/internal/kubernetes/formdefinitions/formdefinitions.go deleted file mode 100644 index 8e4081e..0000000 --- a/internal/kubernetes/formdefinitions/formdefinitions.go +++ /dev/null @@ -1,185 +0,0 @@ -package formdefinitions - -import ( - "context" - "time" - - "github.com/krateoplatformops/krateo-bff/apis" - "github.com/krateoplatformops/krateo-bff/apis/core/formdefinitions/v1alpha1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/runtime/serializer" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/rest" -) - -const ( - resourceName = "formdefinitions" - listKind = "FormDefinitionList" -) - -func NewClient(rc *rest.Config) (*Client, error) { - s := runtime.NewScheme() - apis.AddToScheme(s) - - config := *rc - config.APIPath = "/apis" - config.GroupVersion = &schema.GroupVersion{ - Group: v1alpha1.Group, Version: v1alpha1.Version, - } - config.NegotiatedSerializer = serializer.NewCodecFactory(s). - WithoutConversion() - config.UserAgent = rest.DefaultKubernetesUserAgent() - - cli, err := rest.RESTClientFor(&config) - if err != nil { - return nil, err - } - - pc := runtime.NewParameterCodec(s) - - return &Client{rc: cli, pc: pc}, nil -} - -type Client struct { - rc rest.Interface - pc runtime.ParameterCodec - ns string -} - -func (c *Client) Namespace(ns string) *Client { - c.ns = ns - return c -} - -func (c *Client) Get(ctx context.Context, name string) (result *v1alpha1.FormDefinition, err error) { - result = &v1alpha1.FormDefinition{} - err = c.rc.Get(). - Namespace(c.ns). - Resource(resourceName). - Name(name). - Do(ctx). - Into(result) - // issue: https://github.com/kubernetes/client-go/issues/541 - result.SetGroupVersionKind(v1alpha1.FormDefinitionGroupVersionKind) - return -} - -func (c *Client) List(ctx context.Context, opts metav1.ListOptions) (result *v1alpha1.FormDefinitionList, err error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - result = &v1alpha1.FormDefinitionList{} - err = c.rc.Get(). - Namespace(c.ns). - Resource(resourceName). - VersionedParams(&opts, c.pc). - Timeout(timeout). - Do(ctx). - Into(result) - - result.SetGroupVersionKind(v1alpha1.SchemeGroupVersion.WithKind(listKind)) - return -} - -func (c *Client) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { - var timeout time.Duration - if opts.TimeoutSeconds != nil { - timeout = time.Duration(*opts.TimeoutSeconds) * time.Second - } - opts.Watch = true - return c.rc.Get(). - Namespace(c.ns). - Resource(resourceName). - VersionedParams(&opts, c.pc). - Timeout(timeout). - Watch(ctx) -} - -func (c *Client) Create(ctx context.Context, obj *v1alpha1.FormDefinition, opts metav1.CreateOptions) (result *v1alpha1.FormDefinition, err error) { - result = &v1alpha1.FormDefinition{} - err = c.rc.Post(). - Namespace(c.ns). - Resource(resourceName). - VersionedParams(&opts, c.pc). - Body(obj). - Do(ctx). - Into(result) - // issue: https://github.com/kubernetes/client-go/issues/541 - result.SetGroupVersionKind(v1alpha1.FormDefinitionGroupVersionKind) - return -} - -func (c *Client) Update(ctx context.Context, obj *v1alpha1.FormDefinition, opts metav1.UpdateOptions) (result *v1alpha1.FormDefinition, err error) { - result = &v1alpha1.FormDefinition{} - err = c.rc.Put(). - Namespace(c.ns). - Resource(resourceName). - Name(obj.Name). - VersionedParams(&opts, c.pc). - Body(obj). - Do(ctx). - Into(result) - // issue: https://github.com/kubernetes/client-go/issues/541 - result.SetGroupVersionKind(v1alpha1.FormDefinitionGroupVersionKind) - return -} - -func (c *Client) UpdateStatus(ctx context.Context, obj *v1alpha1.FormDefinition) (result *v1alpha1.FormDefinition, err error) { - result = &v1alpha1.FormDefinition{} - err = c.rc.Put(). - Namespace(c.ns). - Resource(resourceName). - Name(obj.Name). - SubResource("status"). - Body(obj). - Do(ctx). - Into(result) - // issue: https://github.com/kubernetes/client-go/issues/541 - result.SetGroupVersionKind(v1alpha1.FormDefinitionGroupVersionKind) - return -} - -func (c *Client) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { - return c.rc.Delete(). - Namespace(c.ns). - Resource(resourceName). - Name(name). - Body(&opts). - Do(ctx). - Error() -} - -func (c *Client) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { - var timeout time.Duration - if listOpts.TimeoutSeconds != nil { - timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second - } - return c.rc.Delete(). - Namespace(c.ns). - Resource(resourceName). - VersionedParams(&listOpts, c.pc). - Timeout(timeout). - Body(&opts). - Do(ctx). - Error() -} - -func (c *Client) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1alpha1.FormDefinition, err error) { - result = &v1alpha1.FormDefinition{} - err = c.rc.Patch(pt). - Namespace(c.ns). - Resource(resourceName). - Name(name). - SubResource(subresources...). - VersionedParams(&opts, c.pc). - Body(data). - Do(ctx). - Into(result) - // issue: https://github.com/kubernetes/client-go/issues/541 - result.SetGroupVersionKind(v1alpha1.FormDefinitionGroupVersionKind) - return -} diff --git a/internal/kubernetes/formdefinitions/formdefinitions_test.go b/internal/kubernetes/formdefinitions/formdefinitions_test.go deleted file mode 100644 index a5da0cb..0000000 --- a/internal/kubernetes/formdefinitions/formdefinitions_test.go +++ /dev/null @@ -1,76 +0,0 @@ -//go:build integration -// +build integration - -package formdefinitions_test - -import ( - "context" - "encoding/json" - "os" - "path/filepath" - "testing" - - "github.com/krateoplatformops/krateo-bff/internal/kubernetes/formdefinitions" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" -) - -const ( - namespace = "demo-system" -) - -func TestFormDefinitionGet(t *testing.T) { - cfg, err := newRestConfig() - if err != nil { - t.Fatal(err) - } - - cli, err := formdefinitions.NewClient(cfg) - if err != nil { - t.Fatal(err) - } - - res, err := cli.Namespace(namespace).Get(context.TODO(), "fireworksapp") - if err != nil { - t.Fatal(err) - } - - enc := json.NewEncoder(os.Stdout) - enc.SetIndent("", " ") - if err := enc.Encode(res); err != nil { - t.Fatal(err) - } -} - -func TestFormDefinitionList(t *testing.T) { - cfg, err := newRestConfig() - if err != nil { - t.Fatal(err) - } - - cli, err := formdefinitions.NewClient(cfg) - if err != nil { - t.Fatal(err) - } - - all, err := cli.Namespace(namespace).List(context.TODO(), v1.ListOptions{}) - if err != nil { - t.Fatal(err) - } - - enc := json.NewEncoder(os.Stdout) - enc.SetIndent("", " ") - if err := enc.Encode(all); err != nil { - t.Fatal(err) - } -} - -func newRestConfig() (*rest.Config, error) { - home, err := os.UserHomeDir() - if err != nil { - return nil, err - } - - return clientcmd.BuildConfigFromFlags("", filepath.Join(home, ".kube", "config")) -} diff --git a/internal/kubernetes/formdefinitions/util/util.go b/internal/kubernetes/formdefinitions/util/util.go deleted file mode 100644 index fe638b9..0000000 --- a/internal/kubernetes/formdefinitions/util/util.go +++ /dev/null @@ -1,77 +0,0 @@ -package util - -import ( - "context" - "fmt" - "strings" - - "github.com/krateoplatformops/krateo-bff/apis/core/formdefinitions/v1alpha1" - formtemplatesv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/formtemplates/v1alpha1" - "github.com/krateoplatformops/krateo-bff/internal/kubernetes/dynamic" - "github.com/krateoplatformops/krateo-bff/internal/kubernetes/formdefinitions" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/rest" - "k8s.io/gengo/namer" - "k8s.io/gengo/types" -) - -const ( - openAPIV3SchemaFilter = `.spec.versions[] | select(.name="%s") | .schema.openAPIV3Schema` -) - -func GetFormSchema(ctx context.Context, rc *rest.Config, in *formtemplatesv1alpha1.FormTemplate) (*runtime.RawExtension, error) { - formdefinitionsClient, err := formdefinitions.NewClient(rc) - if err != nil { - return nil, err - } - - ref, err := formdefinitionsClient. - Namespace(in.Spec.DefinitionRef.Namespace). - Get(ctx, in.Spec.DefinitionRef.Name) - if err != nil { - return nil, err - } - - dyn, err := dynamic.NewGetter(rc) - if err != nil { - return nil, err - } - - crd, err := dyn.Get(ctx, dynamic.GetOptions{ - GVK: schema.GroupVersionKind{ - Group: "apiextensions.k8s.io", - Version: "v1", - Kind: "CustomResourceDefinition", - }, - Name: InferGroupResource(ref).String(), - }) - if err != nil { - return nil, err - } - - filter := fmt.Sprintf(openAPIV3SchemaFilter, ref.Spec.Schema.Version) - sch, err := dynamic.Extract(ctx, crd, filter) - if err != nil { - return nil, err - } - - return &runtime.RawExtension{Object: &unstructured.Unstructured{ - Object: sch.(map[string]any), - }}, nil -} - -func InferGroupResource(obj *v1alpha1.FormDefinition) schema.GroupResource { - gk := schema.GroupKind{ - Group: obj.Spec.Schema.Group, - Kind: obj.Spec.Schema.Kind, - } - - kind := types.Type{Name: types.Name{Name: gk.Kind}} - namer := namer.NewPrivatePluralNamer(nil) - return schema.GroupResource{ - Group: gk.Group, - Resource: strings.ToLower(namer.Name(&kind)), - } -} diff --git a/internal/kubernetes/formdefinitions/util/util_test.go b/internal/kubernetes/formdefinitions/util/util_test.go deleted file mode 100644 index 9362f47..0000000 --- a/internal/kubernetes/formdefinitions/util/util_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package util - -import ( - "testing" - - "github.com/krateoplatformops/krateo-bff/apis/core/formdefinitions/v1alpha1" -) - -func TestInferGroupResource(t *testing.T) { - table := []struct { - in v1alpha1.FormDefinition - want string - }{ - { - in: v1alpha1.FormDefinition{ - Spec: v1alpha1.FormDefinitionSpec{ - Schema: v1alpha1.SchemaInfo{ - Group: "apps.krateo.io", - Version: "v1beta1", - Kind: "FireworksappForm", - }, - }, - }, - want: "fireworksappforms.apps.krateo.io", - }, - { - in: v1alpha1.FormDefinition{ - Spec: v1alpha1.FormDefinitionSpec{ - Schema: v1alpha1.SchemaInfo{ - Group: "examples.org", - Version: "v1", - Kind: "MagnificentResource", - }, - }, - }, - want: "magnificentresources.examples.org", - }, - } - - for i, tc := range table { - got := InferGroupResource(&tc.in) - if got.String() != tc.want { - t.Fatalf("[tc: %d] got: %v, expected: %v", i, got, tc.want) - } - } -} diff --git a/internal/kubernetes/schemadefinitions/schemadefinitions.go b/internal/kubernetes/schemadefinitions/schemadefinitions.go new file mode 100644 index 0000000..26bce0f --- /dev/null +++ b/internal/kubernetes/schemadefinitions/schemadefinitions.go @@ -0,0 +1,107 @@ +package schemadefinitions + +import ( + "context" + "fmt" + + "github.com/krateoplatformops/krateo-bff/internal/kubernetes/dynamic" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/rest" +) + +const ( + openAPIV3SchemaFilter = `.spec.versions[] | select(.name="%s") | .schema.openAPIV3Schema` +) + +func NewClient(rc *rest.Config) (*Client, error) { + dyn, err := dynamic.NewGetter(rc) + if err != nil { + return nil, err + } + + return &Client{ + dyn: dyn, + gvk: schema.GroupVersionKind{ + Group: "core.krateo.io", + Version: "v1alpha1", + Kind: "SchemaDefinition", + }, + }, nil +} + +type Client struct { + dyn *dynamic.Getter + gvk schema.GroupVersionKind + ns string +} + +func (c *Client) Namespace(ns string) *Client { + c.ns = ns + return c +} + +func (c *Client) Get(ctx context.Context, name string) (result *unstructured.Unstructured, err error) { + result, err = c.dyn.Get(ctx, dynamic.GetOptions{ + GVK: c.gvk, + Namespace: c.ns, + Name: name, + }) + + return +} + +func (c *Client) GVK(ctx context.Context, name string) (schema.GroupVersionKind, error) { + obj, err := c.dyn.Get(ctx, dynamic.GetOptions{ + GVK: c.gvk, + Namespace: c.ns, + Name: name, + }) + if err != nil { + return schema.GroupVersionKind{}, nil + } + + data, ok, err := unstructured.NestedStringMap(obj.Object, "spec", "schema") + if err != nil { + return schema.GroupVersionKind{}, err + } + if !ok { + return schema.GroupVersionKind{}, nil + } + + kind := data["kind"] + version := data["version"] + if len(version) == 0 { + version = "v1alpha1" + } + + return schema.GroupVersionKind{ + Group: "apps.krateo.io", + Version: version, + Kind: kind, + }, nil +} + +func (c *Client) OpenAPISchema(ctx context.Context, gkv schema.GroupVersionKind) (*unstructured.Unstructured, error) { + crd, err := c.Namespace("").dyn.Get(ctx, dynamic.GetOptions{ + GVK: schema.GroupVersionKind{ + Group: "apiextensions.k8s.io", + Version: "v1", + Kind: "CustomResourceDefinition", + }, + Name: dynamic.InferGroupResource(gkv.Group, gkv.Kind).String(), + }) + if err != nil { + return nil, err + } + + filter := fmt.Sprintf(openAPIV3SchemaFilter, gkv.Version) + sch, err := dynamic.Extract(ctx, crd, filter) + if err != nil { + return nil, err + } + + return &unstructured.Unstructured{ + Object: sch.(map[string]any), + }, nil +} diff --git a/internal/kubernetes/schemadefinitions/schemadefinitions_test.go b/internal/kubernetes/schemadefinitions/schemadefinitions_test.go new file mode 100644 index 0000000..eab1e16 --- /dev/null +++ b/internal/kubernetes/schemadefinitions/schemadefinitions_test.go @@ -0,0 +1,147 @@ +//go:build integration +// +build integration + +package schemadefinitions_test + +import ( + "context" + "encoding/json" + "fmt" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/krateoplatformops/krateo-bff/internal/kubernetes/schemadefinitions" + "github.com/krateoplatformops/krateo-bff/internal/strvals" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" +) + +const ( + namespace = "demo-system" +) + +func TestGet(t *testing.T) { + cfg, err := newRestConfig() + if err != nil { + t.Fatal(err) + } + + cli, err := schemadefinitions.NewClient(cfg) + if err != nil { + t.Fatal(err) + } + + res, err := cli.Namespace(namespace).Get(context.TODO(), "fireworksapp") + if err != nil { + t.Fatal(err) + } + + enc := json.NewEncoder(os.Stdout) + enc.SetIndent("", " ") + if err := enc.Encode(res); err != nil { + t.Fatal(err) + } +} + +func TestGVK(t *testing.T) { + cfg, err := newRestConfig() + if err != nil { + t.Fatal(err) + } + + cli, err := schemadefinitions.NewClient(cfg) + if err != nil { + t.Fatal(err) + } + + res, err := cli.Namespace(namespace).GVK(context.TODO(), "fireworksapp") + if err != nil { + t.Fatal(err) + } + + enc := json.NewEncoder(os.Stdout) + enc.SetIndent("", " ") + if err := enc.Encode(res); err != nil { + t.Fatal(err) + } +} + +func TestOpenAPISchema(t *testing.T) { + cfg, err := newRestConfig() + if err != nil { + t.Fatal(err) + } + + cli, err := schemadefinitions.NewClient(cfg) + if err != nil { + t.Fatal(err) + } + + gvk, err := cli.Namespace(namespace).GVK(context.TODO(), "fireworksapp") + if err != nil { + t.Fatal(err) + } + + res, err := cli.OpenAPISchema(context.TODO(), gvk) + if err != nil { + t.Fatal(err) + } + + lines := []string{ + "properties.metadata.type=object", + "properties.metadata.properties.name.type=string", + "properties.metadata.properties.namespace.type=string", + "properties.metadata.properties.namespace.type=string", + "properties.metadata.required={name,namespace}", + } + + metadata := strings.Join(lines, ",") + fmt.Println(metadata) + + err = strvals.ParseInto(metadata, res.UnstructuredContent()) + if err != nil { + t.Fatal(err) + } + + enc := json.NewEncoder(os.Stdout) + enc.SetIndent("", " ") + if err := enc.Encode(res); err != nil { + t.Fatal(err) + } +} + +/* +metadata.type=object +metadata.properties.name.type=string +metadata.properties.namespace.type=string +metadata.properties.namespace.type=string +metadata.required={name,namespace} + + { + "metadata":{ + "type":"object", + "properties":{ + "name":{ + "type":"string" + }, + "namespace":{ + "type":"string" + } + }, + "required":[ + "name", + "namespace" + ] + } + } +*/ +func newRestConfig() (*rest.Config, error) { + home, err := os.UserHomeDir() + if err != nil { + return nil, err + } + + return clientcmd.BuildConfigFromFlags("", filepath.Join(home, ".kube", "config")) +} diff --git a/internal/kubernetes/widgets/formtemplates/evaluator/evaluator.go b/internal/kubernetes/widgets/formtemplates/evaluator/evaluator.go.txt similarity index 100% rename from internal/kubernetes/widgets/formtemplates/evaluator/evaluator.go rename to internal/kubernetes/widgets/formtemplates/evaluator/evaluator.go.txt diff --git a/internal/kubernetes/widgets/formtemplates/evaluator/evaluator_test.go b/internal/kubernetes/widgets/formtemplates/evaluator/evaluator_test.go.txt similarity index 100% rename from internal/kubernetes/widgets/formtemplates/evaluator/evaluator_test.go rename to internal/kubernetes/widgets/formtemplates/evaluator/evaluator_test.go.txt diff --git a/internal/kubernetes/widgets/formtemplates/merger/merger.go b/internal/kubernetes/widgets/formtemplates/merger/merger.go.txt similarity index 100% rename from internal/kubernetes/widgets/formtemplates/merger/merger.go rename to internal/kubernetes/widgets/formtemplates/merger/merger.go.txt diff --git a/internal/kubernetes/widgets/formtemplates/merger/merger_test.go b/internal/kubernetes/widgets/formtemplates/merger/merger_test.go.txt similarity index 100% rename from internal/kubernetes/widgets/formtemplates/merger/merger_test.go rename to internal/kubernetes/widgets/formtemplates/merger/merger_test.go.txt diff --git a/internal/server/routes/layout/columns/getter.go b/internal/server/routes/layout/columns/getter.go index 6506d84..7e2401c 100644 --- a/internal/server/routes/layout/columns/getter.go +++ b/internal/server/routes/layout/columns/getter.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/go-chi/chi/v5" - columnsv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/columns/v1alpha1" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/layout/columns" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/layout/columns/evaluator" @@ -22,18 +21,17 @@ import ( ) const ( - getterPath = "/apis/layout.ui.krateo.io/v1alpha1/columns/{name}" + getterPath = "/apis/layout.ui.krateo.io/columns/{name}" forbiddenGetMsgFmt = "forbidden: User %q cannot get resource %q in API group \"layout.ui.krateo.io\" in namespace %s" ) func newGetter(rc *rest.Config, authnNS string) (string, http.HandlerFunc) { - gr := columnsv1alpha1.ColumnGroupVersionKind.GroupVersion(). - WithResource(resources). - GroupResource() - handler := &getter{ - rc: rc, - gr: gr, + rc: rc, + gr: schema.GroupResource{ + Group: group, + Resource: resource, + }, authnNS: authnNS, } return getterPath, func(wri http.ResponseWriter, req *http.Request) { @@ -62,13 +60,11 @@ func (r *getter) ServeHTTP(wri http.ResponseWriter, req *http.Request) { orgs := strings.Split(qs.Get("orgs"), ",") ok, err := rbacutil.CanListResource(context.TODO(), r.rc, rbacutil.ResourceInfo{ - Subject: sub, - Groups: orgs, - GroupResource: schema.GroupResource{ - Group: columnsv1alpha1.Group, Resource: resources, - }, - ResourceName: name, - Namespace: namespace, + Subject: sub, + Groups: orgs, + GroupResource: r.gr, + ResourceName: name, + Namespace: namespace, }) if err != nil { log.Err(err). @@ -164,11 +160,6 @@ func (r *getter) ServeHTTP(wri http.ResponseWriter, req *http.Request) { } m[allowedVerbsAnnotationKey] = strings.Join(verbs, ",") obj.SetAnnotations(m) - - // _, err = r.client.Namespace(namespace).UpdateStatus(context.TODO(), obj) - // if err != nil { - // log.Err(err).Str("object", obj.GetName()).Msg("unable to update object status") - // } } wri.Header().Set("Content-Type", "application/json") diff --git a/internal/server/routes/layout/columns/lister.go b/internal/server/routes/layout/columns/lister.go index 4c558f0..0039aa9 100644 --- a/internal/server/routes/layout/columns/lister.go +++ b/internal/server/routes/layout/columns/lister.go @@ -7,7 +7,6 @@ import ( "net/http" "strings" - columnsv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/columns/v1alpha1" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/layout/columns" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/layout/columns/evaluator" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/rbac/util" @@ -21,16 +20,20 @@ import ( ) const ( - listerPath = "/apis/layout.ui.krateo.io/v1alpha1/columns" + listerPath = "/apis/layout.ui.krateo.io/columns" forbiddenListAtClusterScopeMsgFmt = "forbidden: User %q cannot list resource \"columns\" in API group \"layout.ui.krateo.io\" at cluster scope" forbiddenListInNamespaceMsgFmt = "forbidden: User %q cannot list resource \"columns\" in API group \"layout.ui.krateo.io\" in namespace %s" ) func newLister(rc *rest.Config, authnNS string) (string, http.HandlerFunc) { - gr := columnsv1alpha1.ColumnGroupVersionKind.GroupVersion(). - WithResource(resources). - GroupResource() - handler := &lister{rc: rc, authnNS: authnNS, gr: gr} + handler := &lister{ + rc: rc, + authnNS: authnNS, + gr: schema.GroupResource{ + Group: group, + Resource: resource, + }, + } return listerPath, func(wri http.ResponseWriter, req *http.Request) { handler.ServeHTTP(wri, req) } @@ -55,12 +58,10 @@ func (r *lister) ServeHTTP(wri http.ResponseWriter, req *http.Request) { orgs := strings.Split(qs.Get("orgs"), ",") ok, err := rbacutil.CanListResource(context.TODO(), r.rc, rbacutil.ResourceInfo{ - Subject: sub, - Groups: orgs, - GroupResource: schema.GroupResource{ - Group: columnsv1alpha1.Group, Resource: resources, - }, - Namespace: namespace, + Subject: sub, + Groups: orgs, + GroupResource: r.gr, + Namespace: namespace, }) if err != nil { log.Err(err). diff --git a/internal/server/routes/layout/columns/register.go b/internal/server/routes/layout/columns/register.go index c514ef1..cce9774 100644 --- a/internal/server/routes/layout/columns/register.go +++ b/internal/server/routes/layout/columns/register.go @@ -7,7 +7,8 @@ import ( const ( allowedVerbsAnnotationKey = "krateo.io/allowed-verbs" - resources = "columns" + group = "layout.ui.krateo.io" + resource = "columns" ) func Register(r *chi.Mux, rc *rest.Config, authnNS string) { diff --git a/internal/server/routes/layout/rows/getter.go b/internal/server/routes/layout/rows/getter.go index cc7456c..184b999 100644 --- a/internal/server/routes/layout/rows/getter.go +++ b/internal/server/routes/layout/rows/getter.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/go-chi/chi/v5" - rowsv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/rows/v1alpha1" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/layout/rows" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/layout/rows/evaluator" @@ -22,18 +21,17 @@ import ( ) const ( - getterPath = "/apis/layout.ui.krateo.io/v1alpha1/rows/{name}" + getterPath = "/apis/layout.ui.krateo.io/rows/{name}" forbiddenGetMsgFmt = "forbidden: User %q cannot get resource %q in API group \"layout.ui.krateo.io\" in namespace %s" ) func newGetter(rc *rest.Config, authnNS string) (string, http.HandlerFunc) { - gr := rowsv1alpha1.RowGroupVersionKind.GroupVersion(). - WithResource(resources). - GroupResource() - handler := &getter{ - rc: rc, - gr: gr, + rc: rc, + gr: schema.GroupResource{ + Group: group, + Resource: resource, + }, authnNS: authnNS, } return getterPath, func(wri http.ResponseWriter, req *http.Request) { @@ -62,13 +60,11 @@ func (r *getter) ServeHTTP(wri http.ResponseWriter, req *http.Request) { orgs := strings.Split(qs.Get("orgs"), ",") ok, err := rbacutil.CanListResource(context.TODO(), r.rc, rbacutil.ResourceInfo{ - Subject: sub, - Groups: orgs, - GroupResource: schema.GroupResource{ - Group: rowsv1alpha1.Group, Resource: resources, - }, - ResourceName: name, - Namespace: namespace, + Subject: sub, + Groups: orgs, + GroupResource: r.gr, + ResourceName: name, + Namespace: namespace, }) if err != nil { log.Err(err). diff --git a/internal/server/routes/layout/rows/lister.go b/internal/server/routes/layout/rows/lister.go index 85ab640..b46274a 100644 --- a/internal/server/routes/layout/rows/lister.go +++ b/internal/server/routes/layout/rows/lister.go @@ -7,7 +7,6 @@ import ( "net/http" "strings" - rowsv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/rows/v1alpha1" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/layout/rows" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/layout/rows/evaluator" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/rbac/util" @@ -21,16 +20,20 @@ import ( ) const ( - listerPath = "/apis/layout.ui.krateo.io/v1alpha1/rows" + listerPath = "/apis/layout.ui.krateo.io/rows" forbiddenListAtClusterScopeMsgFmt = "forbidden: User %q cannot list resource \"rows\" in API group \"layout.ui.krateo.io\" at cluster scope" forbiddenListInNamespaceMsgFmt = "forbidden: User %q cannot list resource \"rows\" in API group \"layout.ui.krateo.io\" in namespace %s" ) func newLister(rc *rest.Config, authnNS string) (string, http.HandlerFunc) { - gr := rowsv1alpha1.RowGroupVersionKind.GroupVersion(). - WithResource(resources). - GroupResource() - handler := &lister{rc: rc, authnNS: authnNS, gr: gr} + handler := &lister{ + rc: rc, + authnNS: authnNS, + gr: schema.GroupResource{ + Group: group, + Resource: resource, + }, + } return listerPath, func(wri http.ResponseWriter, req *http.Request) { handler.ServeHTTP(wri, req) } @@ -55,12 +58,10 @@ func (r *lister) ServeHTTP(wri http.ResponseWriter, req *http.Request) { orgs := strings.Split(qs.Get("orgs"), ",") ok, err := rbacutil.CanListResource(context.TODO(), r.rc, rbacutil.ResourceInfo{ - Subject: sub, - Groups: orgs, - GroupResource: schema.GroupResource{ - Group: rowsv1alpha1.Group, Resource: resources, - }, - Namespace: namespace, + Subject: sub, + Groups: orgs, + GroupResource: r.gr, + Namespace: namespace, }) if err != nil { log.Err(err). diff --git a/internal/server/routes/layout/rows/register.go b/internal/server/routes/layout/rows/register.go index 471fc8f..c65e790 100644 --- a/internal/server/routes/layout/rows/register.go +++ b/internal/server/routes/layout/rows/register.go @@ -7,7 +7,8 @@ import ( const ( allowedVerbsAnnotationKey = "krateo.io/allowed-verbs" - resources = "rows" + group = "layout.ui.krateo.io" + resource = "rows" ) func Register(r *chi.Mux, rc *rest.Config, authnNS string) { diff --git a/internal/server/routes/widgets/cardtemplates/getter.go b/internal/server/routes/widgets/cardtemplates/getter.go index 37d9486..48bd4fd 100644 --- a/internal/server/routes/widgets/cardtemplates/getter.go +++ b/internal/server/routes/widgets/cardtemplates/getter.go @@ -8,7 +8,6 @@ import ( "strings" "github.com/go-chi/chi/v5" - cardtemplatev1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/cardtemplates/v1alpha1" rbacutil "github.com/krateoplatformops/krateo-bff/internal/kubernetes/rbac/util" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/widgets/cardtemplates" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/widgets/cardtemplates/evaluator" @@ -20,17 +19,16 @@ import ( ) const ( - getterPath = "/apis/widgets.ui.krateo.io/v1alpha1/cardtemplates/{name}" + getterPath = "/apis/widgets.ui.krateo.io/cardtemplates/{name}" ) func newGetter(rc *rest.Config, authnNS string) (string, http.HandlerFunc) { - gr := cardtemplatev1alpha1.CardTemplateGroupVersionKind.GroupVersion(). - WithResource("cardtemplates"). - GroupResource() - handler := &getter{ - rc: rc, - gr: gr, + rc: rc, + gr: schema.GroupResource{ + Group: group, + Resource: resource, + }, authnNS: authnNS, } return getterPath, func(wri http.ResponseWriter, req *http.Request) { diff --git a/internal/server/routes/widgets/cardtemplates/lister.go b/internal/server/routes/widgets/cardtemplates/lister.go index 05d32da..919924a 100644 --- a/internal/server/routes/widgets/cardtemplates/lister.go +++ b/internal/server/routes/widgets/cardtemplates/lister.go @@ -7,7 +7,6 @@ import ( "net/http" "strings" - cardtemplatev1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/cardtemplates/v1alpha1" rbacutil "github.com/krateoplatformops/krateo-bff/internal/kubernetes/rbac/util" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/widgets/cardtemplates" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/widgets/cardtemplates/evaluator" @@ -20,16 +19,20 @@ import ( ) const ( - listerPath = "/apis/widgets.ui.krateo.io/v1alpha1/cardtemplates" + listerPath = "/apis/widgets.ui.krateo.io/cardtemplates" forbiddenAtClusterScopeMsgFmt = "forbidden: User %q cannot list resource \"cardtemplates\" in API group \"widgets.ui.krateo.io\" at cluster scope" forbiddenInNamespaceMsgFmt = "forbidden: User %q cannot list resource \"cardtemplates\" in API group \"widgets.ui.krateo.io\" in namespace %s" ) func newLister(rc *rest.Config, authnNS string) (string, http.HandlerFunc) { - gr := cardtemplatev1alpha1.CardTemplateGroupVersionKind.GroupVersion(). - WithResource("cardtemplates"). - GroupResource() - handler := &lister{rc: rc, authnNS: authnNS, gr: gr} + handler := &lister{ + rc: rc, + authnNS: authnNS, + gr: schema.GroupResource{ + Group: group, + Resource: resource, + }, + } return listerPath, func(wri http.ResponseWriter, req *http.Request) { handler.ServeHTTP(wri, req) } @@ -54,12 +57,10 @@ func (r *lister) ServeHTTP(wri http.ResponseWriter, req *http.Request) { orgs := strings.Split(qs.Get("orgs"), ",") ok, err := rbacutil.CanListResource(context.TODO(), r.rc, rbacutil.ResourceInfo{ - Subject: sub, - Groups: orgs, - GroupResource: schema.GroupResource{ - Group: cardtemplatev1alpha1.Group, Resource: "cardtemplates", - }, - Namespace: namespace, + Subject: sub, + Groups: orgs, + GroupResource: r.gr, + Namespace: namespace, }) if err != nil { log.Err(err). diff --git a/internal/server/routes/widgets/cardtemplates/register.go b/internal/server/routes/widgets/cardtemplates/register.go index 383335b..33ccf64 100644 --- a/internal/server/routes/widgets/cardtemplates/register.go +++ b/internal/server/routes/widgets/cardtemplates/register.go @@ -7,6 +7,8 @@ import ( const ( allowedVerbsAnnotationKey = "krateo.io/allowed-verbs" + group = "widgets.ui.krateo.io" + resource = "cardtemplates" ) func Register(r *chi.Mux, rc *rest.Config, authnNS string) { diff --git a/internal/server/routes/widgets/formtemplates/definition.go b/internal/server/routes/widgets/formtemplates/definition.go deleted file mode 100644 index c8b8623..0000000 --- a/internal/server/routes/widgets/formtemplates/definition.go +++ /dev/null @@ -1,21 +0,0 @@ -package formtemplates - -import ( - "context" - - formdefinitionsv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/core/formdefinitions/v1alpha1" - formtemplatesv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/formtemplates/v1alpha1" - "github.com/krateoplatformops/krateo-bff/internal/kubernetes/formdefinitions" - "k8s.io/client-go/rest" -) - -func getFormDefinition(ctx context.Context, rc *rest.Config, in *formtemplatesv1alpha1.FormTemplate) (*formdefinitionsv1alpha1.FormDefinition, error) { - formdefinitionsClient, err := formdefinitions.NewClient(rc) - if err != nil { - return nil, err - } - - return formdefinitionsClient. - Namespace(in.Spec.DefinitionRef.Namespace). - Get(ctx, in.Spec.DefinitionRef.Name) -} diff --git a/internal/server/routes/widgets/formtemplates/getter.go b/internal/server/routes/widgets/formtemplates/getter.go index 4a6589f..e47298c 100644 --- a/internal/server/routes/widgets/formtemplates/getter.go +++ b/internal/server/routes/widgets/formtemplates/getter.go @@ -9,7 +9,9 @@ import ( "github.com/go-chi/chi/v5" formtemplatesv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/formtemplates/v1alpha1" + "github.com/krateoplatformops/krateo-bff/internal/kubernetes/dynamic" rbacutil "github.com/krateoplatformops/krateo-bff/internal/kubernetes/rbac/util" + "github.com/krateoplatformops/krateo-bff/internal/kubernetes/schemadefinitions" "github.com/krateoplatformops/krateo-bff/internal/kubernetes/widgets/formtemplates" "github.com/krateoplatformops/krateo-bff/internal/server/encode" "github.com/rs/zerolog" @@ -20,17 +22,16 @@ import ( ) const ( - getterPath = "/apis/widgets.ui.krateo.io/v1alpha1/formtemplates/{name}" + getterPath = "/apis/widgets.ui.krateo.io/formtemplates/{name}" ) func newGetter(rc *rest.Config, authnNS string) (string, http.HandlerFunc) { - gr := formtemplatesv1alpha1.FormTemplateGroupVersionKind.GroupVersion(). - WithResource("formtemplates"). - GroupResource() - handler := &getter{ - rc: rc, - gr: gr, + rc: rc, + gr: schema.GroupResource{ + Group: group, + Resource: resource, + }, authnNS: authnNS, } return getterPath, func(wri http.ResponseWriter, req *http.Request) { @@ -41,10 +42,11 @@ func newGetter(rc *rest.Config, authnNS string) (string, http.HandlerFunc) { var _ http.Handler = (*getter)(nil) type getter struct { - rc *rest.Config - client *formtemplates.Client - gr schema.GroupResource - authnNS string + rc *rest.Config + gr schema.GroupResource + templatesClient *formtemplates.Client + definitionsClient *schemadefinitions.Client + authnNS string } func (r *getter) ServeHTTP(wri http.ResponseWriter, req *http.Request) { @@ -57,56 +59,24 @@ func (r *getter) ServeHTTP(wri http.ResponseWriter, req *http.Request) { namespace := qs.Get("namespace") sub := qs.Get("sub") orgs := strings.Split(qs.Get("orgs"), ",") + version := qs.Get("version") + if len(version) == 0 { + version = "v1alpha1" + } - ok, err := rbacutil.CanListResource(context.TODO(), r.rc, rbacutil.ResourceInfo{ - Subject: sub, - Groups: orgs, - GroupResource: r.gr, - ResourceName: name, - Namespace: namespace, - }) - if err != nil { + if err := r.complete(); err != nil { log.Err(err). Str("sub", sub). Strs("orgs", orgs). Str("name", name). Str("namespace", namespace). - Msg("checking if 'get' verb is allowed") - encode.InternalError(wri, err) - return - } + Msg("unable to initialize rest clients") - if !ok { - encode.Forbidden(wri, - fmt.Errorf("forbidden: User %q cannot get resource \"formtemplates/%s\" in API group \"widgets.ui.krateo.io\"", sub, name)) + encode.InternalError(wri, err) return } - log.Debug(). - Str("sub", sub). - Strs("orgs", orgs). - Str("name", name). - Str("namespace", namespace). - Msg("resolving form template") - - if r.client == nil { - cli, err := formtemplates.NewClient(r.rc) - if err != nil { - log.Err(err). - Str("sub", sub). - Strs("orgs", orgs). - Str("name", name). - Str("namespace", namespace). - Msg("unable to create form template rest client") - - encode.InternalError(wri, err) - return - } - - r.client = cli - } - - obj, err := r.client.Namespace(namespace).Get(context.TODO(), name) + obj, err := r.templatesClient.Namespace(namespace).Get(context.Background(), name) if err != nil { log.Err(err). Str("sub", sub). @@ -123,42 +93,69 @@ func (r *getter) ServeHTTP(wri http.ResponseWriter, req *http.Request) { return } - def, err := getFormDefinition(context.TODO(), r.rc, obj) + formGVK, err := r.definitionsClient.Namespace(obj.Spec.SchemaDefinitionRef.Namespace). + GVK(context.Background(), obj.Spec.SchemaDefinitionRef.Name) if err != nil { log.Err(err). + Str("sub", sub). + Strs("orgs", orgs). + Str("name", name). Str("namespace", namespace). - Str("object", obj.GetName()). - Msg("unable to resolve form definition reference") - - encode.Invalid(wri, err) + Msg("unable to resolve form definition gvk") + if apierrors.IsNotFound(err) { + encode.NotFound(wri, err) + } else { + encode.Invalid(wri, err) + } return } - sch, err := getFormSchema(context.TODO(), r.rc, def) + ok, err := rbacutil.CanListResource(context.TODO(), r.rc, rbacutil.ResourceInfo{ + Subject: sub, + Groups: orgs, + GroupResource: dynamic.InferGroupResource(formGVK.Group, formGVK.Kind), + ResourceName: name, + Namespace: namespace, + }) if err != nil { log.Err(err). + Str("sub", sub). + Strs("orgs", orgs). + Str("name", name). Str("namespace", namespace). - Str("object", obj.GetName()). - Msg("unable to resolve form definition openAPI schema") + Msg("checking if 'get' verb is allowed") + encode.InternalError(wri, err) + return + } - encode.Invalid(wri, err) + if !ok { + gr := dynamic.InferGroupResource(formGVK.Group, formGVK.Kind) + encode.Forbidden(wri, + fmt.Errorf("forbidden: User %q cannot get resource %q", sub, gr)) return } - vals, err := getFormValues(context.TODO(), r.rc, def, obj) + log.Debug(). + Str("sub", sub). + Strs("orgs", orgs). + Str("name", name). + Str("namespace", namespace). + Msg("resolving form template") + + sch, err := r.definitionsClient.OpenAPISchema(context.Background(), formGVK) if err != nil { log.Err(err). Str("namespace", namespace). Str("object", obj.GetName()). - Msg("unable to resolve form values") + Msg("unable to resolve schema definition openAPI schema") encode.Invalid(wri, err) return } obj.Status.Content = &formtemplatesv1alpha1.FormTemplateStatusContent{ - Instance: &runtime.RawExtension{Object: vals}, - Schema: &runtime.RawExtension{Object: sch}, + //Instance: &runtime.RawExtension{Object: vals}, + Schema: &runtime.RawExtension{Object: sch}, } wri.Header().Set("Content-Type", "application/json") @@ -170,3 +167,25 @@ func (r *getter) ServeHTTP(wri http.ResponseWriter, req *http.Request) { log.Err(err).Msg("unable to serve json encoded form template") } } + +func (r *getter) complete() error { + if r.templatesClient == nil { + cli, err := formtemplates.NewClient(r.rc) + if err != nil { + return err + } + + r.templatesClient = cli + } + + if r.definitionsClient == nil { + cli, err := schemadefinitions.NewClient(r.rc) + if err != nil { + return err + } + + r.definitionsClient = cli + } + + return nil +} diff --git a/internal/server/routes/widgets/formtemplates/register.go b/internal/server/routes/widgets/formtemplates/register.go index cb4e3b6..907600d 100644 --- a/internal/server/routes/widgets/formtemplates/register.go +++ b/internal/server/routes/widgets/formtemplates/register.go @@ -7,6 +7,8 @@ import ( const ( allowedVerbsAnnotationKey = "krateo.io/allowed-verbs" + group = "widgets.ui.krateo.io" + resource = "formtemplates" ) func Register(r *chi.Mux, rc *rest.Config, authnNS string) { diff --git a/internal/server/routes/widgets/formtemplates/resource.go b/internal/server/routes/widgets/formtemplates/resource.go deleted file mode 100644 index 49d9538..0000000 --- a/internal/server/routes/widgets/formtemplates/resource.go +++ /dev/null @@ -1,64 +0,0 @@ -package formtemplates - -import ( - "context" - "fmt" - - formdefinitionsv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/core/formdefinitions/v1alpha1" - formtemplatesv1alpha1 "github.com/krateoplatformops/krateo-bff/apis/ui/formtemplates/v1alpha1" - "github.com/krateoplatformops/krateo-bff/internal/kubernetes/dynamic" - formdefinitionsutil "github.com/krateoplatformops/krateo-bff/internal/kubernetes/formdefinitions/util" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/rest" -) - -const ( - openAPIV3SchemaFilter = `.spec.versions[] | select(.name="%s") | .schema.openAPIV3Schema` -) - -func getFormValues(ctx context.Context, rc *rest.Config, ref *formdefinitionsv1alpha1.FormDefinition, in *formtemplatesv1alpha1.FormTemplate) (*unstructured.Unstructured, error) { - dyn, err := dynamic.NewGetter(rc) - if err != nil { - return nil, err - } - - return dyn.Get(ctx, dynamic.GetOptions{ - GVK: schema.GroupVersionKind{ - Group: ref.Spec.Schema.Group, - Version: ref.Spec.Schema.Version, - Kind: ref.Spec.Schema.Kind, - }, - Namespace: in.Spec.ResourceRef.Namespace, - Name: in.Spec.ResourceRef.Name, - }) -} - -func getFormSchema(ctx context.Context, rc *rest.Config, ref *formdefinitionsv1alpha1.FormDefinition) (*unstructured.Unstructured, error) { - dyn, err := dynamic.NewGetter(rc) - if err != nil { - return nil, err - } - - crd, err := dyn.Get(ctx, dynamic.GetOptions{ - GVK: schema.GroupVersionKind{ - Group: "apiextensions.k8s.io", - Version: "v1", - Kind: "CustomResourceDefinition", - }, - Name: formdefinitionsutil.InferGroupResource(ref).String(), - }) - if err != nil { - return nil, err - } - - filter := fmt.Sprintf(openAPIV3SchemaFilter, ref.Spec.Schema.Version) - sch, err := dynamic.Extract(ctx, crd, filter) - if err != nil { - return nil, err - } - - return &unstructured.Unstructured{ - Object: sch.(map[string]any), - }, nil -} diff --git a/scripts/server-run.sh b/scripts/server-run.sh index 5cd7932..ac902b0 100755 --- a/scripts/server-run.sh +++ b/scripts/server-run.sh @@ -1,5 +1,8 @@ #!/bin/bash +# Startup Kind +kind get kubeconfig >/dev/null 2>&1 || kind create cluster + export KRATEO_BFF_DEBUG=true export KRATEO_BFF_DUMP_ENV=true export KRATEO_BFF_PORT=8090 @@ -7,6 +10,7 @@ export AUTHN_STORE_NAMESPACE=demo-system # All CRDs kubectl apply -f crds/ + # Create the 'demo' namespace kubectl apply -f testdata/ns.yaml # CardTemplate sample @@ -15,12 +19,20 @@ kubectl apply -f testdata/cardtemplate-demo.yaml kubectl apply -f testdata/column-demo.yaml # Row sample kubectl apply -f testdata/row-demo.yaml -# FormDefinition sample -kubectl apply -f testdata/formdefinition.sample.yaml + +# SchemaDefinition sample +kubectl apply -f testdata/schemadefinition.crd.yaml +kubectl apply -f testdata/schemadefinition.sample.yaml # FormTemplate sample kubectl apply -f testdata/formtemplate.sample.yaml # Dummy 'FireworksApp' CRD (just for test/demo scopes) kubectl apply -f testdata/fireworksapp.crd.yaml kubectl apply -f testdata/fireworksapp.sample.yaml +# Install roles +kubectl apply -f testdata/clusterrole-widgets-viewer.yaml +kubectl apply -f testdata/clusterrole-layout-viewer.yaml +kubectl apply -f testdata/clusterrole-formtemplates-viewer.yaml +kubectl apply -f testdata/clusterrole-apps-viewer.yaml + go run main.go -kubeconfig $HOME/.kube/config diff --git a/testdata/clusterrole-apps-viewer.yaml b/testdata/clusterrole-apps-viewer.yaml new file mode 100644 index 0000000..05f104c --- /dev/null +++ b/testdata/clusterrole-apps-viewer.yaml @@ -0,0 +1,26 @@ +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: apps-viewer +rules: +- apiGroups: + - apps.krateo.io + resources: + - '*' + verbs: + - get + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: apps-viewer +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: apps-viewer +subjects: +- kind: Group + name: devs + apiGroup: rbac.authorization.k8s.io diff --git a/testdata/fireworksapp.crd.yaml b/testdata/fireworksapp.crd.yaml index befd602..0cc72f0 100644 --- a/testdata/fireworksapp.crd.yaml +++ b/testdata/fireworksapp.crd.yaml @@ -4,7 +4,7 @@ kind: CustomResourceDefinition metadata: annotations: controller-gen.kubebuilder.io/version: v0.14.0 - name: fireworksappforms.apps.krateo.io + name: fireworksapps.apps.krateo.io spec: group: apps.krateo.io names: @@ -12,10 +12,10 @@ spec: - app - fireworks - krateo - kind: FireworksappForm - listKind: FireworksappFormList - plural: fireworksappforms - singular: fireworksappform + kind: Fireworksapp + listKind: FireworksappList + plural: fireworksapps + singular: fireworksapp scope: Namespaced versions: - name: v1alpha1 diff --git a/testdata/fireworksapp.sample.yaml b/testdata/fireworksapp.sample.yaml index 1c4d4b6..a16a86a 100644 --- a/testdata/fireworksapp.sample.yaml +++ b/testdata/fireworksapp.sample.yaml @@ -1,6 +1,6 @@ --- apiVersion: apps.krateo.io/v1alpha1 -kind: FireworksappForm +kind: Fireworksapp metadata: annotations: "krateo.io/connector-verbose": "true" diff --git a/testdata/formtemplate.api.sample.yaml b/testdata/formtemplate.api.sample.yaml deleted file mode 100644 index 0219af3..0000000 --- a/testdata/formtemplate.api.sample.yaml +++ /dev/null @@ -1,39 +0,0 @@ ---- -apiVersion: v1 -kind: Secret -type: Opaque -metadata: - name: dummyjson-endpoint - namespace: demo-system -stringData: - #debug: "true" - server-url: https://dummyjson.com ---- -apiVersion: widgets.ui.krateo.io/v1alpha1 -kind: FormTemplate -metadata: - name: fireworksapp-with-api - namespace: demo-system -spec: - definitionRef: - name: fireworksapp - namespace: demo-system - resourceRef: - name: fireworksapp - namespace: demo-system - data: - - path: git.replaceValues.key1 - value: ${ .product1.title } - - path: git.replaceValues.key2 - value: ${ .product1.stock } - - path: git.replaceValues.key2 - value: ${ .product1.category } - api: - - name: product1 - path: "/products/1" - endpointRef: - name: dummyjson-endpoint - namespace: demo-system - verb: GET - headers: - - 'Accept: application/json' diff --git a/testdata/formtemplate.sample.yaml b/testdata/formtemplate.sample.yaml index 36664cf..4ed02b2 100644 --- a/testdata/formtemplate.sample.yaml +++ b/testdata/formtemplate.sample.yaml @@ -5,16 +5,6 @@ metadata: name: fireworksapp namespace: demo-system spec: - definitionRef: + schemaDefinitionRef: name: fireworksapp namespace: demo-system - resourceRef: - name: fireworksapp - namespace: demo-system - data: - - path: spec.git.replaceValues.key1 - value: "Hello" - - path: spec.git.replaceValues.key2 - value: "32" - - path: spec.git.replaceValues.key3 - value: "true" diff --git a/crds/core.krateo.io_formdefinitions.yaml b/testdata/schemadefinition.crd.yaml similarity index 60% rename from crds/core.krateo.io_formdefinitions.yaml rename to testdata/schemadefinition.crd.yaml index 00d027d..39024e1 100644 --- a/crds/core.krateo.io_formdefinitions.yaml +++ b/testdata/schemadefinition.crd.yaml @@ -3,8 +3,8 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.13.0 - name: formdefinitions.core.krateo.io + controller-gen.kubebuilder.io/version: v0.14.0 + name: schemadefinitions.core.krateo.io spec: group: core.krateo.io names: @@ -12,11 +12,11 @@ spec: - krateo - definition - frontend - - forms - kind: FormDefinition - listKind: FormDefinitionList - plural: formdefinitions - singular: formdefinition + - schema + kind: SchemaDefinition + listKind: SchemaDefinitionList + plural: schemadefinitions + singular: schemadefinition scope: Namespaced versions: - additionalPrinterColumns: @@ -33,28 +33,32 @@ spec: name: v1alpha1 schema: openAPIV3Schema: - description: FormDefinition is a definition type with a spec and a status. 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' + 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' + 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: FormDefinitionSpec is the specification of a Definition. properties: deletionPolicy: default: Delete - description: DeletionPolicy specifies what will happen to the underlying - external when this managed resource is deleted - either "Delete" - or "Orphan" the external resource. + description: |- + DeletionPolicy specifies what will happen to the underlying external + when this managed resource is deleted - either "Delete" or "Orphan" the + external resource. enum: - Orphan - Delete @@ -62,9 +66,6 @@ spec: schema: description: 'Schema: the schema info' properties: - group: - description: 'Group: collection of kinds.' - type: string kind: description: 'Kind: the name of the object you are trying to generate' type: string @@ -76,16 +77,13 @@ spec: versions.' type: string required: - - group - kind - url - - version type: object required: - schema type: object status: - description: FormDefinitionStatus is the status of a Definition. properties: conditions: description: Conditions of the resource. @@ -93,13 +91,15 @@ spec: description: A Condition that may apply to a resource. properties: lastTransitionTime: - description: LastTransitionTime is the last time this condition - transitioned from one status to another. + 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. + 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 @@ -110,8 +110,9 @@ spec: 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. + 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 @@ -131,4 +132,4 @@ spec: served: true storage: true subresources: - status: {} + status: {} \ No newline at end of file diff --git a/testdata/formdefinition.sample.yaml b/testdata/schemadefinition.sample.yaml similarity index 80% rename from testdata/formdefinition.sample.yaml rename to testdata/schemadefinition.sample.yaml index c8a85f8..7fd6f25 100644 --- a/testdata/formdefinition.sample.yaml +++ b/testdata/schemadefinition.sample.yaml @@ -1,5 +1,5 @@ apiVersion: core.krateo.io/v1alpha1 -kind: FormDefinition +kind: SchemaDefinition metadata: annotations: "krateo.io/connector-verbose": "true" @@ -7,7 +7,6 @@ metadata: namespace: demo-system spec: schema: - #group: apps.krateo.io version: v1alpha1 - kind: FireworksappForm + kind: Fireworksapp url: https://raw.githubusercontent.com/krateoplatformops/krateo-v2-template-fireworksapp/main/chart/values.schema.json