From 717d480152d32b991e28b87ba18bbd4d762c49ce Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 23 Jun 2023 15:34:16 -0400 Subject: [PATCH 1/4] 06/23/2023 CFN Resource Provider Definition Schema. --- testdata/provider.definition.schema.v1.json | 68 ++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/testdata/provider.definition.schema.v1.json b/testdata/provider.definition.schema.v1.json index 4b3fa4d..1d32814 100644 --- a/testdata/provider.definition.schema.v1.json +++ b/testdata/provider.definition.schema.v1.json @@ -4,6 +4,57 @@ "title": "CloudFormation Resource Provider Definition MetaSchema", "description": "This schema validates a CloudFormation resource provider definition.", "definitions": { + "handlerSchema": { + "type": "object", + "properties": { + "properties": { + "$ref": "file://./base.definition.schema.v1.json#/properties/properties" + }, + "required": { + "$ref": "file://./base.definition.schema.v1.json#/properties/required" + }, + "allOf": { + "$ref": "file://./base.definition.schema.v1.json#/definitions/schemaArray" + }, + "anyOf": { + "$ref": "file://./base.definition.schema.v1.json#/definitions/schemaArray" + }, + "oneOf": { + "$ref": "file://./base.definition.schema.v1.json#/definitions/schemaArray" + } + }, + "required": [ + "properties" + ], + "additionalProperties": false + }, + "handlerDefinitionWithSchemaOverride": { + "description": "Defines any execution operations which can be performed on this resource provider", + "type": "object", + "properties": { + "handlerSchema": { + "$ref": "#/definitions/handlerSchema" + }, + "permissions": { + "type": "array", + "items": { + "type": "string" + }, + "additionalItems": false + }, + "timeoutInMinutes": { + "description": "Defines the timeout for the entire operation to be interpreted by the invoker of the handler. The default is 120 (2 hours).", + "type": "integer", + "minimum": 2, + "maximum": 2160, + "default": 120 + } + }, + "additionalProperties": false, + "required": [ + "permissions" + ] + }, "handlerDefinition": { "description": "Defines any execution operations which can be performed on this resource provider", "type": "object", @@ -145,6 +196,13 @@ "description": "A reference to the Tags property in the schema.", "$ref": "http://json-schema.org/draft-07/schema#/properties/$ref", "default": "/properties/Tags" + }, + "permissions": { + "type": "array", + "items": { + "type": "string" + }, + "additionalItems": false } }, "required": [ @@ -183,7 +241,7 @@ "$ref": "#/definitions/handlerDefinition" }, "list": { - "$ref": "#/definitions/handlerDefinition" + "$ref": "#/definitions/handlerDefinitionWithSchemaOverride" } }, "additionalProperties": false @@ -204,6 +262,14 @@ "description": "A list of JSON pointers for properties that can only be updated under certain conditions. For example, you can upgrade the engine version of an RDS DBInstance but you cannot downgrade it. When updating this property for a resource in a CloudFormation stack, the resource will be replaced if it cannot be updated.", "$ref": "file://./base.definition.schema.v1.json#/definitions/jsonPointerArray" }, + "nonPublicProperties": { + "description": "A list of JSON pointers for properties that are hidden. These properties will still be used but will not be visible", + "$ref": "file://./base.definition.schema.v1.json#/definitions/jsonPointerArray" + }, + "nonPublicDefinitions": { + "description": "A list of JSON pointers for definitions that are hidden. These definitions will still be used but will not be visible", + "$ref": "file://./base.definition.schema.v1.json#/definitions/jsonPointerArray" + }, "createOnlyProperties": { "description": "A list of JSON pointers to properties that are only able to be specified by the customer when creating a resource. Conversely, any property *not* in this list can be applied to an Update request.", "$ref": "file://./base.definition.schema.v1.json#/definitions/jsonPointerArray" From 89cb083056222cef71c943dcbfacf5fbeccf2669 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 23 Jun 2023 15:35:07 -0400 Subject: [PATCH 2/4] Add Tagging.Permissions. --- tagging.go | 1 + 1 file changed, 1 insertion(+) diff --git a/tagging.go b/tagging.go index ef981c4..3a7bc95 100644 --- a/tagging.go +++ b/tagging.go @@ -9,4 +9,5 @@ type Tagging struct { TagUpdatable *bool `json:"tagUpdatable,omitempty"` CloudFormationSystemTags *bool `json:"cloudFormationSystemTags,omitempty"` TagProperty *PropertyJsonPointer `json:"tagProperty,omitempty"` + Permissions []string `json:"permissions,omitempty"` } From 12cdf4812c29cc6a8d01a5728c16609628aaf909 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 23 Jun 2023 15:35:22 -0400 Subject: [PATCH 3/4] Add HandlerSchema. --- handler.go | 5 +- handler_schema.go | 12 +++ handler_schema_test.go | 75 +++++++++++++++++++ resource.go | 2 + ...orkManager_TransitGatewayRegistration.json | 62 +++++++++++++++ 5 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 handler_schema.go create mode 100644 handler_schema_test.go create mode 100644 testdata/AWS_NetworkManager_TransitGatewayRegistration.json diff --git a/handler.go b/handler.go index aa8b796..bba792b 100644 --- a/handler.go +++ b/handler.go @@ -12,6 +12,7 @@ const ( ) type Handler struct { - Permissions []string `json:"permissions,omitempty"` - TimeoutInMinutes int `json:"timeoutInMinutes,omitempty"` + HandlerSchema *HandlerSchema `json:"handlerSchema,omitempty"` + Permissions []string `json:"permissions,omitempty"` + TimeoutInMinutes int `json:"timeoutInMinutes,omitempty"` } diff --git a/handler_schema.go b/handler_schema.go new file mode 100644 index 0000000..3b14431 --- /dev/null +++ b/handler_schema.go @@ -0,0 +1,12 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package cfschema + +type HandlerSchema struct { + AllOf []*PropertySubschema `json:"allOf,omitempty"` + AnyOf []*PropertySubschema `json:"anyOf,omitempty"` + OneOf []*PropertySubschema `json:"oneOf,omitempty"` + Properties map[string]*Property `json:"properties,omitempty"` + Required []string `json:"required,omitempty"` +} diff --git a/handler_schema_test.go b/handler_schema_test.go new file mode 100644 index 0000000..5f3252b --- /dev/null +++ b/handler_schema_test.go @@ -0,0 +1,75 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package cfschema_test + +import ( + "path/filepath" + "testing" + + cfschema "github.com/hashicorp/aws-cloudformation-resource-schema-sdk-go" +) + +func TestHandlerSchema(t *testing.T) { + testCases := []struct { + TestDescription string + MetaSchemaPath string + ResourceSchemaPath string + ExpectError bool + ExpectedHandlerSchema int + }{ + { + TestDescription: "no handlerSchema", + MetaSchemaPath: "provider.definition.schema.v1.json", + ResourceSchemaPath: "AWS_CloudWatch_MetricStream.json", + }, + { + TestDescription: "list handlerSchema", + MetaSchemaPath: "provider.definition.schema.v1.json", + ResourceSchemaPath: "AWS_NetworkManager_TransitGatewayRegistration.json", + ExpectedHandlerSchema: 1, + }, + } + + for _, testCase := range testCases { + testCase := testCase + + t.Run(testCase.TestDescription, func(t *testing.T) { + metaSchema, err := cfschema.NewMetaJsonSchemaPath(filepath.Join("testdata", testCase.MetaSchemaPath)) + + if err != nil { + t.Fatalf("unexpected NewMetaJsonSchemaPath() error: %s", err) + } + + resourceSchema, err := cfschema.NewResourceJsonSchemaPath(filepath.Join("testdata", testCase.ResourceSchemaPath)) + + if err != nil { + t.Fatalf("unexpected NewResourceJsonSchemaPath() error: %s", err) + } + + err = metaSchema.ValidateResourceJsonSchema(resourceSchema) + + if err != nil { + t.Fatalf("unexpected ValidateResourceJsonSchema() error: %s", err) + } + + resource, err := resourceSchema.Resource() + + if err != nil { + t.Fatalf("unexpected Resource() error: %s", err) + } + + got := 0 + + for _, handler := range resource.Handlers { + if handler.HandlerSchema != nil { + got++ + } + } + + if actual, expected := got, testCase.ExpectedHandlerSchema; actual != expected { + t.Errorf("expected %d handlerSchema elements, got: %d", expected, actual) + } + }) + } +} diff --git a/resource.go b/resource.go index 9859967..1b8bb70 100644 --- a/resource.go +++ b/resource.go @@ -18,6 +18,8 @@ type Resource struct { DeprecatedProperties PropertyJsonPointers `json:"deprecatedProperties,omitempty"` Description *string `json:"description,omitempty"` Handlers map[string]*Handler `json:"handlers,omitempty"` + NonPublicDefinitions PropertyJsonPointers `json:"nonPublicDefinitions,omitempty"` + NonPublicProperties PropertyJsonPointers `json:"nonPublicProperties,omitempty"` OneOf []*PropertySubschema `json:"oneOf,omitempty"` PrimaryIdentifier PropertyJsonPointers `json:"primaryIdentifier,omitempty"` Properties map[string]*Property `json:"properties,omitempty"` diff --git a/testdata/AWS_NetworkManager_TransitGatewayRegistration.json b/testdata/AWS_NetworkManager_TransitGatewayRegistration.json new file mode 100644 index 0000000..1e4bab7 --- /dev/null +++ b/testdata/AWS_NetworkManager_TransitGatewayRegistration.json @@ -0,0 +1,62 @@ +{ + "typeName": "AWS::NetworkManager::TransitGatewayRegistration", + "description": "The AWS::NetworkManager::TransitGatewayRegistration type registers a transit gateway in your global network. The transit gateway can be in any AWS Region, but it must be owned by the same AWS account that owns the global network. You cannot register a transit gateway in more than one global network.", + "sourceUrl": "https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-networkmanager.git", + "properties": { + "GlobalNetworkId": { + "description": "The ID of the global network.", + "type": "string" + }, + "TransitGatewayArn": { + "description": "The Amazon Resource Name (ARN) of the transit gateway.", + "type": "string" + } + }, + "taggable": false, + "additionalProperties": false, + "required": [ + "GlobalNetworkId", + "TransitGatewayArn" + ], + "createOnlyProperties": [ + "/properties/GlobalNetworkId", + "/properties/TransitGatewayArn" + ], + "primaryIdentifier": [ + "/properties/GlobalNetworkId", + "/properties/TransitGatewayArn" + ], + "handlers": { + "create": { + "permissions": [ + "networkmanager:RegisterTransitGateway" + ], + "timeoutInMinutes": 30 + }, + "read": { + "permissions": [ + "networkmanager:GetTransitGatewayRegistrations" + ] + }, + "list": { + "handlerSchema": { + "properties": { + "GlobalNetworkId": { + "$ref": "resource-schema.json#/properties/GlobalNetworkId" + } + }, + "required": ["GlobalNetworkId"] + }, + "permissions": [ + "networkmanager:GetTransitGatewayRegistrations" + ] + }, + "delete": { + "permissions": [ + "networkmanager:DeregisterTransitGateway" + ], + "timeoutInMinutes": 30 + } + } +} + \ No newline at end of file From 42dce43b007c0f069ddac6354b88c17c9d1d821d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 23 Jun 2023 16:26:36 -0400 Subject: [PATCH 4/4] Add CHANGELOG entry. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 535c8be..bb1a2d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v0.21.0 (Unreleased) + +Support [`handlers.handlerSchema`](https://github.com/aws-cloudformation/cloudformation-resource-schema#handlers). + ## v0.20.0 (December 19, 2022) Support [`arrayType`](https://github.com/aws-cloudformation/cloudformation-resource-schema#arraytype).