Skip to content

Commit

Permalink
Return delete_option and update_strategy
Browse files Browse the repository at this point in the history
Signed-off-by: clyang82 <[email protected]>
  • Loading branch information
clyang82 committed May 27, 2024
1 parent a3c8bcd commit 2c0d4b5
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 39 deletions.
19 changes: 17 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,24 @@ ocm post /api/maestro/v1/resources << EOF
}
},
"update_strategy": {
"type": "Orphan"
"type": "ServerSideApply"
},
"delete_option": {
"propagationPolicy": "CreateOnly"
"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

Expand All @@ -194,6 +203,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",
Expand Down Expand Up @@ -282,6 +294,9 @@ ocm get /api/maestro/v1/resources
"SequenceID": "1744926882802962432"
}
},
"update_strategy": {
"type":"ServerSideApply"
},
"updated_at": "2023-11-23T09:26:13.457419Z",
"version": 1
}
Expand Down
24 changes: 13 additions & 11 deletions pkg/api/presenters/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func ConvertResourceManifest(manifest, deleteOption, updateStrategy map[string]i

// 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
}
Expand All @@ -42,15 +42,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
}
56 changes: 49 additions & 7 deletions pkg/api/resource_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ func CloudEventToJSONMap(evt *cloudevents.Event) (datatypes.JSONMap, error) {
return res, nil
}

// EncodeManifest converts a resource manifest (map[string]interface{}) into a CloudEvent JSONMap representation.
// 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
Expand Down Expand Up @@ -193,23 +193,65 @@ func EncodeManifest(manifest, deleteOption, updateStrategy map[string]interface{
}

// 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
Expand Down
40 changes: 26 additions & 14 deletions pkg/api/resource_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,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: newJSONMap(t, "{\"specversion\":\"1.0\",\"datacontenttype\":\"application/json\",\"data\":{\"manifest\":{\"apiVersion\":\"v1\",\"kind\":\"ConfigMap\",\"metadata\":{\"name\":\"test\",\"namespace\":\"test\"}}}}"),
expected: newJSONMap(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)
}
})
}
Expand Down
7 changes: 4 additions & 3 deletions pkg/services/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down
4 changes: 2 additions & 2 deletions test/grpc_codec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
}
Expand Down

0 comments on commit 2c0d4b5

Please sign in to comment.