From 15b243aea65d307febbf167f03bdf5d45ff8d56a Mon Sep 17 00:00:00 2001 From: Chunlin Yang Date: Wed, 29 May 2024 21:51:16 +0800 Subject: [PATCH 1/3] Set maestro as source (#98) Signed-off-by: clyang82 --- pkg/api/presenters/resource.go | 10 +++++++--- pkg/constants/constants.go | 5 +++++ 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 pkg/constants/constants.go diff --git a/pkg/api/presenters/resource.go b/pkg/api/presenters/resource.go index 929efec5..5a18703b 100755 --- a/pkg/api/presenters/resource.go +++ b/pkg/api/presenters/resource.go @@ -1,10 +1,12 @@ package presenters import ( + "gorm.io/datatypes" + "github.com/openshift-online/maestro/pkg/api" "github.com/openshift-online/maestro/pkg/api/openapi" + "github.com/openshift-online/maestro/pkg/constants" "github.com/openshift-online/maestro/pkg/util" - "gorm.io/datatypes" ) // ConvertResource converts a resource from the API to the openapi representation. @@ -20,8 +22,10 @@ func ConvertResource(resource openapi.Resource) (*api.Resource, error) { }, ConsumerName: util.NilToEmptyString(resource.ConsumerName), Version: util.NilToEmptyInt32(resource.Version), - Type: api.ResourceTypeSingle, - Manifest: manifest, + // Set the default source ID for RESTful API calls and do not allow modification + Source: constants.DefaultSourceID, + Type: api.ResourceTypeSingle, + Manifest: manifest, }, nil } diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go new file mode 100644 index 00000000..6467883b --- /dev/null +++ b/pkg/constants/constants.go @@ -0,0 +1,5 @@ +package constants + +const ( + DefaultSourceID = "maestro" +) From 253a30058b78cd8e9a4467d2393e769dadf8a1dd Mon Sep 17 00:00:00 2001 From: Chunlin Yang Date: Thu, 30 May 2024 10:52:48 +0800 Subject: [PATCH 2/3] Support UpdateStrategy and DeleteOption (#99) * Support UpdateStrategy and DeleteOption Signed-off-by: clyang82 * Return delete_option and update_strategy Signed-off-by: clyang82 * Add e2e tests Signed-off-by: clyang82 --------- Signed-off-by: clyang82 --- README.md | 21 +++ data/generated/openapi/openapi.go | 4 +- openapi/openapi.yaml | 8 + pkg/api/openapi/api/openapi.yaml | 10 ++ pkg/api/openapi/docs/Resource.md | 52 +++++++ pkg/api/openapi/docs/ResourceAllOf.md | 52 +++++++ pkg/api/openapi/docs/ResourcePatchRequest.md | 52 +++++++ pkg/api/openapi/model_resource.go | 92 +++++++++-- pkg/api/openapi/model_resource_all_of.go | 86 ++++++++++- .../openapi/model_resource_patch_request.go | 76 ++++++++- pkg/api/presenters/resource.go | 30 ++-- pkg/api/resource_types.go | 100 ++++++++++-- pkg/api/resource_types_test.go | 73 +++++---- pkg/handlers/resource.go | 2 +- pkg/services/validation.go | 7 +- test/e2e/pkg/resources_test.go | 145 +++++++++++++++++- test/e2e/pkg/serverside_test.go | 6 + test/factories.go | 2 +- test/grpc_codec.go | 4 +- 19 files changed, 730 insertions(+), 92 deletions(-) diff --git a/README.md b/README.md index 6cbaf01c..ccf6cfb4 100755 --- a/README.md +++ b/README.md @@ -204,11 +204,26 @@ ocm post /api/maestro/v1/resources << EOF } } } + }, + "update_strategy": { + "type": "ServerSideApply" + }, + "delete_option": { + "propagationPolicy": "Foreground" } } EOF ``` +delete_option defines the option to delete the resource. It is optional when creating a resource. The propagationPolicy of `delete_option` can be: +- `Foreground` represents that the resource should be fourground deleted. This is a default value. +- `Orphan` represents that the resource is orphaned when deleting the resource. + +update_strategy defines the strategy to update the resource. It is optional when creating a resource. The type of `update_strategy` can be: +- `ServerSideApply` means to update resource using server side apply with work-controller as the field manager. This is a default value. +- `Update` means to update resource by an update call. +- `CreateOnly` means do not update resource based on current manifest. +- `ReadOnly` means only check the existence of the resource based on the resource's metadata. #### Get your Resource @@ -219,6 +234,9 @@ ocm get /api/maestro/v1/resources { "consumer_name": "cluster1", "created_at": "2023-11-23T09:26:13.43061Z", + "delete_option": { + "propagationPolicy":"Foreground" + }, "href": "/api/maestro/v1/resources/f428e21d-71cb-47a4-8d7f-82a65d9a4048", "id": "f428e21d-71cb-47a4-8d7f-82a65d9a4048", "kind": "Resource", @@ -307,6 +325,9 @@ ocm get /api/maestro/v1/resources "SequenceID": "1744926882802962432" } }, + "update_strategy": { + "type":"ServerSideApply" + }, "updated_at": "2023-11-23T09:26:13.457419Z", "version": 1 } diff --git a/data/generated/openapi/openapi.go b/data/generated/openapi/openapi.go index 4aec3434..97c79a55 100755 --- a/data/generated/openapi/openapi.go +++ b/data/generated/openapi/openapi.go @@ -77,7 +77,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _openapiYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5c\x5f\x8f\xdb\xb8\x11\x7f\xf7\xa7\x18\xa0\x2d\x7c\x39\x78\x6d\xa7\x77\x05\x5a\x23\x39\x20\xb9\x5e\x8a\x3b\xe4\x92\x34\x9b\xb4\x0f\x45\xb1\x4b\x93\x23\x8b\xb7\x12\xa9\x90\xd4\xee\x3a\x6d\xbf\x7b\x41\x52\xff\x2d\x69\x65\x63\x37\x56\x16\xbe\x97\x5b\x51\xc3\xe1\x0c\xf9\x9b\x9f\x86\x1c\x3a\x32\x41\x41\x12\xbe\x82\xef\xe6\xcb\xf9\x72\xc2\x45\x20\x57\x13\x00\xc3\x4d\x84\x2b\x88\x09\x6a\xa3\x24\x9c\xa3\xba\xe6\x14\xe1\xc5\xbb\x9f\x27\x00\x0c\x35\x55\x3c\x31\x5c\x8a\x2e\x91\x6b\x54\xda\xbd\x5e\xce\x97\xf3\xa7\x13\x8d\xca\xb6\x58\xcd\x67\x90\xaa\x68\x05\xa1\x31\xc9\x6a\xb1\x88\x24\x25\x51\x28\xb5\x59\xfd\x79\xb9\x5c\x4e\x00\x1a\xda\x69\xaa\x14\x0a\x03\x4c\xc6\x84\x8b\x7a\x77\xbd\x5a\x2c\x48\xc2\xe7\xd6\x05\x1d\xf2\xc0\xcc\xa9\x8c\x77\x55\xfc\x4a\xb8\x80\x6f\x12\x25\x59\x4a\x6d\xcb\x13\xf0\xd6\xb4\x2b\xd3\x86\x6c\xf0\x2e\x95\xe7\x86\x6c\xb8\xd8\xe4\x8a\x12\x62\x42\xe7\x9b\xd5\xb0\xc8\x26\x64\x71\xfd\x74\xa1\x50\xcb\x54\x51\x74\x2f\x01\x36\x68\xfc\x1f\x00\x3a\x8d\x63\xa2\xb6\x2b\x78\x8f\x26\x55\x42\x03\x81\x88\x6b\x03\x32\x80\xa2\x53\x2e\x8a\x34\x55\xdc\x6c\xf3\xae\xd6\xec\x97\x48\x14\xaa\x15\xfc\xeb\xdf\x59\xa3\x42\x9d\x48\xa1\xf3\x91\xec\x7f\xd3\x3f\x2e\x97\xd3\xf2\xb1\xe1\xc2\x0b\xf8\xe5\xfc\xed\x1b\x20\x4a\x91\x6d\x75\x54\x90\xeb\xdf\x90\x1a\x5d\xe9\x47\xa5\x30\x28\x4c\x55\x15\x00\x49\x92\x88\x53\x62\x95\x2d\x7e\xd3\x52\xd4\xdf\x02\x68\x1a\x62\x4c\x9a\xad\x00\xbf\x57\x18\xac\x60\xfa\xbb\x05\x95\x71\x22\x05\x0a\xa3\x17\x5e\x56\x2f\xde\x67\x36\xbc\xe6\xda\x4c\x4b\x3f\xbe\x5f\x3e\xed\xf1\x23\x35\x21\x18\x79\x85\x02\xb8\x06\x2e\xae\x49\xc4\xd9\x31\x8c\xff\x49\x29\xa9\x6a\x56\x7f\xd7\x6d\xf5\x47\x41\x52\x13\x4a\xc5\x3f\x23\x03\x23\x21\x41\x15\x48\x15\x83\x4c\x50\x39\xb3\xc6\xe0\xc1\x9f\xfa\xf0\xf3\x51\xe0\x6d\x82\xd4\x20\x03\xb4\xfd\x40\x52\x17\xab\xc7\x9f\xfb\x84\x28\x12\xa3\xc9\xe8\x06\x5c\xbc\xb4\x75\x2e\xe5\x16\x09\xd9\xe0\x74\xa8\xb0\xe6\x9f\xf7\x10\x46\xa2\x68\x38\x58\x5c\x2a\x86\xea\xe5\x76\xb0\x7c\xc0\x31\x62\xda\x8b\x27\x96\x45\x9b\xf4\xf2\xa3\x42\x62\x10\x08\x08\xbc\x29\x62\x7c\x3f\x62\xf9\x94\xa2\x36\x2f\x25\xab\xc8\xd5\x90\x90\x47\x2d\x30\x62\x48\x21\x62\xfb\x71\x85\x6c\x05\x46\xa5\x38\xe9\x81\x44\x3f\x20\xda\xe1\x30\x84\x45\xa6\xbd\xd4\xd8\x43\x29\x7e\xce\x8e\x02\xe4\xa6\xed\x8e\x47\x7a\xa2\xf0\x1f\x96\xed\x9c\x09\x3e\x0a\xf5\x78\xc2\xf0\x44\xdc\x47\xf4\xe0\x2f\xdd\x1e\x14\xe1\x4a\x22\x85\x84\x6d\x01\x6f\xb9\x3e\xce\xf7\x7e\xaf\x0f\xce\x0b\x01\x69\xd7\x37\x07\xa8\x0d\x59\x9b\x91\x99\x10\x9b\x34\x77\x1c\x97\x3a\x53\xc1\xc5\x7f\x38\xfb\x5f\x77\x3e\xf8\x37\x34\x40\x44\x99\x8e\xad\xb7\x50\x84\xc5\xc3\x64\x82\x05\x20\x02\x99\x0a\x56\x1b\xf0\x8b\x4e\x5d\x2b\xf7\x9d\x08\xe4\x38\x1e\x7c\xdf\xed\xc1\x1b\x59\xa2\xf3\x86\x9b\x10\x74\x82\x94\x07\x1c\x19\x70\xf6\xb5\xb0\xc9\x58\xd3\xd7\x84\x18\x1a\xee\x90\xc2\xc7\x84\xb9\x2c\x4e\x3c\x50\x0a\xe7\xf5\xb3\x72\x5d\x47\x96\xca\xbd\xb3\xb3\xf2\xde\xbb\xd1\x9f\xd6\x0d\xe1\xb9\x34\xf3\x56\xa7\x94\xa2\xd6\x41\x1a\x45\xdb\xd1\x10\xde\x29\xd9\xfb\xc2\x56\x9f\xb8\x7a\x14\x4e\x3c\xc2\x8c\x75\xe7\x1b\xe3\x88\xc7\x66\xa9\xa3\xc8\x50\xad\xb5\x11\x1a\xdc\xf9\xda\xfc\xd5\x35\x03\x39\xf0\x63\xd3\x46\xcb\x3d\x10\x2d\x8f\x0f\xdc\xb0\x1d\xb4\x7c\x62\xc6\x2f\x6f\xf5\x89\x19\x47\xe0\xc4\x7e\x0c\xe3\x62\x68\x44\x0c\xd3\x3c\x8b\xbd\xf3\x40\x93\xb3\xb6\xcd\x33\x95\x42\xa7\x71\xa1\x65\x58\x1d\xa5\xe8\xf4\xa0\xbb\xe7\x66\x1d\x25\x1f\xf5\x98\x75\x94\x1f\x33\x1b\x4e\x75\x94\x51\xf0\xd0\x57\xb9\x11\x6d\xab\xa3\xec\x59\x49\xd9\xb3\x96\xb2\x77\x35\x65\xff\x7a\xca\xbd\x57\x54\xf2\x68\xbf\xdf\xed\x78\x1e\xbf\x63\xd9\x86\xe7\xf6\x7c\x8d\x15\x95\xa6\xed\xa7\x54\xf2\x44\xe1\x87\x78\xd0\xb3\x3f\x2d\xc2\xf5\x2b\xdb\x9f\x0e\xaf\xa8\x34\x68\xee\x38\x2e\x75\x26\x85\xc3\x2a\x2a\x45\x62\xf6\xf0\x15\x95\x02\x10\x47\xae\xa8\xb4\x72\xdf\x89\x40\xc6\xb8\x17\x2d\xd0\xf9\x78\xf6\xa2\x23\xf9\x6e\xde\x55\x51\x79\x98\x14\x2e\xaf\xa8\xd0\x91\xa6\x72\xf7\x52\x51\x29\x78\x6e\x2c\x15\x95\x53\xb2\x37\x06\xab\x4f\x5c\x3d\x0a\x27\x1e\x61\xc6\xda\x5d\x51\x19\x45\x86\x7a\x77\x45\xe5\xb0\x8f\xcd\x9e\x15\x95\xf2\xf8\xe0\x54\x51\x39\x31\xe3\xfd\x7a\xf0\x08\x98\xf1\xc0\x8a\xca\x48\x18\xe6\x80\xdb\xed\x9c\x4d\x27\xe5\x1b\xdb\x2d\xe7\x9d\x73\xab\x3f\x27\x96\x8c\x78\x32\xad\x66\x9b\xa0\xff\x65\xcc\xa4\x62\x37\xae\x60\xed\xc4\xb2\x46\xff\xf0\x4a\xaa\x98\x98\x15\xfc\xf2\xcf\x0f\x93\xdc\xc1\x4c\xe9\x5b\x57\x05\x79\x8f\x01\x2a\x14\x14\xeb\xda\x7d\x89\x24\x6b\x4a\x94\x85\xba\xe1\x55\x9e\xe3\xac\x3a\x4f\xbe\x93\x36\x8a\x8b\x4d\xd1\x7c\xc5\xc5\xdd\x42\xa1\x9d\xa0\x3e\xa1\xd7\xbc\x3c\xe9\x1d\x68\xdb\xa0\x81\x13\xb2\xc1\x5d\x21\x2e\x0c\x6e\x2a\x48\xd2\xfc\xf3\x00\x29\x23\x0d\x89\xee\x12\x2b\x76\x16\x95\x2f\x8a\xb5\xb4\xf2\x68\x6d\xaa\x3c\xda\xc1\x2b\x8f\x6e\x94\xca\x33\x37\x18\xfb\xb0\x75\x20\xcc\xf5\x92\x28\x7a\x1b\xf4\x23\x30\x07\x6f\x03\x02\xe5\x6f\x1b\x5a\x26\xba\x7d\xaa\x6d\xa4\x31\xac\x87\x4c\xeb\x74\x5b\xff\xc9\x4e\xcc\x75\x88\x16\xcc\x7a\x51\x87\x59\x4b\x07\xe7\x7a\x15\x23\x7b\xb8\x5f\x2d\xc2\xed\xe5\xb3\x9b\xf9\x36\xc3\x5c\xad\xb1\xd6\xde\x22\x3a\x98\x50\xf2\xfb\x17\x47\x5a\x59\x41\xe2\x61\x2b\x9b\xf3\xef\xc5\xe0\x1e\xf9\x6f\x10\x5b\x64\x9b\xb1\x05\xfe\xbc\x13\xd9\x05\x31\x83\x74\x03\x04\x19\xe9\xd9\x9d\xef\x99\xe1\x71\xb5\xd4\x9e\xed\x87\xef\x47\x59\x4c\x04\x0f\x50\xb7\xaa\x6a\x4c\x31\x80\x36\xc4\xa4\xad\xa8\xa9\x88\x56\x7f\x67\xf7\x58\x10\x5d\xbf\x4c\xd9\x76\x71\x74\x4f\x7e\x6f\x41\x4f\x3b\x76\xda\xd6\x67\x67\x8c\x3c\x27\x6f\x9d\xee\x03\xe3\xac\x73\xf6\xbb\xe6\xbf\x2d\xda\x7a\x40\x19\x91\x35\x46\x3b\x8b\xd0\x31\xa2\x73\x8a\x31\x6e\x09\x95\x44\xef\x3a\xc6\xef\x1d\xaf\x2b\x04\x7b\xba\xf4\x47\x4e\x77\x20\x1e\xa0\xb2\x7a\xa9\xe2\xa0\x55\xac\xdf\xc6\xd8\x7b\xe9\x5a\x23\xa2\x2b\x7c\x3a\xc4\xf7\x39\x3d\x6b\x3b\x29\xdc\x33\x84\x76\x01\xd4\xe1\xf3\xdd\xc0\x69\x2c\x57\x33\x0b\x2e\xbf\xe0\x0e\xe1\x65\xbd\x85\x8b\x15\x24\xc4\x84\xd9\x63\x2d\xd7\xff\x10\xa2\xdd\x99\xb8\x1f\x3f\x53\xa9\x58\x33\x85\xaa\x1e\xce\x36\xb3\xf6\x1d\xf8\x54\x33\x3d\x6f\x43\x25\xcf\xb2\x56\x7c\x4a\x51\x6d\xdb\xcc\x78\x47\x36\x08\x22\x8d\xd7\xa8\x4a\x5b\xfc\x2d\xa6\x9b\x10\x45\xad\x01\x6f\x29\x22\xd3\x95\xad\x95\x1d\xa5\x9a\xc3\xb5\x1b\xda\xe4\x2c\x86\x01\x49\x23\xb3\x82\xa7\x25\x8d\x71\xc1\xe3\x34\x2e\x9b\xca\x79\x08\x48\xa4\xbd\xfe\x6a\xa6\xea\xbd\xac\x0c\xdd\xeb\xe5\xaf\xe4\xd6\xaa\xdf\x71\x54\xdb\xcd\xae\x72\x97\xb7\x0e\xf4\x20\xfb\x67\x03\x6a\x3e\x2c\xfb\x7c\x70\x97\x48\x1a\x5e\xb8\xb6\x0e\x3f\xda\x94\x34\xbc\xfb\xef\x59\x61\xc3\x79\xb6\x34\xda\x55\x4e\xbd\x62\xa0\x8a\x1b\x54\x9c\xcc\x1d\xe8\xf4\x56\x18\x72\x6b\xe7\xc0\x84\x5c\x97\x60\x06\x5e\x6e\x90\x35\x8f\x79\x44\x94\x9d\x1d\xd3\xe8\x82\x70\x71\x13\xa2\xc2\x0b\xa0\x11\x49\x35\xda\x56\x22\xe0\xfc\xef\xaf\xdd\xe7\x1f\x63\x14\x66\x56\x28\x4a\x75\x5e\xc5\xb5\xae\xea\x5c\x85\xdd\x9a\x02\x31\x46\xf1\x75\x6a\x50\xc3\x02\xa8\x8c\xd2\x58\xd4\xa5\x08\xa5\x32\x15\x66\x0e\x85\xba\x57\x52\x01\xde\x92\x38\x89\x70\x06\x5c\x80\xbb\x61\x93\xad\xa1\xe2\x78\x8d\x96\x14\xab\x7d\xb5\x3f\x0c\x20\x90\x6a\x54\x56\x79\xe9\xa2\x21\xca\x6d\xad\x9d\xc0\x65\xbc\xbd\x5c\x4d\x8a\x97\x97\x97\x97\xfa\x53\x54\xf1\xc2\x77\x86\x88\x5f\x21\x4c\xe3\xed\x1f\xa6\x55\xd1\xb2\xdf\x87\xdd\x49\x07\x4a\x04\x90\x48\x4b\x58\xa3\xdf\x9e\x23\x03\x69\x03\x2b\xaa\xfd\xea\x65\x7e\x80\x93\x3a\x5d\x17\x30\xd0\x9e\xf0\xd0\x55\x7c\x2f\x03\x29\x9f\xaf\x89\xba\x9c\x75\xfa\x54\xed\x7b\xe1\xb9\x72\x7e\x85\x5b\x78\x0e\xd3\x40\xca\x29\x10\xc1\x5a\x65\xae\x49\x94\xa2\x95\x5a\x13\xd5\x31\x0b\x3f\xfb\xe5\xab\x22\x4b\x4c\x8d\x25\xe9\x6b\xce\x90\xcd\x40\x2a\xe0\x5e\xc6\x6b\xe3\x1a\x30\x4e\xcc\x76\x66\xdb\xca\xb3\xa6\x9d\xb5\x34\x21\x31\xae\xc5\x2e\x08\x84\x44\x43\x82\x2a\xe6\xda\xa6\x4a\x76\x82\x34\x22\xdc\xf0\x28\x82\x75\xb9\xce\x3e\xba\x91\xcd\x87\x72\x69\x76\x6b\xab\x1e\xa2\x59\xe3\x03\xc4\xa8\x5f\xdd\xf5\xf6\xde\xa3\x34\x57\x3c\x2c\x50\xd7\xa9\xd9\x3b\x58\x1b\x61\xba\x27\x80\x8b\x55\x75\xaf\x3d\x6e\xf3\x40\x1b\x10\x8a\x44\xd3\x76\xf4\xbd\x55\x87\x8d\x09\x17\x44\xb0\x0b\x08\xb8\xd2\x06\x86\x1b\x31\xf3\x3d\xde\xf4\xda\x74\x5f\x11\x21\x24\xe0\x6d\x12\x71\xca\x8d\x77\xc1\x13\x98\x43\x7c\x4e\x2e\x83\x81\xee\x2f\x1b\xd6\x71\xee\xdb\xee\x07\xe6\xa9\xb3\x47\xbb\xc2\x43\x1c\x93\x33\x8d\xd6\x7f\xcb\x79\xf9\x25\x69\x3f\x9a\x5d\xa5\x35\xee\x04\x2a\xc0\x2b\xff\x5a\x06\x96\x88\xce\xb4\x51\x29\x35\xa9\xb2\x1a\x85\x4b\x9c\x5c\xe6\xa9\xed\x6a\xc0\xb3\xe2\xed\x0f\xf3\x67\x4e\xed\x0f\x20\xa4\x71\x27\x2c\xa5\xc2\x67\xda\xe4\x42\xdf\x42\x8c\x44\x68\x87\x0a\x27\xef\x14\x42\xa1\xa6\xe8\xf3\x93\x07\xf2\xca\xa3\x9a\xd0\x10\xce\x2b\xac\x68\x6d\xdf\xa0\x01\xce\x66\xee\x9c\x6f\x06\x49\x44\xc4\x37\x9c\x39\x1b\xaf\xb8\x60\x4f\xdc\x5f\x9e\x3c\xe1\x9b\x62\x38\xfd\xa4\x86\xae\xe2\x6f\x49\x63\xa7\xb0\x4e\xed\x67\x67\x25\x74\x7c\xf7\xe7\x9c\xcd\xdc\x80\x76\xbc\x39\x67\xfe\xff\x76\xc0\x59\x46\xd4\xdf\xd6\x7b\xa1\xa1\xe1\x6b\xf7\xe6\x79\xad\xec\x5f\x0e\xde\x0b\x98\xff\x07\x00\x00\xff\xff\x08\x8d\x91\xbe\xaa\x49\x00\x00") +var _openapiYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5c\x5f\x8f\xdb\xb8\x11\x7f\xf7\xa7\x18\xa0\x2d\x7c\x39\x78\x6d\xa7\x77\x05\x5a\x23\x39\x20\xb9\x5e\x8a\x3b\xe4\x92\x34\x9b\xb4\x0f\x45\xe1\xa5\xc9\x91\xc5\x8b\x44\x2a\x24\xb5\x59\xa7\xed\x77\x2f\x48\xea\xbf\x25\xad\x6c\xec\xc6\xca\xc2\x79\x89\x45\xcd\x0c\x67\xc8\x99\x1f\x87\x1c\x6a\x65\x82\x82\x24\x7c\x05\xdf\xcd\x97\xf3\xe5\x84\x8b\x40\xae\x26\x00\x86\x9b\x08\x57\x10\x13\xd4\x46\x49\xb8\x44\x75\xcd\x29\xc2\xb3\x37\x3f\x4f\x00\x18\x6a\xaa\x78\x62\xb8\x14\x5d\x24\xd7\xa8\xb4\x7b\xbd\x9c\x2f\xe7\x8f\x27\x1a\x95\x6d\xb1\x92\x2f\x20\x55\xd1\x0a\x42\x63\x92\xd5\x62\x11\x49\x4a\xa2\x50\x6a\xb3\xfa\xf3\x72\xb9\x9c\x00\x34\xa4\xd3\x54\x29\x14\x06\x98\x8c\x09\x17\x75\x76\xbd\x5a\x2c\x48\xc2\xe7\xd6\x04\x1d\xf2\xc0\xcc\xa9\x8c\xf7\x45\xfc\x4a\xb8\x80\x6f\x12\x25\x59\x4a\x6d\xcb\x23\xf0\xda\xb4\x0b\xd3\x86\x6c\xf1\x36\x91\x97\x86\x6c\xb9\xd8\xe6\x82\x12\x62\x42\x67\x9b\x95\xb0\xc8\x06\x64\x71\xfd\x78\xa1\x50\xcb\x54\x51\x74\x2f\x01\xb6\x68\xfc\x0f\x00\x9d\xc6\x31\x51\xbb\x15\xbc\x45\x93\x2a\xa1\x81\x40\xc4\xb5\x01\x19\x40\xc1\x94\x93\x22\x4d\x15\x37\xbb\x9c\xd5\xaa\xfd\x1c\x89\x42\xb5\x82\x7f\xfd\x3b\x6b\x54\xa8\x13\x29\x74\xde\x93\xfd\x37\xfd\xe3\x72\x39\x2d\x1f\x1b\x26\x3c\x83\x5f\x2e\x5f\xbf\x02\xa2\x14\xd9\x55\x7b\x05\xb9\xf9\x0d\xa9\xd1\x15\x3e\x2a\x85\x41\x61\xaa\xa2\x00\x48\x92\x44\x9c\x12\x2b\x6c\xf1\x9b\x96\xa2\xfe\x16\x40\xd3\x10\x63\xd2\x6c\x05\xf8\xbd\xc2\x60\x05\xd3\xdf\x2d\xa8\x8c\x13\x29\x50\x18\xbd\xf0\xb4\x7a\xf1\x36\xd3\xe1\x25\xd7\x66\x5a\xda\xf1\xfd\xf2\x71\x8f\x1d\xa9\x09\xc1\xc8\x0f\x28\x80\x6b\xe0\xe2\x9a\x44\x9c\x9d\x42\xf9\x9f\x94\x92\xaa\xa6\xf5\x77\xdd\x5a\xbf\x17\x24\x35\xa1\x54\xfc\x33\x32\x30\x12\x12\x54\x81\x54\x31\xc8\x04\x95\x53\x6b\x0c\x16\xfc\xa9\xcf\x7f\xde\x0b\xbc\x49\x90\x1a\x64\x80\x96\x0f\x24\x75\xb1\x7a\xfa\xb1\x4f\x88\x22\x31\x9a\x0c\x6e\xc0\xc5\x4b\x1b\x73\x49\xb7\x48\xc8\x16\xa7\x43\x89\x35\xff\x7c\x00\x31\x12\x45\xc3\xc1\xe4\x52\x31\x54\xcf\x77\x83\xe9\x03\x8e\x11\xd3\x9e\x3c\xb1\x28\xda\x84\x97\x1f\x15\x12\x83\x40\x40\xe0\xa7\x22\xc6\x0f\x03\x96\x8f\x29\x6a\xf3\x5c\xb2\x0a\x5d\xcd\x13\xf2\xa8\x05\x46\x0c\x29\x48\x2c\x1f\x57\xc8\x56\x60\x54\x8a\x93\x1e\x97\xe8\x77\x88\x76\x77\x18\x82\x22\xd3\x5e\x68\xec\x81\x14\x3f\x66\x27\x71\xe4\xa6\xee\x0e\x47\x7a\xa2\xf0\x1f\x16\xed\x9c\x0a\x3e\x0a\xf5\x78\xc2\xf0\x0c\xdc\x27\xb4\xe0\x2f\xdd\x16\x14\xe1\x4a\x22\x85\x84\xed\x00\x6f\xb8\x3e\xcd\x7a\x7f\xd0\x82\xf3\x4c\x40\xda\xb5\xe6\x00\xb5\x21\x6b\x33\x32\x13\x62\x13\xe6\x4e\x63\x52\x67\x2a\xb8\xf8\x0f\x67\xff\xeb\xce\x07\xff\x86\x06\x88\x28\xd3\xb1\xcd\x0e\x8a\xb0\xb8\x9f\x4c\xb0\x70\x88\x40\xa6\x82\xd5\x3a\xfc\xa2\x43\xd7\x8a\x7d\x67\x00\x39\x8d\x05\xdf\x77\x5b\xf0\x4a\x96\xde\xf9\x89\x9b\x10\x74\x82\x94\x07\x1c\x19\x70\xf6\xb5\xa0\xc9\x58\xd3\xd7\x84\x18\x1a\xee\x81\xc2\xfb\x84\xb9\x2c\x4e\xdc\x53\x0a\xe7\xe5\xb3\x72\x5e\x47\x96\xca\xbd\xb1\xa3\xf2\xd6\x9b\xd1\x9f\xd6\x0d\xc1\xb9\x34\xb3\x56\xa7\x94\xa2\xd6\x41\x1a\x45\xbb\xd1\x00\xde\x39\xd9\xfb\xc2\x5a\x9f\xb1\x7a\x14\x46\x3c\xc0\x8c\x75\x6f\x8d\x71\xc0\x63\xb3\xd4\x51\x64\xa8\x56\xdb\x08\x0d\xee\xad\x36\x7f\x75\xcd\x40\x8e\x5c\x6c\xda\x60\xb9\xc7\x45\xcb\xe3\x03\xd7\x6d\x07\x2c\x9f\x91\xf1\xcb\x6b\x7d\x46\xc6\x11\x18\x71\x18\xc2\xb8\x18\x1a\x11\xc2\x34\xcf\x62\x6f\x3d\xd0\xe4\xac\x6d\xf3\x4c\xa5\xd0\x69\x5c\x48\x19\x56\x47\x29\x98\xee\x75\xf7\xdc\xac\xa3\xe4\xbd\x9e\xb2\x8e\xf2\x63\xa6\xc3\xb9\x8e\x32\x0a\x1c\xfa\x2a\x37\xa2\x6d\x75\x94\x03\x2b\x29\x07\xd6\x52\x0e\xae\xa6\x1c\x5e\x4f\xb9\xf3\x8a\x4a\x1e\xed\x77\xbb\x1d\xcf\xe3\x77\x2c\xdb\xf0\x5c\x9f\xaf\xb1\xa2\xd2\xd4\xfd\x9c\x4a\x9e\x21\xfc\x18\x0b\x7a\xf6\xa7\x45\xb8\x7e\x65\xfb\xd3\xe1\x15\x95\x06\xcc\x9d\xc6\xa4\xce\xa4\x70\x58\x45\xa5\x48\xcc\xee\xbf\xa2\x52\x38\xc4\x89\x2b\x2a\xad\xd8\x77\x06\x90\x31\xee\x45\x0b\xef\x7c\x38\x7b\xd1\x91\xac\x9b\xb7\x55\x54\xee\x27\x85\xcb\x2b\x2a\x74\xa4\xa9\xdc\x9d\x54\x54\x0a\x9c\x1b\x4b\x45\xe5\x9c\xec\x8d\x41\xeb\x33\x56\x8f\xc2\x88\x07\x98\xb1\x76\x57\x54\x46\x91\xa1\xde\x5e\x51\x39\x6e\xb1\x39\xb0\xa2\x52\x1e\x1f\x9c\x2b\x2a\x67\x64\xbc\x5b\x0b\x1e\x00\x32\x1e\x59\x51\x19\x09\xc2\x1c\x71\xbb\x9d\xb3\xe9\xa4\x7c\x63\xd9\x72\xdc\xb9\xb4\xf2\x73\x60\xc9\x80\x27\x93\x6a\x76\x09\xfa\x2f\x63\x26\x15\xbd\x71\x05\x1b\x47\x96\x35\xfa\x87\x17\x52\xc5\xc4\xac\xe0\x97\x7f\xbe\x9b\xe4\x06\x66\x42\x5f\xbb\x2a\xc8\x5b\x0c\x50\xa1\xa0\x58\x97\xee\x4b\x24\x59\x53\xa2\xac\xab\x1b\x5e\xc5\x39\xce\xaa\xe3\xe4\x99\xb4\x51\x5c\x6c\x8b\xe6\x0f\x5c\xdc\x4e\x14\xda\x01\xea\x23\x7a\xc9\xcb\x93\xde\x81\xba\x0d\xea\x38\x21\x5b\xdc\x27\xe2\xc2\xe0\xb6\xe2\x49\x9a\x7f\x1e\x40\x65\xa4\x21\xd1\x6d\x64\xc5\xce\xa2\xb2\xa2\x58\x4d\x2b\x8f\x56\xa7\xca\xa3\xed\xbc\xf2\xe8\x7a\xa9\x3c\x73\x83\xb1\x0f\x5b\xe7\x84\xb9\x5c\x12\x45\xaf\x83\x7e\x0f\xcc\x9d\xb7\xe1\x02\xe5\xb7\x0d\x2d\x03\xdd\x3e\xd4\x36\xd2\x18\xd6\x43\xa6\x75\xb8\xad\xfd\x64\x2f\xe6\x3a\x48\x0b\x64\x5d\xd7\xdd\xac\x85\xc1\x99\x5e\xf5\x91\x03\xcc\xaf\x16\xe1\x0e\xb2\xd9\x8d\x7c\x9b\x62\xae\xd6\x58\x6b\x6f\x21\x1d\x0c\x28\xf9\xfd\x8b\x13\xcd\xac\x20\xf1\xb0\x99\xcd\xf1\x77\x3d\x98\x23\xff\x06\xb1\x85\xb6\x19\x5b\xe0\xcf\x3b\x91\xad\x89\x19\x24\x1b\x20\xc8\x40\xcf\xee\x7c\x2f\x0c\x8f\xab\xa5\xf6\x6c\x3f\x7c\x37\xc2\x62\x22\x78\x80\xba\x55\x54\x63\x88\xf3\x04\x74\x2d\xfd\x72\x36\x84\xc3\xeb\xba\xd6\x46\x11\x83\xdb\xdd\x20\x1e\x6d\x88\x49\x5b\x7d\xb3\x42\x5a\xfd\x9a\xef\xa1\xc4\x4d\xfd\xca\x66\xdb\xf5\xd4\x03\x57\x91\x16\x1f\x6d\xf7\xd0\x36\x2f\x68\x1d\x94\x4e\x0f\x68\xa5\xee\x99\xfd\x3d\xfa\x7c\x5f\xd1\x3a\x99\x47\x62\x45\xe7\xdc\x76\xcd\x6e\x1b\x62\xf4\x04\x56\x44\x36\x18\xed\x4d\x71\x47\x8f\xce\x28\xc6\xb8\x1d\x39\x12\xbd\xe9\xe8\xbf\xb7\xbf\x2e\x18\xe9\x61\xe9\x8f\xfe\x6e\x30\x39\x42\x64\xf5\x62\xc8\x51\xb3\x58\xbf\x51\x72\xf0\xd4\xb5\xc6\x5b\x57\x70\x76\x90\x1f\x72\x02\xd8\x76\xda\x79\x60\x80\xee\x3b\x50\x87\xcd\xb7\x3b\x4e\x63\xba\x9a\x99\x7c\x99\x85\x38\x0f\x2f\x6b\x46\x5c\xac\x20\x21\x26\xcc\x1e\x6b\xfb\x95\x77\x21\xda\xdd\x95\xfb\x80\x9b\x4a\xc5\x9a\x69\x60\xf5\x80\xb9\xb9\xf3\xd8\x73\x9f\x6a\xb6\xea\x75\xa8\xe4\x8a\x56\x8b\x8f\x29\xaa\x5d\x9b\x1a\x6f\xc8\x16\x41\xa4\xf1\x06\x55\xa9\x8b\xbf\x89\xf5\x29\x44\x51\x6b\xc0\x1b\x8a\xc8\x74\x65\x7b\x68\x7b\xa9\xe6\xa1\xed\x8a\x36\x11\x91\x61\x40\xd2\xc8\xac\xe0\x71\x09\x92\x5c\xf0\x38\x8d\xcb\xa6\x72\x1c\x02\x12\x69\x2f\xbf\x9a\x6d\x7b\x2b\x2b\x5d\xf7\x5a\xf9\x2b\xb9\xb1\xe2\xf7\x0c\xd5\x76\xc3\xae\xdc\x05\xb4\x23\x2d\xc8\xfe\xf4\x41\xcd\x86\x65\x9f\x0d\xee\x22\x4c\xc3\x0a\xd7\xd6\x61\x47\x9b\x90\x86\x75\xff\xbd\x28\x74\xb8\xcc\xa6\x46\xbb\xea\xaf\x17\x0c\x54\x71\x83\x8a\x93\xb9\x73\x3a\xbd\x13\x86\xdc\xd8\x31\x30\x21\xd7\xa5\x33\x03\x2f\x37\xf9\x9a\xc7\x3c\x22\xca\x8e\x8e\x69\xb0\x20\xac\x3f\x85\xa8\x70\x0d\x34\x22\xa9\x46\xdb\x4a\x04\x5c\xfe\xfd\xa5\x4b\x2e\x30\x46\x61\x66\xe5\x2a\xa5\xf3\x4a\xb4\x35\x55\xe7\x22\xec\xf6\x1a\x88\x31\x8a\x6f\x52\x83\x1a\x16\x40\x65\x94\xc6\xa2\x4e\x45\x28\x95\xa9\x30\x73\x28\xc4\xbd\x90\x0a\xf0\x86\xc4\x49\x84\x33\xe0\x02\xdc\x2d\xa1\x6c\x0e\x15\xc7\x6b\xb4\xa0\x58\xe5\xd5\xfe\x40\x83\x40\xaa\x51\x59\xe1\xa5\x89\x86\x28\x77\x3c\xe0\x08\xae\xe2\xdd\xd5\x6a\x52\xbc\xbc\xba\xba\xd2\x1f\xa3\x8a\x15\x9e\x19\x22\xfe\x01\x61\x1a\xef\xfe\x30\xad\x92\x96\x7c\xef\xf6\x07\x1d\x28\x11\x40\x22\x2d\x61\x83\xfe\x88\x01\x19\x48\x1b\x58\x51\xed\xcb\x9d\xf9\x11\x46\xea\x74\x53\xb8\x81\xf6\x80\x87\xae\x6a\x7d\x15\x48\xf9\x74\x43\xd4\xd5\xac\xd3\xa6\x2a\xef\xda\x63\xe5\xfc\x03\xee\xe0\x29\x4c\x03\x29\xa7\x40\x04\x6b\xa5\xb9\x26\x51\x8a\x96\x6a\x43\x54\xc7\x28\xfc\xec\xa7\xaf\xea\x59\x62\x6a\x2c\x48\x5f\x73\x86\x6c\x06\x52\x01\xf7\x34\x5e\x1a\xd7\x80\x71\x62\x76\x33\xdb\x56\x9e\x97\xed\xcd\xa5\x09\x89\x71\x2d\x76\x42\x20\x24\x1a\x12\x54\x31\xd7\x36\x11\xb3\x03\xa4\x11\xe1\x13\x8f\x22\xd8\x94\xf3\xec\xa3\x1b\xd9\x7c\x28\x96\x66\x37\xcf\xea\x21\x9a\x35\xde\x43\x8c\xfa\xd9\xdd\xec\xee\x3c\x4a\x73\xc1\xc3\x02\x75\x93\x9a\x83\x83\xb5\x11\xa6\x07\x3a\x70\x31\xab\xee\xb5\xf7\xdb\x3c\xd0\x06\x84\x22\xd1\xb4\xdd\xfb\x5e\xab\xe3\xfa\x84\x35\x11\x6c\x0d\x01\x57\xda\xc0\x70\x25\x66\x9e\xe3\x55\xaf\x4e\x77\x15\x11\x42\x02\xde\x24\x11\xa7\xdc\x78\x13\x3c\x80\x39\x8f\xcf\xc1\x65\xb0\xa3\xfb\x0b\x93\x75\x3f\xf7\x6d\x77\xe3\xe6\xa9\xd3\x47\xbb\xe2\x49\x1c\x93\x0b\x8d\xd6\x7e\x8b\x79\xf9\x45\x6f\xdf\x9b\x9d\xa5\x0d\xee\x05\x2a\xc0\x0b\xff\x5a\x06\x16\x88\x2e\xb4\x51\x29\x35\xa9\xb2\x12\x85\x4b\x9c\x5c\xe6\xa9\xed\x6c\xc0\x93\xe2\xed\x0f\xf3\x27\x4e\xec\x0f\x20\xa4\x71\xa7\x44\xa5\xc0\x27\xda\xe4\x44\xdf\x42\x8c\x44\x68\xe7\x15\x8e\xde\x09\x84\x42\x4c\xc1\xf3\x93\x77\xe4\x95\xf7\x6a\x42\x43\xb8\xac\xa0\xa2\xd5\x7d\x8b\x06\x38\x9b\xb9\xb3\xca\x19\x24\x11\x11\xdf\x70\xe6\x74\xfc\xc0\x05\x7b\xe4\x7e\x79\xf0\x84\x6f\x8a\xee\xf4\xa3\x9a\x77\x15\xbf\x25\x8d\x9d\xc0\x3a\xb4\x5f\x5c\x94\xae\xe3\xd9\x9f\x72\x36\x73\x1d\xda\xfe\xe6\x9c\xf9\xff\x6d\x87\xb3\x0c\xa8\xbf\xad\x73\xa1\xa1\xe1\x4b\xf7\xe6\x69\xed\xea\x42\xd9\x79\xaf\xc3\xfc\x3f\x00\x00\xff\xff\xe3\xa8\xf9\x43\x6e\x4a\x00\x00") func openapiYamlBytes() ([]byte, error) { return bindataRead( @@ -92,7 +92,7 @@ func openapiYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "openapi.yaml", size: 18858, mode: os.FileMode(493), modTime: time.Unix(1713249971, 0)} + info := bindataFileInfo{name: "openapi.yaml", size: 19054, mode: os.FileMode(493), modTime: time.Unix(1716477375, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index ac1fca7f..68509b21 100755 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -509,6 +509,10 @@ components: format: date-time manifest: type: object + delete_option: + type: object + update_strategy: + type: object status: type: object ResourceList: @@ -527,6 +531,10 @@ components: type: integer manifest: type: object + delete_option: + type: object + update_strategy: + type: object Consumer: allOf: - $ref: '#/components/schemas/ObjectReference' diff --git a/pkg/api/openapi/api/openapi.yaml b/pkg/api/openapi/api/openapi.yaml index 1cd83608..903bc260 100644 --- a/pkg/api/openapi/api/openapi.yaml +++ b/pkg/api/openapi/api/openapi.yaml @@ -774,6 +774,8 @@ components: - $ref: '#/components/schemas/ResourceList_allOf' ResourcePatchRequest: example: + delete_option: "{}" + update_strategy: "{}" manifest: "{}" version: 0 properties: @@ -781,6 +783,10 @@ components: type: integer manifest: type: object + delete_option: + type: object + update_strategy: + type: object type: object Consumer: allOf: @@ -834,6 +840,10 @@ components: type: string manifest: type: object + delete_option: + type: object + update_strategy: + type: object status: type: object type: object diff --git a/pkg/api/openapi/docs/Resource.md b/pkg/api/openapi/docs/Resource.md index 86c3aa1f..0736ecc4 100644 --- a/pkg/api/openapi/docs/Resource.md +++ b/pkg/api/openapi/docs/Resource.md @@ -13,6 +13,8 @@ Name | Type | Description | Notes **CreatedAt** | Pointer to **time.Time** | | [optional] **UpdatedAt** | Pointer to **time.Time** | | [optional] **Manifest** | Pointer to **map[string]interface{}** | | [optional] +**DeleteOption** | Pointer to **map[string]interface{}** | | [optional] +**UpdateStrategy** | Pointer to **map[string]interface{}** | | [optional] **Status** | Pointer to **map[string]interface{}** | | [optional] ## Methods @@ -259,6 +261,56 @@ SetManifest sets Manifest field to given value. HasManifest returns a boolean if a field has been set. +### GetDeleteOption + +`func (o *Resource) GetDeleteOption() map[string]interface{}` + +GetDeleteOption returns the DeleteOption field if non-nil, zero value otherwise. + +### GetDeleteOptionOk + +`func (o *Resource) GetDeleteOptionOk() (*map[string]interface{}, bool)` + +GetDeleteOptionOk returns a tuple with the DeleteOption field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetDeleteOption + +`func (o *Resource) SetDeleteOption(v map[string]interface{})` + +SetDeleteOption sets DeleteOption field to given value. + +### HasDeleteOption + +`func (o *Resource) HasDeleteOption() bool` + +HasDeleteOption returns a boolean if a field has been set. + +### GetUpdateStrategy + +`func (o *Resource) GetUpdateStrategy() map[string]interface{}` + +GetUpdateStrategy returns the UpdateStrategy field if non-nil, zero value otherwise. + +### GetUpdateStrategyOk + +`func (o *Resource) GetUpdateStrategyOk() (*map[string]interface{}, bool)` + +GetUpdateStrategyOk returns a tuple with the UpdateStrategy field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUpdateStrategy + +`func (o *Resource) SetUpdateStrategy(v map[string]interface{})` + +SetUpdateStrategy sets UpdateStrategy field to given value. + +### HasUpdateStrategy + +`func (o *Resource) HasUpdateStrategy() bool` + +HasUpdateStrategy returns a boolean if a field has been set. + ### GetStatus `func (o *Resource) GetStatus() map[string]interface{}` diff --git a/pkg/api/openapi/docs/ResourceAllOf.md b/pkg/api/openapi/docs/ResourceAllOf.md index ab434420..7a0f972c 100644 --- a/pkg/api/openapi/docs/ResourceAllOf.md +++ b/pkg/api/openapi/docs/ResourceAllOf.md @@ -10,6 +10,8 @@ Name | Type | Description | Notes **CreatedAt** | Pointer to **time.Time** | | [optional] **UpdatedAt** | Pointer to **time.Time** | | [optional] **Manifest** | Pointer to **map[string]interface{}** | | [optional] +**DeleteOption** | Pointer to **map[string]interface{}** | | [optional] +**UpdateStrategy** | Pointer to **map[string]interface{}** | | [optional] **Status** | Pointer to **map[string]interface{}** | | [optional] ## Methods @@ -181,6 +183,56 @@ SetManifest sets Manifest field to given value. HasManifest returns a boolean if a field has been set. +### GetDeleteOption + +`func (o *ResourceAllOf) GetDeleteOption() map[string]interface{}` + +GetDeleteOption returns the DeleteOption field if non-nil, zero value otherwise. + +### GetDeleteOptionOk + +`func (o *ResourceAllOf) GetDeleteOptionOk() (*map[string]interface{}, bool)` + +GetDeleteOptionOk returns a tuple with the DeleteOption field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetDeleteOption + +`func (o *ResourceAllOf) SetDeleteOption(v map[string]interface{})` + +SetDeleteOption sets DeleteOption field to given value. + +### HasDeleteOption + +`func (o *ResourceAllOf) HasDeleteOption() bool` + +HasDeleteOption returns a boolean if a field has been set. + +### GetUpdateStrategy + +`func (o *ResourceAllOf) GetUpdateStrategy() map[string]interface{}` + +GetUpdateStrategy returns the UpdateStrategy field if non-nil, zero value otherwise. + +### GetUpdateStrategyOk + +`func (o *ResourceAllOf) GetUpdateStrategyOk() (*map[string]interface{}, bool)` + +GetUpdateStrategyOk returns a tuple with the UpdateStrategy field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUpdateStrategy + +`func (o *ResourceAllOf) SetUpdateStrategy(v map[string]interface{})` + +SetUpdateStrategy sets UpdateStrategy field to given value. + +### HasUpdateStrategy + +`func (o *ResourceAllOf) HasUpdateStrategy() bool` + +HasUpdateStrategy returns a boolean if a field has been set. + ### GetStatus `func (o *ResourceAllOf) GetStatus() map[string]interface{}` diff --git a/pkg/api/openapi/docs/ResourcePatchRequest.md b/pkg/api/openapi/docs/ResourcePatchRequest.md index 6b01c129..eebeba0d 100644 --- a/pkg/api/openapi/docs/ResourcePatchRequest.md +++ b/pkg/api/openapi/docs/ResourcePatchRequest.md @@ -6,6 +6,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **Version** | Pointer to **int32** | | [optional] **Manifest** | Pointer to **map[string]interface{}** | | [optional] +**DeleteOption** | Pointer to **map[string]interface{}** | | [optional] +**UpdateStrategy** | Pointer to **map[string]interface{}** | | [optional] ## Methods @@ -76,6 +78,56 @@ SetManifest sets Manifest field to given value. HasManifest returns a boolean if a field has been set. +### GetDeleteOption + +`func (o *ResourcePatchRequest) GetDeleteOption() map[string]interface{}` + +GetDeleteOption returns the DeleteOption field if non-nil, zero value otherwise. + +### GetDeleteOptionOk + +`func (o *ResourcePatchRequest) GetDeleteOptionOk() (*map[string]interface{}, bool)` + +GetDeleteOptionOk returns a tuple with the DeleteOption field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetDeleteOption + +`func (o *ResourcePatchRequest) SetDeleteOption(v map[string]interface{})` + +SetDeleteOption sets DeleteOption field to given value. + +### HasDeleteOption + +`func (o *ResourcePatchRequest) HasDeleteOption() bool` + +HasDeleteOption returns a boolean if a field has been set. + +### GetUpdateStrategy + +`func (o *ResourcePatchRequest) GetUpdateStrategy() map[string]interface{}` + +GetUpdateStrategy returns the UpdateStrategy field if non-nil, zero value otherwise. + +### GetUpdateStrategyOk + +`func (o *ResourcePatchRequest) GetUpdateStrategyOk() (*map[string]interface{}, bool)` + +GetUpdateStrategyOk returns a tuple with the UpdateStrategy field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUpdateStrategy + +`func (o *ResourcePatchRequest) SetUpdateStrategy(v map[string]interface{})` + +SetUpdateStrategy sets UpdateStrategy field to given value. + +### HasUpdateStrategy + +`func (o *ResourcePatchRequest) HasUpdateStrategy() bool` + +HasUpdateStrategy returns a boolean if a field has been set. + [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/pkg/api/openapi/model_resource.go b/pkg/api/openapi/model_resource.go index 2529fe94..8dbc705d 100644 --- a/pkg/api/openapi/model_resource.go +++ b/pkg/api/openapi/model_resource.go @@ -20,16 +20,18 @@ var _ MappedNullable = &Resource{} // Resource struct for Resource type Resource struct { - Id *string `json:"id,omitempty"` - Kind *string `json:"kind,omitempty"` - Href *string `json:"href,omitempty"` - Name *string `json:"name,omitempty"` - ConsumerName *string `json:"consumer_name,omitempty"` - Version *int32 `json:"version,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - Manifest map[string]interface{} `json:"manifest,omitempty"` - Status map[string]interface{} `json:"status,omitempty"` + Id *string `json:"id,omitempty"` + Kind *string `json:"kind,omitempty"` + Href *string `json:"href,omitempty"` + Name *string `json:"name,omitempty"` + ConsumerName *string `json:"consumer_name,omitempty"` + Version *int32 `json:"version,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` + Manifest map[string]interface{} `json:"manifest,omitempty"` + DeleteOption map[string]interface{} `json:"delete_option,omitempty"` + UpdateStrategy map[string]interface{} `json:"update_strategy,omitempty"` + Status map[string]interface{} `json:"status,omitempty"` } // NewResource instantiates a new Resource object @@ -337,6 +339,70 @@ func (o *Resource) SetManifest(v map[string]interface{}) { o.Manifest = v } +// GetDeleteOption returns the DeleteOption field value if set, zero value otherwise. +func (o *Resource) GetDeleteOption() map[string]interface{} { + if o == nil || IsNil(o.DeleteOption) { + var ret map[string]interface{} + return ret + } + return o.DeleteOption +} + +// GetDeleteOptionOk returns a tuple with the DeleteOption field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Resource) GetDeleteOptionOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.DeleteOption) { + return map[string]interface{}{}, false + } + return o.DeleteOption, true +} + +// HasDeleteOption returns a boolean if a field has been set. +func (o *Resource) HasDeleteOption() bool { + if o != nil && !IsNil(o.DeleteOption) { + return true + } + + return false +} + +// SetDeleteOption gets a reference to the given map[string]interface{} and assigns it to the DeleteOption field. +func (o *Resource) SetDeleteOption(v map[string]interface{}) { + o.DeleteOption = v +} + +// GetUpdateStrategy returns the UpdateStrategy field value if set, zero value otherwise. +func (o *Resource) GetUpdateStrategy() map[string]interface{} { + if o == nil || IsNil(o.UpdateStrategy) { + var ret map[string]interface{} + return ret + } + return o.UpdateStrategy +} + +// GetUpdateStrategyOk returns a tuple with the UpdateStrategy field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *Resource) GetUpdateStrategyOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.UpdateStrategy) { + return map[string]interface{}{}, false + } + return o.UpdateStrategy, true +} + +// HasUpdateStrategy returns a boolean if a field has been set. +func (o *Resource) HasUpdateStrategy() bool { + if o != nil && !IsNil(o.UpdateStrategy) { + return true + } + + return false +} + +// SetUpdateStrategy gets a reference to the given map[string]interface{} and assigns it to the UpdateStrategy field. +func (o *Resource) SetUpdateStrategy(v map[string]interface{}) { + o.UpdateStrategy = v +} + // GetStatus returns the Status field value if set, zero value otherwise. func (o *Resource) GetStatus() map[string]interface{} { if o == nil || IsNil(o.Status) { @@ -406,6 +472,12 @@ func (o Resource) ToMap() (map[string]interface{}, error) { if !IsNil(o.Manifest) { toSerialize["manifest"] = o.Manifest } + if !IsNil(o.DeleteOption) { + toSerialize["delete_option"] = o.DeleteOption + } + if !IsNil(o.UpdateStrategy) { + toSerialize["update_strategy"] = o.UpdateStrategy + } if !IsNil(o.Status) { toSerialize["status"] = o.Status } diff --git a/pkg/api/openapi/model_resource_all_of.go b/pkg/api/openapi/model_resource_all_of.go index d94f6097..79d99f8d 100644 --- a/pkg/api/openapi/model_resource_all_of.go +++ b/pkg/api/openapi/model_resource_all_of.go @@ -20,13 +20,15 @@ var _ MappedNullable = &ResourceAllOf{} // ResourceAllOf struct for ResourceAllOf type ResourceAllOf struct { - Name *string `json:"name,omitempty"` - ConsumerName *string `json:"consumer_name,omitempty"` - Version *int32 `json:"version,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - Manifest map[string]interface{} `json:"manifest,omitempty"` - Status map[string]interface{} `json:"status,omitempty"` + Name *string `json:"name,omitempty"` + ConsumerName *string `json:"consumer_name,omitempty"` + Version *int32 `json:"version,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` + Manifest map[string]interface{} `json:"manifest,omitempty"` + DeleteOption map[string]interface{} `json:"delete_option,omitempty"` + UpdateStrategy map[string]interface{} `json:"update_strategy,omitempty"` + Status map[string]interface{} `json:"status,omitempty"` } // NewResourceAllOf instantiates a new ResourceAllOf object @@ -238,6 +240,70 @@ func (o *ResourceAllOf) SetManifest(v map[string]interface{}) { o.Manifest = v } +// GetDeleteOption returns the DeleteOption field value if set, zero value otherwise. +func (o *ResourceAllOf) GetDeleteOption() map[string]interface{} { + if o == nil || IsNil(o.DeleteOption) { + var ret map[string]interface{} + return ret + } + return o.DeleteOption +} + +// GetDeleteOptionOk returns a tuple with the DeleteOption field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceAllOf) GetDeleteOptionOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.DeleteOption) { + return map[string]interface{}{}, false + } + return o.DeleteOption, true +} + +// HasDeleteOption returns a boolean if a field has been set. +func (o *ResourceAllOf) HasDeleteOption() bool { + if o != nil && !IsNil(o.DeleteOption) { + return true + } + + return false +} + +// SetDeleteOption gets a reference to the given map[string]interface{} and assigns it to the DeleteOption field. +func (o *ResourceAllOf) SetDeleteOption(v map[string]interface{}) { + o.DeleteOption = v +} + +// GetUpdateStrategy returns the UpdateStrategy field value if set, zero value otherwise. +func (o *ResourceAllOf) GetUpdateStrategy() map[string]interface{} { + if o == nil || IsNil(o.UpdateStrategy) { + var ret map[string]interface{} + return ret + } + return o.UpdateStrategy +} + +// GetUpdateStrategyOk returns a tuple with the UpdateStrategy field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceAllOf) GetUpdateStrategyOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.UpdateStrategy) { + return map[string]interface{}{}, false + } + return o.UpdateStrategy, true +} + +// HasUpdateStrategy returns a boolean if a field has been set. +func (o *ResourceAllOf) HasUpdateStrategy() bool { + if o != nil && !IsNil(o.UpdateStrategy) { + return true + } + + return false +} + +// SetUpdateStrategy gets a reference to the given map[string]interface{} and assigns it to the UpdateStrategy field. +func (o *ResourceAllOf) SetUpdateStrategy(v map[string]interface{}) { + o.UpdateStrategy = v +} + // GetStatus returns the Status field value if set, zero value otherwise. func (o *ResourceAllOf) GetStatus() map[string]interface{} { if o == nil || IsNil(o.Status) { @@ -298,6 +364,12 @@ func (o ResourceAllOf) ToMap() (map[string]interface{}, error) { if !IsNil(o.Manifest) { toSerialize["manifest"] = o.Manifest } + if !IsNil(o.DeleteOption) { + toSerialize["delete_option"] = o.DeleteOption + } + if !IsNil(o.UpdateStrategy) { + toSerialize["update_strategy"] = o.UpdateStrategy + } if !IsNil(o.Status) { toSerialize["status"] = o.Status } diff --git a/pkg/api/openapi/model_resource_patch_request.go b/pkg/api/openapi/model_resource_patch_request.go index f59bd335..a72ea467 100644 --- a/pkg/api/openapi/model_resource_patch_request.go +++ b/pkg/api/openapi/model_resource_patch_request.go @@ -19,8 +19,10 @@ var _ MappedNullable = &ResourcePatchRequest{} // ResourcePatchRequest struct for ResourcePatchRequest type ResourcePatchRequest struct { - Version *int32 `json:"version,omitempty"` - Manifest map[string]interface{} `json:"manifest,omitempty"` + Version *int32 `json:"version,omitempty"` + Manifest map[string]interface{} `json:"manifest,omitempty"` + DeleteOption map[string]interface{} `json:"delete_option,omitempty"` + UpdateStrategy map[string]interface{} `json:"update_strategy,omitempty"` } // NewResourcePatchRequest instantiates a new ResourcePatchRequest object @@ -104,6 +106,70 @@ func (o *ResourcePatchRequest) SetManifest(v map[string]interface{}) { o.Manifest = v } +// GetDeleteOption returns the DeleteOption field value if set, zero value otherwise. +func (o *ResourcePatchRequest) GetDeleteOption() map[string]interface{} { + if o == nil || IsNil(o.DeleteOption) { + var ret map[string]interface{} + return ret + } + return o.DeleteOption +} + +// GetDeleteOptionOk returns a tuple with the DeleteOption field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourcePatchRequest) GetDeleteOptionOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.DeleteOption) { + return map[string]interface{}{}, false + } + return o.DeleteOption, true +} + +// HasDeleteOption returns a boolean if a field has been set. +func (o *ResourcePatchRequest) HasDeleteOption() bool { + if o != nil && !IsNil(o.DeleteOption) { + return true + } + + return false +} + +// SetDeleteOption gets a reference to the given map[string]interface{} and assigns it to the DeleteOption field. +func (o *ResourcePatchRequest) SetDeleteOption(v map[string]interface{}) { + o.DeleteOption = v +} + +// GetUpdateStrategy returns the UpdateStrategy field value if set, zero value otherwise. +func (o *ResourcePatchRequest) GetUpdateStrategy() map[string]interface{} { + if o == nil || IsNil(o.UpdateStrategy) { + var ret map[string]interface{} + return ret + } + return o.UpdateStrategy +} + +// GetUpdateStrategyOk returns a tuple with the UpdateStrategy field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourcePatchRequest) GetUpdateStrategyOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.UpdateStrategy) { + return map[string]interface{}{}, false + } + return o.UpdateStrategy, true +} + +// HasUpdateStrategy returns a boolean if a field has been set. +func (o *ResourcePatchRequest) HasUpdateStrategy() bool { + if o != nil && !IsNil(o.UpdateStrategy) { + return true + } + + return false +} + +// SetUpdateStrategy gets a reference to the given map[string]interface{} and assigns it to the UpdateStrategy field. +func (o *ResourcePatchRequest) SetUpdateStrategy(v map[string]interface{}) { + o.UpdateStrategy = v +} + func (o ResourcePatchRequest) MarshalJSON() ([]byte, error) { toSerialize, err := o.ToMap() if err != nil { @@ -120,6 +186,12 @@ func (o ResourcePatchRequest) ToMap() (map[string]interface{}, error) { if !IsNil(o.Manifest) { toSerialize["manifest"] = o.Manifest } + if !IsNil(o.DeleteOption) { + toSerialize["delete_option"] = o.DeleteOption + } + if !IsNil(o.UpdateStrategy) { + toSerialize["update_strategy"] = o.UpdateStrategy + } return toSerialize, nil } diff --git a/pkg/api/presenters/resource.go b/pkg/api/presenters/resource.go index 5a18703b..0197281f 100755 --- a/pkg/api/presenters/resource.go +++ b/pkg/api/presenters/resource.go @@ -11,7 +11,7 @@ import ( // ConvertResource converts a resource from the API to the openapi representation. func ConvertResource(resource openapi.Resource) (*api.Resource, error) { - manifest, err := ConvertResourceManifest(resource.Manifest) + manifest, err := ConvertResourceManifest(resource.Manifest, resource.DeleteOption, resource.UpdateStrategy) if err != nil { return nil, err } @@ -30,13 +30,13 @@ func ConvertResource(resource openapi.Resource) (*api.Resource, error) { } // ConvertResourceManifest converts a resource manifest from the openapi representation to the API. -func ConvertResourceManifest(manifest map[string]interface{}) (datatypes.JSONMap, error) { - return api.EncodeManifest(manifest) +func ConvertResourceManifest(manifest, deleteOption, updateStrategy map[string]interface{}) (datatypes.JSONMap, error) { + return api.EncodeManifest(manifest, deleteOption, updateStrategy) } // PresentResource converts a resource from the API to the openapi representation. func PresentResource(resource *api.Resource) (*openapi.Resource, error) { - manifest, err := api.DecodeManifest(resource.Manifest) + manifest, deleteOption, updateStrategy, err := api.DecodeManifest(resource.Manifest) if err != nil { return nil, err } @@ -46,15 +46,17 @@ func PresentResource(resource *api.Resource) (*openapi.Resource, error) { } reference := PresentReference(resource.ID, resource) return &openapi.Resource{ - Id: reference.Id, - Kind: reference.Kind, - Href: reference.Href, - Name: openapi.PtrString(resource.Name), - ConsumerName: openapi.PtrString(resource.ConsumerName), - Version: openapi.PtrInt32(resource.Version), - CreatedAt: openapi.PtrTime(resource.CreatedAt), - UpdatedAt: openapi.PtrTime(resource.UpdatedAt), - Manifest: manifest, - Status: status, + Id: reference.Id, + Kind: reference.Kind, + Href: reference.Href, + Name: openapi.PtrString(resource.Name), + ConsumerName: openapi.PtrString(resource.ConsumerName), + Version: openapi.PtrInt32(resource.Version), + CreatedAt: openapi.PtrTime(resource.CreatedAt), + UpdatedAt: openapi.PtrTime(resource.UpdatedAt), + Manifest: manifest, + DeleteOption: deleteOption, + UpdateStrategy: updateStrategy, + Status: status, }, nil } diff --git a/pkg/api/resource_types.go b/pkg/api/resource_types.go index 409c51e0..52c67d5d 100755 --- a/pkg/api/resource_types.go +++ b/pkg/api/resource_types.go @@ -121,19 +121,48 @@ func CloudEventToJSONMap(evt *cloudevents.Event) (datatypes.JSONMap, error) { return res, nil } -// EncodeManifest converts a resource manifest (map[string]interface{}) into a CloudEvent JSONMap representation. -func EncodeManifest(manifest map[string]interface{}) (datatypes.JSONMap, error) { +// EncodeManifest converts resource manifest, deleteOption and updateStrategy (map[string]interface{}) into a CloudEvent JSONMap representation. +func EncodeManifest(manifest, deleteOption, updateStrategy map[string]interface{}) (datatypes.JSONMap, error) { if len(manifest) == 0 { return nil, nil } + delOption := &workv1.DeleteOption{ + PropagationPolicy: workv1.DeletePropagationPolicyTypeForeground, + } + if len(deleteOption) != 0 { + delOption = &workv1.DeleteOption{} + deleteOptionBytes, err := json.Marshal(deleteOption) + if err != nil { + return nil, fmt.Errorf("failed to marshal deleteOption to json: %v", err) + } + err = json.Unmarshal(deleteOptionBytes, delOption) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal json to deleteOption: %v", err) + } + } + + upStrategy := &workv1.UpdateStrategy{ + Type: workv1.UpdateStrategyTypeServerSideApply, + } + if len(updateStrategy) != 0 { + upStrategy = &workv1.UpdateStrategy{} + updateStrategyBytes, err := json.Marshal(updateStrategy) + if err != nil { + return nil, fmt.Errorf("failed to marshal updateStrategy to json: %v", err) + } + err = json.Unmarshal(updateStrategyBytes, upStrategy) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal json to updateStrategy: %v", err) + } + fmt.Println("upStrategy", upStrategy) + } + // create a cloud event with the manifest as the data evt := cetypes.NewEventBuilder("maestro", cetypes.CloudEventsType{}).NewEvent() eventPayload := &workpayload.Manifest{ - Manifest: unstructured.Unstructured{Object: manifest}, - DeleteOption: &workv1.DeleteOption{ - PropagationPolicy: workv1.DeletePropagationPolicyTypeForeground, - }, + Manifest: unstructured.Unstructured{Object: manifest}, + DeleteOption: delOption, ConfigOption: &workpayload.ManifestConfigOption{ FeedbackRules: []workv1.FeedbackRule{ { @@ -146,10 +175,7 @@ func EncodeManifest(manifest map[string]interface{}) (datatypes.JSONMap, error) }, }, }, - UpdateStrategy: &workv1.UpdateStrategy{ - // TODO support external configuration, e.g. configure this through manifest annotations - Type: workv1.UpdateStrategyTypeServerSideApply, - }, + UpdateStrategy: upStrategy, }, } @@ -167,23 +193,65 @@ func EncodeManifest(manifest map[string]interface{}) (datatypes.JSONMap, error) } // DecodeManifest converts a CloudEvent JSONMap representation of a resource manifest -// into resource manifest (map[string]interface{}). -func DecodeManifest(manifest datatypes.JSONMap) (map[string]interface{}, error) { +// into resource manifest, deleteOption and updateStrategy (map[string]interface{}). +func DecodeManifest(manifest datatypes.JSONMap) (map[string]interface{}, map[string]interface{}, map[string]interface{}, error) { if len(manifest) == 0 { - return nil, nil + return nil, nil, nil, nil } evt, err := JSONMAPToCloudEvent(manifest) if err != nil { - return nil, fmt.Errorf("failed to convert resource manifest to cloudevent: %v", err) + return nil, nil, nil, fmt.Errorf("failed to convert resource manifest to cloudevent: %v", err) } eventPayload := &workpayload.Manifest{} if err := evt.DataAs(eventPayload); err != nil { - return nil, fmt.Errorf("failed to decode cloudevent payload as resource manifest: %v", err) + return nil, nil, nil, fmt.Errorf("failed to decode cloudevent payload as resource manifest: %v", err) + } + + deleteOptionObj := &map[string]interface{}{} + if eventPayload.DeleteOption != nil { + deleteOptionJsonData, err := json.Marshal(eventPayload.DeleteOption) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to marshal deleteOption to json: %v", err) + } + if err := json.Unmarshal(deleteOptionJsonData, deleteOptionObj); err != nil { + return nil, nil, nil, fmt.Errorf("failed to unmarshal deleteOption to cloudevent: %v", err) + } + } + + updateStrategyObj := &map[string]interface{}{} + if eventPayload.ConfigOption != nil && eventPayload.ConfigOption.UpdateStrategy != nil { + updateStrategyJsonData, err := json.Marshal(eventPayload.ConfigOption.UpdateStrategy) + if err != nil { + return nil, nil, nil, fmt.Errorf("failed to marshal updateStrategy to json: %v", err) + } + if err := json.Unmarshal(updateStrategyJsonData, updateStrategyObj); err != nil { + return nil, nil, nil, fmt.Errorf("failed to unmarshal updateStrategy to cloudevent: %v", err) + } + } + + return eventPayload.Manifest.Object, *deleteOptionObj, *updateStrategyObj, nil +} + +// DecodeDeleteOption converts a CloudEvent JSONMap representation of a resoure deleteOption +// into resource deleteOption (map[string]interface{}). +func DecodeDeleteOption(deleteOption datatypes.JSONMap) (map[string]interface{}, error) { + if len(deleteOption) == 0 { + return nil, nil + } + + jsonData, err := deleteOption.MarshalJSON() + if err != nil { + return nil, fmt.Errorf("failed to marshal deleteOption to json: %v", err) + } + + obj := &map[string]interface{}{} + if err := json.Unmarshal(jsonData, obj); err != nil { + return nil, fmt.Errorf("failed to unmarshal deleteOption to cloudevent: %v", err) } - return eventPayload.Manifest.Object, nil + return *obj, nil } // DecodeManifestBundle converts a CloudEvent JSONMap representation of a list of resource manifest diff --git a/pkg/api/resource_types_test.go b/pkg/api/resource_types_test.go index 9f3f63c1..a667ad93 100644 --- a/pkg/api/resource_types_test.go +++ b/pkg/api/resource_types_test.go @@ -12,6 +12,8 @@ func TestEncodeManifest(t *testing.T) { cases := []struct { name string input map[string]interface{} + deleteOption map[string]interface{} + updateStrategy map[string]interface{} expected datatypes.JSONMap expectedErrorMsg string }{ @@ -22,13 +24,20 @@ func TestEncodeManifest(t *testing.T) { }, { name: "valid", - input: newManifest(t, "{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}"), - expected: newManifest(t, "{\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifest\":{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}}}"), + input: newJSONMap(t, "{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}"), + expected: newJSONMap(t, "{\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifest\":{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}}}"), + }, + { + name: "valid", + deleteOption: newJSONMap(t, "{\"propagationPolicy\": \"Orphan\"}"), + updateStrategy: newJSONMap(t, "{\"type\": \"CreateOnly\"}"), + input: newJSONMap(t, "{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}"), + expected: newJSONMap(t, "{\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"configOption\":{\"updateStrategy\": {\"type\": \"CreateOnly\"}},\"deleteOption\": {\"propagationPolicy\": \"Orphan\"},\"manifest\":{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}}}"), }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { - gotManifest, err := EncodeManifest(c.input) + gotManifest, err := EncodeManifest(c.input, c.deleteOption, c.updateStrategy) if err != nil { if err.Error() != c.expectedErrorMsg { t.Errorf("expected %#v but got: %#v", c.expectedErrorMsg, err) @@ -44,34 +53,46 @@ func TestEncodeManifest(t *testing.T) { func TestDecodeManifest(t *testing.T) { cases := []struct { - name string - input datatypes.JSONMap - expected map[string]interface{} - expectedErrorMsg string + name string + input datatypes.JSONMap + expectedManifest map[string]interface{} + expectedDeleteOption map[string]interface{} + expectedUpdateStrategy map[string]interface{} + expectedErrorMsg string }{ { - name: "empty", - input: datatypes.JSONMap{}, - expected: nil, - expectedErrorMsg: "", + name: "empty", + input: datatypes.JSONMap{}, + expectedManifest: nil, + expectedDeleteOption: nil, + expectedUpdateStrategy: nil, + expectedErrorMsg: "", }, { - name: "valid", - input: newManifest(t, "{\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifest\":{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}}}"), - expected: newManifest(t, "{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}"), + name: "valid", + input: newJSONMap(t, "{\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"configOption\":{\"updateStrategy\": {\"type\": \"CreateOnly\"}},\"deleteOption\": {\"propagationPolicy\": \"Orphan\"},\"manifest\":{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}}}"), + expectedManifest: newJSONMap(t, "{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}"), + expectedDeleteOption: newJSONMap(t, "{\"propagationPolicy\": \"Orphan\"}"), + expectedUpdateStrategy: newJSONMap(t, "{\"type\": \"CreateOnly\"}"), }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { - gotManifest, err := DecodeManifest(c.input) + gotManifest, gotDeleteOption, gotUpdateStrategy, err := DecodeManifest(c.input) if err != nil { if err.Error() != c.expectedErrorMsg { t.Errorf("expected %#v but got: %#v", c.expectedErrorMsg, err) } return } - if !equality.Semantic.DeepDerivative(c.expected, gotManifest) { - t.Errorf("expected %#v but got: %#v", c.expected, gotManifest) + if !equality.Semantic.DeepDerivative(c.expectedManifest, gotManifest) { + t.Errorf("expected %#v but got: %#v", c.expectedManifest, gotManifest) + } + if !equality.Semantic.DeepDerivative(c.expectedDeleteOption, gotDeleteOption) { + t.Errorf("expected %#v but got: %#v", c.expectedDeleteOption, gotDeleteOption) + } + if !equality.Semantic.DeepDerivative(c.expectedUpdateStrategy, gotUpdateStrategy) { + t.Errorf("expected %#v but got: %#v", c.expectedUpdateStrategy, gotUpdateStrategy) } }) } @@ -92,10 +113,10 @@ func TestDecodeManifestBundle(t *testing.T) { }, { name: "valid", - input: newManifest(t, "{\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifests\":[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"}},{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginxinc/nginx-unprivileged\"}]},\"metadata\":{\"labels\":{\"app\":\"nginx\"}}}}}],\"deleteOption\":{\"propagationPolicy\":\"Foreground\"},\"manifestConfigs\":[{\"updateStrategy\":{\"type\":\"ServerSideApply\"},\"resourceIdentifier\":{\"name\":\"nginx\",\"group\":\"apps\",\"resource\":\"deployments\",\"namespace\":\"default\"}}]}}"), + input: newJSONMap(t, "{\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifests\":[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"}},{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginxinc/nginx-unprivileged\"}]},\"metadata\":{\"labels\":{\"app\":\"nginx\"}}}}}],\"deleteOption\":{\"propagationPolicy\":\"Foreground\"},\"manifestConfigs\":[{\"updateStrategy\":{\"type\":\"ServerSideApply\"},\"resourceIdentifier\":{\"name\":\"nginx\",\"group\":\"apps\",\"resource\":\"deployments\",\"namespace\":\"default\"}}]}}"), expected: []map[string]interface{}{ - newManifest(t, "{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"}}"), - newManifest(t, "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginxinc/nginx-unprivileged\"}]},\"metadata\":{\"labels\":{\"app\":\"nginx\"}}}}}"), + newJSONMap(t, "{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"}}"), + newJSONMap(t, "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginxinc/nginx-unprivileged\"}]},\"metadata\":{\"labels\":{\"app\":\"nginx\"}}}}}"), }, }, } @@ -136,8 +157,8 @@ func TestDecodeStatus(t *testing.T) { }, { name: "valid", - input: newManifest(t, "{\"id\":\"1f21fcbe-3e41-4639-ab8d-1713c578e4cd\",\"time\":\"2024-03-07T03:29:12.094854533Z\",\"type\":\"io.open-cluster-management.works.v1alpha1.manifests.status.update_request\",\"source\":\"maestro-agent-59d9c485d9-7bvwb\",\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"resourceid\":\"b9368296-3200-42ec-bfbb-f7d44a06c4e0\",\"sequenceid\":\"1765580430112722944\",\"clustername\":\"b288a9da-8bfe-4c82-94cc-2b48e773fc46\",\"originalsource\":\"maestro\",\"resourceversion\":\"1\",\"data\":{\"status\":{\"conditions\":[{\"type\":\"Applied\",\"reason\":\"AppliedManifestComplete\",\"status\":\"True\",\"message\":\"Apply manifest complete\",\"lastTransitionTime\":\"2024-03-07T03:29:03Z\"},{\"type\":\"Available\",\"reason\":\"ResourceAvailable\",\"status\":\"True\",\"message\":\"Resource is available\",\"lastTransitionTime\":\"2024-03-07T03:29:03Z\"},{\"type\":\"StatusFeedbackSynced\",\"reason\":\"StatusFeedbackSynced\",\"status\":\"True\",\"message\":\"\",\"lastTransitionTime\":\"2024-03-07T03:29:03Z\"}],\"resourceMeta\":{\"kind\":\"Deployment\",\"name\":\"nginx1\",\"group\":\"apps\",\"ordinal\":0,\"version\":\"v1\",\"resource\":\"deployments\",\"namespace\":\"default\"},\"statusFeedback\":{\"values\":[{\"name\":\"status\",\"fieldValue\":{\"type\":\"JsonRaw\",\"jsonRaw\":\"{\\\"availableReplicas\\\":1,\\\"conditions\\\":[{\\\"lastTransitionTime\\\":\\\"2024-03-07T03:29:06Z\\\",\\\"lastUpdateTime\\\":\\\"2024-03-07T03:29:06Z\\\",\\\"message\\\":\\\"Deployment has minimum availability.\\\",\\\"reason\\\":\\\"MinimumReplicasAvailable\\\",\\\"status\\\":\\\"True\\\",\\\"type\\\":\\\"Available\\\"},{\\\"lastTransitionTime\\\":\\\"2024-03-07T03:29:03Z\\\",\\\"lastUpdateTime\\\":\\\"2024-03-07T03:29:06Z\\\",\\\"message\\\":\\\"ReplicaSet \\\\\\\"nginx1-5d6b548959\\\\\\\" has successfully progressed.\\\",\\\"reason\\\":\\\"NewReplicaSetAvailable\\\",\\\"status\\\":\\\"True\\\",\\\"type\\\":\\\"Progressing\\\"}],\\\"observedGeneration\\\":1,\\\"readyReplicas\\\":1,\\\"replicas\\\":1,\\\"updatedReplicas\\\":1}\"}}]}},\"conditions\":[{\"type\":\"Applied\",\"reason\":\"AppliedManifestWorkComplete\",\"status\":\"True\",\"message\":\"Apply manifest work complete\",\"lastTransitionTime\":\"2024-03-07T03:29:03Z\"},{\"type\":\"Available\",\"reason\":\"ResourcesAvailable\",\"status\":\"True\",\"message\":\"All resources are available\",\"lastTransitionTime\":\"2024-03-07T03:29:03Z\"}]}}"), - expected: newManifest(t, "{\"ContentStatus\":{\"availableReplicas\":1,\"observedGeneration\":1,\"readyReplicas\":1,\"replicas\":1,\"updatedReplicas\":1,\"conditions\":[{\"lastTransitionTime\":\"2024-03-07T03:29:06Z\",\"lastUpdateTime\":\"2024-03-07T03:29:06Z\",\"message\":\"Deployment has minimum availability.\",\"reason\":\"MinimumReplicasAvailable\",\"status\":\"True\",\"type\":\"Available\"},{\"lastTransitionTime\":\"2024-03-07T03:29:03Z\",\"lastUpdateTime\":\"2024-03-07T03:29:06Z\",\"message\":\"ReplicaSet \\\"nginx1-5d6b548959\\\" has successfully progressed.\",\"reason\":\"NewReplicaSetAvailable\",\"status\":\"True\",\"type\":\"Progressing\"}]},\"ReconcileStatus\":{\"Conditions\":[{\"lastTransitionTime\":\"2024-03-07T03:29:03Z\",\"message\":\"Apply manifest complete\",\"reason\":\"AppliedManifestComplete\",\"status\":\"True\",\"type\":\"Applied\"},{\"lastTransitionTime\":\"2024-03-07T03:29:03Z\",\"message\":\"Resource is available\",\"reason\":\"ResourceAvailable\",\"status\":\"True\",\"type\":\"Available\"},{\"lastTransitionTime\":\"2024-03-07T03:29:03Z\",\"message\":\"\",\"reason\":\"StatusFeedbackSynced\",\"status\":\"True\",\"type\":\"StatusFeedbackSynced\"}],\"ObservedVersion\":1,\"SequenceID\":\"1765580430112722944\"}}"), + input: newJSONMap(t, "{\"id\":\"1f21fcbe-3e41-4639-ab8d-1713c578e4cd\",\"time\":\"2024-03-07T03:29:12.094854533Z\",\"type\":\"io.open-cluster-management.works.v1alpha1.manifests.status.update_request\",\"source\":\"maestro-agent-59d9c485d9-7bvwb\",\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"resourceid\":\"b9368296-3200-42ec-bfbb-f7d44a06c4e0\",\"sequenceid\":\"1765580430112722944\",\"clustername\":\"b288a9da-8bfe-4c82-94cc-2b48e773fc46\",\"originalsource\":\"maestro\",\"resourceversion\":\"1\",\"data\":{\"status\":{\"conditions\":[{\"type\":\"Applied\",\"reason\":\"AppliedManifestComplete\",\"status\":\"True\",\"message\":\"Apply manifest complete\",\"lastTransitionTime\":\"2024-03-07T03:29:03Z\"},{\"type\":\"Available\",\"reason\":\"ResourceAvailable\",\"status\":\"True\",\"message\":\"Resource is available\",\"lastTransitionTime\":\"2024-03-07T03:29:03Z\"},{\"type\":\"StatusFeedbackSynced\",\"reason\":\"StatusFeedbackSynced\",\"status\":\"True\",\"message\":\"\",\"lastTransitionTime\":\"2024-03-07T03:29:03Z\"}],\"resourceMeta\":{\"kind\":\"Deployment\",\"name\":\"nginx1\",\"group\":\"apps\",\"ordinal\":0,\"version\":\"v1\",\"resource\":\"deployments\",\"namespace\":\"default\"},\"statusFeedback\":{\"values\":[{\"name\":\"status\",\"fieldValue\":{\"type\":\"JsonRaw\",\"jsonRaw\":\"{\\\"availableReplicas\\\":1,\\\"conditions\\\":[{\\\"lastTransitionTime\\\":\\\"2024-03-07T03:29:06Z\\\",\\\"lastUpdateTime\\\":\\\"2024-03-07T03:29:06Z\\\",\\\"message\\\":\\\"Deployment has minimum availability.\\\",\\\"reason\\\":\\\"MinimumReplicasAvailable\\\",\\\"status\\\":\\\"True\\\",\\\"type\\\":\\\"Available\\\"},{\\\"lastTransitionTime\\\":\\\"2024-03-07T03:29:03Z\\\",\\\"lastUpdateTime\\\":\\\"2024-03-07T03:29:06Z\\\",\\\"message\\\":\\\"ReplicaSet \\\\\\\"nginx1-5d6b548959\\\\\\\" has successfully progressed.\\\",\\\"reason\\\":\\\"NewReplicaSetAvailable\\\",\\\"status\\\":\\\"True\\\",\\\"type\\\":\\\"Progressing\\\"}],\\\"observedGeneration\\\":1,\\\"readyReplicas\\\":1,\\\"replicas\\\":1,\\\"updatedReplicas\\\":1}\"}}]}},\"conditions\":[{\"type\":\"Applied\",\"reason\":\"AppliedManifestWorkComplete\",\"status\":\"True\",\"message\":\"Apply manifest work complete\",\"lastTransitionTime\":\"2024-03-07T03:29:03Z\"},{\"type\":\"Available\",\"reason\":\"ResourcesAvailable\",\"status\":\"True\",\"message\":\"All resources are available\",\"lastTransitionTime\":\"2024-03-07T03:29:03Z\"}]}}"), + expected: newJSONMap(t, "{\"ContentStatus\":{\"availableReplicas\":1,\"observedGeneration\":1,\"readyReplicas\":1,\"replicas\":1,\"updatedReplicas\":1,\"conditions\":[{\"lastTransitionTime\":\"2024-03-07T03:29:06Z\",\"lastUpdateTime\":\"2024-03-07T03:29:06Z\",\"message\":\"Deployment has minimum availability.\",\"reason\":\"MinimumReplicasAvailable\",\"status\":\"True\",\"type\":\"Available\"},{\"lastTransitionTime\":\"2024-03-07T03:29:03Z\",\"lastUpdateTime\":\"2024-03-07T03:29:06Z\",\"message\":\"ReplicaSet \\\"nginx1-5d6b548959\\\" has successfully progressed.\",\"reason\":\"NewReplicaSetAvailable\",\"status\":\"True\",\"type\":\"Progressing\"}]},\"ReconcileStatus\":{\"Conditions\":[{\"lastTransitionTime\":\"2024-03-07T03:29:03Z\",\"message\":\"Apply manifest complete\",\"reason\":\"AppliedManifestComplete\",\"status\":\"True\",\"type\":\"Applied\"},{\"lastTransitionTime\":\"2024-03-07T03:29:03Z\",\"message\":\"Resource is available\",\"reason\":\"ResourceAvailable\",\"status\":\"True\",\"type\":\"Available\"},{\"lastTransitionTime\":\"2024-03-07T03:29:03Z\",\"message\":\"\",\"reason\":\"StatusFeedbackSynced\",\"status\":\"True\",\"type\":\"StatusFeedbackSynced\"}],\"ObservedVersion\":1,\"SequenceID\":\"1765580430112722944\"}}"), }, } for _, c := range cases { @@ -156,11 +177,11 @@ func TestDecodeStatus(t *testing.T) { } } -func newManifest(t *testing.T, data string) datatypes.JSONMap { - manifest := map[string]interface{}{} - if err := json.Unmarshal([]byte(data), &manifest); err != nil { +func newJSONMap(t *testing.T, data string) datatypes.JSONMap { + jsonmap := map[string]interface{}{} + if err := json.Unmarshal([]byte(data), &jsonmap); err != nil { t.Fatal(err) } - return manifest + return jsonmap } diff --git a/pkg/handlers/resource.go b/pkg/handlers/resource.go index b40c1752..fd18e05d 100755 --- a/pkg/handlers/resource.go +++ b/pkg/handlers/resource.go @@ -70,7 +70,7 @@ func (h resourceHandler) Patch(w http.ResponseWriter, r *http.Request) { func() (interface{}, *errors.ServiceError) { ctx := r.Context() id := mux.Vars(r)["id"] - manifest, err := presenters.ConvertResourceManifest(patch.Manifest) + manifest, err := presenters.ConvertResourceManifest(patch.Manifest, patch.DeleteOption, patch.UpdateStrategy) if err != nil { return nil, errors.GeneralError("failed to convert resource manifest: %s", err) } diff --git a/pkg/services/validation.go b/pkg/services/validation.go index 88e9c457..3ee6bba2 100644 --- a/pkg/services/validation.go +++ b/pkg/services/validation.go @@ -43,7 +43,8 @@ func ValidateConsumer(consumer *api.Consumer) error { func ValidateManifest(resType api.ResourceType, manifest datatypes.JSONMap) error { switch resType { case api.ResourceTypeSingle: - obj, err := api.DecodeManifest(manifest) + // TODO: validate the deleteOption and updateStrategy + obj, _, _, err := api.DecodeManifest(manifest) if err != nil { return fmt.Errorf("failed to decode manifest: %v", err) } @@ -104,11 +105,11 @@ func ValidateObject(obj datatypes.JSONMap) error { func ValidateManifestUpdate(resType api.ResourceType, new, old datatypes.JSONMap) error { switch resType { case api.ResourceTypeSingle: - newObj, err := api.DecodeManifest(new) + newObj, _, _, err := api.DecodeManifest(new) if err != nil { return fmt.Errorf("failed to decode new manifest: %v", err) } - oldObj, err := api.DecodeManifest(old) + oldObj, _, _, err := api.DecodeManifest(old) if err != nil { return fmt.Errorf("failed to decode old manifest: %v", err) } diff --git a/test/e2e/pkg/resources_test.go b/test/e2e/pkg/resources_test.go index 84ab71c0..7e400d6b 100644 --- a/test/e2e/pkg/resources_test.go +++ b/test/e2e/pkg/resources_test.go @@ -15,12 +15,9 @@ import ( var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { - It("is CRUD tests", func() { - }) - var resource *openapi.Resource - Context("Create Resource", func() { + Context("Resource CRUD Tests", func() { It("post the nginx resource to the maestro api", func() { res := helper.NewAPIResource(consumer_name, 1) @@ -39,9 +36,6 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { return nil }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) - }) - - Context("Patch Resource", func() { It("patch the nginx resource", func() { @@ -63,9 +57,144 @@ var _ = Describe("Resources", Ordered, Label("e2e-tests-resources"), func() { return fmt.Errorf("replicas is not 2") }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) }) + + It("delete the nginx resource", func() { + + resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(context.Background(), *resource.Id).Execute() + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + + Eventually(func() error { + _, err := kubeClient.AppsV1().Deployments("default").Get(context.Background(), "nginx", metav1.GetOptions{}) + if err != nil { + if errors.IsNotFound(err) { + return nil + } + return err + } + return fmt.Errorf("nginx deployment still exists") + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }) + }) + + Context("Resource Delete Option Tests", func() { + res := helper.NewAPIResource(consumer_name, 1) + It("post the nginx resource to the maestro api", func() { + var resp *http.Response + var err error + resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(context.Background()).Resource(res).Execute() + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusCreated)) + Expect(*resource.Id).ShouldNot(BeEmpty()) + + Eventually(func() error { + _, err := kubeClient.AppsV1().Deployments("default").Get(context.Background(), "nginx", metav1.GetOptions{}) + if err != nil { + return err + } + return nil + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }) + + It("patch the nginx resource with orphan delete option", func() { + + patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(context.Background(), *resource.Id). + ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resource.Version, Manifest: res.Manifest, DeleteOption: map[string]interface{}{"propagationPolicy": "Orphan"}}).Execute() + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + Expect(*patchedResource.Version).To(Equal(*resource.Version + 1)) + + }) + + It("delete the nginx resource from the maestro api", func() { + + resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(context.Background(), *resource.Id).Execute() + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + + retry := 0 + Eventually(func() error { + // Attempt to retrieve the "nginx" deployment in the "default" namespace + _, err := kubeClient.AppsV1().Deployments("default").Get(context.Background(), "nginx", metav1.GetOptions{}) + + // If an error occurs + if err != nil { + // Return any other errors directly + return err + } + + // Increment the retry counter + retry++ + + // If the retry count reaches 30, consider it successful + if retry == 30 { + return nil + } + + // Otherwise, indicate that another retry is needed + return fmt.Errorf("need to retry again") + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }) + + It("delete the nginx deployment", func() { + err := kubeClient.AppsV1().Deployments("default").Delete(context.Background(), "nginx", metav1.DeleteOptions{}) + Expect(err).ShouldNot(HaveOccurred()) + + Eventually(func() error { + _, err := kubeClient.AppsV1().Deployments("default").Get(context.Background(), "nginx", metav1.GetOptions{}) + if err != nil { + if errors.IsNotFound(err) { + return nil + } + return err + } + return fmt.Errorf("nginx deployment still exists") + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }) + }) - Context("Delete Resource", func() { + Context("Resource Update Strategy Tests", func() { + + It("post the nginx resource to the maestro api with createOnly updateStrategy", func() { + res := helper.NewAPIResource(consumer_name, 1) + var resp *http.Response + var err error + res.UpdateStrategy = map[string]interface{}{"type": "CreateOnly"} + resource, resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesPost(context.Background()).Resource(res).Execute() + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusCreated)) + Expect(*resource.Id).ShouldNot(BeEmpty()) + + Eventually(func() error { + _, err := kubeClient.AppsV1().Deployments("default").Get(context.Background(), "nginx", metav1.GetOptions{}) + if err != nil { + return err + } + return nil + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }) + + It("patch the nginx resource", func() { + + newRes := helper.NewAPIResource(consumer_name, 2) + patchedResource, resp, err := apiClient.DefaultApi.ApiMaestroV1ResourcesIdPatch(context.Background(), *resource.Id). + ResourcePatchRequest(openapi.ResourcePatchRequest{Version: resource.Version, Manifest: newRes.Manifest}).Execute() + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + Expect(*patchedResource.Version).To(Equal(*resource.Version + 1)) + + Eventually(func() error { + deploy, err := kubeClient.AppsV1().Deployments("default").Get(context.Background(), "nginx", metav1.GetOptions{}) + if err != nil { + return err + } + if *deploy.Spec.Replicas == 1 { + return nil + } + return fmt.Errorf("replicas is not 1") + }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + }) It("delete the nginx resource", func() { diff --git a/test/e2e/pkg/serverside_test.go b/test/e2e/pkg/serverside_test.go index b164992b..61675c22 100644 --- a/test/e2e/pkg/serverside_test.go +++ b/test/e2e/pkg/serverside_test.go @@ -103,5 +103,11 @@ var _ = Describe("Server Side Apply", func() { return nil }, 1*time.Minute, 1*time.Second).ShouldNot(HaveOccurred()) + + // cleanup the job + resp, err = apiClient.DefaultApi.ApiMaestroV1ResourcesIdDelete(context.Background(), resourceID).Execute() + Expect(err).ShouldNot(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusNoContent)) + }) }) diff --git a/test/factories.go b/test/factories.go index 9711efa5..971846b6 100755 --- a/test/factories.go +++ b/test/factories.go @@ -58,7 +58,7 @@ func (helper *Helper) NewAPIResource(consumerName string, replicas int) openapi. func (helper *Helper) NewResource(consumerName string, replicas int) *api.Resource { testResource := helper.NewAPIResource(consumerName, replicas) - testManifest, err := api.EncodeManifest(testResource.Manifest) + testManifest, err := api.EncodeManifest(testResource.Manifest, testResource.DeleteOption, testResource.UpdateStrategy) if err != nil { helper.T.Errorf("error encoding manifest: %q", err) } diff --git a/test/grpc_codec.go b/test/grpc_codec.go index 1a2e7a30..fd9292b4 100644 --- a/test/grpc_codec.go +++ b/test/grpc_codec.go @@ -41,7 +41,7 @@ func (c *ResourceCodec) Encode(source string, eventType types.CloudEventsType, r return &evt, nil } - manifest, err := api.DecodeManifest(resource.Manifest) + manifest, _, _, err := api.DecodeManifest(resource.Manifest) if err != nil { return nil, fmt.Errorf("failed to decode manifest: %v", err) } @@ -153,7 +153,7 @@ func (c *ResourceBundleCodec) Encode(source string, eventType types.CloudEventsT return &evt, nil } - manifest, err := api.DecodeManifest(resource.Manifest) + manifest, _, _, err := api.DecodeManifest(resource.Manifest) if err != nil { return nil, fmt.Errorf("failed to decode manifest: %v", err) } From be8dc759035dc65ad760e91cea285cc84231dd10 Mon Sep 17 00:00:00 2001 From: Morven Cao Date: Mon, 3 Jun 2024 16:45:15 +0800 Subject: [PATCH 3/3] add resource bundle api. (#106) * add resource bundle api. Signed-off-by: morvencao * add document for resource bundle API. Signed-off-by: morvencao --------- Signed-off-by: morvencao --- README.md | 214 +++++++ cmd/maestro/server/routes.go | 8 +- data/generated/openapi/openapi.go | 4 +- examples/cloudevent-bundle.json | 80 +++ examples/grpcclient.go | 71 +++ openapi/openapi.yaml | 112 ++++ pkg/api/openapi/.openapi-generator/FILES | 8 + pkg/api/openapi/README.md | 6 + pkg/api/openapi/api/openapi.yaml | 199 +++++++ pkg/api/openapi/api_default.go | 325 +++++++++++ pkg/api/openapi/docs/DefaultApi.md | 142 +++++ pkg/api/openapi/docs/ResourceBundle.md | 342 ++++++++++++ pkg/api/openapi/docs/ResourceBundleAllOf.md | 264 +++++++++ pkg/api/openapi/docs/ResourceBundleList.md | 135 +++++ .../openapi/docs/ResourceBundleListAllOf.md | 56 ++ pkg/api/openapi/model_resource_bundle.go | 521 ++++++++++++++++++ .../openapi/model_resource_bundle_all_of.go | 413 ++++++++++++++ pkg/api/openapi/model_resource_bundle_list.go | 223 ++++++++ .../model_resource_bundle_list_all_of.go | 124 +++++ pkg/api/presenters/resource.go | 70 +++ pkg/api/resource_bundle_types.go | 112 ++++ pkg/api/resource_bundle_types_test.go | 170 ++++++ pkg/api/resource_types.go | 53 -- pkg/api/resource_types_test.go | 44 -- pkg/dao/mocks/resource.go | 11 + pkg/dao/resource.go | 10 + pkg/handlers/resource.go | 66 +++ pkg/services/resource.go | 9 + pkg/services/validation.go | 6 +- test/factories.go | 107 ++++ test/integration/resource_test.go | 80 ++- 31 files changed, 3881 insertions(+), 104 deletions(-) create mode 100644 examples/cloudevent-bundle.json create mode 100644 examples/grpcclient.go create mode 100644 pkg/api/openapi/docs/ResourceBundle.md create mode 100644 pkg/api/openapi/docs/ResourceBundleAllOf.md create mode 100644 pkg/api/openapi/docs/ResourceBundleList.md create mode 100644 pkg/api/openapi/docs/ResourceBundleListAllOf.md create mode 100644 pkg/api/openapi/model_resource_bundle.go create mode 100644 pkg/api/openapi/model_resource_bundle_all_of.go create mode 100644 pkg/api/openapi/model_resource_bundle_list.go create mode 100644 pkg/api/openapi/model_resource_bundle_list_all_of.go create mode 100755 pkg/api/resource_bundle_types.go create mode 100644 pkg/api/resource_bundle_types_test.go diff --git a/README.md b/README.md index ccf6cfb4..5376d0de 100755 --- a/README.md +++ b/README.md @@ -339,6 +339,220 @@ ocm get /api/maestro/v1/resources } ``` +#### Create/Get resource bundle with multiple resources + +1. Enable gRPC server by passing `--enable-grpc-server=true` to the maestro server start command, for example: + +```shell +$ oc -n maestro patch deploy/maestro --type=json -p='[{"op": "add", "path": "/spec/template/spec/containers/0/command/-", "value": "--enable-grpc-server=true"}]' +``` + +2. Port-forward the gRPC service to your local machine, for example: + +```shell +$ oc -n maestro port-forward svc/maestro-grpc 8090 & +``` + +3. Create a resource bundle with multiple resources using the gRPC client, for example: + +```shell +go run ./examples/grpcclient.go -cloudevents_json_file ./examples/cloudevent-bundle.json -grpc_server localhost:8090 +``` + +4. Get the resource bundle with multiple resources, for example: + +```shell +ocm get /api/maestro/v1/resource-bundles +{ + "items": [ + { + "consumer_name": "cluster1", + "created_at": "2024-05-30T05:03:08.493083Z", + "delete_option": { + "propagationPolicy": "Foreground" + }, + "href": "/api/maestro/v1/resource-bundles/68ebf474-6709-48bb-b760-386181268060", + "id": "68ebf474-6709-48bb-b760-386181268060", + "kind": "ResourceBundle", + "manifest_configs": [ + { + "feedbackRules": [ + { + "jsonPaths": [ + { + "name": "status", + "path": ".status" + } + ], + "type": "JSONPaths" + } + ], + "resourceIdentifier": { + "group": "apps", + "name": "web", + "namespace": "default", + "resource": "deployments" + }, + "updateStrategy": { + "type": "ServerSideApply" + } + } + ], + "manifests": [ + { + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": { + "name": "web", + "namespace": "default" + } + }, + { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "web", + "namespace": "default" + }, + "spec": { + "replicas": 1, + "selector": { + "matchLabels": { + "app": "web" + } + }, + "template": { + "metadata": { + "labels": { + "app": "web" + } + }, + "spec": { + "containers": [ + { + "image": "nginxinc/nginx-unprivileged", + "name": "nginx" + } + ] + } + } + } + } + ], + "name": "68ebf474-6709-48bb-b760-386181268060", + "status": { + "ObservedVersion": 1, + "SequenceID": "1796044690592632832", + "conditions": [ + { + "lastTransitionTime": "2024-05-30T05:03:08Z", + "message": "Apply manifest work complete", + "reason": "AppliedManifestWorkComplete", + "status": "True", + "type": "Applied" + }, + { + "lastTransitionTime": "2024-05-30T05:03:08Z", + "message": "All resources are available", + "reason": "ResourcesAvailable", + "status": "True", + "type": "Available" + } + ], + "resourceStatus": [ + { + "conditions": [ + { + "lastTransitionTime": "2024-05-30T05:03:08Z", + "message": "Apply manifest complete", + "reason": "AppliedManifestComplete", + "status": "True", + "type": "Applied" + }, + { + "lastTransitionTime": "2024-05-30T05:03:08Z", + "message": "Resource is available", + "reason": "ResourceAvailable", + "status": "True", + "type": "Available" + }, + { + "lastTransitionTime": "2024-05-30T05:03:08Z", + "message": "", + "reason": "NoStatusFeedbackSynced", + "status": "True", + "type": "StatusFeedbackSynced" + } + ], + "resourceMeta": { + "group": "", + "kind": "ConfigMap", + "name": "web", + "namespace": "default", + "ordinal": 0, + "resource": "configmaps", + "version": "v1" + }, + "statusFeedback": {} + }, + { + "conditions": [ + { + "lastTransitionTime": "2024-05-30T05:03:08Z", + "message": "Apply manifest complete", + "reason": "AppliedManifestComplete", + "status": "True", + "type": "Applied" + }, + { + "lastTransitionTime": "2024-05-30T05:03:08Z", + "message": "Resource is available", + "reason": "ResourceAvailable", + "status": "True", + "type": "Available" + }, + { + "lastTransitionTime": "2024-05-30T05:03:08Z", + "message": "", + "reason": "StatusFeedbackSynced", + "status": "True", + "type": "StatusFeedbackSynced" + } + ], + "resourceMeta": { + "group": "apps", + "kind": "Deployment", + "name": "web", + "namespace": "default", + "ordinal": 1, + "resource": "deployments", + "version": "v1" + }, + "statusFeedback": { + "values": [ + { + "fieldValue": { + "jsonRaw": "{\"availableReplicas\":1,\"conditions\":[{\"lastTransitionTime\":\"2024-05-30T05:03:13Z\",\"lastUpdateTime\":\"2024-05-30T05:03:13Z\",\"message\":\"Deployment has minimum availability.\",\"reason\":\"MinimumReplicasAvailable\",\"status\":\"True\",\"type\":\"Available\"},{\"lastTransitionTime\":\"2024-05-30T05:03:08Z\",\"lastUpdateTime\":\"2024-05-30T05:03:13Z\",\"message\":\"ReplicaSet \\\"web-dcffc4f85\\\" has successfully progressed.\",\"reason\":\"NewReplicaSetAvailable\",\"status\":\"True\",\"type\":\"Progressing\"}],\"observedGeneration\":1,\"readyReplicas\":1,\"replicas\":1,\"updatedReplicas\":1}", + "type": "JsonRaw" + }, + "name": "status" + } + ] + } + } + ] + }, + "updated_at": "2024-05-30T05:03:17.796496Z", + "version": 1 + } + ], + "kind": "ResourceBundleList", + "page": 1, + "size": 1, + "total": 1 +} +``` + #### Run in OpenShift Take OpenShift Local as an example to deploy the maestro. If you want to deploy maestro in an OpenShift cluster, you need to set the `external_apps_domain` environment variable to point your cluster. diff --git a/cmd/maestro/server/routes.go b/cmd/maestro/server/routes.go index 7b42c115..4be41cc4 100755 --- a/cmd/maestro/server/routes.go +++ b/cmd/maestro/server/routes.go @@ -79,9 +79,15 @@ func (s *apiServer) routes() *mux.Router { apiV1ResourceRouter.HandleFunc("/{id}", resourceHandler.Patch).Methods(http.MethodPatch) apiV1ResourceRouter.HandleFunc("/{id}", resourceHandler.Delete).Methods(http.MethodDelete) apiV1ResourceRouter.Use(authMiddleware.AuthenticateAccountJWT) - apiV1ResourceRouter.Use(authzMiddleware.AuthorizeApi) + // /api/maestro/v1/resource-bundles + apiV1ResourceBundleRouter := apiV1Router.PathPrefix("/resource-bundles").Subrouter() + apiV1ResourceBundleRouter.HandleFunc("", resourceHandler.ListBundle).Methods(http.MethodGet) + apiV1ResourceBundleRouter.HandleFunc("/{id}", resourceHandler.GetBundle).Methods(http.MethodGet) + apiV1ResourceBundleRouter.Use(authMiddleware.AuthenticateAccountJWT) + apiV1ResourceBundleRouter.Use(authzMiddleware.AuthorizeApi) + // /api/maestro/v1/consumers apiV1ConsumersRouter := apiV1Router.PathPrefix("/consumers").Subrouter() apiV1ConsumersRouter.HandleFunc("", consumerHandler.List).Methods(http.MethodGet) diff --git a/data/generated/openapi/openapi.go b/data/generated/openapi/openapi.go index 97c79a55..ce159dfb 100755 --- a/data/generated/openapi/openapi.go +++ b/data/generated/openapi/openapi.go @@ -77,7 +77,7 @@ func (fi bindataFileInfo) Sys() interface{} { return nil } -var _openapiYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5c\x5f\x8f\xdb\xb8\x11\x7f\xf7\xa7\x18\xa0\x2d\x7c\x39\x78\x6d\xa7\x77\x05\x5a\x23\x39\x20\xb9\x5e\x8a\x3b\xe4\x92\x34\x9b\xb4\x0f\x45\xe1\xa5\xc9\x91\xc5\x8b\x44\x2a\x24\xb5\x59\xa7\xed\x77\x2f\x48\xea\xbf\x25\xad\x6c\xec\xc6\xca\xc2\x79\x89\x45\xcd\x0c\x67\xc8\x99\x1f\x87\x1c\x6a\x65\x82\x82\x24\x7c\x05\xdf\xcd\x97\xf3\xe5\x84\x8b\x40\xae\x26\x00\x86\x9b\x08\x57\x10\x13\xd4\x46\x49\xb8\x44\x75\xcd\x29\xc2\xb3\x37\x3f\x4f\x00\x18\x6a\xaa\x78\x62\xb8\x14\x5d\x24\xd7\xa8\xb4\x7b\xbd\x9c\x2f\xe7\x8f\x27\x1a\x95\x6d\xb1\x92\x2f\x20\x55\xd1\x0a\x42\x63\x92\xd5\x62\x11\x49\x4a\xa2\x50\x6a\xb3\xfa\xf3\x72\xb9\x9c\x00\x34\xa4\xd3\x54\x29\x14\x06\x98\x8c\x09\x17\x75\x76\xbd\x5a\x2c\x48\xc2\xe7\xd6\x04\x1d\xf2\xc0\xcc\xa9\x8c\xf7\x45\xfc\x4a\xb8\x80\x6f\x12\x25\x59\x4a\x6d\xcb\x23\xf0\xda\xb4\x0b\xd3\x86\x6c\xf1\x36\x91\x97\x86\x6c\xb9\xd8\xe6\x82\x12\x62\x42\x67\x9b\x95\xb0\xc8\x06\x64\x71\xfd\x78\xa1\x50\xcb\x54\x51\x74\x2f\x01\xb6\x68\xfc\x0f\x00\x9d\xc6\x31\x51\xbb\x15\xbc\x45\x93\x2a\xa1\x81\x40\xc4\xb5\x01\x19\x40\xc1\x94\x93\x22\x4d\x15\x37\xbb\x9c\xd5\xaa\xfd\x1c\x89\x42\xb5\x82\x7f\xfd\x3b\x6b\x54\xa8\x13\x29\x74\xde\x93\xfd\x37\xfd\xe3\x72\x39\x2d\x1f\x1b\x26\x3c\x83\x5f\x2e\x5f\xbf\x02\xa2\x14\xd9\x55\x7b\x05\xb9\xf9\x0d\xa9\xd1\x15\x3e\x2a\x85\x41\x61\xaa\xa2\x00\x48\x92\x44\x9c\x12\x2b\x6c\xf1\x9b\x96\xa2\xfe\x16\x40\xd3\x10\x63\xd2\x6c\x05\xf8\xbd\xc2\x60\x05\xd3\xdf\x2d\xa8\x8c\x13\x29\x50\x18\xbd\xf0\xb4\x7a\xf1\x36\xd3\xe1\x25\xd7\x66\x5a\xda\xf1\xfd\xf2\x71\x8f\x1d\xa9\x09\xc1\xc8\x0f\x28\x80\x6b\xe0\xe2\x9a\x44\x9c\x9d\x42\xf9\x9f\x94\x92\xaa\xa6\xf5\x77\xdd\x5a\xbf\x17\x24\x35\xa1\x54\xfc\x33\x32\x30\x12\x12\x54\x81\x54\x31\xc8\x04\x95\x53\x6b\x0c\x16\xfc\xa9\xcf\x7f\xde\x0b\xbc\x49\x90\x1a\x64\x80\x96\x0f\x24\x75\xb1\x7a\xfa\xb1\x4f\x88\x22\x31\x9a\x0c\x6e\xc0\xc5\x4b\x1b\x73\x49\xb7\x48\xc8\x16\xa7\x43\x89\x35\xff\x7c\x00\x31\x12\x45\xc3\xc1\xe4\x52\x31\x54\xcf\x77\x83\xe9\x03\x8e\x11\xd3\x9e\x3c\xb1\x28\xda\x84\x97\x1f\x15\x12\x83\x40\x40\xe0\xa7\x22\xc6\x0f\x03\x96\x8f\x29\x6a\xf3\x5c\xb2\x0a\x5d\xcd\x13\xf2\xa8\x05\x46\x0c\x29\x48\x2c\x1f\x57\xc8\x56\x60\x54\x8a\x93\x1e\x97\xe8\x77\x88\x76\x77\x18\x82\x22\xd3\x5e\x68\xec\x81\x14\x3f\x66\x27\x71\xe4\xa6\xee\x0e\x47\x7a\xa2\xf0\x1f\x16\xed\x9c\x0a\x3e\x0a\xf5\x78\xc2\xf0\x0c\xdc\x27\xb4\xe0\x2f\xdd\x16\x14\xe1\x4a\x22\x85\x84\xed\x00\x6f\xb8\x3e\xcd\x7a\x7f\xd0\x82\xf3\x4c\x40\xda\xb5\xe6\x00\xb5\x21\x6b\x33\x32\x13\x62\x13\xe6\x4e\x63\x52\x67\x2a\xb8\xf8\x0f\x67\xff\xeb\xce\x07\xff\x86\x06\x88\x28\xd3\xb1\xcd\x0e\x8a\xb0\xb8\x9f\x4c\xb0\x70\x88\x40\xa6\x82\xd5\x3a\xfc\xa2\x43\xd7\x8a\x7d\x67\x00\x39\x8d\x05\xdf\x77\x5b\xf0\x4a\x96\xde\xf9\x89\x9b\x10\x74\x82\x94\x07\x1c\x19\x70\xf6\xb5\xa0\xc9\x58\xd3\xd7\x84\x18\x1a\xee\x81\xc2\xfb\x84\xb9\x2c\x4e\xdc\x53\x0a\xe7\xe5\xb3\x72\x5e\x47\x96\xca\xbd\xb1\xa3\xf2\xd6\x9b\xd1\x9f\xd6\x0d\xc1\xb9\x34\xb3\x56\xa7\x94\xa2\xd6\x41\x1a\x45\xbb\xd1\x00\xde\x39\xd9\xfb\xc2\x5a\x9f\xb1\x7a\x14\x46\x3c\xc0\x8c\x75\x6f\x8d\x71\xc0\x63\xb3\xd4\x51\x64\xa8\x56\xdb\x08\x0d\xee\xad\x36\x7f\x75\xcd\x40\x8e\x5c\x6c\xda\x60\xb9\xc7\x45\xcb\xe3\x03\xd7\x6d\x07\x2c\x9f\x91\xf1\xcb\x6b\x7d\x46\xc6\x11\x18\x71\x18\xc2\xb8\x18\x1a\x11\xc2\x34\xcf\x62\x6f\x3d\xd0\xe4\xac\x6d\xf3\x4c\xa5\xd0\x69\x5c\x48\x19\x56\x47\x29\x98\xee\x75\xf7\xdc\xac\xa3\xe4\xbd\x9e\xb2\x8e\xf2\x63\xa6\xc3\xb9\x8e\x32\x0a\x1c\xfa\x2a\x37\xa2\x6d\x75\x94\x03\x2b\x29\x07\xd6\x52\x0e\xae\xa6\x1c\x5e\x4f\xb9\xf3\x8a\x4a\x1e\xed\x77\xbb\x1d\xcf\xe3\x77\x2c\xdb\xf0\x5c\x9f\xaf\xb1\xa2\xd2\xd4\xfd\x9c\x4a\x9e\x21\xfc\x18\x0b\x7a\xf6\xa7\x45\xb8\x7e\x65\xfb\xd3\xe1\x15\x95\x06\xcc\x9d\xc6\xa4\xce\xa4\x70\x58\x45\xa5\x48\xcc\xee\xbf\xa2\x52\x38\xc4\x89\x2b\x2a\xad\xd8\x77\x06\x90\x31\xee\x45\x0b\xef\x7c\x38\x7b\xd1\x91\xac\x9b\xb7\x55\x54\xee\x27\x85\xcb\x2b\x2a\x74\xa4\xa9\xdc\x9d\x54\x54\x0a\x9c\x1b\x4b\x45\xe5\x9c\xec\x8d\x41\xeb\x33\x56\x8f\xc2\x88\x07\x98\xb1\x76\x57\x54\x46\x91\xa1\xde\x5e\x51\x39\x6e\xb1\x39\xb0\xa2\x52\x1e\x1f\x9c\x2b\x2a\x67\x64\xbc\x5b\x0b\x1e\x00\x32\x1e\x59\x51\x19\x09\xc2\x1c\x71\xbb\x9d\xb3\xe9\xa4\x7c\x63\xd9\x72\xdc\xb9\xb4\xf2\x73\x60\xc9\x80\x27\x93\x6a\x76\x09\xfa\x2f\x63\x26\x15\xbd\x71\x05\x1b\x47\x96\x35\xfa\x87\x17\x52\xc5\xc4\xac\xe0\x97\x7f\xbe\x9b\xe4\x06\x66\x42\x5f\xbb\x2a\xc8\x5b\x0c\x50\xa1\xa0\x58\x97\xee\x4b\x24\x59\x53\xa2\xac\xab\x1b\x5e\xc5\x39\xce\xaa\xe3\xe4\x99\xb4\x51\x5c\x6c\x8b\xe6\x0f\x5c\xdc\x4e\x14\xda\x01\xea\x23\x7a\xc9\xcb\x93\xde\x81\xba\x0d\xea\x38\x21\x5b\xdc\x27\xe2\xc2\xe0\xb6\xe2\x49\x9a\x7f\x1e\x40\x65\xa4\x21\xd1\x6d\x64\xc5\xce\xa2\xb2\xa2\x58\x4d\x2b\x8f\x56\xa7\xca\xa3\xed\xbc\xf2\xe8\x7a\xa9\x3c\x73\x83\xb1\x0f\x5b\xe7\x84\xb9\x5c\x12\x45\xaf\x83\x7e\x0f\xcc\x9d\xb7\xe1\x02\xe5\xb7\x0d\x2d\x03\xdd\x3e\xd4\x36\xd2\x18\xd6\x43\xa6\x75\xb8\xad\xfd\x64\x2f\xe6\x3a\x48\x0b\x64\x5d\xd7\xdd\xac\x85\xc1\x99\x5e\xf5\x91\x03\xcc\xaf\x16\xe1\x0e\xb2\xd9\x8d\x7c\x9b\x62\xae\xd6\x58\x6b\x6f\x21\x1d\x0c\x28\xf9\xfd\x8b\x13\xcd\xac\x20\xf1\xb0\x99\xcd\xf1\x77\x3d\x98\x23\xff\x06\xb1\x85\xb6\x19\x5b\xe0\xcf\x3b\x91\xad\x89\x19\x24\x1b\x20\xc8\x40\xcf\xee\x7c\x2f\x0c\x8f\xab\xa5\xf6\x6c\x3f\x7c\x37\xc2\x62\x22\x78\x80\xba\x55\x54\x63\x88\xf3\x04\x74\x2d\xfd\x72\x36\x84\xc3\xeb\xba\xd6\x46\x11\x83\xdb\xdd\x20\x1e\x6d\x88\x49\x5b\x7d\xb3\x42\x5a\xfd\x9a\xef\xa1\xc4\x4d\xfd\xca\x66\xdb\xf5\xd4\x03\x57\x91\x16\x1f\x6d\xf7\xd0\x36\x2f\x68\x1d\x94\x4e\x0f\x68\xa5\xee\x99\xfd\x3d\xfa\x7c\x5f\xd1\x3a\x99\x47\x62\x45\xe7\xdc\x76\xcd\x6e\x1b\x62\xf4\x04\x56\x44\x36\x18\xed\x4d\x71\x47\x8f\xce\x28\xc6\xb8\x1d\x39\x12\xbd\xe9\xe8\xbf\xb7\xbf\x2e\x18\xe9\x61\xe9\x8f\xfe\x6e\x30\x39\x42\x64\xf5\x62\xc8\x51\xb3\x58\xbf\x51\x72\xf0\xd4\xb5\xc6\x5b\x57\x70\x76\x90\x1f\x72\x02\xd8\x76\xda\x79\x60\x80\xee\x3b\x50\x87\xcd\xb7\x3b\x4e\x63\xba\x9a\x99\x7c\x99\x85\x38\x0f\x2f\x6b\x46\x5c\xac\x20\x21\x26\xcc\x1e\x6b\xfb\x95\x77\x21\xda\xdd\x95\xfb\x80\x9b\x4a\xc5\x9a\x69\x60\xf5\x80\xb9\xb9\xf3\xd8\x73\x9f\x6a\xb6\xea\x75\xa8\xe4\x8a\x56\x8b\x8f\x29\xaa\x5d\x9b\x1a\x6f\xc8\x16\x41\xa4\xf1\x06\x55\xa9\x8b\xbf\x89\xf5\x29\x44\x51\x6b\xc0\x1b\x8a\xc8\x74\x65\x7b\x68\x7b\xa9\xe6\xa1\xed\x8a\x36\x11\x91\x61\x40\xd2\xc8\xac\xe0\x71\x09\x92\x5c\xf0\x38\x8d\xcb\xa6\x72\x1c\x02\x12\x69\x2f\xbf\x9a\x6d\x7b\x2b\x2b\x5d\xf7\x5a\xf9\x2b\xb9\xb1\xe2\xf7\x0c\xd5\x76\xc3\xae\xdc\x05\xb4\x23\x2d\xc8\xfe\xf4\x41\xcd\x86\x65\x9f\x0d\xee\x22\x4c\xc3\x0a\xd7\xd6\x61\x47\x9b\x90\x86\x75\xff\xbd\x28\x74\xb8\xcc\xa6\x46\xbb\xea\xaf\x17\x0c\x54\x71\x83\x8a\x93\xb9\x73\x3a\xbd\x13\x86\xdc\xd8\x31\x30\x21\xd7\xa5\x33\x03\x2f\x37\xf9\x9a\xc7\x3c\x22\xca\x8e\x8e\x69\xb0\x20\xac\x3f\x85\xa8\x70\x0d\x34\x22\xa9\x46\xdb\x4a\x04\x5c\xfe\xfd\xa5\x4b\x2e\x30\x46\x61\x66\xe5\x2a\xa5\xf3\x4a\xb4\x35\x55\xe7\x22\xec\xf6\x1a\x88\x31\x8a\x6f\x52\x83\x1a\x16\x40\x65\x94\xc6\xa2\x4e\x45\x28\x95\xa9\x30\x73\x28\xc4\xbd\x90\x0a\xf0\x86\xc4\x49\x84\x33\xe0\x02\xdc\x2d\xa1\x6c\x0e\x15\xc7\x6b\xb4\xa0\x58\xe5\xd5\xfe\x40\x83\x40\xaa\x51\x59\xe1\xa5\x89\x86\x28\x77\x3c\xe0\x08\xae\xe2\xdd\xd5\x6a\x52\xbc\xbc\xba\xba\xd2\x1f\xa3\x8a\x15\x9e\x19\x22\xfe\x01\x61\x1a\xef\xfe\x30\xad\x92\x96\x7c\xef\xf6\x07\x1d\x28\x11\x40\x22\x2d\x61\x83\xfe\x88\x01\x19\x48\x1b\x58\x51\xed\xcb\x9d\xf9\x11\x46\xea\x74\x53\xb8\x81\xf6\x80\x87\xae\x6a\x7d\x15\x48\xf9\x74\x43\xd4\xd5\xac\xd3\xa6\x2a\xef\xda\x63\xe5\xfc\x03\xee\xe0\x29\x4c\x03\x29\xa7\x40\x04\x6b\xa5\xb9\x26\x51\x8a\x96\x6a\x43\x54\xc7\x28\xfc\xec\xa7\xaf\xea\x59\x62\x6a\x2c\x48\x5f\x73\x86\x6c\x06\x52\x01\xf7\x34\x5e\x1a\xd7\x80\x71\x62\x76\x33\xdb\x56\x9e\x97\xed\xcd\xa5\x09\x89\x71\x2d\x76\x42\x20\x24\x1a\x12\x54\x31\xd7\x36\x11\xb3\x03\xa4\x11\xe1\x13\x8f\x22\xd8\x94\xf3\xec\xa3\x1b\xd9\x7c\x28\x96\x66\x37\xcf\xea\x21\x9a\x35\xde\x43\x8c\xfa\xd9\xdd\xec\xee\x3c\x4a\x73\xc1\xc3\x02\x75\x93\x9a\x83\x83\xb5\x11\xa6\x07\x3a\x70\x31\xab\xee\xb5\xf7\xdb\x3c\xd0\x06\x84\x22\xd1\xb4\xdd\xfb\x5e\xab\xe3\xfa\x84\x35\x11\x6c\x0d\x01\x57\xda\xc0\x70\x25\x66\x9e\xe3\x55\xaf\x4e\x77\x15\x11\x42\x02\xde\x24\x11\xa7\xdc\x78\x13\x3c\x80\x39\x8f\xcf\xc1\x65\xb0\xa3\xfb\x0b\x93\x75\x3f\xf7\x6d\x77\xe3\xe6\xa9\xd3\x47\xbb\xe2\x49\x1c\x93\x0b\x8d\xd6\x7e\x8b\x79\xf9\x45\x6f\xdf\x9b\x9d\xa5\x0d\xee\x05\x2a\xc0\x0b\xff\x5a\x06\x16\x88\x2e\xb4\x51\x29\x35\xa9\xb2\x12\x85\x4b\x9c\x5c\xe6\xa9\xed\x6c\xc0\x93\xe2\xed\x0f\xf3\x27\x4e\xec\x0f\x20\xa4\x71\xa7\x44\xa5\xc0\x27\xda\xe4\x44\xdf\x42\x8c\x44\x68\xe7\x15\x8e\xde\x09\x84\x42\x4c\xc1\xf3\x93\x77\xe4\x95\xf7\x6a\x42\x43\xb8\xac\xa0\xa2\xd5\x7d\x8b\x06\x38\x9b\xb9\xb3\xca\x19\x24\x11\x11\xdf\x70\xe6\x74\xfc\xc0\x05\x7b\xe4\x7e\x79\xf0\x84\x6f\x8a\xee\xf4\xa3\x9a\x77\x15\xbf\x25\x8d\x9d\xc0\x3a\xb4\x5f\x5c\x94\xae\xe3\xd9\x9f\x72\x36\x73\x1d\xda\xfe\xe6\x9c\xf9\xff\x6d\x87\xb3\x0c\xa8\xbf\xad\x73\xa1\xa1\xe1\x4b\xf7\xe6\x69\xed\xea\x42\xd9\x79\xaf\xc3\xfc\x3f\x00\x00\xff\xff\xe3\xa8\xf9\x43\x6e\x4a\x00\x00") +var _openapiYaml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x5c\x5f\x8f\xdb\xb8\x11\x7f\xdf\x4f\x31\x40\x5b\xf8\x72\xf0\xda\x4e\xef\x0a\xb4\x46\x72\x40\x72\xbd\x14\x77\xc8\x25\x69\x36\x69\x1f\x8a\xc2\x4b\x93\x23\x8b\x89\x44\x2a\x24\xb5\x59\xa7\xed\x77\x2f\x48\xea\xbf\x25\xad\xec\xee\xc6\xda\xad\xf3\x92\x35\x35\x1c\xce\x90\xbf\xf9\x69\x48\x8e\x2d\x13\x14\x24\xe1\x4b\xf8\x6e\xb6\x98\x2d\xce\xb8\x08\xe4\xf2\x0c\xc0\x70\x13\xe1\x12\x62\x82\xda\x28\x09\x17\xa8\xae\x38\x45\x78\xf6\xe6\xe7\x33\x00\x86\x9a\x2a\x9e\x18\x2e\x45\x97\xc8\x15\x2a\xed\x1e\x2f\x66\x8b\xd9\xe3\x33\x8d\xca\xb6\x58\xcd\xe7\x90\xaa\x68\x09\xa1\x31\xc9\x72\x3e\x8f\x24\x25\x51\x28\xb5\x59\xfe\x71\xb1\x58\x9c\x01\x34\xb4\xd3\x54\x29\x14\x06\x98\x8c\x09\x17\xf5\xee\x7a\x39\x9f\x93\x84\xcf\xac\x0b\x3a\xe4\x81\x99\x51\x19\xef\xaa\xf8\x95\x70\x01\xdf\x24\x4a\xb2\x94\xda\x96\x47\xe0\xad\x69\x57\xa6\x0d\xd9\xe0\x4d\x2a\x2f\x0c\xd9\x70\xb1\xc9\x15\x25\xc4\x84\xce\x37\xab\x61\x9e\x4d\xc8\xfc\xea\xf1\x5c\xa1\x96\xa9\xa2\xe8\x1e\x02\x6c\xd0\xf8\x3f\x00\x74\x1a\xc7\x44\x6d\x97\xf0\x16\x4d\xaa\x84\x06\x02\x11\xd7\x06\x64\x00\x45\xa7\x5c\x14\x69\xaa\xb8\xd9\xe6\x5d\xad\xd9\xcf\x91\x28\x54\x4b\xf8\xc7\x3f\xb3\x46\x85\x3a\x91\x42\xe7\x23\xd9\x7f\x93\xdf\x2f\x16\x93\xf2\x63\xc3\x85\x67\xf0\xcb\xc5\xeb\x57\x40\x94\x22\xdb\xea\xa8\x20\xd7\x1f\x90\x1a\x5d\xe9\x47\xa5\x30\x28\x4c\x55\x15\x00\x49\x92\x88\x53\x62\x95\xcd\x3f\x68\x29\xea\x4f\x01\x34\x0d\x31\x26\xcd\x56\x80\xdf\x2a\x0c\x96\x30\xf9\xcd\x9c\xca\x38\x91\x02\x85\xd1\x73\x2f\xab\xe7\x6f\x33\x1b\x5e\x72\x6d\x26\xa5\x1f\xdf\x2f\x1e\xf7\xf8\x91\x9a\x10\x8c\xfc\x88\x02\xb8\x06\x2e\xae\x48\xc4\xd9\x31\x8c\xff\x49\x29\xa9\x6a\x56\x7f\xd7\x6d\xf5\x7b\x41\x52\x13\x4a\xc5\xbf\x20\x03\x23\x21\x41\x15\x48\x15\x83\x4c\x50\x39\xb3\xc6\xe0\xc1\x1f\xfa\xf0\xf3\x5e\xe0\x75\x82\xd4\x20\x03\xb4\xfd\x40\x52\x17\xab\xc7\x9f\xfb\x84\x28\x12\xa3\xc9\xe8\x06\x5c\xbc\xb4\x75\x2e\xe5\xe6\x09\xd9\xe0\x64\xa8\xb0\xe6\x5f\xf6\x10\x46\xa2\x68\x38\x58\x5c\x2a\x86\xea\xf9\x76\xb0\x7c\xc0\x31\x62\xda\x8b\x27\x96\x45\x9b\xf4\xf2\xa3\x42\x62\x10\x08\x08\xfc\x5c\xc4\xf8\x7e\xc4\xf2\x29\x45\x6d\x9e\x4b\x56\x91\xab\x21\x21\x8f\x5a\x60\xc4\x90\x42\xc4\xf6\xe3\x0a\xd9\x12\x8c\x4a\xf1\xac\x07\x12\xfd\x80\x68\x87\xc3\x10\x16\x99\xf4\x52\x63\x0f\xa5\xf8\x39\x3b\x0a\x90\x9b\xb6\x3b\x1e\xe9\x89\xc2\xbf\x59\xb6\x73\x26\xf8\x28\xd4\xe3\x09\xc3\x13\x71\x1f\xd1\x83\x3f\x75\x7b\x50\x84\x2b\x89\x14\x12\xb6\x05\xbc\xe6\xfa\x38\xef\xfb\xbd\x5e\x38\xcf\x04\xa4\x5d\xef\x1c\xa0\x36\x64\x6d\x46\x66\x42\x6c\xd2\xdc\x71\x5c\xea\x4c\x05\xe7\xff\xe2\xec\x3f\xdd\xf9\xe0\x5f\xd0\x00\x11\x65\x3a\xb6\xde\x42\x11\x16\x77\x93\x09\x16\x80\x08\x64\x2a\x58\x6d\xc0\xaf\x3a\x75\xad\xdc\x77\x22\x90\xe3\x78\xf0\x7d\xb7\x07\xaf\x64\x89\xce\xcf\xdc\x84\xa0\x13\xa4\x3c\xe0\xc8\x80\xb3\xfb\xc2\x26\x63\x4d\x5f\x13\x62\x68\xb8\x43\x0a\xef\x13\xe6\xb2\x38\x71\x47\x29\x9c\xd7\xcf\xca\x75\x1d\x59\x2a\xf7\xc6\xce\xca\x5b\xef\x46\x7f\x5a\x37\x84\xe7\xd2\xcc\x5b\x9d\x52\x8a\x5a\x07\x69\x14\x6d\x47\x43\x78\xa7\x64\xef\x2b\x5b\x7d\xe2\xea\x51\x38\xf1\x00\x33\xd6\x9d\x77\x8c\x23\x1e\x9b\xa5\x8e\x22\x43\xb5\xd6\x46\x68\x70\xe7\x6d\xf3\x67\xd7\x0c\xe4\xc0\x97\x4d\x1b\x2d\xf7\x40\xb4\x3c\x3e\x70\xc3\x76\xd0\xf2\x89\x19\xbf\xbe\xd5\x27\x66\x1c\x81\x13\xfb\x31\x8c\x8b\xa1\x11\x31\x4c\xf3\x2c\xf6\xc6\x03\x4d\xce\xfa\x36\xcf\xe7\xeb\x54\xb0\xe8\xb0\xeb\x14\xc8\xfa\xde\xe9\x5e\xba\xf3\x56\xc5\x0f\x3e\x86\xcb\x95\xe7\xce\x92\xd3\x15\xcb\x28\x28\xea\x5e\xee\x51\xff\x5f\xaf\x58\x6e\x62\xa5\x7d\x4f\xf6\x3c\x25\x7c\xc5\x03\xbe\x6c\xc4\x91\x9c\xf3\x79\x22\x3a\x91\xd0\x08\x3c\x18\x98\x27\x65\xf8\x79\x38\xe9\xd2\x7d\x26\xd4\xf6\x4c\x89\x4a\xa1\xd3\xb8\xd0\x33\x2c\x45\x2a\x3a\x7d\xd5\xdc\x28\x1f\xf5\x98\x49\xd1\x8f\x99\x0d\xa7\x74\x68\x14\x4c\xf4\x60\xa2\x77\xcf\x84\x68\xcf\x94\x68\xef\xa4\x68\xff\xb4\xe8\xd6\x6b\x4f\xf2\x68\xdf\x8f\x62\x6e\xba\xb8\xc8\xe3\x77\x2c\x17\x16\xb9\x3d\xf7\xb1\xf6\xa4\x69\xfb\xe9\xd0\xed\x44\xe1\x87\x78\xd0\x73\x92\x5f\x84\xeb\x3d\x3b\xc9\x1f\x5e\x7b\xd2\xa0\xb9\xe3\xb8\xd4\x99\x14\x0e\xdb\xa1\x16\x89\xd9\xdd\x6f\x4d\x0b\x40\x1c\x79\x4f\xda\xca\x7d\x27\x02\x19\xe3\x6e\xb4\x40\xe7\x69\x1b\x7a\xeb\x87\xf5\xfd\xb5\x27\x77\x93\xc2\xe5\xb5\x27\x74\xa4\xa9\xdc\xad\xd4\x9e\x14\x3c\x37\x96\xda\x93\x53\xb2\x37\x06\xab\x4f\x5c\x3d\x0a\x27\x1e\x60\xc6\xda\x5d\x7b\x32\x8a\x0c\xf5\xe6\xda\x93\xc3\x5e\x36\x7b\xd6\x9e\x94\xc7\x07\xa7\xda\x93\x13\x33\xde\xae\x07\x0f\x80\x19\x0f\xac\x3d\x19\x09\xc3\x1c\x78\xa7\x52\x3e\xb1\xdd\x72\xde\xb9\xb0\xfa\x73\x62\xc9\x88\x27\xd3\x6a\xb6\x09\xfa\xef\x10\x9f\x55\xec\xc6\x25\xac\x9d\x58\xd6\xe8\x3f\xbc\x90\x2a\x26\x66\x09\xbf\xfc\xfd\xdd\x59\xee\x60\xa6\xf4\xb5\xbb\x05\x79\x8b\x01\x2a\x14\x14\xeb\xda\xfd\x15\x49\xd6\x94\x28\x0b\x75\xc3\xab\x3c\xc7\x59\x75\x9e\x7c\x27\x6d\x14\x17\x9b\xa2\xf9\x23\x17\x37\x0b\x85\x76\x82\xfa\x84\x5e\xf2\xf2\xa4\x77\xa0\x6d\x83\x06\x4e\xc8\x06\x77\x85\xb8\x30\xb8\xa9\x20\x49\xf3\x2f\x03\xa4\x8c\x34\x24\xba\x49\xac\xd8\x59\x54\xde\x28\xd6\xd2\xca\x47\x6b\x53\xe5\xa3\x1d\xbc\xf2\xd1\x8d\x52\xf9\xcc\x0d\xc6\x3e\x6c\x1d\x08\x73\xbd\x24\x8a\x5e\x07\xfd\x08\xcc\xc1\xdb\x80\x40\x59\xa2\xd0\x32\xd1\xed\x53\x6d\x23\x8d\x61\x3d\x64\x5a\xa7\xdb\xfa\x4f\x76\x62\xae\x43\xb4\x60\xd6\x55\x1d\x66\x2d\x1d\x9c\xeb\x55\x8c\xec\xe1\x7e\xf5\x12\x6e\x2f\x9f\xdd\xcc\xb7\x19\xe6\xee\x1a\x6b\xed\x2d\xa2\x83\x09\x25\x2f\x5c\x38\xd2\xca\x0a\x12\x0f\x5b\xd9\x9c\x7f\x57\x83\x7b\xe4\xbf\xd6\xd0\x22\xdb\x8c\x2d\xf0\xe7\x9d\xc8\x56\xc4\x0c\xd2\x0d\x10\x64\xa4\x67\x77\xbe\xe7\x86\xc7\xd5\xa2\xc4\x6c\x3f\x7c\x3b\xca\x62\x22\x78\x80\xba\x55\x55\x63\x8a\xf3\x04\x74\x25\xfd\xeb\x6c\x48\x0f\x6f\xeb\x4a\x1b\x45\x0c\x6e\xb6\x83\xfa\x68\x43\x4c\xda\x8a\xcd\x8a\x68\xf5\x77\x0f\x1e\x4a\xdc\xd4\xbf\xdc\xd2\xf6\x45\x9e\x3d\xdf\x22\x2d\x18\x6d\x47\x68\x1b\x0a\x5a\x27\xa5\x13\x01\xad\xd2\x3d\xab\xdf\xb9\xa0\x65\xad\xe5\x43\x5b\xd6\x6a\xf1\x56\xbd\xed\xc4\x8e\x23\x67\xc7\xff\x05\x1a\xb7\xc6\xa5\xb9\x31\x2b\x2a\x45\xc0\x37\x77\x60\xd3\x20\xe6\xcd\x0f\x00\x5a\x41\x7b\x20\x6c\x3b\x81\xdb\x05\xdd\x36\xf0\xf6\xac\x71\x44\xd6\x18\x0d\x9d\x05\xe7\x14\x63\xdc\x2e\x0c\x89\xde\x74\x8c\xdf\x3b\x5e\x17\xa2\x7b\xba\xf4\x03\xb1\x1b\xd7\x07\xa8\xac\x56\x70\x1d\xb4\x8a\xf5\xd2\xaf\xbd\x97\xae\x07\x92\xbb\xf8\xed\x10\xdf\xe7\xa8\xbe\xed\x5a\x62\xcf\x37\xe9\x2e\x80\x3a\x7c\xbe\x19\x38\x8d\xe5\x6a\x6e\xb9\xcb\xed\x82\x43\x78\x79\xb9\xcb\xc5\x12\x12\x62\xc2\xec\x63\xed\x60\xe1\x5d\x88\xc0\x99\xff\xf6\x04\x95\x2a\xef\xd2\x7a\x13\xd4\x3c\x22\xd8\x81\x4f\x75\x5b\xe9\x6d\xa8\x6c\xea\xac\x15\x9f\x52\x54\xdb\x36\x33\xde\x90\x0d\x82\x48\xe3\x35\xaa\xd2\x16\x5f\x32\xf9\x39\x44\x51\x6b\xc0\x6b\x8a\xc8\x74\xe5\x1c\xc7\x8e\x52\xdd\x30\xb6\x1b\xda\x7c\x7d\x30\x0c\x48\x1a\x99\x25\x3c\x2e\xb3\x19\x2e\x78\x9c\xc6\x65\x53\x39\x0f\x01\x89\xb4\xd7\x5f\xdd\x16\x7b\x2f\x2b\x43\xf7\x7a\xf9\x2b\xb9\xb6\xea\x77\x1c\xd5\x60\x24\x28\x57\x29\x7a\xa0\x07\xd9\xaf\xb9\xd5\x7c\x58\xf4\xf9\xe0\x2a\xd6\x1a\x5e\xb8\xb6\x0e\x3f\xda\x94\x34\xbc\xfb\xf7\x79\x61\xc3\x45\xb6\x34\xda\x95\x69\x78\xc5\x40\x15\x37\xa8\x38\x99\x39\xd0\xe9\xad\x30\xe4\xda\xce\x81\x09\xb9\x2e\xc1\x0c\xbc\x3c\x8d\xd3\x3c\xe6\x11\x51\x76\x76\x4c\xa3\x0b\xc2\xea\x73\x88\x0a\x57\x40\x23\x92\x6a\xb4\xad\x44\xc0\xc5\x5f\x5f\xba\x77\x11\xc6\x28\xcc\xb4\x4c\x27\x75\x5e\x32\x62\x5d\xd5\xb9\x8a\x0f\x5a\x0a\x20\xc6\x28\xbe\x4e\x0d\x6a\x98\x03\x95\x51\x1a\x8b\xba\x14\xa1\x54\xa6\xc2\xcc\xa0\x50\xf7\x42\x2a\xc0\x6b\x12\x27\x11\x4e\x81\x0b\x70\xe5\x7c\xd9\x1a\x2a\x8e\x57\x68\x49\xb1\xda\x57\xfb\x93\x47\x02\xa9\x46\x65\x95\x97\x2e\x1a\xa2\xdc\x39\x9e\x13\xb8\x8c\xb7\x97\xcb\xb3\xe2\xe1\xe5\xe5\xa5\xfe\x14\x55\xbc\xf0\x9d\x21\xe2\x1f\x11\x26\xf1\xf6\x77\x93\xaa\x68\xd9\xef\xdd\xee\xa4\x03\x25\x02\x48\xa4\x25\xac\xd1\x9f\x05\x22\x03\x69\x03\x2b\xaa\xfd\x18\xc1\xec\x00\x27\x75\xba\x2e\x60\xa0\x3d\xe1\xa1\x2b\x2f\xb9\x0c\xa4\x7c\xba\x26\xea\x72\xda\xe9\x53\xb5\xef\xca\x73\xe5\xec\x23\x6e\xe1\x29\x4c\x02\x29\x27\x40\x04\x6b\x95\xb9\x22\x51\x8a\x56\x6a\x4d\x54\xc7\x2c\xfc\xec\x97\xaf\x8a\x2c\x31\x31\x96\xa4\xaf\x38\x43\x36\x05\xa9\x80\x7b\x19\xaf\x8d\x6b\xc0\x38\x31\xdb\xa9\x6d\x2b\x0f\xb6\x77\xd6\xd2\x84\xc4\xb8\x16\xbb\x20\x10\x12\x0d\x09\xaa\x98\x6b\x9b\xb7\xda\x09\xd2\x88\xf0\x99\x47\x11\xac\xcb\x75\xf6\xd1\x8d\x6c\x36\x94\x4b\xb3\x12\xd1\x7a\x88\x66\x8d\x77\x10\xa3\x7e\x75\xd7\xdb\x5b\x8f\xd2\x5c\xf1\xb0\x40\x5d\xa7\x66\xef\x60\x6d\x84\xe9\x9e\x00\x2e\x56\xd5\x3d\xf6\xb8\xcd\x03\x6d\x40\x28\x12\x4d\xdb\xd1\xf7\x5a\x1d\x36\x26\xac\x88\x60\x2b\x08\xb8\xd2\x06\x86\x1b\x31\xf5\x3d\x5e\xf5\xda\x74\x5b\x11\x21\x24\xe0\x75\x12\x71\xca\x8d\x77\xc1\x13\x98\x43\x7c\x4e\x2e\x83\x81\xee\x2b\x9b\xeb\x38\xf7\x6d\xb7\x03\xf3\xd4\xd9\xa3\xdd\x2d\x67\x1c\x93\x73\x8d\xd6\x7f\xcb\x79\xf9\x37\x32\xfc\x68\x76\x95\xd6\xb8\x13\xa8\x00\x2f\xfc\x63\x19\x58\x22\x3a\xd7\x46\xa5\xd4\xa4\xca\x6a\x14\x2e\x71\x72\x99\xa7\xb6\xab\x01\x4f\x8a\xa7\x3f\xcc\x9e\x38\xb5\x3f\x80\x90\xc6\x1d\xe7\x96\x0a\x9f\x68\x93\x0b\x7d\x0b\x31\x12\xa1\x1d\x2a\x9c\xbc\x53\x08\x85\x9a\xa2\xcf\x4f\x1e\xc8\x4b\x8f\x6a\x42\x43\xb8\xa8\xb0\xa2\xb5\x7d\x83\x06\x38\x9b\xba\x4b\x85\x29\x24\x11\x11\xdf\x70\xe6\x6c\xfc\xc8\x05\x7b\xe4\xfe\xf2\xe4\x09\xdf\x14\xc3\xe9\x47\x35\x74\x15\x7f\x4b\x1a\x3b\x85\x75\x6a\x3f\x3f\x2f\xa1\xe3\xbb\x3f\xe5\x6c\xea\x06\xb4\xe3\xcd\x38\xf3\xff\xdb\x01\xa7\x19\x51\x7f\x5b\xef\x85\x86\x86\x2f\xdd\x93\xa7\xb5\x1a\xa3\x72\xf0\x5e\xc0\xfc\x37\x00\x00\xff\xff\x66\x05\x16\x0d\x41\x57\x00\x00") func openapiYamlBytes() ([]byte, error) { return bindataRead( @@ -92,7 +92,7 @@ func openapiYaml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "openapi.yaml", size: 19054, mode: os.FileMode(493), modTime: time.Unix(1716477375, 0)} + info := bindataFileInfo{name: "openapi.yaml", size: 22337, mode: os.FileMode(493), modTime: time.Unix(1717126081, 0)} a := &asset{bytes: bytes, info: info} return a, nil } diff --git a/examples/cloudevent-bundle.json b/examples/cloudevent-bundle.json new file mode 100644 index 00000000..54b03d7a --- /dev/null +++ b/examples/cloudevent-bundle.json @@ -0,0 +1,80 @@ +{ + "specversion": "1.0", + "id": "0192bd68-8444-4743-b02b-4a6605ec0413", + "type": "io.open-cluster-management.works.v1alpha1.manifestbundles.spec.create_request", + "source": "grpc", + "clustername": "cluster1", + "resourceid": "68ebf474-6709-48bb-b760-386181268064", + "resourceversion": 1, + "datacontenttype": "application/json", + "data": { + "manifests": [ + { + "apiVersion": "v1", + "kind": "ConfigMap", + "metadata": { + "name": "web", + "namespace": "default" + } + }, + { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "name": "web", + "namespace": "default" + }, + "spec": { + "replicas": 1, + "selector": { + "matchLabels": { + "app": "web" + } + }, + "template": { + "metadata": { + "labels": { + "app": "web" + } + }, + "spec": { + "containers": [ + { + "image": "nginxinc/nginx-unprivileged", + "name": "nginx" + } + ] + } + } + } + } + ], + "deleteOption": { + "propagationPolicy": "Foreground" + }, + "manifestConfigs": [ + { + "resourceIdentifier": { + "group": "apps", + "resource": "deployments", + "namespace": "default", + "name": "web" + }, + "feedbackRules": [ + { + "type": "JSONPaths", + "jsonPaths": [ + { + "name": "status", + "path": ".status" + } + ] + } + ], + "updateStrategy": { + "type": "ServerSideApply" + } + } + ] + } +} \ No newline at end of file diff --git a/examples/grpcclient.go b/examples/grpcclient.go new file mode 100644 index 00000000..99ab720d --- /dev/null +++ b/examples/grpcclient.go @@ -0,0 +1,71 @@ +package main + +import ( + "context" + "encoding/json" + "flag" + "log" + "os" + + cloudevents "github.com/cloudevents/sdk-go/v2" + "github.com/cloudevents/sdk-go/v2/binding" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + pbv1 "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protobuf/v1" + grpcprotocol "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/options/grpc/protocol" +) + +var ( + tls = flag.Bool("tls", false, "Connection uses TLS if true, else plain TCP") + caFile = flag.String("ca_file", "", "The absolute file path containing the CA root cert file") + serverAddr = flag.String("grpc_server", "localhost:8090", "The server address in the format of host:port") + serverHostOverride = flag.String("server_host_override", "x.test.example.com", "The server name used to verify the hostname returned by the TLS handshake") + cloudEventFile = flag.String("cloudevents_json_file", "", "The absolute file path containing the CloudEvent resource") +) + +func main() { + flag.Parse() + var opts []grpc.DialOption + if *tls { + creds, err := credentials.NewClientTLSFromFile(*caFile, *serverHostOverride) + if err != nil { + log.Fatalf("Failed to create TLS credentials: %v", err) + } + opts = append(opts, grpc.WithTransportCredentials(creds)) + } else { + opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials())) + } + + conn, err := grpc.Dial(*serverAddr, opts...) + if err != nil { + log.Fatalf("fail to dial: %v", err) + } + defer conn.Close() + + client := pbv1.NewCloudEventServiceClient(conn) + + cloudeventJSON, err := os.ReadFile(*cloudEventFile) + if err != nil { + log.Fatalf("failed to read cloudevent file: %v", err) + } + + evt := &cloudevents.Event{} + if err := json.Unmarshal(cloudeventJSON, evt); err != nil { + log.Fatalf("failed to unmarshal cloudevent: %v", err) + } + + ctx := context.TODO() + pbEvt := &pbv1.CloudEvent{} + if err = grpcprotocol.WritePBMessage(ctx, binding.ToMessage(evt), pbEvt); err != nil { + log.Fatalf("failed to convert spec from cloudevent to protobuf: %v", err) + } + + if _, err = client.Publish(ctx, &pbv1.PublishRequest{Event: pbEvt}); err != nil { + log.Fatalf("failed to publish: %v", err) + } + + log.Printf("=======================================") + log.Printf("Published spec with cloudevent:\n%v\n\n", evt) + log.Printf("=======================================") +} diff --git a/openapi/openapi.yaml b/openapi/openapi.yaml index 68509b21..1da772aa 100755 --- a/openapi/openapi.yaml +++ b/openapi/openapi.yaml @@ -224,6 +224,80 @@ paths: $ref: '#/components/schemas/Error' parameters: - $ref: '#/components/parameters/id' + /api/maestro/v1/resource-bundles: + get: + summary: Returns a list of resource bundles + security: + - Bearer: [] + responses: + '200': + description: A JSON array of resource bundle objects + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceBundleList' + '401': + description: Auth token is invalid + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Unauthorized to perform operation + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Unexpected error occurred + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + parameters: + - $ref: '#/components/parameters/page' + - $ref: '#/components/parameters/size' + - $ref: '#/components/parameters/search' + - $ref: '#/components/parameters/orderBy' + - $ref: '#/components/parameters/fields' + /api/maestro/v1/resource-bundles/{id}: + get: + summary: Get an resource bundle by id + security: + - Bearer: [] + responses: + '200': + description: Resource bundle found by id + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceBundle' + '401': + description: Auth token is invalid + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '403': + description: Unauthorized to perform operation + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '404': + description: No resource bundle with specified id exists + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + '500': + description: Unexpected error occurred + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + parameters: + - $ref: '#/components/parameters/id' /api/maestro/v1/consumers: get: summary: Returns a list of consumers @@ -535,6 +609,44 @@ components: type: object update_strategy: type: object + ResourceBundleList: + allOf: + - $ref: '#/components/schemas/List' + - type: object + properties: + items: + type: array + items: + $ref: '#/components/schemas/ResourceBundle' + ResourceBundle: + allOf: + - $ref: '#/components/schemas/ObjectReference' + - type: object + properties: + name: + type: string + consumer_name: + type: string + version: + type: integer + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + manifests: + type: array + items: + type: object + delete_option: + type: object + manifest_configs: + type: array + items: + type: object + status: + type: object Consumer: allOf: - $ref: '#/components/schemas/ObjectReference' diff --git a/pkg/api/openapi/.openapi-generator/FILES b/pkg/api/openapi/.openapi-generator/FILES index 81c6717b..e19f8922 100644 --- a/pkg/api/openapi/.openapi-generator/FILES +++ b/pkg/api/openapi/.openapi-generator/FILES @@ -20,6 +20,10 @@ docs/List.md docs/ObjectReference.md docs/Resource.md docs/ResourceAllOf.md +docs/ResourceBundle.md +docs/ResourceBundleAllOf.md +docs/ResourceBundleList.md +docs/ResourceBundleListAllOf.md docs/ResourceList.md docs/ResourceListAllOf.md docs/ResourcePatchRequest.md @@ -39,6 +43,10 @@ model_list.go model_object_reference.go model_resource.go model_resource_all_of.go +model_resource_bundle.go +model_resource_bundle_all_of.go +model_resource_bundle_list.go +model_resource_bundle_list_all_of.go model_resource_list.go model_resource_list_all_of.go model_resource_patch_request.go diff --git a/pkg/api/openapi/README.md b/pkg/api/openapi/README.md index 10bbace4..04e6c4ee 100644 --- a/pkg/api/openapi/README.md +++ b/pkg/api/openapi/README.md @@ -82,6 +82,8 @@ Class | Method | HTTP request | Description *DefaultApi* | [**ApiMaestroV1ConsumersIdGet**](docs/DefaultApi.md#apimaestrov1consumersidget) | **Get** /api/maestro/v1/consumers/{id} | Get an consumer by id *DefaultApi* | [**ApiMaestroV1ConsumersIdPatch**](docs/DefaultApi.md#apimaestrov1consumersidpatch) | **Patch** /api/maestro/v1/consumers/{id} | Update an consumer *DefaultApi* | [**ApiMaestroV1ConsumersPost**](docs/DefaultApi.md#apimaestrov1consumerspost) | **Post** /api/maestro/v1/consumers | Create a new consumer +*DefaultApi* | [**ApiMaestroV1ResourceBundlesGet**](docs/DefaultApi.md#apimaestrov1resourcebundlesget) | **Get** /api/maestro/v1/resource-bundles | Returns a list of resource bundles +*DefaultApi* | [**ApiMaestroV1ResourceBundlesIdGet**](docs/DefaultApi.md#apimaestrov1resourcebundlesidget) | **Get** /api/maestro/v1/resource-bundles/{id} | Get an resource bundle by id *DefaultApi* | [**ApiMaestroV1ResourcesGet**](docs/DefaultApi.md#apimaestrov1resourcesget) | **Get** /api/maestro/v1/resources | Returns a list of resources *DefaultApi* | [**ApiMaestroV1ResourcesIdDelete**](docs/DefaultApi.md#apimaestrov1resourcesiddelete) | **Delete** /api/maestro/v1/resources/{id} | Delete a resource *DefaultApi* | [**ApiMaestroV1ResourcesIdGet**](docs/DefaultApi.md#apimaestrov1resourcesidget) | **Get** /api/maestro/v1/resources/{id} | Get an resource by id @@ -104,6 +106,10 @@ Class | Method | HTTP request | Description - [ObjectReference](docs/ObjectReference.md) - [Resource](docs/Resource.md) - [ResourceAllOf](docs/ResourceAllOf.md) + - [ResourceBundle](docs/ResourceBundle.md) + - [ResourceBundleAllOf](docs/ResourceBundleAllOf.md) + - [ResourceBundleList](docs/ResourceBundleList.md) + - [ResourceBundleListAllOf](docs/ResourceBundleListAllOf.md) - [ResourceList](docs/ResourceList.md) - [ResourceListAllOf](docs/ResourceListAllOf.md) - [ResourcePatchRequest](docs/ResourcePatchRequest.md) diff --git a/pkg/api/openapi/api/openapi.yaml b/pkg/api/openapi/api/openapi.yaml index 903bc260..fa69af04 100644 --- a/pkg/api/openapi/api/openapi.yaml +++ b/pkg/api/openapi/api/openapi.yaml @@ -323,6 +323,161 @@ paths: security: - Bearer: [] summary: Update an resource + /api/maestro/v1/resource-bundles: + get: + parameters: + - description: Page number of record list when record list exceeds specified + page size + explode: true + in: query + name: page + required: false + schema: + default: 1 + minimum: 1 + type: integer + style: form + - description: Maximum number of records to return + explode: true + in: query + name: size + required: false + schema: + default: 100 + minimum: 0 + type: integer + style: form + - description: "Specifies the search criteria. The syntax of this parameter\ + \ is\nsimilar to the syntax of the _where_ clause of an SQL statement,\n\ + using the names of the json attributes / column names of the account. \n\ + For example, in order to retrieve all the accounts with a username\nstarting\ + \ with `my`:\n\n```sql\nusername like 'my%'\n```\n\nThe search criteria\ + \ can also be applied on related resource.\nFor example, in order to retrieve\ + \ all the subscriptions labeled by `foo=bar`,\n\n```sql\nsubscription_labels.key\ + \ = 'foo' and subscription_labels.value = 'bar'\n```\n\nIf the parameter\ + \ isn't provided, or if the value is empty, then\nall the accounts that\ + \ the user has permission to see will be\nreturned." + explode: true + in: query + name: search + required: false + schema: + type: string + style: form + - description: |- + Specifies the order by criteria. The syntax of this parameter is + similar to the syntax of the _order by_ clause of an SQL statement, + but using the names of the json attributes / column of the account. + For example, in order to retrieve all accounts ordered by username: + + ```sql + username asc + ``` + + Or in order to retrieve all accounts ordered by username _and_ first name: + + ```sql + username asc, firstName asc + ``` + + If the parameter isn't provided, or if the value is empty, then + no explicit ordering will be applied. + explode: true + in: query + name: orderBy + required: false + schema: + type: string + style: form + - description: |- + Supplies a comma-separated list of fields to be returned. + Fields of sub-structures and of arrays use . notation. + .* means all field of a structure + Example: For each Subscription to get id, href, plan(id and kind) and labels (all fields) + + ``` + ocm get subscriptions --parameter fields=id,href,plan.id,plan.kind,labels.* --parameter fetchLabels=true + ``` + explode: true + in: query + name: fields + required: false + schema: + type: string + style: form + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceBundleList' + description: A JSON array of resource bundle objects + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Auth token is invalid + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized to perform operation + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unexpected error occurred + security: + - Bearer: [] + summary: Returns a list of resource bundles + /api/maestro/v1/resource-bundles/{id}: + get: + parameters: + - description: The id of record + explode: false + in: path + name: id + required: true + schema: + type: string + style: simple + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/ResourceBundle' + description: Resource bundle found by id + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Auth token is invalid + "403": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized to perform operation + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: No resource bundle with specified id exists + "500": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unexpected error occurred + security: + - Bearer: [] + summary: Get an resource bundle by id /api/maestro/v1/consumers: get: parameters: @@ -788,6 +943,14 @@ components: update_strategy: type: object type: object + ResourceBundleList: + allOf: + - $ref: '#/components/schemas/List' + - $ref: '#/components/schemas/ResourceBundleList_allOf' + ResourceBundle: + allOf: + - $ref: '#/components/schemas/ObjectReference' + - $ref: '#/components/schemas/ResourceBundle_allOf' Consumer: allOf: - $ref: '#/components/schemas/ObjectReference' @@ -856,6 +1019,42 @@ components: type: array type: object example: null + ResourceBundleList_allOf: + properties: + items: + items: + $ref: '#/components/schemas/ResourceBundle' + type: array + type: object + example: null + ResourceBundle_allOf: + properties: + name: + type: string + consumer_name: + type: string + version: + type: integer + created_at: + format: date-time + type: string + updated_at: + format: date-time + type: string + manifests: + items: + type: object + type: array + delete_option: + type: object + manifest_configs: + items: + type: object + type: array + status: + type: object + type: object + example: null Consumer_allOf: properties: name: diff --git a/pkg/api/openapi/api_default.go b/pkg/api/openapi/api_default.go index ed3e1b24..96a74e55 100644 --- a/pkg/api/openapi/api_default.go +++ b/pkg/api/openapi/api_default.go @@ -834,6 +834,331 @@ func (a *DefaultApiService) ApiMaestroV1ConsumersPostExecute(r ApiApiMaestroV1Co return localVarReturnValue, localVarHTTPResponse, nil } +type ApiApiMaestroV1ResourceBundlesGetRequest struct { + ctx context.Context + ApiService *DefaultApiService + page *int32 + size *int32 + search *string + orderBy *string + fields *string +} + +// Page number of record list when record list exceeds specified page size +func (r ApiApiMaestroV1ResourceBundlesGetRequest) Page(page int32) ApiApiMaestroV1ResourceBundlesGetRequest { + r.page = &page + return r +} + +// Maximum number of records to return +func (r ApiApiMaestroV1ResourceBundlesGetRequest) Size(size int32) ApiApiMaestroV1ResourceBundlesGetRequest { + r.size = &size + return r +} + +// Specifies the search criteria. The syntax of this parameter is similar to the syntax of the _where_ clause of an SQL statement, using the names of the json attributes / column names of the account. For example, in order to retrieve all the accounts with a username starting with `my`: ```sql username like 'my%' ``` The search criteria can also be applied on related resource. For example, in order to retrieve all the subscriptions labeled by `foo=bar`, ```sql subscription_labels.key = 'foo' and subscription_labels.value = 'bar' ``` If the parameter isn't provided, or if the value is empty, then all the accounts that the user has permission to see will be returned. +func (r ApiApiMaestroV1ResourceBundlesGetRequest) Search(search string) ApiApiMaestroV1ResourceBundlesGetRequest { + r.search = &search + return r +} + +// Specifies the order by criteria. The syntax of this parameter is similar to the syntax of the _order by_ clause of an SQL statement, but using the names of the json attributes / column of the account. For example, in order to retrieve all accounts ordered by username: ```sql username asc ``` Or in order to retrieve all accounts ordered by username _and_ first name: ```sql username asc, firstName asc ``` If the parameter isn't provided, or if the value is empty, then no explicit ordering will be applied. +func (r ApiApiMaestroV1ResourceBundlesGetRequest) OrderBy(orderBy string) ApiApiMaestroV1ResourceBundlesGetRequest { + r.orderBy = &orderBy + return r +} + +// Supplies a comma-separated list of fields to be returned. Fields of sub-structures and of arrays use <structure>.<field> notation. <stucture>.* means all field of a structure Example: For each Subscription to get id, href, plan(id and kind) and labels (all fields) ``` ocm get subscriptions --parameter fields=id,href,plan.id,plan.kind,labels.* --parameter fetchLabels=true ``` +func (r ApiApiMaestroV1ResourceBundlesGetRequest) Fields(fields string) ApiApiMaestroV1ResourceBundlesGetRequest { + r.fields = &fields + return r +} + +func (r ApiApiMaestroV1ResourceBundlesGetRequest) Execute() (*ResourceBundleList, *http.Response, error) { + return r.ApiService.ApiMaestroV1ResourceBundlesGetExecute(r) +} + +/* +ApiMaestroV1ResourceBundlesGet Returns a list of resource bundles + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiApiMaestroV1ResourceBundlesGetRequest +*/ +func (a *DefaultApiService) ApiMaestroV1ResourceBundlesGet(ctx context.Context) ApiApiMaestroV1ResourceBundlesGetRequest { + return ApiApiMaestroV1ResourceBundlesGetRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return ResourceBundleList +func (a *DefaultApiService) ApiMaestroV1ResourceBundlesGetExecute(r ApiApiMaestroV1ResourceBundlesGetRequest) (*ResourceBundleList, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *ResourceBundleList + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "DefaultApiService.ApiMaestroV1ResourceBundlesGet") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/api/maestro/v1/resource-bundles" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + if r.page != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "page", r.page, "") + } + if r.size != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "size", r.size, "") + } + if r.search != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "search", r.search, "") + } + if r.orderBy != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "orderBy", r.orderBy, "") + } + if r.fields != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "fields", r.fields, "") + } + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 401 { + var v Error + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 403 { + var v Error + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 500 { + var v Error + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiApiMaestroV1ResourceBundlesIdGetRequest struct { + ctx context.Context + ApiService *DefaultApiService + id string +} + +func (r ApiApiMaestroV1ResourceBundlesIdGetRequest) Execute() (*ResourceBundle, *http.Response, error) { + return r.ApiService.ApiMaestroV1ResourceBundlesIdGetExecute(r) +} + +/* +ApiMaestroV1ResourceBundlesIdGet Get an resource bundle by id + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param id The id of record + @return ApiApiMaestroV1ResourceBundlesIdGetRequest +*/ +func (a *DefaultApiService) ApiMaestroV1ResourceBundlesIdGet(ctx context.Context, id string) ApiApiMaestroV1ResourceBundlesIdGetRequest { + return ApiApiMaestroV1ResourceBundlesIdGetRequest{ + ApiService: a, + ctx: ctx, + id: id, + } +} + +// Execute executes the request +// +// @return ResourceBundle +func (a *DefaultApiService) ApiMaestroV1ResourceBundlesIdGetExecute(r ApiApiMaestroV1ResourceBundlesIdGetRequest) (*ResourceBundle, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *ResourceBundle + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "DefaultApiService.ApiMaestroV1ResourceBundlesIdGet") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/api/maestro/v1/resource-bundles/{id}" + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 401 { + var v Error + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 403 { + var v Error + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 404 { + var v Error + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 500 { + var v Error + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + type ApiApiMaestroV1ResourcesGetRequest struct { ctx context.Context ApiService *DefaultApiService diff --git a/pkg/api/openapi/docs/DefaultApi.md b/pkg/api/openapi/docs/DefaultApi.md index f5f27e79..093e9108 100644 --- a/pkg/api/openapi/docs/DefaultApi.md +++ b/pkg/api/openapi/docs/DefaultApi.md @@ -9,6 +9,8 @@ Method | HTTP request | Description [**ApiMaestroV1ConsumersIdGet**](DefaultApi.md#ApiMaestroV1ConsumersIdGet) | **Get** /api/maestro/v1/consumers/{id} | Get an consumer by id [**ApiMaestroV1ConsumersIdPatch**](DefaultApi.md#ApiMaestroV1ConsumersIdPatch) | **Patch** /api/maestro/v1/consumers/{id} | Update an consumer [**ApiMaestroV1ConsumersPost**](DefaultApi.md#ApiMaestroV1ConsumersPost) | **Post** /api/maestro/v1/consumers | Create a new consumer +[**ApiMaestroV1ResourceBundlesGet**](DefaultApi.md#ApiMaestroV1ResourceBundlesGet) | **Get** /api/maestro/v1/resource-bundles | Returns a list of resource bundles +[**ApiMaestroV1ResourceBundlesIdGet**](DefaultApi.md#ApiMaestroV1ResourceBundlesIdGet) | **Get** /api/maestro/v1/resource-bundles/{id} | Get an resource bundle by id [**ApiMaestroV1ResourcesGet**](DefaultApi.md#ApiMaestroV1ResourcesGet) | **Get** /api/maestro/v1/resources | Returns a list of resources [**ApiMaestroV1ResourcesIdDelete**](DefaultApi.md#ApiMaestroV1ResourcesIdDelete) | **Delete** /api/maestro/v1/resources/{id} | Delete a resource [**ApiMaestroV1ResourcesIdGet**](DefaultApi.md#ApiMaestroV1ResourcesIdGet) | **Get** /api/maestro/v1/resources/{id} | Get an resource by id @@ -357,6 +359,146 @@ Name | Type | Description | Notes [[Back to README]](../README.md) +## ApiMaestroV1ResourceBundlesGet + +> ResourceBundleList ApiMaestroV1ResourceBundlesGet(ctx).Page(page).Size(size).Search(search).OrderBy(orderBy).Fields(fields).Execute() + +Returns a list of resource bundles + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID" +) + +func main() { + page := int32(56) // int32 | Page number of record list when record list exceeds specified page size (optional) (default to 1) + size := int32(56) // int32 | Maximum number of records to return (optional) (default to 100) + search := "search_example" // string | Specifies the search criteria. The syntax of this parameter is similar to the syntax of the _where_ clause of an SQL statement, using the names of the json attributes / column names of the account. For example, in order to retrieve all the accounts with a username starting with `my`: ```sql username like 'my%' ``` The search criteria can also be applied on related resource. For example, in order to retrieve all the subscriptions labeled by `foo=bar`, ```sql subscription_labels.key = 'foo' and subscription_labels.value = 'bar' ``` If the parameter isn't provided, or if the value is empty, then all the accounts that the user has permission to see will be returned. (optional) + orderBy := "orderBy_example" // string | Specifies the order by criteria. The syntax of this parameter is similar to the syntax of the _order by_ clause of an SQL statement, but using the names of the json attributes / column of the account. For example, in order to retrieve all accounts ordered by username: ```sql username asc ``` Or in order to retrieve all accounts ordered by username _and_ first name: ```sql username asc, firstName asc ``` If the parameter isn't provided, or if the value is empty, then no explicit ordering will be applied. (optional) + fields := "fields_example" // string | Supplies a comma-separated list of fields to be returned. Fields of sub-structures and of arrays use . notation. .* means all field of a structure Example: For each Subscription to get id, href, plan(id and kind) and labels (all fields) ``` ocm get subscriptions --parameter fields=id,href,plan.id,plan.kind,labels.* --parameter fetchLabels=true ``` (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.DefaultApi.ApiMaestroV1ResourceBundlesGet(context.Background()).Page(page).Size(size).Search(search).OrderBy(orderBy).Fields(fields).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `DefaultApi.ApiMaestroV1ResourceBundlesGet``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `ApiMaestroV1ResourceBundlesGet`: ResourceBundleList + fmt.Fprintf(os.Stdout, "Response from `DefaultApi.ApiMaestroV1ResourceBundlesGet`: %v\n", resp) +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiApiMaestroV1ResourceBundlesGetRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **page** | **int32** | Page number of record list when record list exceeds specified page size | [default to 1] + **size** | **int32** | Maximum number of records to return | [default to 100] + **search** | **string** | Specifies the search criteria. The syntax of this parameter is similar to the syntax of the _where_ clause of an SQL statement, using the names of the json attributes / column names of the account. For example, in order to retrieve all the accounts with a username starting with `my`: ```sql username like 'my%' ``` The search criteria can also be applied on related resource. For example, in order to retrieve all the subscriptions labeled by `foo=bar`, ```sql subscription_labels.key = 'foo' and subscription_labels.value = 'bar' ``` If the parameter isn't provided, or if the value is empty, then all the accounts that the user has permission to see will be returned. | + **orderBy** | **string** | Specifies the order by criteria. The syntax of this parameter is similar to the syntax of the _order by_ clause of an SQL statement, but using the names of the json attributes / column of the account. For example, in order to retrieve all accounts ordered by username: ```sql username asc ``` Or in order to retrieve all accounts ordered by username _and_ first name: ```sql username asc, firstName asc ``` If the parameter isn't provided, or if the value is empty, then no explicit ordering will be applied. | + **fields** | **string** | Supplies a comma-separated list of fields to be returned. Fields of sub-structures and of arrays use <structure>.<field> notation. <stucture>.* means all field of a structure Example: For each Subscription to get id, href, plan(id and kind) and labels (all fields) ``` ocm get subscriptions --parameter fields=id,href,plan.id,plan.kind,labels.* --parameter fetchLabels=true ``` | + +### Return type + +[**ResourceBundleList**](ResourceBundleList.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + +## ApiMaestroV1ResourceBundlesIdGet + +> ResourceBundle ApiMaestroV1ResourceBundlesIdGet(ctx, id).Execute() + +Get an resource bundle by id + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID" +) + +func main() { + id := "id_example" // string | The id of record + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.DefaultApi.ApiMaestroV1ResourceBundlesIdGet(context.Background(), id).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `DefaultApi.ApiMaestroV1ResourceBundlesIdGet``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `ApiMaestroV1ResourceBundlesIdGet`: ResourceBundle + fmt.Fprintf(os.Stdout, "Response from `DefaultApi.ApiMaestroV1ResourceBundlesIdGet`: %v\n", resp) +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**id** | **string** | The id of record | + +### Other Parameters + +Other parameters are passed through a pointer to a apiApiMaestroV1ResourceBundlesIdGetRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + +### Return type + +[**ResourceBundle**](ResourceBundle.md) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + ## ApiMaestroV1ResourcesGet > ResourceList ApiMaestroV1ResourcesGet(ctx).Page(page).Size(size).Search(search).OrderBy(orderBy).Fields(fields).Execute() diff --git a/pkg/api/openapi/docs/ResourceBundle.md b/pkg/api/openapi/docs/ResourceBundle.md new file mode 100644 index 00000000..29ee9474 --- /dev/null +++ b/pkg/api/openapi/docs/ResourceBundle.md @@ -0,0 +1,342 @@ +# ResourceBundle + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Id** | Pointer to **string** | | [optional] +**Kind** | Pointer to **string** | | [optional] +**Href** | Pointer to **string** | | [optional] +**Name** | Pointer to **string** | | [optional] +**ConsumerName** | Pointer to **string** | | [optional] +**Version** | Pointer to **int32** | | [optional] +**CreatedAt** | Pointer to **time.Time** | | [optional] +**UpdatedAt** | Pointer to **time.Time** | | [optional] +**Manifests** | Pointer to **[]map[string]interface{}** | | [optional] +**DeleteOption** | Pointer to **map[string]interface{}** | | [optional] +**ManifestConfigs** | Pointer to **[]map[string]interface{}** | | [optional] +**Status** | Pointer to **map[string]interface{}** | | [optional] + +## Methods + +### NewResourceBundle + +`func NewResourceBundle() *ResourceBundle` + +NewResourceBundle instantiates a new ResourceBundle object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewResourceBundleWithDefaults + +`func NewResourceBundleWithDefaults() *ResourceBundle` + +NewResourceBundleWithDefaults instantiates a new ResourceBundle object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetId + +`func (o *ResourceBundle) GetId() string` + +GetId returns the Id field if non-nil, zero value otherwise. + +### GetIdOk + +`func (o *ResourceBundle) GetIdOk() (*string, bool)` + +GetIdOk returns a tuple with the Id field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetId + +`func (o *ResourceBundle) SetId(v string)` + +SetId sets Id field to given value. + +### HasId + +`func (o *ResourceBundle) HasId() bool` + +HasId returns a boolean if a field has been set. + +### GetKind + +`func (o *ResourceBundle) GetKind() string` + +GetKind returns the Kind field if non-nil, zero value otherwise. + +### GetKindOk + +`func (o *ResourceBundle) GetKindOk() (*string, bool)` + +GetKindOk returns a tuple with the Kind field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetKind + +`func (o *ResourceBundle) SetKind(v string)` + +SetKind sets Kind field to given value. + +### HasKind + +`func (o *ResourceBundle) HasKind() bool` + +HasKind returns a boolean if a field has been set. + +### GetHref + +`func (o *ResourceBundle) GetHref() string` + +GetHref returns the Href field if non-nil, zero value otherwise. + +### GetHrefOk + +`func (o *ResourceBundle) GetHrefOk() (*string, bool)` + +GetHrefOk returns a tuple with the Href field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetHref + +`func (o *ResourceBundle) SetHref(v string)` + +SetHref sets Href field to given value. + +### HasHref + +`func (o *ResourceBundle) HasHref() bool` + +HasHref returns a boolean if a field has been set. + +### GetName + +`func (o *ResourceBundle) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *ResourceBundle) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *ResourceBundle) SetName(v string)` + +SetName sets Name field to given value. + +### HasName + +`func (o *ResourceBundle) HasName() bool` + +HasName returns a boolean if a field has been set. + +### GetConsumerName + +`func (o *ResourceBundle) GetConsumerName() string` + +GetConsumerName returns the ConsumerName field if non-nil, zero value otherwise. + +### GetConsumerNameOk + +`func (o *ResourceBundle) GetConsumerNameOk() (*string, bool)` + +GetConsumerNameOk returns a tuple with the ConsumerName field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetConsumerName + +`func (o *ResourceBundle) SetConsumerName(v string)` + +SetConsumerName sets ConsumerName field to given value. + +### HasConsumerName + +`func (o *ResourceBundle) HasConsumerName() bool` + +HasConsumerName returns a boolean if a field has been set. + +### GetVersion + +`func (o *ResourceBundle) GetVersion() int32` + +GetVersion returns the Version field if non-nil, zero value otherwise. + +### GetVersionOk + +`func (o *ResourceBundle) GetVersionOk() (*int32, bool)` + +GetVersionOk returns a tuple with the Version field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetVersion + +`func (o *ResourceBundle) SetVersion(v int32)` + +SetVersion sets Version field to given value. + +### HasVersion + +`func (o *ResourceBundle) HasVersion() bool` + +HasVersion returns a boolean if a field has been set. + +### GetCreatedAt + +`func (o *ResourceBundle) GetCreatedAt() time.Time` + +GetCreatedAt returns the CreatedAt field if non-nil, zero value otherwise. + +### GetCreatedAtOk + +`func (o *ResourceBundle) GetCreatedAtOk() (*time.Time, bool)` + +GetCreatedAtOk returns a tuple with the CreatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCreatedAt + +`func (o *ResourceBundle) SetCreatedAt(v time.Time)` + +SetCreatedAt sets CreatedAt field to given value. + +### HasCreatedAt + +`func (o *ResourceBundle) HasCreatedAt() bool` + +HasCreatedAt returns a boolean if a field has been set. + +### GetUpdatedAt + +`func (o *ResourceBundle) GetUpdatedAt() time.Time` + +GetUpdatedAt returns the UpdatedAt field if non-nil, zero value otherwise. + +### GetUpdatedAtOk + +`func (o *ResourceBundle) GetUpdatedAtOk() (*time.Time, bool)` + +GetUpdatedAtOk returns a tuple with the UpdatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUpdatedAt + +`func (o *ResourceBundle) SetUpdatedAt(v time.Time)` + +SetUpdatedAt sets UpdatedAt field to given value. + +### HasUpdatedAt + +`func (o *ResourceBundle) HasUpdatedAt() bool` + +HasUpdatedAt returns a boolean if a field has been set. + +### GetManifests + +`func (o *ResourceBundle) GetManifests() []map[string]interface{}` + +GetManifests returns the Manifests field if non-nil, zero value otherwise. + +### GetManifestsOk + +`func (o *ResourceBundle) GetManifestsOk() (*[]map[string]interface{}, bool)` + +GetManifestsOk returns a tuple with the Manifests field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetManifests + +`func (o *ResourceBundle) SetManifests(v []map[string]interface{})` + +SetManifests sets Manifests field to given value. + +### HasManifests + +`func (o *ResourceBundle) HasManifests() bool` + +HasManifests returns a boolean if a field has been set. + +### GetDeleteOption + +`func (o *ResourceBundle) GetDeleteOption() map[string]interface{}` + +GetDeleteOption returns the DeleteOption field if non-nil, zero value otherwise. + +### GetDeleteOptionOk + +`func (o *ResourceBundle) GetDeleteOptionOk() (*map[string]interface{}, bool)` + +GetDeleteOptionOk returns a tuple with the DeleteOption field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetDeleteOption + +`func (o *ResourceBundle) SetDeleteOption(v map[string]interface{})` + +SetDeleteOption sets DeleteOption field to given value. + +### HasDeleteOption + +`func (o *ResourceBundle) HasDeleteOption() bool` + +HasDeleteOption returns a boolean if a field has been set. + +### GetManifestConfigs + +`func (o *ResourceBundle) GetManifestConfigs() []map[string]interface{}` + +GetManifestConfigs returns the ManifestConfigs field if non-nil, zero value otherwise. + +### GetManifestConfigsOk + +`func (o *ResourceBundle) GetManifestConfigsOk() (*[]map[string]interface{}, bool)` + +GetManifestConfigsOk returns a tuple with the ManifestConfigs field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetManifestConfigs + +`func (o *ResourceBundle) SetManifestConfigs(v []map[string]interface{})` + +SetManifestConfigs sets ManifestConfigs field to given value. + +### HasManifestConfigs + +`func (o *ResourceBundle) HasManifestConfigs() bool` + +HasManifestConfigs returns a boolean if a field has been set. + +### GetStatus + +`func (o *ResourceBundle) GetStatus() map[string]interface{}` + +GetStatus returns the Status field if non-nil, zero value otherwise. + +### GetStatusOk + +`func (o *ResourceBundle) GetStatusOk() (*map[string]interface{}, bool)` + +GetStatusOk returns a tuple with the Status field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetStatus + +`func (o *ResourceBundle) SetStatus(v map[string]interface{})` + +SetStatus sets Status field to given value. + +### HasStatus + +`func (o *ResourceBundle) HasStatus() bool` + +HasStatus returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/api/openapi/docs/ResourceBundleAllOf.md b/pkg/api/openapi/docs/ResourceBundleAllOf.md new file mode 100644 index 00000000..127f8b4c --- /dev/null +++ b/pkg/api/openapi/docs/ResourceBundleAllOf.md @@ -0,0 +1,264 @@ +# ResourceBundleAllOf + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Name** | Pointer to **string** | | [optional] +**ConsumerName** | Pointer to **string** | | [optional] +**Version** | Pointer to **int32** | | [optional] +**CreatedAt** | Pointer to **time.Time** | | [optional] +**UpdatedAt** | Pointer to **time.Time** | | [optional] +**Manifests** | Pointer to **[]map[string]interface{}** | | [optional] +**DeleteOption** | Pointer to **map[string]interface{}** | | [optional] +**ManifestConfigs** | Pointer to **[]map[string]interface{}** | | [optional] +**Status** | Pointer to **map[string]interface{}** | | [optional] + +## Methods + +### NewResourceBundleAllOf + +`func NewResourceBundleAllOf() *ResourceBundleAllOf` + +NewResourceBundleAllOf instantiates a new ResourceBundleAllOf object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewResourceBundleAllOfWithDefaults + +`func NewResourceBundleAllOfWithDefaults() *ResourceBundleAllOf` + +NewResourceBundleAllOfWithDefaults instantiates a new ResourceBundleAllOf object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetName + +`func (o *ResourceBundleAllOf) GetName() string` + +GetName returns the Name field if non-nil, zero value otherwise. + +### GetNameOk + +`func (o *ResourceBundleAllOf) GetNameOk() (*string, bool)` + +GetNameOk returns a tuple with the Name field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetName + +`func (o *ResourceBundleAllOf) SetName(v string)` + +SetName sets Name field to given value. + +### HasName + +`func (o *ResourceBundleAllOf) HasName() bool` + +HasName returns a boolean if a field has been set. + +### GetConsumerName + +`func (o *ResourceBundleAllOf) GetConsumerName() string` + +GetConsumerName returns the ConsumerName field if non-nil, zero value otherwise. + +### GetConsumerNameOk + +`func (o *ResourceBundleAllOf) GetConsumerNameOk() (*string, bool)` + +GetConsumerNameOk returns a tuple with the ConsumerName field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetConsumerName + +`func (o *ResourceBundleAllOf) SetConsumerName(v string)` + +SetConsumerName sets ConsumerName field to given value. + +### HasConsumerName + +`func (o *ResourceBundleAllOf) HasConsumerName() bool` + +HasConsumerName returns a boolean if a field has been set. + +### GetVersion + +`func (o *ResourceBundleAllOf) GetVersion() int32` + +GetVersion returns the Version field if non-nil, zero value otherwise. + +### GetVersionOk + +`func (o *ResourceBundleAllOf) GetVersionOk() (*int32, bool)` + +GetVersionOk returns a tuple with the Version field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetVersion + +`func (o *ResourceBundleAllOf) SetVersion(v int32)` + +SetVersion sets Version field to given value. + +### HasVersion + +`func (o *ResourceBundleAllOf) HasVersion() bool` + +HasVersion returns a boolean if a field has been set. + +### GetCreatedAt + +`func (o *ResourceBundleAllOf) GetCreatedAt() time.Time` + +GetCreatedAt returns the CreatedAt field if non-nil, zero value otherwise. + +### GetCreatedAtOk + +`func (o *ResourceBundleAllOf) GetCreatedAtOk() (*time.Time, bool)` + +GetCreatedAtOk returns a tuple with the CreatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCreatedAt + +`func (o *ResourceBundleAllOf) SetCreatedAt(v time.Time)` + +SetCreatedAt sets CreatedAt field to given value. + +### HasCreatedAt + +`func (o *ResourceBundleAllOf) HasCreatedAt() bool` + +HasCreatedAt returns a boolean if a field has been set. + +### GetUpdatedAt + +`func (o *ResourceBundleAllOf) GetUpdatedAt() time.Time` + +GetUpdatedAt returns the UpdatedAt field if non-nil, zero value otherwise. + +### GetUpdatedAtOk + +`func (o *ResourceBundleAllOf) GetUpdatedAtOk() (*time.Time, bool)` + +GetUpdatedAtOk returns a tuple with the UpdatedAt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetUpdatedAt + +`func (o *ResourceBundleAllOf) SetUpdatedAt(v time.Time)` + +SetUpdatedAt sets UpdatedAt field to given value. + +### HasUpdatedAt + +`func (o *ResourceBundleAllOf) HasUpdatedAt() bool` + +HasUpdatedAt returns a boolean if a field has been set. + +### GetManifests + +`func (o *ResourceBundleAllOf) GetManifests() []map[string]interface{}` + +GetManifests returns the Manifests field if non-nil, zero value otherwise. + +### GetManifestsOk + +`func (o *ResourceBundleAllOf) GetManifestsOk() (*[]map[string]interface{}, bool)` + +GetManifestsOk returns a tuple with the Manifests field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetManifests + +`func (o *ResourceBundleAllOf) SetManifests(v []map[string]interface{})` + +SetManifests sets Manifests field to given value. + +### HasManifests + +`func (o *ResourceBundleAllOf) HasManifests() bool` + +HasManifests returns a boolean if a field has been set. + +### GetDeleteOption + +`func (o *ResourceBundleAllOf) GetDeleteOption() map[string]interface{}` + +GetDeleteOption returns the DeleteOption field if non-nil, zero value otherwise. + +### GetDeleteOptionOk + +`func (o *ResourceBundleAllOf) GetDeleteOptionOk() (*map[string]interface{}, bool)` + +GetDeleteOptionOk returns a tuple with the DeleteOption field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetDeleteOption + +`func (o *ResourceBundleAllOf) SetDeleteOption(v map[string]interface{})` + +SetDeleteOption sets DeleteOption field to given value. + +### HasDeleteOption + +`func (o *ResourceBundleAllOf) HasDeleteOption() bool` + +HasDeleteOption returns a boolean if a field has been set. + +### GetManifestConfigs + +`func (o *ResourceBundleAllOf) GetManifestConfigs() []map[string]interface{}` + +GetManifestConfigs returns the ManifestConfigs field if non-nil, zero value otherwise. + +### GetManifestConfigsOk + +`func (o *ResourceBundleAllOf) GetManifestConfigsOk() (*[]map[string]interface{}, bool)` + +GetManifestConfigsOk returns a tuple with the ManifestConfigs field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetManifestConfigs + +`func (o *ResourceBundleAllOf) SetManifestConfigs(v []map[string]interface{})` + +SetManifestConfigs sets ManifestConfigs field to given value. + +### HasManifestConfigs + +`func (o *ResourceBundleAllOf) HasManifestConfigs() bool` + +HasManifestConfigs returns a boolean if a field has been set. + +### GetStatus + +`func (o *ResourceBundleAllOf) GetStatus() map[string]interface{}` + +GetStatus returns the Status field if non-nil, zero value otherwise. + +### GetStatusOk + +`func (o *ResourceBundleAllOf) GetStatusOk() (*map[string]interface{}, bool)` + +GetStatusOk returns a tuple with the Status field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetStatus + +`func (o *ResourceBundleAllOf) SetStatus(v map[string]interface{})` + +SetStatus sets Status field to given value. + +### HasStatus + +`func (o *ResourceBundleAllOf) HasStatus() bool` + +HasStatus returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/api/openapi/docs/ResourceBundleList.md b/pkg/api/openapi/docs/ResourceBundleList.md new file mode 100644 index 00000000..9163ce34 --- /dev/null +++ b/pkg/api/openapi/docs/ResourceBundleList.md @@ -0,0 +1,135 @@ +# ResourceBundleList + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Kind** | **string** | | +**Page** | **int32** | | +**Size** | **int32** | | +**Total** | **int32** | | +**Items** | [**[]ResourceBundle**](ResourceBundle.md) | | + +## Methods + +### NewResourceBundleList + +`func NewResourceBundleList(kind string, page int32, size int32, total int32, items []ResourceBundle, ) *ResourceBundleList` + +NewResourceBundleList instantiates a new ResourceBundleList object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewResourceBundleListWithDefaults + +`func NewResourceBundleListWithDefaults() *ResourceBundleList` + +NewResourceBundleListWithDefaults instantiates a new ResourceBundleList object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetKind + +`func (o *ResourceBundleList) GetKind() string` + +GetKind returns the Kind field if non-nil, zero value otherwise. + +### GetKindOk + +`func (o *ResourceBundleList) GetKindOk() (*string, bool)` + +GetKindOk returns a tuple with the Kind field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetKind + +`func (o *ResourceBundleList) SetKind(v string)` + +SetKind sets Kind field to given value. + + +### GetPage + +`func (o *ResourceBundleList) GetPage() int32` + +GetPage returns the Page field if non-nil, zero value otherwise. + +### GetPageOk + +`func (o *ResourceBundleList) GetPageOk() (*int32, bool)` + +GetPageOk returns a tuple with the Page field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetPage + +`func (o *ResourceBundleList) SetPage(v int32)` + +SetPage sets Page field to given value. + + +### GetSize + +`func (o *ResourceBundleList) GetSize() int32` + +GetSize returns the Size field if non-nil, zero value otherwise. + +### GetSizeOk + +`func (o *ResourceBundleList) GetSizeOk() (*int32, bool)` + +GetSizeOk returns a tuple with the Size field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetSize + +`func (o *ResourceBundleList) SetSize(v int32)` + +SetSize sets Size field to given value. + + +### GetTotal + +`func (o *ResourceBundleList) GetTotal() int32` + +GetTotal returns the Total field if non-nil, zero value otherwise. + +### GetTotalOk + +`func (o *ResourceBundleList) GetTotalOk() (*int32, bool)` + +GetTotalOk returns a tuple with the Total field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTotal + +`func (o *ResourceBundleList) SetTotal(v int32)` + +SetTotal sets Total field to given value. + + +### GetItems + +`func (o *ResourceBundleList) GetItems() []ResourceBundle` + +GetItems returns the Items field if non-nil, zero value otherwise. + +### GetItemsOk + +`func (o *ResourceBundleList) GetItemsOk() (*[]ResourceBundle, bool)` + +GetItemsOk returns a tuple with the Items field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetItems + +`func (o *ResourceBundleList) SetItems(v []ResourceBundle)` + +SetItems sets Items field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/api/openapi/docs/ResourceBundleListAllOf.md b/pkg/api/openapi/docs/ResourceBundleListAllOf.md new file mode 100644 index 00000000..0e4f556e --- /dev/null +++ b/pkg/api/openapi/docs/ResourceBundleListAllOf.md @@ -0,0 +1,56 @@ +# ResourceBundleListAllOf + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Items** | Pointer to [**[]ResourceBundle**](ResourceBundle.md) | | [optional] + +## Methods + +### NewResourceBundleListAllOf + +`func NewResourceBundleListAllOf() *ResourceBundleListAllOf` + +NewResourceBundleListAllOf instantiates a new ResourceBundleListAllOf object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewResourceBundleListAllOfWithDefaults + +`func NewResourceBundleListAllOfWithDefaults() *ResourceBundleListAllOf` + +NewResourceBundleListAllOfWithDefaults instantiates a new ResourceBundleListAllOf object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetItems + +`func (o *ResourceBundleListAllOf) GetItems() []ResourceBundle` + +GetItems returns the Items field if non-nil, zero value otherwise. + +### GetItemsOk + +`func (o *ResourceBundleListAllOf) GetItemsOk() (*[]ResourceBundle, bool)` + +GetItemsOk returns a tuple with the Items field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetItems + +`func (o *ResourceBundleListAllOf) SetItems(v []ResourceBundle)` + +SetItems sets Items field to given value. + +### HasItems + +`func (o *ResourceBundleListAllOf) HasItems() bool` + +HasItems returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/api/openapi/model_resource_bundle.go b/pkg/api/openapi/model_resource_bundle.go new file mode 100644 index 00000000..e363b5c5 --- /dev/null +++ b/pkg/api/openapi/model_resource_bundle.go @@ -0,0 +1,521 @@ +/* +maestro Service API + +maestro Service API + +API version: 0.0.1 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" + "time" +) + +// checks if the ResourceBundle type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &ResourceBundle{} + +// ResourceBundle struct for ResourceBundle +type ResourceBundle struct { + Id *string `json:"id,omitempty"` + Kind *string `json:"kind,omitempty"` + Href *string `json:"href,omitempty"` + Name *string `json:"name,omitempty"` + ConsumerName *string `json:"consumer_name,omitempty"` + Version *int32 `json:"version,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` + Manifests []map[string]interface{} `json:"manifests,omitempty"` + DeleteOption map[string]interface{} `json:"delete_option,omitempty"` + ManifestConfigs []map[string]interface{} `json:"manifest_configs,omitempty"` + Status map[string]interface{} `json:"status,omitempty"` +} + +// NewResourceBundle instantiates a new ResourceBundle object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewResourceBundle() *ResourceBundle { + this := ResourceBundle{} + return &this +} + +// NewResourceBundleWithDefaults instantiates a new ResourceBundle object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewResourceBundleWithDefaults() *ResourceBundle { + this := ResourceBundle{} + return &this +} + +// GetId returns the Id field value if set, zero value otherwise. +func (o *ResourceBundle) GetId() string { + if o == nil || IsNil(o.Id) { + var ret string + return ret + } + return *o.Id +} + +// GetIdOk returns a tuple with the Id field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundle) GetIdOk() (*string, bool) { + if o == nil || IsNil(o.Id) { + return nil, false + } + return o.Id, true +} + +// HasId returns a boolean if a field has been set. +func (o *ResourceBundle) HasId() bool { + if o != nil && !IsNil(o.Id) { + return true + } + + return false +} + +// SetId gets a reference to the given string and assigns it to the Id field. +func (o *ResourceBundle) SetId(v string) { + o.Id = &v +} + +// GetKind returns the Kind field value if set, zero value otherwise. +func (o *ResourceBundle) GetKind() string { + if o == nil || IsNil(o.Kind) { + var ret string + return ret + } + return *o.Kind +} + +// GetKindOk returns a tuple with the Kind field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundle) GetKindOk() (*string, bool) { + if o == nil || IsNil(o.Kind) { + return nil, false + } + return o.Kind, true +} + +// HasKind returns a boolean if a field has been set. +func (o *ResourceBundle) HasKind() bool { + if o != nil && !IsNil(o.Kind) { + return true + } + + return false +} + +// SetKind gets a reference to the given string and assigns it to the Kind field. +func (o *ResourceBundle) SetKind(v string) { + o.Kind = &v +} + +// GetHref returns the Href field value if set, zero value otherwise. +func (o *ResourceBundle) GetHref() string { + if o == nil || IsNil(o.Href) { + var ret string + return ret + } + return *o.Href +} + +// GetHrefOk returns a tuple with the Href field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundle) GetHrefOk() (*string, bool) { + if o == nil || IsNil(o.Href) { + return nil, false + } + return o.Href, true +} + +// HasHref returns a boolean if a field has been set. +func (o *ResourceBundle) HasHref() bool { + if o != nil && !IsNil(o.Href) { + return true + } + + return false +} + +// SetHref gets a reference to the given string and assigns it to the Href field. +func (o *ResourceBundle) SetHref(v string) { + o.Href = &v +} + +// GetName returns the Name field value if set, zero value otherwise. +func (o *ResourceBundle) GetName() string { + if o == nil || IsNil(o.Name) { + var ret string + return ret + } + return *o.Name +} + +// GetNameOk returns a tuple with the Name field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundle) GetNameOk() (*string, bool) { + if o == nil || IsNil(o.Name) { + return nil, false + } + return o.Name, true +} + +// HasName returns a boolean if a field has been set. +func (o *ResourceBundle) HasName() bool { + if o != nil && !IsNil(o.Name) { + return true + } + + return false +} + +// SetName gets a reference to the given string and assigns it to the Name field. +func (o *ResourceBundle) SetName(v string) { + o.Name = &v +} + +// GetConsumerName returns the ConsumerName field value if set, zero value otherwise. +func (o *ResourceBundle) GetConsumerName() string { + if o == nil || IsNil(o.ConsumerName) { + var ret string + return ret + } + return *o.ConsumerName +} + +// GetConsumerNameOk returns a tuple with the ConsumerName field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundle) GetConsumerNameOk() (*string, bool) { + if o == nil || IsNil(o.ConsumerName) { + return nil, false + } + return o.ConsumerName, true +} + +// HasConsumerName returns a boolean if a field has been set. +func (o *ResourceBundle) HasConsumerName() bool { + if o != nil && !IsNil(o.ConsumerName) { + return true + } + + return false +} + +// SetConsumerName gets a reference to the given string and assigns it to the ConsumerName field. +func (o *ResourceBundle) SetConsumerName(v string) { + o.ConsumerName = &v +} + +// GetVersion returns the Version field value if set, zero value otherwise. +func (o *ResourceBundle) GetVersion() int32 { + if o == nil || IsNil(o.Version) { + var ret int32 + return ret + } + return *o.Version +} + +// GetVersionOk returns a tuple with the Version field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundle) GetVersionOk() (*int32, bool) { + if o == nil || IsNil(o.Version) { + return nil, false + } + return o.Version, true +} + +// HasVersion returns a boolean if a field has been set. +func (o *ResourceBundle) HasVersion() bool { + if o != nil && !IsNil(o.Version) { + return true + } + + return false +} + +// SetVersion gets a reference to the given int32 and assigns it to the Version field. +func (o *ResourceBundle) SetVersion(v int32) { + o.Version = &v +} + +// GetCreatedAt returns the CreatedAt field value if set, zero value otherwise. +func (o *ResourceBundle) GetCreatedAt() time.Time { + if o == nil || IsNil(o.CreatedAt) { + var ret time.Time + return ret + } + return *o.CreatedAt +} + +// GetCreatedAtOk returns a tuple with the CreatedAt field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundle) GetCreatedAtOk() (*time.Time, bool) { + if o == nil || IsNil(o.CreatedAt) { + return nil, false + } + return o.CreatedAt, true +} + +// HasCreatedAt returns a boolean if a field has been set. +func (o *ResourceBundle) HasCreatedAt() bool { + if o != nil && !IsNil(o.CreatedAt) { + return true + } + + return false +} + +// SetCreatedAt gets a reference to the given time.Time and assigns it to the CreatedAt field. +func (o *ResourceBundle) SetCreatedAt(v time.Time) { + o.CreatedAt = &v +} + +// GetUpdatedAt returns the UpdatedAt field value if set, zero value otherwise. +func (o *ResourceBundle) GetUpdatedAt() time.Time { + if o == nil || IsNil(o.UpdatedAt) { + var ret time.Time + return ret + } + return *o.UpdatedAt +} + +// GetUpdatedAtOk returns a tuple with the UpdatedAt field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundle) GetUpdatedAtOk() (*time.Time, bool) { + if o == nil || IsNil(o.UpdatedAt) { + return nil, false + } + return o.UpdatedAt, true +} + +// HasUpdatedAt returns a boolean if a field has been set. +func (o *ResourceBundle) HasUpdatedAt() bool { + if o != nil && !IsNil(o.UpdatedAt) { + return true + } + + return false +} + +// SetUpdatedAt gets a reference to the given time.Time and assigns it to the UpdatedAt field. +func (o *ResourceBundle) SetUpdatedAt(v time.Time) { + o.UpdatedAt = &v +} + +// GetManifests returns the Manifests field value if set, zero value otherwise. +func (o *ResourceBundle) GetManifests() []map[string]interface{} { + if o == nil || IsNil(o.Manifests) { + var ret []map[string]interface{} + return ret + } + return o.Manifests +} + +// GetManifestsOk returns a tuple with the Manifests field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundle) GetManifestsOk() ([]map[string]interface{}, bool) { + if o == nil || IsNil(o.Manifests) { + return nil, false + } + return o.Manifests, true +} + +// HasManifests returns a boolean if a field has been set. +func (o *ResourceBundle) HasManifests() bool { + if o != nil && !IsNil(o.Manifests) { + return true + } + + return false +} + +// SetManifests gets a reference to the given []map[string]interface{} and assigns it to the Manifests field. +func (o *ResourceBundle) SetManifests(v []map[string]interface{}) { + o.Manifests = v +} + +// GetDeleteOption returns the DeleteOption field value if set, zero value otherwise. +func (o *ResourceBundle) GetDeleteOption() map[string]interface{} { + if o == nil || IsNil(o.DeleteOption) { + var ret map[string]interface{} + return ret + } + return o.DeleteOption +} + +// GetDeleteOptionOk returns a tuple with the DeleteOption field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundle) GetDeleteOptionOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.DeleteOption) { + return map[string]interface{}{}, false + } + return o.DeleteOption, true +} + +// HasDeleteOption returns a boolean if a field has been set. +func (o *ResourceBundle) HasDeleteOption() bool { + if o != nil && !IsNil(o.DeleteOption) { + return true + } + + return false +} + +// SetDeleteOption gets a reference to the given map[string]interface{} and assigns it to the DeleteOption field. +func (o *ResourceBundle) SetDeleteOption(v map[string]interface{}) { + o.DeleteOption = v +} + +// GetManifestConfigs returns the ManifestConfigs field value if set, zero value otherwise. +func (o *ResourceBundle) GetManifestConfigs() []map[string]interface{} { + if o == nil || IsNil(o.ManifestConfigs) { + var ret []map[string]interface{} + return ret + } + return o.ManifestConfigs +} + +// GetManifestConfigsOk returns a tuple with the ManifestConfigs field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundle) GetManifestConfigsOk() ([]map[string]interface{}, bool) { + if o == nil || IsNil(o.ManifestConfigs) { + return nil, false + } + return o.ManifestConfigs, true +} + +// HasManifestConfigs returns a boolean if a field has been set. +func (o *ResourceBundle) HasManifestConfigs() bool { + if o != nil && !IsNil(o.ManifestConfigs) { + return true + } + + return false +} + +// SetManifestConfigs gets a reference to the given []map[string]interface{} and assigns it to the ManifestConfigs field. +func (o *ResourceBundle) SetManifestConfigs(v []map[string]interface{}) { + o.ManifestConfigs = v +} + +// GetStatus returns the Status field value if set, zero value otherwise. +func (o *ResourceBundle) GetStatus() map[string]interface{} { + if o == nil || IsNil(o.Status) { + var ret map[string]interface{} + return ret + } + return o.Status +} + +// GetStatusOk returns a tuple with the Status field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundle) GetStatusOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.Status) { + return map[string]interface{}{}, false + } + return o.Status, true +} + +// HasStatus returns a boolean if a field has been set. +func (o *ResourceBundle) HasStatus() bool { + if o != nil && !IsNil(o.Status) { + return true + } + + return false +} + +// SetStatus gets a reference to the given map[string]interface{} and assigns it to the Status field. +func (o *ResourceBundle) SetStatus(v map[string]interface{}) { + o.Status = v +} + +func (o ResourceBundle) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o ResourceBundle) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.Id) { + toSerialize["id"] = o.Id + } + if !IsNil(o.Kind) { + toSerialize["kind"] = o.Kind + } + if !IsNil(o.Href) { + toSerialize["href"] = o.Href + } + if !IsNil(o.Name) { + toSerialize["name"] = o.Name + } + if !IsNil(o.ConsumerName) { + toSerialize["consumer_name"] = o.ConsumerName + } + if !IsNil(o.Version) { + toSerialize["version"] = o.Version + } + if !IsNil(o.CreatedAt) { + toSerialize["created_at"] = o.CreatedAt + } + if !IsNil(o.UpdatedAt) { + toSerialize["updated_at"] = o.UpdatedAt + } + if !IsNil(o.Manifests) { + toSerialize["manifests"] = o.Manifests + } + if !IsNil(o.DeleteOption) { + toSerialize["delete_option"] = o.DeleteOption + } + if !IsNil(o.ManifestConfigs) { + toSerialize["manifest_configs"] = o.ManifestConfigs + } + if !IsNil(o.Status) { + toSerialize["status"] = o.Status + } + return toSerialize, nil +} + +type NullableResourceBundle struct { + value *ResourceBundle + isSet bool +} + +func (v NullableResourceBundle) Get() *ResourceBundle { + return v.value +} + +func (v *NullableResourceBundle) Set(val *ResourceBundle) { + v.value = val + v.isSet = true +} + +func (v NullableResourceBundle) IsSet() bool { + return v.isSet +} + +func (v *NullableResourceBundle) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableResourceBundle(val *ResourceBundle) *NullableResourceBundle { + return &NullableResourceBundle{value: val, isSet: true} +} + +func (v NullableResourceBundle) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableResourceBundle) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/api/openapi/model_resource_bundle_all_of.go b/pkg/api/openapi/model_resource_bundle_all_of.go new file mode 100644 index 00000000..88fc764a --- /dev/null +++ b/pkg/api/openapi/model_resource_bundle_all_of.go @@ -0,0 +1,413 @@ +/* +maestro Service API + +maestro Service API + +API version: 0.0.1 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" + "time" +) + +// checks if the ResourceBundleAllOf type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &ResourceBundleAllOf{} + +// ResourceBundleAllOf struct for ResourceBundleAllOf +type ResourceBundleAllOf struct { + Name *string `json:"name,omitempty"` + ConsumerName *string `json:"consumer_name,omitempty"` + Version *int32 `json:"version,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` + Manifests []map[string]interface{} `json:"manifests,omitempty"` + DeleteOption map[string]interface{} `json:"delete_option,omitempty"` + ManifestConfigs []map[string]interface{} `json:"manifest_configs,omitempty"` + Status map[string]interface{} `json:"status,omitempty"` +} + +// NewResourceBundleAllOf instantiates a new ResourceBundleAllOf object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewResourceBundleAllOf() *ResourceBundleAllOf { + this := ResourceBundleAllOf{} + return &this +} + +// NewResourceBundleAllOfWithDefaults instantiates a new ResourceBundleAllOf object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewResourceBundleAllOfWithDefaults() *ResourceBundleAllOf { + this := ResourceBundleAllOf{} + return &this +} + +// GetName returns the Name field value if set, zero value otherwise. +func (o *ResourceBundleAllOf) GetName() string { + if o == nil || IsNil(o.Name) { + var ret string + return ret + } + return *o.Name +} + +// GetNameOk returns a tuple with the Name field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundleAllOf) GetNameOk() (*string, bool) { + if o == nil || IsNil(o.Name) { + return nil, false + } + return o.Name, true +} + +// HasName returns a boolean if a field has been set. +func (o *ResourceBundleAllOf) HasName() bool { + if o != nil && !IsNil(o.Name) { + return true + } + + return false +} + +// SetName gets a reference to the given string and assigns it to the Name field. +func (o *ResourceBundleAllOf) SetName(v string) { + o.Name = &v +} + +// GetConsumerName returns the ConsumerName field value if set, zero value otherwise. +func (o *ResourceBundleAllOf) GetConsumerName() string { + if o == nil || IsNil(o.ConsumerName) { + var ret string + return ret + } + return *o.ConsumerName +} + +// GetConsumerNameOk returns a tuple with the ConsumerName field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundleAllOf) GetConsumerNameOk() (*string, bool) { + if o == nil || IsNil(o.ConsumerName) { + return nil, false + } + return o.ConsumerName, true +} + +// HasConsumerName returns a boolean if a field has been set. +func (o *ResourceBundleAllOf) HasConsumerName() bool { + if o != nil && !IsNil(o.ConsumerName) { + return true + } + + return false +} + +// SetConsumerName gets a reference to the given string and assigns it to the ConsumerName field. +func (o *ResourceBundleAllOf) SetConsumerName(v string) { + o.ConsumerName = &v +} + +// GetVersion returns the Version field value if set, zero value otherwise. +func (o *ResourceBundleAllOf) GetVersion() int32 { + if o == nil || IsNil(o.Version) { + var ret int32 + return ret + } + return *o.Version +} + +// GetVersionOk returns a tuple with the Version field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundleAllOf) GetVersionOk() (*int32, bool) { + if o == nil || IsNil(o.Version) { + return nil, false + } + return o.Version, true +} + +// HasVersion returns a boolean if a field has been set. +func (o *ResourceBundleAllOf) HasVersion() bool { + if o != nil && !IsNil(o.Version) { + return true + } + + return false +} + +// SetVersion gets a reference to the given int32 and assigns it to the Version field. +func (o *ResourceBundleAllOf) SetVersion(v int32) { + o.Version = &v +} + +// GetCreatedAt returns the CreatedAt field value if set, zero value otherwise. +func (o *ResourceBundleAllOf) GetCreatedAt() time.Time { + if o == nil || IsNil(o.CreatedAt) { + var ret time.Time + return ret + } + return *o.CreatedAt +} + +// GetCreatedAtOk returns a tuple with the CreatedAt field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundleAllOf) GetCreatedAtOk() (*time.Time, bool) { + if o == nil || IsNil(o.CreatedAt) { + return nil, false + } + return o.CreatedAt, true +} + +// HasCreatedAt returns a boolean if a field has been set. +func (o *ResourceBundleAllOf) HasCreatedAt() bool { + if o != nil && !IsNil(o.CreatedAt) { + return true + } + + return false +} + +// SetCreatedAt gets a reference to the given time.Time and assigns it to the CreatedAt field. +func (o *ResourceBundleAllOf) SetCreatedAt(v time.Time) { + o.CreatedAt = &v +} + +// GetUpdatedAt returns the UpdatedAt field value if set, zero value otherwise. +func (o *ResourceBundleAllOf) GetUpdatedAt() time.Time { + if o == nil || IsNil(o.UpdatedAt) { + var ret time.Time + return ret + } + return *o.UpdatedAt +} + +// GetUpdatedAtOk returns a tuple with the UpdatedAt field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundleAllOf) GetUpdatedAtOk() (*time.Time, bool) { + if o == nil || IsNil(o.UpdatedAt) { + return nil, false + } + return o.UpdatedAt, true +} + +// HasUpdatedAt returns a boolean if a field has been set. +func (o *ResourceBundleAllOf) HasUpdatedAt() bool { + if o != nil && !IsNil(o.UpdatedAt) { + return true + } + + return false +} + +// SetUpdatedAt gets a reference to the given time.Time and assigns it to the UpdatedAt field. +func (o *ResourceBundleAllOf) SetUpdatedAt(v time.Time) { + o.UpdatedAt = &v +} + +// GetManifests returns the Manifests field value if set, zero value otherwise. +func (o *ResourceBundleAllOf) GetManifests() []map[string]interface{} { + if o == nil || IsNil(o.Manifests) { + var ret []map[string]interface{} + return ret + } + return o.Manifests +} + +// GetManifestsOk returns a tuple with the Manifests field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundleAllOf) GetManifestsOk() ([]map[string]interface{}, bool) { + if o == nil || IsNil(o.Manifests) { + return nil, false + } + return o.Manifests, true +} + +// HasManifests returns a boolean if a field has been set. +func (o *ResourceBundleAllOf) HasManifests() bool { + if o != nil && !IsNil(o.Manifests) { + return true + } + + return false +} + +// SetManifests gets a reference to the given []map[string]interface{} and assigns it to the Manifests field. +func (o *ResourceBundleAllOf) SetManifests(v []map[string]interface{}) { + o.Manifests = v +} + +// GetDeleteOption returns the DeleteOption field value if set, zero value otherwise. +func (o *ResourceBundleAllOf) GetDeleteOption() map[string]interface{} { + if o == nil || IsNil(o.DeleteOption) { + var ret map[string]interface{} + return ret + } + return o.DeleteOption +} + +// GetDeleteOptionOk returns a tuple with the DeleteOption field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundleAllOf) GetDeleteOptionOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.DeleteOption) { + return map[string]interface{}{}, false + } + return o.DeleteOption, true +} + +// HasDeleteOption returns a boolean if a field has been set. +func (o *ResourceBundleAllOf) HasDeleteOption() bool { + if o != nil && !IsNil(o.DeleteOption) { + return true + } + + return false +} + +// SetDeleteOption gets a reference to the given map[string]interface{} and assigns it to the DeleteOption field. +func (o *ResourceBundleAllOf) SetDeleteOption(v map[string]interface{}) { + o.DeleteOption = v +} + +// GetManifestConfigs returns the ManifestConfigs field value if set, zero value otherwise. +func (o *ResourceBundleAllOf) GetManifestConfigs() []map[string]interface{} { + if o == nil || IsNil(o.ManifestConfigs) { + var ret []map[string]interface{} + return ret + } + return o.ManifestConfigs +} + +// GetManifestConfigsOk returns a tuple with the ManifestConfigs field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundleAllOf) GetManifestConfigsOk() ([]map[string]interface{}, bool) { + if o == nil || IsNil(o.ManifestConfigs) { + return nil, false + } + return o.ManifestConfigs, true +} + +// HasManifestConfigs returns a boolean if a field has been set. +func (o *ResourceBundleAllOf) HasManifestConfigs() bool { + if o != nil && !IsNil(o.ManifestConfigs) { + return true + } + + return false +} + +// SetManifestConfigs gets a reference to the given []map[string]interface{} and assigns it to the ManifestConfigs field. +func (o *ResourceBundleAllOf) SetManifestConfigs(v []map[string]interface{}) { + o.ManifestConfigs = v +} + +// GetStatus returns the Status field value if set, zero value otherwise. +func (o *ResourceBundleAllOf) GetStatus() map[string]interface{} { + if o == nil || IsNil(o.Status) { + var ret map[string]interface{} + return ret + } + return o.Status +} + +// GetStatusOk returns a tuple with the Status field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundleAllOf) GetStatusOk() (map[string]interface{}, bool) { + if o == nil || IsNil(o.Status) { + return map[string]interface{}{}, false + } + return o.Status, true +} + +// HasStatus returns a boolean if a field has been set. +func (o *ResourceBundleAllOf) HasStatus() bool { + if o != nil && !IsNil(o.Status) { + return true + } + + return false +} + +// SetStatus gets a reference to the given map[string]interface{} and assigns it to the Status field. +func (o *ResourceBundleAllOf) SetStatus(v map[string]interface{}) { + o.Status = v +} + +func (o ResourceBundleAllOf) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o ResourceBundleAllOf) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.Name) { + toSerialize["name"] = o.Name + } + if !IsNil(o.ConsumerName) { + toSerialize["consumer_name"] = o.ConsumerName + } + if !IsNil(o.Version) { + toSerialize["version"] = o.Version + } + if !IsNil(o.CreatedAt) { + toSerialize["created_at"] = o.CreatedAt + } + if !IsNil(o.UpdatedAt) { + toSerialize["updated_at"] = o.UpdatedAt + } + if !IsNil(o.Manifests) { + toSerialize["manifests"] = o.Manifests + } + if !IsNil(o.DeleteOption) { + toSerialize["delete_option"] = o.DeleteOption + } + if !IsNil(o.ManifestConfigs) { + toSerialize["manifest_configs"] = o.ManifestConfigs + } + if !IsNil(o.Status) { + toSerialize["status"] = o.Status + } + return toSerialize, nil +} + +type NullableResourceBundleAllOf struct { + value *ResourceBundleAllOf + isSet bool +} + +func (v NullableResourceBundleAllOf) Get() *ResourceBundleAllOf { + return v.value +} + +func (v *NullableResourceBundleAllOf) Set(val *ResourceBundleAllOf) { + v.value = val + v.isSet = true +} + +func (v NullableResourceBundleAllOf) IsSet() bool { + return v.isSet +} + +func (v *NullableResourceBundleAllOf) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableResourceBundleAllOf(val *ResourceBundleAllOf) *NullableResourceBundleAllOf { + return &NullableResourceBundleAllOf{value: val, isSet: true} +} + +func (v NullableResourceBundleAllOf) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableResourceBundleAllOf) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/api/openapi/model_resource_bundle_list.go b/pkg/api/openapi/model_resource_bundle_list.go new file mode 100644 index 00000000..dfa1cd29 --- /dev/null +++ b/pkg/api/openapi/model_resource_bundle_list.go @@ -0,0 +1,223 @@ +/* +maestro Service API + +maestro Service API + +API version: 0.0.1 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// checks if the ResourceBundleList type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &ResourceBundleList{} + +// ResourceBundleList struct for ResourceBundleList +type ResourceBundleList struct { + Kind string `json:"kind"` + Page int32 `json:"page"` + Size int32 `json:"size"` + Total int32 `json:"total"` + Items []ResourceBundle `json:"items"` +} + +// NewResourceBundleList instantiates a new ResourceBundleList object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewResourceBundleList(kind string, page int32, size int32, total int32, items []ResourceBundle) *ResourceBundleList { + this := ResourceBundleList{} + this.Kind = kind + this.Page = page + this.Size = size + this.Total = total + this.Items = items + return &this +} + +// NewResourceBundleListWithDefaults instantiates a new ResourceBundleList object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewResourceBundleListWithDefaults() *ResourceBundleList { + this := ResourceBundleList{} + return &this +} + +// GetKind returns the Kind field value +func (o *ResourceBundleList) GetKind() string { + if o == nil { + var ret string + return ret + } + + return o.Kind +} + +// GetKindOk returns a tuple with the Kind field value +// and a boolean to check if the value has been set. +func (o *ResourceBundleList) GetKindOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Kind, true +} + +// SetKind sets field value +func (o *ResourceBundleList) SetKind(v string) { + o.Kind = v +} + +// GetPage returns the Page field value +func (o *ResourceBundleList) GetPage() int32 { + if o == nil { + var ret int32 + return ret + } + + return o.Page +} + +// GetPageOk returns a tuple with the Page field value +// and a boolean to check if the value has been set. +func (o *ResourceBundleList) GetPageOk() (*int32, bool) { + if o == nil { + return nil, false + } + return &o.Page, true +} + +// SetPage sets field value +func (o *ResourceBundleList) SetPage(v int32) { + o.Page = v +} + +// GetSize returns the Size field value +func (o *ResourceBundleList) GetSize() int32 { + if o == nil { + var ret int32 + return ret + } + + return o.Size +} + +// GetSizeOk returns a tuple with the Size field value +// and a boolean to check if the value has been set. +func (o *ResourceBundleList) GetSizeOk() (*int32, bool) { + if o == nil { + return nil, false + } + return &o.Size, true +} + +// SetSize sets field value +func (o *ResourceBundleList) SetSize(v int32) { + o.Size = v +} + +// GetTotal returns the Total field value +func (o *ResourceBundleList) GetTotal() int32 { + if o == nil { + var ret int32 + return ret + } + + return o.Total +} + +// GetTotalOk returns a tuple with the Total field value +// and a boolean to check if the value has been set. +func (o *ResourceBundleList) GetTotalOk() (*int32, bool) { + if o == nil { + return nil, false + } + return &o.Total, true +} + +// SetTotal sets field value +func (o *ResourceBundleList) SetTotal(v int32) { + o.Total = v +} + +// GetItems returns the Items field value +func (o *ResourceBundleList) GetItems() []ResourceBundle { + if o == nil { + var ret []ResourceBundle + return ret + } + + return o.Items +} + +// GetItemsOk returns a tuple with the Items field value +// and a boolean to check if the value has been set. +func (o *ResourceBundleList) GetItemsOk() ([]ResourceBundle, bool) { + if o == nil { + return nil, false + } + return o.Items, true +} + +// SetItems sets field value +func (o *ResourceBundleList) SetItems(v []ResourceBundle) { + o.Items = v +} + +func (o ResourceBundleList) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o ResourceBundleList) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["kind"] = o.Kind + toSerialize["page"] = o.Page + toSerialize["size"] = o.Size + toSerialize["total"] = o.Total + toSerialize["items"] = o.Items + return toSerialize, nil +} + +type NullableResourceBundleList struct { + value *ResourceBundleList + isSet bool +} + +func (v NullableResourceBundleList) Get() *ResourceBundleList { + return v.value +} + +func (v *NullableResourceBundleList) Set(val *ResourceBundleList) { + v.value = val + v.isSet = true +} + +func (v NullableResourceBundleList) IsSet() bool { + return v.isSet +} + +func (v *NullableResourceBundleList) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableResourceBundleList(val *ResourceBundleList) *NullableResourceBundleList { + return &NullableResourceBundleList{value: val, isSet: true} +} + +func (v NullableResourceBundleList) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableResourceBundleList) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/api/openapi/model_resource_bundle_list_all_of.go b/pkg/api/openapi/model_resource_bundle_list_all_of.go new file mode 100644 index 00000000..d8404785 --- /dev/null +++ b/pkg/api/openapi/model_resource_bundle_list_all_of.go @@ -0,0 +1,124 @@ +/* +maestro Service API + +maestro Service API + +API version: 0.0.1 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// checks if the ResourceBundleListAllOf type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &ResourceBundleListAllOf{} + +// ResourceBundleListAllOf struct for ResourceBundleListAllOf +type ResourceBundleListAllOf struct { + Items []ResourceBundle `json:"items,omitempty"` +} + +// NewResourceBundleListAllOf instantiates a new ResourceBundleListAllOf object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewResourceBundleListAllOf() *ResourceBundleListAllOf { + this := ResourceBundleListAllOf{} + return &this +} + +// NewResourceBundleListAllOfWithDefaults instantiates a new ResourceBundleListAllOf object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewResourceBundleListAllOfWithDefaults() *ResourceBundleListAllOf { + this := ResourceBundleListAllOf{} + return &this +} + +// GetItems returns the Items field value if set, zero value otherwise. +func (o *ResourceBundleListAllOf) GetItems() []ResourceBundle { + if o == nil || IsNil(o.Items) { + var ret []ResourceBundle + return ret + } + return o.Items +} + +// GetItemsOk returns a tuple with the Items field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *ResourceBundleListAllOf) GetItemsOk() ([]ResourceBundle, bool) { + if o == nil || IsNil(o.Items) { + return nil, false + } + return o.Items, true +} + +// HasItems returns a boolean if a field has been set. +func (o *ResourceBundleListAllOf) HasItems() bool { + if o != nil && !IsNil(o.Items) { + return true + } + + return false +} + +// SetItems gets a reference to the given []ResourceBundle and assigns it to the Items field. +func (o *ResourceBundleListAllOf) SetItems(v []ResourceBundle) { + o.Items = v +} + +func (o ResourceBundleListAllOf) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o ResourceBundleListAllOf) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.Items) { + toSerialize["items"] = o.Items + } + return toSerialize, nil +} + +type NullableResourceBundleListAllOf struct { + value *ResourceBundleListAllOf + isSet bool +} + +func (v NullableResourceBundleListAllOf) Get() *ResourceBundleListAllOf { + return v.value +} + +func (v *NullableResourceBundleListAllOf) Set(val *ResourceBundleListAllOf) { + v.value = val + v.isSet = true +} + +func (v NullableResourceBundleListAllOf) IsSet() bool { + return v.isSet +} + +func (v *NullableResourceBundleListAllOf) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableResourceBundleListAllOf(val *ResourceBundleListAllOf) *NullableResourceBundleListAllOf { + return &NullableResourceBundleListAllOf{value: val, isSet: true} +} + +func (v NullableResourceBundleListAllOf) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableResourceBundleListAllOf) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/api/presenters/resource.go b/pkg/api/presenters/resource.go index 0197281f..b3e18093 100755 --- a/pkg/api/presenters/resource.go +++ b/pkg/api/presenters/resource.go @@ -1,6 +1,9 @@ package presenters import ( + "encoding/json" + "fmt" + "gorm.io/datatypes" "github.com/openshift-online/maestro/pkg/api" @@ -60,3 +63,70 @@ func PresentResource(resource *api.Resource) (*openapi.Resource, error) { Status: status, }, nil } + +// PresentResourceBundle converts a resource from the API to the openapi representation. +func PresentResourceBundle(resource *api.Resource) (*openapi.ResourceBundle, error) { + manifestBundle, err := api.DecodeManifestBundle(resource.Manifest) + if err != nil { + return nil, err + } + status, err := api.DecodeBundleStatus(resource.Status) + if err != nil { + return nil, err + } + + reference := openapi.ObjectReference{ + Id: openapi.PtrString(resource.ID), + Kind: openapi.PtrString("ResourceBundle"), + Href: openapi.PtrString(fmt.Sprintf("%s/%s/%s", BasePath, "resource-bundles", resource.ID)), + } + + manifests := make([]map[string]interface{}, 0, len(manifestBundle.Manifests)) + for _, manifest := range manifestBundle.Manifests { + mbytes, err := json.Marshal(manifest) + if err != nil { + return nil, err + } + m := map[string]interface{}{} + if err := json.Unmarshal(mbytes, &m); err != nil { + return nil, err + } + manifests = append(manifests, m) + } + deleteOption := map[string]interface{}{} + if manifestBundle.DeleteOption != nil { + dbytes, err := json.Marshal(manifestBundle.DeleteOption) + if err != nil { + return nil, err + } + if err := json.Unmarshal(dbytes, &deleteOption); err != nil { + return nil, err + } + } + manifestConfigs := make([]map[string]interface{}, 0, len(manifestBundle.ManifestConfigs)) + for _, manifestConfig := range manifestBundle.ManifestConfigs { + mbytes, err := json.Marshal(manifestConfig) + if err != nil { + return nil, err + } + m := map[string]interface{}{} + if err := json.Unmarshal(mbytes, &m); err != nil { + return nil, err + } + manifestConfigs = append(manifestConfigs, m) + } + return &openapi.ResourceBundle{ + Id: reference.Id, + Kind: reference.Kind, + Href: reference.Href, + Name: openapi.PtrString(resource.Name), + ConsumerName: openapi.PtrString(resource.ConsumerName), + Version: openapi.PtrInt32(resource.Version), + CreatedAt: openapi.PtrTime(resource.CreatedAt), + UpdatedAt: openapi.PtrTime(resource.UpdatedAt), + Manifests: manifests, + DeleteOption: deleteOption, + ManifestConfigs: manifestConfigs, + Status: status, + }, nil +} diff --git a/pkg/api/resource_bundle_types.go b/pkg/api/resource_bundle_types.go new file mode 100755 index 00000000..a27745c8 --- /dev/null +++ b/pkg/api/resource_bundle_types.go @@ -0,0 +1,112 @@ +package api + +import ( + "encoding/json" + "fmt" + + cloudeventstypes "github.com/cloudevents/sdk-go/v2/types" + "gorm.io/datatypes" + + cetypes "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" + workpayload "open-cluster-management.io/sdk-go/pkg/cloudevents/work/payload" +) + +type ResourceBundleStatus struct { + ObservedVersion int32 + SequenceID string + *workpayload.ManifestBundleStatus +} + +// DecodeManifestBundle converts a CloudEvent JSONMap representation of a list of resource manifest +// into manifest bundle payload. +func DecodeManifestBundle(manifest datatypes.JSONMap) (*workpayload.ManifestBundle, error) { + if len(manifest) == 0 { + return nil, nil + } + + evt, err := JSONMAPToCloudEvent(manifest) + if err != nil { + return nil, fmt.Errorf("failed to convert resource manifest to cloudevent: %v", err) + } + + eventPayload := &workpayload.ManifestBundle{} + if err := evt.DataAs(eventPayload); err != nil { + return nil, fmt.Errorf("failed to decode cloudevent payload as resource manifest bundle: %v", err) + } + + return eventPayload, nil +} + +// DecodeManifestBundleToObjects converts a CloudEvent JSONMap representation of a list of resource manifest +// into a list of resource object (map[string]interface{}). +func DecodeManifestBundleToObjects(manifest datatypes.JSONMap) ([]map[string]interface{}, error) { + if len(manifest) == 0 { + return nil, nil + } + + eventPayload, err := DecodeManifestBundle(manifest) + if err != nil { + return nil, err + } + + objects := make([]map[string]interface{}, 0, len(eventPayload.Manifests)) + for _, m := range eventPayload.Manifests { + if len(m.Raw) == 0 { + return nil, fmt.Errorf("manifest in bundle is empty") + } + // unmarshal the raw JSON into the object + obj := &map[string]interface{}{} + if err := json.Unmarshal(m.Raw, obj); err != nil { + return nil, fmt.Errorf("failed to unmarshal manifest in bundle: %v", err) + } + objects = append(objects, *obj) + } + + return objects, nil +} + +// DecodeBundleStatus converts a CloudEvent JSONMap representation of a resource bundle status +// into resource bundle status (map[string]interface{}) in openapi output. +func DecodeBundleStatus(status datatypes.JSONMap) (map[string]interface{}, error) { + if len(status) == 0 { + return nil, nil + } + + evt, err := JSONMAPToCloudEvent(status) + if err != nil { + return nil, fmt.Errorf("failed to convert resource bundle status to cloudevent: %v", err) + } + + evtExtensions := evt.Extensions() + resourceVersion, err := cloudeventstypes.ToInteger(evtExtensions[cetypes.ExtensionResourceVersion]) + if err != nil { + return nil, fmt.Errorf("failed to get resourceversion extension: %v", err) + } + + sequenceID, err := cloudeventstypes.ToString(evtExtensions[cetypes.ExtensionStatusUpdateSequenceID]) + if err != nil { + return nil, fmt.Errorf("failed to get sequenceid extension: %v", err) + } + + resourceBundleStatus := &ResourceBundleStatus{ + ObservedVersion: resourceVersion, + SequenceID: sequenceID, + } + + eventPayload := &workpayload.ManifestBundleStatus{} + if err := evt.DataAs(eventPayload); err != nil { + return nil, fmt.Errorf("failed to decode cloudevent data as resource bundle status: %v", err) + } + resourceBundleStatus.ManifestBundleStatus = eventPayload + + resourceBundleStatusJSON, err := json.Marshal(resourceBundleStatus) + if err != nil { + return nil, fmt.Errorf("failed to marshal resource bundle status to JSON: %v", err) + } + statusMap := make(map[string]interface{}) + if err := json.Unmarshal(resourceBundleStatusJSON, &statusMap); err != nil { + return nil, fmt.Errorf("failed to unmarshal resource bundle status JSON to map: %v", err) + } + + return statusMap, nil +} diff --git a/pkg/api/resource_bundle_types_test.go b/pkg/api/resource_bundle_types_test.go new file mode 100644 index 00000000..abefa0b7 --- /dev/null +++ b/pkg/api/resource_bundle_types_test.go @@ -0,0 +1,170 @@ +package api + +import ( + "encoding/json" + "testing" + + "gorm.io/datatypes" + "k8s.io/apimachinery/pkg/api/equality" + "k8s.io/apimachinery/pkg/runtime" + workv1 "open-cluster-management.io/api/work/v1" + workpayload "open-cluster-management.io/sdk-go/pkg/cloudevents/work/payload" +) + +func TestDecodeManifestBundle(t *testing.T) { + cases := []struct { + name string + input datatypes.JSONMap + expected *workpayload.ManifestBundle + expectedErrorMsg string + }{ + { + name: "empty", + input: datatypes.JSONMap{}, + expected: nil, + expectedErrorMsg: "", + }, + { + name: "valid", + input: newJSONMap(t, "{\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifests\":[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"}},{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginxinc/nginx-unprivileged\"}]},\"metadata\":{\"labels\":{\"app\":\"nginx\"}}}}}],\"deleteOption\":{\"propagationPolicy\":\"Foreground\"},\"manifestConfigs\":[{\"updateStrategy\":{\"type\":\"ServerSideApply\"},\"resourceIdentifier\":{\"name\":\"nginx\",\"group\":\"apps\",\"resource\":\"deployments\",\"namespace\":\"default\"}}]}}"), + expected: &workpayload.ManifestBundle{ + Manifests: []workv1.Manifest{ + { + RawExtension: runtime.RawExtension{ + Raw: []byte("{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"}}"), + }, + }, + { + RawExtension: runtime.RawExtension{ + Raw: []byte("{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"metadata\":{\"labels\":{\"app\":\"nginx\"}},\"spec\":{\"containers\":[{\"image\":\"nginxinc/nginx-unprivileged\",\"name\":\"nginx\"}]}}}}"), + }, + }, + }, + DeleteOption: &workv1.DeleteOption{ + PropagationPolicy: "Foreground", + }, + ManifestConfigs: []workv1.ManifestConfigOption{ + { + UpdateStrategy: &workv1.UpdateStrategy{ + Type: "ServerSideApply", + }, + ResourceIdentifier: workv1.ResourceIdentifier{ + Name: "nginx", + Group: "apps", + Resource: "deployments", + Namespace: "default", + }, + }, + }, + }, + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got, err := DecodeManifestBundle(c.input) + if err != nil { + if err.Error() != c.expectedErrorMsg { + t.Errorf("expected %#v but got: %#v", c.expectedErrorMsg, err) + } + return + } + if c.expected != nil && got != nil { + if !equality.Semantic.DeepDerivative(c.expected.Manifests[1], got.Manifests[1]) { + t.Errorf("==== expected Manifests %s but got: %s", c.expected.Manifests[1].RawExtension.Raw, got.Manifests[1].RawExtension.Raw) + } + } + if !equality.Semantic.DeepDerivative(c.expected, got) { + t.Errorf("expected %#v but got: %#v", c.expected, got) + } + }) + } + +} + +func TestDecodeManifestBundleToObjects(t *testing.T) { + cases := []struct { + name string + input datatypes.JSONMap + expected []map[string]interface{} + expectedErrorMsg string + }{ + { + name: "empty", + input: datatypes.JSONMap{}, + expected: nil, + expectedErrorMsg: "", + }, + { + name: "valid", + input: newJSONMap(t, "{\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifests\":[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"}},{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginxinc/nginx-unprivileged\"}]},\"metadata\":{\"labels\":{\"app\":\"nginx\"}}}}}],\"deleteOption\":{\"propagationPolicy\":\"Foreground\"},\"manifestConfigs\":[{\"updateStrategy\":{\"type\":\"ServerSideApply\"},\"resourceIdentifier\":{\"name\":\"nginx\",\"group\":\"apps\",\"resource\":\"deployments\",\"namespace\":\"default\"}}]}}"), + expected: []map[string]interface{}{ + newJSONMap(t, "{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"}}"), + newJSONMap(t, "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginxinc/nginx-unprivileged\"}]},\"metadata\":{\"labels\":{\"app\":\"nginx\"}}}}}"), + }, + }, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + gotObjects, err := DecodeManifestBundleToObjects(c.input) + if err != nil { + if err.Error() != c.expectedErrorMsg { + t.Errorf("expected %#v but got: %#v", c.expectedErrorMsg, err) + } + return + } + if len(gotObjects) != len(c.expected) { + t.Errorf("expected %d resource in manifest bundle but got: %d", len(c.expected), len(gotObjects)) + return + } + for i, expected := range c.expected { + if !equality.Semantic.DeepDerivative(expected, gotObjects[i]) { + t.Errorf("expected %#v but got: %#v", expected, gotObjects[i]) + } + } + }) + } +} + +func TestDecodeBundleStatus(t *testing.T) { + cases := []struct { + name string + input datatypes.JSONMap + expectedJSON string + expectedErrorMsg string + }{ + { + name: "empty", + input: datatypes.JSONMap{}, + expectedJSON: "null", + expectedErrorMsg: "", + }, + { + name: "valid", + input: newJSONMap(t, "{\"id\":\"dfaa4da7-915a-4060-962e-4c741c979989\",\"data\":{\"conditions\":[{\"type\":\"Applied\",\"reason\":\"AppliedManifestWorkComplete\",\"status\":\"True\",\"message\":\"Apply manifest work complete\",\"lastTransitionTime\":\"2024-05-21T08:56:35Z\"},{\"type\":\"Available\",\"reason\":\"ResourcesAvailable\",\"status\":\"True\",\"message\":\"All resources are available\",\"lastTransitionTime\":\"2024-05-21T08:56:35Z\"}],\"resourceStatus\":[{\"conditions\":[{\"type\":\"Applied\",\"reason\":\"AppliedManifestComplete\",\"status\":\"True\",\"message\":\"Apply manifest complete\",\"lastTransitionTime\":\"2024-05-21T08:56:35Z\"},{\"type\":\"Available\",\"reason\":\"ResourceAvailable\",\"status\":\"True\",\"message\":\"Resource is available\",\"lastTransitionTime\":\"2024-05-21T08:56:35Z\"},{\"type\":\"StatusFeedbackSynced\",\"reason\":\"NoStatusFeedbackSynced\",\"status\":\"True\",\"message\":\"\",\"lastTransitionTime\":\"2024-05-21T08:56:35Z\"}],\"resourceMeta\":{\"kind\":\"ConfigMap\",\"name\":\"web\",\"group\":\"\",\"ordinal\":0,\"version\":\"v1\",\"resource\":\"configmaps\",\"namespace\":\"default\"},\"statusFeedback\":{}},{\"conditions\":[{\"type\":\"Applied\",\"reason\":\"AppliedManifestComplete\",\"status\":\"True\",\"message\":\"Apply manifest complete\",\"lastTransitionTime\":\"2024-05-21T08:56:35Z\"},{\"type\":\"Available\",\"reason\":\"ResourceAvailable\",\"status\":\"True\",\"message\":\"Resource is available\",\"lastTransitionTime\":\"2024-05-21T08:56:35Z\"},{\"type\":\"StatusFeedbackSynced\",\"reason\":\"StatusFeedbackSynced\",\"status\":\"True\",\"message\":\"\",\"lastTransitionTime\":\"2024-05-21T08:56:35Z\"}],\"resourceMeta\":{\"kind\":\"Deployment\",\"name\":\"web\",\"group\":\"apps\",\"ordinal\":1,\"version\":\"v1\",\"resource\":\"deployments\",\"namespace\":\"default\"},\"statusFeedback\":{\"values\":[{\"name\":\"status\",\"fieldValue\":{\"type\":\"JsonRaw\",\"jsonRaw\":\"{\\\"availableReplicas\\\":2,\\\"conditions\\\":[{\\\"lastTransitionTime\\\":\\\"2024-05-21T08:56:35Z\\\",\\\"lastUpdateTime\\\":\\\"2024-05-21T08:56:38Z\\\",\\\"message\\\":\\\"ReplicaSet \\\\\\\"web-dcffc4f85\\\\\\\" has successfully progressed.\\\",\\\"reason\\\":\\\"NewReplicaSetAvailable\\\",\\\"status\\\":\\\"True\\\",\\\"type\\\":\\\"Progressing\\\"},{\\\"lastTransitionTime\\\":\\\"2024-05-21T08:58: 26Z\\\",\\\"lastUpdateTime\\\":\\\"2024-05-21T08:58:26Z\\\",\\\"message\\\":\\\"Deployment has minimum availability.\\\",\\\"reason\\\":\\\"MinimumReplicasAvailable\\\",\\\"status\\\":\\\"True\\\",\\\"type\\\":\\\"Available\\\"}],\\\"observedGeneration\\\":2,\\\"readyReplicas\\\":2,\\\"replicas\\\":2,\\\"updatedReplicas\\\":2}\"}}]}}]},\"time\":\"2024-05-21T08:58:31.813194788Z\",\"type\":\"io.open-cluster-management.works.v1alpha1.manifestbundles.status.update_request\",\"source\":\"cluster1-work-agent\",\"resourceid\":\"68ebf474-6709-48bb-b760-386181268064\",\"sequenceid\":\"1792842398301163520\",\"clustername\":\"cluster1\",\"specversion\":\"1.0\",\"originalsource\":\"maestro\",\"datacontenttype\":\"application/json\",\"resourceversion\":\"2\"}"), + expectedJSON: "{\"ObservedVersion\":2,\"SequenceID\":\"1792842398301163520\",\"conditions\":[{\"lastTransitionTime\":\"2024-05-21T08:56:35Z\",\"message\":\"Apply manifest work complete\",\"reason\":\"AppliedManifestWorkComplete\",\"status\":\"True\",\"type\":\"Applied\"},{\"lastTransitionTime\":\"2024-05-21T08:56:35Z\",\"message\":\"All resources are available\",\"reason\":\"ResourcesAvailable\",\"status\":\"True\",\"type\":\"Available\"}],\"resourceStatus\":[{\"conditions\":[{\"lastTransitionTime\":\"2024-05-21T08:56:35Z\",\"message\":\"Apply manifest complete\",\"reason\":\"AppliedManifestComplete\",\"status\":\"True\",\"type\":\"Applied\"},{\"lastTransitionTime\":\"2024-05-21T08:56:35Z\",\"message\":\"Resource is available\",\"reason\":\"ResourceAvailable\",\"status\":\"True\",\"type\":\"Available\"},{\"lastTransitionTime\":\"2024-05-21T08:56:35Z\",\"message\":\"\",\"reason\":\"NoStatusFeedbackSynced\",\"status\":\"True\",\"type\":\"StatusFeedbackSynced\"}],\"resourceMeta\":{\"group\":\"\",\"kind\":\"ConfigMap\",\"name\":\"web\",\"namespace\":\"default\",\"ordinal\":0,\"resource\":\"configmaps\",\"version\":\"v1\"},\"statusFeedback\":{}},{\"conditions\":[{\"lastTransitionTime\":\"2024-05-21T08:56:35Z\",\"message\":\"Apply manifest complete\",\"reason\":\"AppliedManifestComplete\",\"status\":\"True\",\"type\":\"Applied\"},{\"lastTransitionTime\":\"2024-05-21T08:56:35Z\",\"message\":\"Resource is available\",\"reason\":\"ResourceAvailable\",\"status\":\"True\",\"type\":\"Available\"},{\"lastTransitionTime\":\"2024-05-21T08:56:35Z\",\"message\":\"\",\"reason\":\"StatusFeedbackSynced\",\"status\":\"True\",\"type\":\"StatusFeedbackSynced\"}],\"resourceMeta\":{\"group\":\"apps\",\"kind\":\"Deployment\",\"name\":\"web\",\"namespace\":\"default\",\"ordinal\":1,\"resource\":\"deployments\",\"version\":\"v1\"},\"statusFeedback\":{\"values\":[{\"fieldValue\":{\"jsonRaw\":\"{\\\"availableReplicas\\\":2,\\\"conditions\\\":[{\\\"lastTransitionTime\\\":\\\"2024-05-21T08:56:35Z\\\",\\\"lastUpdateTime\\\":\\\"2024-05-21T08:56:38Z\\\",\\\"message\\\":\\\"ReplicaSet \\\\\\\"web-dcffc4f85\\\\\\\" has successfully progressed.\\\",\\\"reason\\\":\\\"NewReplicaSetAvailable\\\",\\\"status\\\":\\\"True\\\",\\\"type\\\":\\\"Progressing\\\"},{\\\"lastTransitionTime\\\":\\\"2024-05-21T08:58: 26Z\\\",\\\"lastUpdateTime\\\":\\\"2024-05-21T08:58:26Z\\\",\\\"message\\\":\\\"Deployment has minimum availability.\\\",\\\"reason\\\":\\\"MinimumReplicasAvailable\\\",\\\"status\\\":\\\"True\\\",\\\"type\\\":\\\"Available\\\"}],\\\"observedGeneration\\\":2,\\\"readyReplicas\\\":2,\\\"replicas\\\":2,\\\"updatedReplicas\\\":2}\",\"type\":\"JsonRaw\"},\"name\":\"status\"}]}}]}", + expectedErrorMsg: "", + }, + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got, err := DecodeBundleStatus(c.input) + if err != nil { + if err.Error() != c.expectedErrorMsg { + t.Errorf("expected %#v but got: %#v", c.expectedErrorMsg, err) + } + return + } + gotBytes, err := json.Marshal(got) + if err != nil { + t.Errorf("failed to marshal got resource bundle status: %v", err) + } + + if string(gotBytes) != c.expectedJSON { + t.Errorf("expected %s but got: %s", c.expectedJSON, string(gotBytes)) + } + }) + } + +} diff --git a/pkg/api/resource_types.go b/pkg/api/resource_types.go index 52c67d5d..292e70a6 100755 --- a/pkg/api/resource_types.go +++ b/pkg/api/resource_types.go @@ -234,59 +234,6 @@ func DecodeManifest(manifest datatypes.JSONMap) (map[string]interface{}, map[str return eventPayload.Manifest.Object, *deleteOptionObj, *updateStrategyObj, nil } -// DecodeDeleteOption converts a CloudEvent JSONMap representation of a resoure deleteOption -// into resource deleteOption (map[string]interface{}). -func DecodeDeleteOption(deleteOption datatypes.JSONMap) (map[string]interface{}, error) { - if len(deleteOption) == 0 { - return nil, nil - } - - jsonData, err := deleteOption.MarshalJSON() - if err != nil { - return nil, fmt.Errorf("failed to marshal deleteOption to json: %v", err) - } - - obj := &map[string]interface{}{} - if err := json.Unmarshal(jsonData, obj); err != nil { - return nil, fmt.Errorf("failed to unmarshal deleteOption to cloudevent: %v", err) - } - - return *obj, nil -} - -// DecodeManifestBundle converts a CloudEvent JSONMap representation of a list of resource manifest -// into a list of resource manifest (map[string]interface{}). -func DecodeManifestBundle(manifest datatypes.JSONMap) ([]map[string]interface{}, error) { - if len(manifest) == 0 { - return nil, nil - } - - evt, err := JSONMAPToCloudEvent(manifest) - if err != nil { - return nil, fmt.Errorf("failed to convert resource manifest to cloudevent: %v", err) - } - - eventPayload := &workpayload.ManifestBundle{} - if err := evt.DataAs(eventPayload); err != nil { - return nil, fmt.Errorf("failed to decode cloudevent payload as resource manifest bundle: %v", err) - } - - manifests := make([]map[string]interface{}, 0, len(eventPayload.Manifests)) - for _, m := range eventPayload.Manifests { - if len(m.Raw) == 0 { - return nil, fmt.Errorf("manifest in bundle is empty") - } - // unmarshal the raw JSON into the object - obj := &map[string]interface{}{} - if err := json.Unmarshal(m.Raw, obj); err != nil { - return nil, fmt.Errorf("failed to unmarshal manifest in bundle: %v", err) - } - manifests = append(manifests, *obj) - } - - return manifests, nil -} - // DecodeStatus converts a CloudEvent JSONMap representation of a resource status // into resource status (map[string]interface{}). func DecodeStatus(status datatypes.JSONMap) (map[string]interface{}, error) { diff --git a/pkg/api/resource_types_test.go b/pkg/api/resource_types_test.go index a667ad93..26b867fa 100644 --- a/pkg/api/resource_types_test.go +++ b/pkg/api/resource_types_test.go @@ -98,50 +98,6 @@ func TestDecodeManifest(t *testing.T) { } } -func TestDecodeManifestBundle(t *testing.T) { - cases := []struct { - name string - input datatypes.JSONMap - expected []map[string]interface{} - expectedErrorMsg string - }{ - { - name: "empty", - input: datatypes.JSONMap{}, - expected: nil, - expectedErrorMsg: "", - }, - { - name: "valid", - input: newJSONMap(t, "{\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifests\":[{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"}},{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginxinc/nginx-unprivileged\"}]},\"metadata\":{\"labels\":{\"app\":\"nginx\"}}}}}],\"deleteOption\":{\"propagationPolicy\":\"Foreground\"},\"manifestConfigs\":[{\"updateStrategy\":{\"type\":\"ServerSideApply\"},\"resourceIdentifier\":{\"name\":\"nginx\",\"group\":\"apps\",\"resource\":\"deployments\",\"namespace\":\"default\"}}]}}"), - expected: []map[string]interface{}{ - newJSONMap(t, "{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"}}"), - newJSONMap(t, "{\"apiVersion\":\"apps/v1\",\"kind\":\"Deployment\",\"metadata\":{\"name\":\"nginx\",\"namespace\":\"default\"},\"spec\":{\"replicas\":1,\"selector\":{\"matchLabels\":{\"app\":\"nginx\"}},\"template\":{\"spec\":{\"containers\":[{\"name\":\"nginx\",\"image\":\"nginxinc/nginx-unprivileged\"}]},\"metadata\":{\"labels\":{\"app\":\"nginx\"}}}}}"), - }, - }, - } - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - gotManifests, err := DecodeManifestBundle(c.input) - if err != nil { - if err.Error() != c.expectedErrorMsg { - t.Errorf("expected %#v but got: %#v", c.expectedErrorMsg, err) - } - return - } - if len(gotManifests) != len(c.expected) { - t.Errorf("expected %d resource in manifest bundle but got: %d", len(c.expected), len(gotManifests)) - return - } - for i, expected := range c.expected { - if !equality.Semantic.DeepDerivative(expected, gotManifests[i]) { - t.Errorf("expected %#v but got: %#v", expected, gotManifests[i]) - } - } - }) - } -} - func TestDecodeStatus(t *testing.T) { cases := []struct { name string diff --git a/pkg/dao/mocks/resource.go b/pkg/dao/mocks/resource.go index ca6a5f9d..8b841602 100755 --- a/pkg/dao/mocks/resource.go +++ b/pkg/dao/mocks/resource.go @@ -30,6 +30,17 @@ func (d *resourceDaoMock) Get(ctx context.Context, id string) (*api.Resource, er return nil, gorm.ErrRecordNotFound } +func (d *resourceDaoMock) GetBundle(ctx context.Context, id string) (*api.Resource, error) { + for _, resource := range d.resources { + if resource.ID == id { + if resource.Type == api.ResourceTypeBundle { + return resource, nil + } + } + } + return nil, gorm.ErrRecordNotFound +} + func (d *resourceDaoMock) Create(ctx context.Context, resource *api.Resource) (*api.Resource, error) { d.resources = append(d.resources, resource) return resource, nil diff --git a/pkg/dao/resource.go b/pkg/dao/resource.go index 7f06abd0..ccfcfba4 100755 --- a/pkg/dao/resource.go +++ b/pkg/dao/resource.go @@ -11,6 +11,7 @@ import ( type ResourceDao interface { Get(ctx context.Context, id string) (*api.Resource, error) + GetBundle(ctx context.Context, id string) (*api.Resource, error) Create(ctx context.Context, resource *api.Resource) (*api.Resource, error) Update(ctx context.Context, resource *api.Resource) (*api.Resource, error) Delete(ctx context.Context, id string) error @@ -39,6 +40,15 @@ func (d *sqlResourceDao) Get(ctx context.Context, id string) (*api.Resource, err return &resource, nil } +func (d *sqlResourceDao) GetBundle(ctx context.Context, id string) (*api.Resource, error) { + g2 := (*d.sessionFactory).New(ctx) + var resource api.Resource + if err := g2.Take(&resource, "id = ? AND type = ?", id, api.ResourceTypeBundle).Error; err != nil { + return nil, err + } + return &resource, nil +} + func (d *sqlResourceDao) Create(ctx context.Context, resource *api.Resource) (*api.Resource, error) { g2 := (*d.sessionFactory).New(ctx) if err := g2.Omit(clause.Associations).Create(resource).Error; err != nil { diff --git a/pkg/handlers/resource.go b/pkg/handlers/resource.go index fd18e05d..8056a72c 100755 --- a/pkg/handlers/resource.go +++ b/pkg/handlers/resource.go @@ -181,3 +181,69 @@ func (h resourceHandler) Delete(w http.ResponseWriter, r *http.Request) { } handleDelete(w, r, cfg, http.StatusNoContent) } + +func (h resourceHandler) GetBundle(w http.ResponseWriter, r *http.Request) { + cfg := &handlerConfig{ + Action: func() (interface{}, *errors.ServiceError) { + id := mux.Vars(r)["id"] + ctx := r.Context() + resource, serviceErr := h.resource.GetBundle(ctx, id) + if serviceErr != nil { + return nil, serviceErr + } + + resBundle, err := presenters.PresentResourceBundle(resource) + if err != nil { + return nil, errors.GeneralError("failed to present resource bundle: %s", err) + } + return resBundle, nil + }, + } + + handleGet(w, r, cfg) +} + +func (h resourceHandler) ListBundle(w http.ResponseWriter, r *http.Request) { + cfg := &handlerConfig{ + Action: func() (interface{}, *errors.ServiceError) { + ctx := r.Context() + + listArgs := services.NewListArguments(r.URL.Query()) + if listArgs.Search == "" { + listArgs.Search = fmt.Sprintf("type='%s'", api.ResourceTypeBundle) + } else { + listArgs.Search = fmt.Sprintf("%s and type='%s'", listArgs.Search, api.ResourceTypeBundle) + } + var resources []api.Resource + paging, serviceErr := h.generic.List(ctx, "username", listArgs, &resources) + if serviceErr != nil { + return nil, serviceErr + } + resourceBundleList := openapi.ResourceBundleList{ + Kind: "ResourceBundleList", + Page: int32(paging.Page), + Size: int32(paging.Size), + Total: int32(paging.Total), + Items: []openapi.ResourceBundle{}, + } + + for _, resource := range resources { + converted, err := presenters.PresentResourceBundle(&resource) + if err != nil { + return nil, errors.GeneralError("failed to present resource: %s", err) + } + resourceBundleList.Items = append(resourceBundleList.Items, *converted) + } + if listArgs.Fields != nil { + filteredItems, err := presenters.SliceFilter(listArgs.Fields, resourceBundleList.Items) + if err != nil { + return nil, err + } + return filteredItems, nil + } + return resourceBundleList, nil + }, + } + + handleList(w, r, cfg) +} diff --git a/pkg/services/resource.go b/pkg/services/resource.go index ce6a03af..a87c7492 100755 --- a/pkg/services/resource.go +++ b/pkg/services/resource.go @@ -19,6 +19,7 @@ import ( type ResourceService interface { Get(ctx context.Context, id string) (*api.Resource, *errors.ServiceError) + GetBundle(ctx context.Context, id string) (*api.Resource, *errors.ServiceError) Create(ctx context.Context, resource *api.Resource) (*api.Resource, *errors.ServiceError) Update(ctx context.Context, resource *api.Resource) (*api.Resource, *errors.ServiceError) UpdateStatus(ctx context.Context, resource *api.Resource) (*api.Resource, bool, *errors.ServiceError) @@ -55,6 +56,14 @@ func (s *sqlResourceService) Get(ctx context.Context, id string) (*api.Resource, return resource, nil } +func (s *sqlResourceService) GetBundle(ctx context.Context, id string) (*api.Resource, *errors.ServiceError) { + resource, err := s.resourceDao.GetBundle(ctx, id) + if err != nil { + return nil, handleGetError("Resource Bundle", "id", id, err) + } + return resource, nil +} + func (s *sqlResourceService) Create(ctx context.Context, resource *api.Resource) (*api.Resource, *errors.ServiceError) { if resource.Name != "" { if err := ValidateResourceName(resource); err != nil { diff --git a/pkg/services/validation.go b/pkg/services/validation.go index 3ee6bba2..254015c5 100644 --- a/pkg/services/validation.go +++ b/pkg/services/validation.go @@ -53,7 +53,7 @@ func ValidateManifest(resType api.ResourceType, manifest datatypes.JSONMap) erro } return ValidateObject(obj) case api.ResourceTypeBundle: - objs, err := api.DecodeManifestBundle(manifest) + objs, err := api.DecodeManifestBundleToObjects(manifest) if err != nil { return fmt.Errorf("failed to decode manifest bundle: %v", err) } @@ -118,11 +118,11 @@ func ValidateManifestUpdate(resType api.ResourceType, new, old datatypes.JSONMap } return ValidateObjectUpdate(newObj, oldObj) case api.ResourceTypeBundle: - newObjs, err := api.DecodeManifestBundle(new) + newObjs, err := api.DecodeManifestBundleToObjects(new) if err != nil { return fmt.Errorf("failed to decode new manifest bundle: %v", err) } - oldObjs, err := api.DecodeManifestBundle(old) + oldObjs, err := api.DecodeManifestBundleToObjects(old) if err != nil { return fmt.Errorf("failed to decode old manifest bundle: %v", err) } diff --git a/test/factories.go b/test/factories.go index 971846b6..f1952cf3 100755 --- a/test/factories.go +++ b/test/factories.go @@ -5,9 +5,17 @@ import ( "encoding/json" "fmt" + cloudevents "github.com/cloudevents/sdk-go/v2" "github.com/openshift-online/maestro/pkg/api" "github.com/openshift-online/maestro/pkg/api/openapi" "github.com/openshift-online/maestro/pkg/db" + "gorm.io/datatypes" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + + workv1 "open-cluster-management.io/api/work/v1" + cetypes "open-cluster-management.io/sdk-go/pkg/cloudevents/generic/types" + workpayload "open-cluster-management.io/sdk-go/pkg/cloudevents/work/payload" ) var testManifestJSON = ` @@ -92,6 +100,105 @@ func (helper *Helper) CreateResourceList(consumerName string, count int) (resour return resources } +// EncodeManifestBundle converts resource manifests into a CloudEvent JSONMap representation. +func (helper *Helper) EncodeManifestBundle(manifest map[string]interface{}) (datatypes.JSONMap, error) { + if len(manifest) == 0 { + return nil, nil + } + + delOption := &workv1.DeleteOption{ + PropagationPolicy: workv1.DeletePropagationPolicyTypeForeground, + } + + upStrategy := &workv1.UpdateStrategy{ + Type: workv1.UpdateStrategyTypeServerSideApply, + } + + // create a cloud event with the manifest as the data + evt := cetypes.NewEventBuilder("maestro", cetypes.CloudEventsType{}).NewEvent() + eventPayload := &workpayload.ManifestBundle{ + Manifests: []workv1.Manifest{ + { + RawExtension: runtime.RawExtension{ + Object: &unstructured.Unstructured{Object: manifest}, + }, + }, + }, + DeleteOption: delOption, + ManifestConfigs: []workv1.ManifestConfigOption{ + { + FeedbackRules: []workv1.FeedbackRule{ + { + Type: workv1.JSONPathsType, + JsonPaths: []workv1.JsonPath{ + { + Name: "status", + Path: ".status", + }, + }, + }, + }, + UpdateStrategy: upStrategy, + ResourceIdentifier: workv1.ResourceIdentifier{ + Group: "apps", + Resource: "deployments", + Name: "nginx", + Namespace: "default", + }, + }, + }, + } + + if err := evt.SetData(cloudevents.ApplicationJSON, eventPayload); err != nil { + return nil, fmt.Errorf("failed to set cloud event data: %v", err) + } + + // convert cloudevent to JSONMap + manifest, err := api.CloudEventToJSONMap(&evt) + if err != nil { + return nil, fmt.Errorf("failed to convert cloudevent to resource manifest: %v", err) + } + + return manifest, nil +} + +func (helper *Helper) NewResourceBundle(name, consumerName string, replicas int) *api.Resource { + testResource := helper.NewAPIResource(consumerName, replicas) + testManifest, err := helper.EncodeManifestBundle(testResource.Manifest) + if err != nil { + helper.T.Errorf("error encoding manifest bundle: %q", err) + } + + resource := &api.Resource{ + Name: name, + ConsumerName: consumerName, + Type: api.ResourceTypeBundle, + Manifest: testManifest, + Version: 1, + } + + return resource +} + +func (helper *Helper) CreateResourceBundle(name, consumerName string, replicas int) *api.Resource { + resourceService := helper.Env().Services.Resources() + resourceBundle := helper.NewResourceBundle(name, consumerName, replicas) + + res, err := resourceService.Create(context.Background(), resourceBundle) + if err != nil { + helper.T.Errorf("error creating resource bundle: %q", err) + } + + return res +} + +func (helper *Helper) CreateResourceBundleList(consumerName string, count int) (resources []*api.Resource) { + for i := 1; i <= count; i++ { + resources = append(resources, helper.CreateResourceBundle(fmt.Sprintf("resource%d", i), consumerName, 1)) + } + return resources +} + func (helper *Helper) CreateConsumer(name string) *api.Consumer { return helper.CreateConsumerWithLabels(name, nil) } diff --git a/test/integration/resource_test.go b/test/integration/resource_test.go index b6af1310..f190ae65 100755 --- a/test/integration/resource_test.go +++ b/test/integration/resource_test.go @@ -387,6 +387,7 @@ func TestResourcePaging(t *testing.T) { // Paging consumer := h.CreateConsumer("cluster1") _ = h.CreateResourceList(consumer.Name, 20) + _ = h.CreateResourceBundleList(consumer.Name, 20) list, _, err := client.DefaultApi.ApiMaestroV1ResourcesGet(ctx).Execute() Expect(err).NotTo(HaveOccurred(), "Error getting resource list: %v", err) @@ -423,6 +424,64 @@ func TestResourceListSearch(t *testing.T) { Expect(*list.Items[0].Id).To(Equal(resources[0].ID)) } +func TestResourceBundleGet(t *testing.T) { + h, client := test.RegisterIntegration(t) + + account := h.NewRandAccount() + ctx := h.NewAuthenticatedContext(account) + + // 401 using no JWT token + _, _, err := client.DefaultApi.ApiMaestroV1ResourcesIdGet(context.Background(), "foo").Execute() + Expect(err).To(HaveOccurred(), "Expected 401 but got nil error") + + // GET responses per openapi spec: 200 and 404, + _, resp, err := client.DefaultApi.ApiMaestroV1ResourcesIdGet(ctx, "foo").Execute() + Expect(err).To(HaveOccurred(), "Expected 404") + Expect(resp.StatusCode).To(Equal(http.StatusNotFound)) + + consumer := h.CreateConsumer("cluster1") + resourceBundle := h.CreateResourceBundle("resource1", consumer.Name, 1) + + resBundle, resp, err := client.DefaultApi.ApiMaestroV1ResourceBundlesIdGet(ctx, resourceBundle.ID).Execute() + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + + Expect(*resBundle.Id).To(Equal(resourceBundle.ID), "found object does not match test object") + Expect(*resBundle.Name).To(Equal(resourceBundle.Name)) + Expect(*resBundle.Kind).To(Equal("ResourceBundle")) + Expect(*resBundle.Href).To(Equal(fmt.Sprintf("/api/maestro/v1/resource-bundles/%s", resourceBundle.ID))) + Expect(*resBundle.CreatedAt).To(BeTemporally("~", resourceBundle.CreatedAt)) + Expect(*resBundle.UpdatedAt).To(BeTemporally("~", resourceBundle.UpdatedAt)) + Expect(*resBundle.Version).To(Equal(resourceBundle.Version)) +} + +func TestResourceBundleListSearch(t *testing.T) { + h, client := test.RegisterIntegration(t) + + account := h.NewRandAccount() + ctx := h.NewAuthenticatedContext(account) + + consumer := h.CreateConsumer("cluster1") + resourceBundles := h.CreateResourceBundleList(consumer.Name, 20) + _ = h.CreateResourceList(consumer.Name, 20) + + search := fmt.Sprintf("name = '%s' and consumer_name = '%s'", resourceBundles[0].Name, consumer.Name) + list, _, err := client.DefaultApi.ApiMaestroV1ResourceBundlesGet(ctx).Search(search).Execute() + Expect(list.Kind).To(Equal("ResourceBundleList")) + Expect(err).NotTo(HaveOccurred(), "Error getting resource bundle list: %v", err) + Expect(len(list.Items)).To(Equal(1)) + Expect(list.Total).To(Equal(int32(1))) + Expect(*list.Items[0].Id).To(Equal(resourceBundles[0].ID)) + Expect(*list.Items[0].Name).To(Equal(resourceBundles[0].Name)) + + search = fmt.Sprintf("consumer_name = '%s'", consumer.Name) + list, _, err = client.DefaultApi.ApiMaestroV1ResourceBundlesGet(ctx).Search(search).Execute() + Expect(list.Kind).To(Equal("ResourceBundleList")) + Expect(err).NotTo(HaveOccurred(), "Error getting resource bundle list: %v", err) + Expect(len(list.Items)).To(Equal(20)) + Expect(list.Total).To(Equal(int32(20))) +} + func TestUpdateResourceWithRacingRequests(t *testing.T) { h, client := test.RegisterIntegration(t) @@ -694,7 +753,7 @@ func TestResourceFromGRPC(t *testing.T) { } func TestResourceBundleFromGRPC(t *testing.T) { - h, _ := test.RegisterIntegration(t) + h, client := test.RegisterIntegration(t) account := h.NewRandAccount() ctx, cancel := context.WithCancel(h.NewAuthenticatedContext(account)) defer cancel() @@ -832,4 +891,23 @@ func TestResourceBundleFromGRPC(t *testing.T) { manifest = map[string]interface{}{} Expect(json.Unmarshal(work.Spec.Workload.Manifests[0].Raw, &manifest)).NotTo(HaveOccurred(), "Error unmarshalling manifest: %v", err) Expect(manifest["spec"].(map[string]interface{})["replicas"]).To(Equal(float64(2))) + + // get the resource bundle with restful API + resBundle, resp, err := client.DefaultApi.ApiMaestroV1ResourceBundlesIdGet(ctx, res.ID).Execute() + Expect(err).NotTo(HaveOccurred()) + Expect(resp.StatusCode).To(Equal(http.StatusOK)) + + Expect(*resBundle.Id).To(Equal(res.ID), "found object does not match test object") + Expect(*resBundle.Name).To(Equal(res.ID)) + Expect(*resBundle.Kind).To(Equal("ResourceBundle")) + Expect(*resBundle.Href).To(Equal(fmt.Sprintf("/api/maestro/v1/resource-bundles/%s", res.ID))) + Expect(*resBundle.Version).To(Equal(int32(2))) + + // list search resource bundle with restful API + search := fmt.Sprintf("consumer_name = '%s'", consumer.Name) + list, _, err := client.DefaultApi.ApiMaestroV1ResourceBundlesGet(ctx).Search(search).Execute() + Expect(list.Kind).To(Equal("ResourceBundleList")) + Expect(err).NotTo(HaveOccurred(), "Error getting resource bundle list: %v", err) + Expect(len(list.Items)).To(Equal(1)) + Expect(list.Total).To(Equal(int32(1))) }