Generating CloudFormation Resource Schemas from Smithy#

This guide describes how Smithy models can generate CloudFormation Resource Schemas.

Introduction#

CloudFormation Resource Schemas are the standard method of modeling a resource provider for use within CloudFormation. These schemas can then be used to develop the resource provider for support in CloudFormation. Generating Resource Schemas automatically from Smithy resources removes the duplicate effort of specifying them.

AWS CloudFormation traits define how CloudFormation Resource Schemas should be generated from Smithy resources. Automatically generating schemas from a service's API lowers the effort needed to generate and maintain them, keeps the schemas in sync with any changes to the Smithy model, reduces the potential for errors in the translation, and provides a more complete depiction of a resource in its schema. These schemas can be utilized by the CloudFormation Command Line Interface to build, register, and deploy resource providers.

Other traits may also influence CloudFormation Resource Schema generation.

Differences between Smithy resources and CloudFormation Resource Schemas#

Smithy and CloudFormation have different approaches to modeling resources. In Smithy, a resource is an entity with an identity that has a set of operations. CloudFormation resources are defined as a collection of properties and their attributes, along with additional information on which properties are identifiers or have restrictions on their mutability.

Generating Schemas with smithy-build#

The cloudformation plugin contained in the software.amazon.smithy:smithy-aws-cloudformation package can be used with either the Smithy Gradle plugin or Smithy CLI to generate CloudFormation Resource Schemas from Smithy models.

The following example shows how to generate CloudFormation Resource Schemas from a Smithy model using the Smithy CLI:

smithy-build.json#
{
    "version": "1.0",
    "maven": {
        "dependencies": [
          "software.amazon.smithy:smithy-aws-cloudformation:1.48.0",
          // Required for @service trait
          "software.amazon.smithy:smithy-aws-traits:1.48.0"
        ]
    },
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy"
        }
    }
}

Important

A dependency on "software.amazon.smithy:smithy-aws-cloudformation:1.48.0" is required in order for smithy-build to map the "cloudformation" plugin name to the correct Java library implementation.

The following example shows how to configure Gradle to generate CloudFormation Resource Schemas from a Smithy model using a build-only dependency:

build.gradle.kts#
plugins {
    java
    id("software.amazon.smithy.gradle.smithy-jar").version("1.0.0")
}

dependencies {
    smithyBuild("software.amazon.smithy:smithy-aws-cloudformation:1.48.0")
    // Required for @service trait
    implementation("software.amazon.smithy:smithy-aws-traits:1.48.0")
}
build.gradle#
plugins {
    id 'java'
    id 'software.amazon.smithy.gradle.smithy-jar' version '1.0.0'
}

dependencies {
    smithyBuild 'software.amazon.smithy:smithy-aws-cloudformation:1.48.0'
    // Required for @service trait
    implementation 'software.amazon.smithy:smithy-aws-traits:1.48.0'
}

Important

A build-only dependency on "software.amazon.smithy:smithy-aws-cloudformation:1.48.0" is required in order for smithy-build to map the "cloudformation" plugin name to the correct Java library implementation.

The Smithy Gradle plugin relies on a smithy-build.json file found at the root of a project to define the actual process of generating the CloudFormation Resource Schemas. The following example defines a smithy-build.json file that generates a CloudFormation Resource Schemas for the specified resource shapes bound to the smithy.example#Queues service using the Smithy organization.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy"
        }
    }
}

AWS Service teams SHOULD NOT set the organizationName property, and instead use the cloudFormationName property of the aws.api#service trait. The following configuration and model would generate one Resource Schema with the typeName of AWS:Queues:Queue.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#QueueService",
        }
    }
}
model.smithy#
$version: "2"

namespace smithy.example

use aws.api#service

@service(sdkId: "Queues", cloudFormationName: "Queues")
service QueueService {
    version: "2020-07-02"
    resources: [Queue]
}

CloudFormation configuration settings#

The cloudformation plugin provides configuration options to influence the Resource Schemas that it generates.

Tip

You typically only need to configure the service and organizationName settings to generate Resource Schemas.

The following settings are supported:

service (string)

Required. The Smithy service shape ID to convert. For example, smithy.example#Queues.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy"
        }
    }
}
organizationName (string)

The Organization component of the resource's type name. Defaults to "AWS" if the aws.api#service trait is present, otherwise is required.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy"
        }
    }
}
serviceName (string)

Allows overriding the Service component of the resource's type name. This value defaults to the cloudFormationName property of the aws.api#service trait if present, or the shape name of the specified service shape otherwise.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#QueueService",
            "organizationName": "Smithy",
            "serviceName": "Queues"
        }
    }
}
externalDocs ([string])

Limits the source of generated "documentationUrl" fields to the specified priority ordered list of names in an externalDocumentation trait. This list is case insensitive. By default, this is a list of the following values: "Documentation Url", "DocumentationUrl", "API Reference", "User Guide", "Developer Guide", "Reference", and "Guide".

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy",
            "externalDocs": [
                "Documentation Url",
                "Custom"
            ]
        }
    }
}
sourceDocs ([string])

Limits the source of generated "sourceUrl" fields to the specified priority ordered list of names in an externalDocumentation trait. This list is case insensitive. By default, this is a list of the following values: "Source Url", "SourceUrl", "Source", and "Source Code".

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy",
            "sourceDocs": [
                "Source Url",
                "Custom"
            ]
        }
    }
}
jsonAdd (Map<String, Map<String, Node>>)

Adds or replaces the JSON value in the generated Resource Schemas at the given JSON pointer locations with a different JSON value. The value must be a map where each key is a resource shape ID. The value is a map where each key is a valid JSON pointer string as defined in RFC 6901. Each value in the nested map is the JSON value to add or replace at the given target.

Values are added using similar semantics of the "add" operation of JSON Patch, as specified in RFC 6902, with the exception that adding properties to an undefined object will create nested objects in the result as needed.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy",
            "jsonAdd": {
                "smithy.example#Queue": {
                    "/info/title": "Replaced title value",
                    "/info/nested/foo": {
                        "hi": "Adding this object created intermediate objects too!"
                    },
                    "/info/nested/foo/baz": true
                }
            }
        }
    }
}
disableHandlerPermissionGeneration (boolean)

Sets whether to disable generating handler permission lists for Resource Schemas. By default, handler permissions lists are automatically added to schemas based on Resource lifecycle operations and permissions listed in the requiredActions property of the aws.iam#iamAction trait on the operation. See the handlers section in the CloudFormation Resource Schemas documentation for more information.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy",
            "disableHandlerPermissionGeneration": true
        }
    }
}

CloudFormation Resource Schema handlers determine what provisioning actions can be performed for the resource. The handlers utilized by CloudFormation align with some Resource lifecycle operations. These operations can also define other permission actions required to invoke them with the requiredActions property of the aws.iam#iamAction trait

When handler permission generation is enabled, all the actions required to invoke the operations related to the handler, including the actions for the operations themselves, are used to populate permission lists:

"handlers": {
    "create": {
        "permissions": [
            "dependency:GetDependencyComponent",
            "queues:CreateQueue"
        ]
    },
    "read": {
        "permissions": [
            "queues:GetQueue"
        ]
    },
    "update": {
        "permissions": [
            "dependency:GetDependencyComponent",
            "queues:UpdateQueue"
        ]
    },
    "delete": {
        "permissions": [
            "queues:DeleteQueue"
        ]
    },
    "list": {
        "permissions": [
            "queues:ListQueues"
        ]
    }
},
disableDeprecatedPropertyGeneration (boolean)

Sets whether to disable generating deprecatedProperties for Resource Schemas. By default, deprecated members are automatically added to the deprecatedProperties schema property. See the deprecatedProperties section in the CloudFormation Resource Schemas documentation for more information.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy",
            "disableDeprecatedPropertyGeneration": true
        }
    }
}
disableRequiredPropertyGeneration (boolean)

Sets whether to disable generating required for Resource Schemas. By default, required members are automatically added to the required schema property. See the required property section in the CloudFormation Resource Schemas documentation for more information.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy",
            "disableRequiredPropertyGeneration": true
        }
    }
}
disableCapitalizedProperties (boolean)

Sets whether to disable automatically capitalizing names of properties of Resource Schemas. By default, property names of resource schemas are capitalized if no cfnName trait is applied.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy",
            "disableCapitalizedProperties": true
        }
    }
}

JSON schema configuration settings#

defaultTimestampFormat (string)

Sets the assumed timestampFormat trait value for timestamps with no explicit timestampFormat trait. The provided value is expected to be a string. Defaults to "date-time" if not set. Can be set to "date-time", "epoch-seconds", or "http-date".

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy",
            "defaultTimestampFormat": "epoch-seconds"
        }
    }
}
schemaDocumentExtensions (Map<String, any>)

Adds custom top-level key-value pairs to all of the generated CloudFormation Resource Schemas. Any existing value is overwritten.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy",
            "schemaDocumentExtensions": {
                "x-my-custom-top-level-property": "Hello!",
                "x-another-custom-top-level-property": {
                    "can be": ["complex", "value", "too!"]
                }
            }
        }
    }
}
disableFeatures ([string])

Disables JSON schema and CloudFormation schema property names from appearing in the generated CloudFormation Resource Schemas.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy",
            "disableFeatures": ["propertyNames"]
        }
    }
}
useIntegerType (boolean)

Set to true to use the integer type when converting byte, short, integer, and long shapes.

By default, these shape types are converted with a type of number.

smithy-build.json#
{
    "version": "1.0",
    "plugins": {
        "cloudformation": {
            "service": "smithy.example#Queues",
            "organizationName": "Smithy",
            "useIntegerType": true
        }
    }
}

Other traits that influence generation#

In addition to the AWS CloudFormation traits, the following traits affect the generation of CloudFormation Resource Schemas.

documentation
When applied to a Resource shape, the contents will be converted into the description property of the generated Resource Schema.
externalDocumentation
When applied to a resource shape, the contents will be converted according to the externalDocs and sourceDocs settings.

Note

Custom traits defined in a Smithy model are not converted and added to CloudFormation Resource Schemas. Doing so requires the creation of a custom software.amazon.smithy.aws.cloudformation.schema.fromsmithy.Smithy2CfnExtension.

Generating Schemas with code#

Developers that need more advanced control over the generation of CloudFormation resources from Smithy can use the software.amazon.smithy:smithy-aws-cloudformation Java library to perform the generation.

First, you'll need to get a copy of the library. The following example shows how to install software.amazon.smithy:smithy-aws-cloudformation through Gradle:

build.gradle.kts#
dependencies {
    implementation("software.amazon.smithy:smithy-aws-cloudformation:1.48.0")
}
build.gradle#
dependencies {
    implementation 'software.amazon.smithy:smithy-aws-cloudformation:1.48.0'
}

Next, you need to create and configure a CloudFormationConverter:

import java.util.List;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.aws.cloudformation.schema.CfnConfig;
import software.amazon.smithy.aws.cloudformation.schema.fromsmithy.CfnConverter;
import software.amazon.smithy.aws.cloudformation.schema.model.ResourceSchema;

CfnConverter converter = CfnConverter.create();

// Add any necessary configuration settings.
CfnConfig config = new CfnConfig();
config.setService(ShapeId.from("smithy.example#Queues"));
config.setOrganizationName("Smithy");

// Generate the schemas.
List<ResourceSchema> schemas = converter.convert(myModel);

The conversion process is highly extensible through software.amazon.smithy.aws.cloudformation.schema.fromsmithy.Smithy2CfnExtension service providers. See the Javadocs for more information.