I created a new CloudFormation resource in the
AwsCommunity organization with Python, created a new Troposphere resource for it, and now can use it in production.
AWS CloudFormation (CFN) is my favorite Infrastructure as Code (IaC) service to use with AWS. However, some resources might not have a CloudFormation equivalent created by the respective product team, for various possible reasons.
So then, you have to either use another IaC tool (i.e. Ansible), create a CustomResource (lambda function invoked by CFN), or you could create your own AWS Resource and publish it for everyone else on AWS to use, with the AWS CloudFormation Registry
The CFN team has created a set of tools and libraries in different languages to allow people to author their own resources.
I created a few myself before, and published these out of my own AWS Accounts. But this time instead of doing this all on my own, I had the opportunity to contribute to the Open Source community driven repository on GitHub. Great place to see what already existed, and have other people actually help and review my code.
If you are used the workflows of CloudFormation resources provisioning and the different stages it goes through, this is a very painless process. And to make the whole process even less so painful, you can (and definitely should) run contract testing locally using the
sam cli which will validate that your code passes all the different use-cases it should.
As mentioned, being a seasoned CloudFormation user, creating a CFN template to publish my resource and create a StackSet to publish it in all AWS regions isn't difficult, but it can be very daunting.
Joining the AWS Community driven repository will remove that concern away from you as the friendly & helpful team at AWS have automated the whole process for you, and will be publishing your resource as part of the
Once the resource is published on AWS, you need only to activate it in your account. This will require you to create an IAM role to allow the resource to perform actions on your behalf. You can also, optionally, have logging output sent to your AWS Account, which can help with your audits and security posture.
After you have activated the resource, you can start using it in your CloudFormation templates, like any other resource. The resource will return attributes, so you can use functions like Fn::GetAtt, Fn::Ref or Fn::Sub and so on.
Here is a snippet of how the resource would be used in a CloudFormation template
AWSTemplateFormatVersion: "2010-09-09" Description: Template to test AwsCommunity::ApplicationAutoscaling::ScheduledAction Parameters: ScheduledActionName: Type: String Default: cfn-testing-resource ServiceNamespace: Type: String AllowedValues: [ "ecs", "elasticmapreduce", "ec2", "appstream", "dynamodb", "rds", "sagemaker", "custom-resource", "comprehend", "lambda", "cassandra", "kafka", "elasticache", "neptune" ] ScalableDimension: Type: String AllowedValues: [ "ecs:service:DesiredCount", "ec2:spot-fleet-request:TargetCapacity", "elasticmapreduce:instancegroup:InstanceCount", "appstream:fleet:DesiredCapacity", "dynamodb:table:ReadCapacityUnits", "dynamodb:table:WriteCapacityUnits", "dynamodb:index:ReadCapacityUnits", "dynamodb:index:WriteCapacityUnits", "rds:cluster:ReadReplicaCount", "sagemaker:variant:DesiredInstanceCount", "custom-resource:ResourceType:Property", "comprehend:document-classifier-endpoint:DesiredInferenceUnits", "comprehend:entity-recognizer-endpoint:DesiredInferenceUnits", "lambda:function:ProvisionedConcurrency", "cassandra:table:ReadCapacityUnits", "cassandra:table:WriteCapacityUnits", "kafka:broker-storage:VolumeSize", "elasticache:replication-group:NodeGroups", "elasticache:replication-group:Replicas", "neptune:cluster:ReadReplicaCount" ] MinCapacity: Type: Number MinValue: 0 MaxCapacity: Type: Number MinValue: 0 ScheduleExpression: Type: String Description: the cron(), rate() or at() expression. EndTime: Type: String Default: none Description: When using cron() or rate(), timestamp of when the rule expires. StartTime: Type: String Default: none Description: When using cron() or rate(), timestamp of when the rule starts. TimeZone: Type: String Default: "UTC" ResourceId: Type: String Description: The Scalable Target ID. Conditions: NoEndTime: !Equals [ !Ref EndTime, "none" ] NoStartTime: !Equals [ !Ref StartTime, "none" ] Resources: ScheduledActionForScalableTarget: Type: AwsCommunity::ApplicationAutoscaling::ScheduledAction Properties: ScheduledActionName: !Ref ScheduledActionName ServiceNamespace: !Ref ServiceNamespace ScalableDimension: !Ref ScalableDimension Schedule: !Ref ScheduleExpression ScalableTargetAction: MinCapacity: !Ref MinCapacity MaxCapacity: !Ref MaxCapacity StartTime: !If - NoStartTime - !Ref AWS::NoValue - !Ref StartTime EndTime: !If - NoEndTime - !Ref AWS::NoValue - !Ref StartTime Timezone: !Ref TimeZone ResourceId: !Ref ResourceId
If you have read my earlier posts or heard me talk with Corey on Screaming in the Cloud, I am the author of a tool called ECS Compose-X. It's designed to support all the docker compose features, and allow for extensions that make it easier to deploy to AWS.
Because ECS Compose-X uses Troposphere, I was able to create a very light and simple python library(https://github.com/JohnPreston/troposphere-awscommunity-applicationautoscaling-scheduledaction) to distribute the resource for other Troposphere users to re-use.
Naturally, as autoscaling was already implemented in the project, this was a natural addition to the x-scaling services feature. This particular resource allows to plan for scaling your ECS service when you need to, and scale back down accordingly.
Creating AWS Resource for CloudFormation might seem like something like you shouldn't have to do, but I see it as a great way to contribute back to the community and to a service I love. And doing so, I hope, will help people who might trying to achieve the same thing.
But it is not limited to AWS resources: MongoDB, NewRelic, DataDog and other AWS partners have taken advantage of this capability to publish their own resources, allowing AWS customers to rely on AWS CloudFormation to provision their resources.
I am not a CDK user, but one could also now create a CDK extension to provision that resource in their code.
Big shoutout to the AWS CloudFormation team (@ericzbeard, @kddejong) & contributors for having helped me out and look forward to seeing more exciting resources and projects coming up!