Coder Social home page Coder Social logo

bayer-group / cloudformation-template-generator Goto Github PK

View Code? Open in Web Editor NEW
211.0 35.0 71.0 13.03 MB

A type-safe Scala DSL for generating CloudFormation templates

License: BSD 3-Clause "New" or "Revised" License

Scala 96.52% HTML 0.07% Shell 1.02% JavaScript 2.39%

cloudformation-template-generator's Introduction

CloudFormation Template Generator

Build Status Coverage Status

Scala DSL to create AWS CloudFormation (CFN) templates. The library allows for easier creation of the AWS CloudFormation JSON by writing Scala code to describe the AWS resources. Lets say we have a handful of CFN templates we want to maintain, and all of those templates use the same AMI. Instead of copying that information into all the templates, lets create an AMI component instead, and then load it into the actual templates.

Why not just write JSON? Because, who in their right mind would want to write all AWS resources in JSON?

Documentation

See the intro blog post.

This library was previously hosted on BinTray, however, with the sunsetting of this service, it is now hosted on Maven Central. You no longer need to add a resolver to pull it in.

The library was previously published under the com.monsanto.arch group ID. With Bayer's acquisition of Monsanto long ago completed, we have renamed the group ID to com.bayer starting with version v3.10.3. Note that the actual Java/SBT packages themselves still use com.monsanto, as that's a more significant breaking change. Only the group ID in SBT/Maven has changed.

libraryDependencies ++= Seq (
  "com.bayer" %% "cloud-formation-template-generator" % "3.10.3"
).map(_.force())

to your build.sbt.

See the Scaladoc for detailed documentation and examples.

See the Change Log for information on new, changed, and deprecated featured.

Note: we are no longer using the git-flow develop/master branch paradigm. Please just branch off master and submit your PRs against it.

Components

Create a Template instance of resources and check out VPCWriter to help write it to a file.

To use the fancier parts of the routing DSL, be sure to import TransportProtocol._.

Misc Features

NEW since the blog post, say you have a topology with subnets across multiple AZ's and you want to specify an autoscaling group that spans them, using our fancy Builders methods. Well this is cross-cutting, so its not strictly nested, so you can use an evil evil var, or now you can use our Template.lookupResource[R <: Resource[R]](name: String) method on previous template parts to extract resources by name. Note this will produce a generation-time error if you lookup something that does not exist or has the wrong type (unfortunately not a generation-time compiler error as most of our other features):

describe("Template Lookup") {
  it("Should lookup resources with the correct type") {

    val expected = `AWS::EC2::VPC`(
      name = "TestVPC",
      CidrBlock = CidrBlock(0,0,0,0,0),
      Tags = Seq.empty[AmazonTag]
    )
    val template = Template.fromResource(expected)

    assert(expected === template.lookupResource[`AWS::EC2::VPC`]("TestVPC"))
}

Currently supported AWS resource types

  • AWS::ApiGateway::Account
  • AWS::ApiGateway::ApiKey
  • AWS::ApiGateway::Authorizer
  • AWS::ApiGateway::BasePathMapping
  • AWS::ApiGateway::ClientCertificate
  • AWS::ApiGateway::Deployment
  • AWS::ApiGateway::Method
  • AWS::ApiGateway::Model
  • AWS::ApiGateway::Resource
  • AWS::ApiGateway::RestApi
  • AWS::ApiGateway::Stage
  • AWS::ApiGateway::UsagePlan
  • AWS::ApiGateway::UsagePlanKey
  • AWS::ApplicationAutoScaling::ScalableTarget
  • AWS::ApplicationAutoScaling::ScalingPolicy
  • AWS::AutoScaling::AutoScalingGroup
  • AWS::AutoScaling::LaunchConfiguration
  • AWS::AutoScaling::ScalingPolicy
  • AWS::Batch::ComputeEnvironment
  • AWS::Batch::JobDefinition
  • AWS::Batch::JobQueue
  • AWS::CloudFormation::CustomResource
  • AWS::CloudFormation::Stack
  • AWS::CloudFormation::WaitCondition
  • AWS::CloudFormation::WaitConditionHandle
  • AWS::CloudFront::Distribution
  • AWS::CloudTrail::Trail
  • AWS::CloudWatch::Alarm::ComparisonOperator
  • AWS::CloudWatch::Alarm::Dimension
  • AWS::CloudWatch::Alarm::Namespace
  • AWS::CloudWatch::Alarm::Statistic
  • AWS::CloudWatch::Alarm::Unit
  • AWS::CloudWatch::Alarm
  • AWS::CodeBuild::Project
  • AWS::CodeCommit::Repository
  • AWS::CodePipeline::CustomActionType
  • AWS::CodePipeline::Pipeline
  • AWS::DataPipeline::Pipeline
  • AWS::DynamoDB::Table
  • AWS::EC2::CustomerGateway
  • AWS::EC2::EIP
  • AWS::EC2::EIPAssociation
  • AWS::EC2::Instance
  • AWS::EC2::InternetGateway
  • AWS::EC2::KeyPair::KeyName
  • AWS::EC2::NatGateway
  • AWS::EC2::NetworkAcl
  • AWS::EC2::NetworkAclEntry
  • AWS::EC2::Route
  • AWS::EC2::RouteTable
  • AWS::EC2::SecurityGroup
  • AWS::EC2::SecurityGroupEgress
  • AWS::EC2::SecurityGroupIngress
  • AWS::EC2::Subnet
  • AWS::EC2::SubnetNetworkAclAssociation
  • AWS::EC2::SubnetRouteTableAssociation
  • AWS::EC2::VPC
  • AWS::EC2::VPCEndpoint
  • AWS::EC2::VPCGatewayAttachment
  • AWS::EC2::VPCPeeringConnection
  • AWS::EC2::VPNConnection
  • AWS::EC2::VPNConnectionRoute
  • AWS::EC2::VPNGateway
  • AWS::EC2::Volume
  • AWS::EC2::VolumeAttachment
  • AWS::ECR::Repository
  • AWS::ECS::Cluster
  • AWS::ECS::Service
  • AWS::ECS::TaskDefinition
  • AWS::EFS::FileSystem
  • AWS::EFS::MountTarget
  • AWS::EKS::Cluster
  • AWS::EMR::Cluster
  • AWS::EMR::Step
  • AWS::ElastiCache::CacheCluster
  • AWS::ElastiCache::SubnetGroup
  • AWS::ElasticBeanstalk::Application
  • AWS::ElasticBeanstalk::ApplicationVersion
  • AWS::ElasticBeanstalk::ConfigurationTemplate
  • AWS::ElasticBeanstalk::Environment
  • AWS::ElasticLoadBalancing::LoadBalancer
  • AWS::ElasticLoadBalancingV2::Listener
  • AWS::ElasticLoadBalancingV2::ListenerRule
  • AWS::ElasticLoadBalancingV2::LoadBalancer
  • AWS::ElasticLoadBalancingV2::TargetGroup
  • AWS::Elasticsearch::Domain
  • AWS::Events::Rule
  • AWS::IAM::AccessKey
  • AWS::IAM::Group
  • AWS::IAM::InstanceProfile
  • AWS::IAM::ManagedPolicy
  • AWS::IAM::Policy
  • AWS::IAM::Role
  • AWS::IAM::User
  • AWS::KMS::Alias
  • AWS::KMS::Key
  • AWS::Kinesis::Stream
  • AWS::KinesisFirehose::DeliveryStream
  • AWS::Lambda::Alias
  • AWS::Lambda::EventSourceMapping
  • AWS::Lambda::Function
  • AWS::Lambda::Permission
  • AWS::Lambda::Version
  • AWS::Logs::Destination
  • AWS::Logs::LogGroup
  • AWS::Logs::LogStream
  • AWS::Logs::MetricFilter
  • AWS::Logs::SubscriptionFilter
  • AWS::RDS::DBInstance::Engine
  • AWS::RDS::DBInstance::LicenseModel
  • AWS::RDS::DBInstance::StorageType
  • AWS::RDS::DBInstance
  • AWS::RDS::DBParameterGroup
  • AWS::RDS::DBSecurityGroup
  • AWS::RDS::DBSubnetGroup
  • AWS::Redshift::Cluster
  • AWS::Redshift::ClusterParameterGroup (along with helper RedshiftClusterParameter type)
  • AWS::Redshift::ClusterSecurityGroup
  • AWS::Redshift::ClusterSecurityGroupIngress
  • AWS::Redshift::ClusterSubnetGroup
  • AWS::Route53::HostedZone
  • AWS::Route53::RecordSet
  • AWS::S3::Bucket
  • AWS::S3::BucketPolicy
  • AWS::SNS::Subscription
  • AWS::SNS::Topic
  • AWS::SNS::TopicPolicy
  • AWS::SQS::Queue
  • AWS::SQS::QueuePolicy
  • AWS::SSM::Association
  • AWS::SSM::Document
  • AWS::SSM::Parameter
  • AWS::SecretsManager::ResourcePolicy
  • AWS::SecretsManager::RotationSchedule
  • AWS::SecretsManager::Secret
  • AWS::SecretsManager::SecretTargetAttachment

Custom types

This project packages certain useful custom CloudFormation types. These are Lambda backed types that perform tasks that CloudFormation does not natively support. In order to use them, you must upload the Lambda function to your account and region. The code for these functions is found in this repo under assets/custom-types.

Remote Route 53 entries

A given domain (or hosted zone, more specifically) must be managed out of a single AWS account. This poses problems if you want to create resources under that domain in templates that will run out of other accounts. A CloudFormation template can only work in one given account. However, with Cloud Formation's custom type functionality, we use custom code to assume a role in the account that owns the hosted zone. This requires some setup steps for each hosted zone and each account. For instructions, please see: https://github.com/bayer-group/cloudformation-template-generator/blob/master/assets/custom-types/remote-route53/README.md for more.

Working with Cloudformation Concatenating

In the CloudFormation DSL, there is support for concatenating strings, parameters, and function calls together to build strings. This can get really ugly as they are chained together. There is a string interpolator to make this easier.

Update 11/17/2016: While we are not deprecating this functionality at this time, CFTG now supports Fn::Sub, a native way to do something very similar. It can replace both Fn::Join and many uses of Fn::GetAtt. Read more here.

Releasing

Make sure the changes for the release are included in CHANGELOG.md.

This project uses the sbt release plugin. After the changes you want to release are committed on the master branch, you simple need to run two commands to publish the library and its documentation.

sbt release
sbt ghpagesPushSite

After publishing, create a new release under Github releases, copying the portion of the change log for this release from CHANGELOG.md.

cloudformation-template-generator's People

Contributors

ajwdev avatar anelson avatar awouda avatar bderickson avatar bkrodgers avatar bpholt avatar carsonfarrell avatar chrisshafer avatar ddgenome avatar dickwall avatar eanderson13 avatar easel avatar elyzion avatar ericbmerritt avatar hibikir avatar jcallin avatar jfklingler avatar joewing avatar koshyvineet avatar linuxfreakus avatar phucnh avatar ryan-richt avatar seanmcl avatar tjcorr avatar tylersouthwick avatar zomboc0m avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cloudformation-template-generator's Issues

Add support for standard amazon policies

I want to make an AWS::IAM::Role that utilizes an AWS Managed Policies. Currently we require
policies to passed in like ManagedPolicyArns: Option[Seq[ResourceRef[AWS::IAM::ManagedPolicy]]]. Unfortunately, I can't build a ResourceRef for the AWS Managed Policies since they only have an ARN. We need to build some new mechanism to allow these to be passed in as well. Ideally we should support a list of both AWS and customer managed policies

Fix `Fn::Not`, `Fn::And`, and `Fn::Or`

In issue #57, our good friend @ddgenome changed Fn::Not, Fn::And, and Fn::Or to require a ConditionRef. As I'm working to update our usage of the library to the new version, I'm now realizing this is not correct. These functions can accept more than just a ConditionRef. They can accept themselves, along with Fn::Equals, in addition to accepting a reference to a defined condition. For example, a condition that checks if a given parameter is not blank would look like this:

``Fn::Not(Fn::Equals`(a = ParameterRef(serviceELBSubdomainNameParameter), b = StringToken("")))`

The only way to make that work in the new model is to define the equals as a intermediate condition, even if I don't ever plan to use it, and then define an additional condition for the Not.

Similarly, if you wanted to do a compound condition that nests Ands and Ors together, you'd have to define an intermediate condition for each component of that.

Of course the easiest "fix" is to back this out and go back to Token[String], but a better solution would be to come up with a type structure that allows the valid types of Fn::Not, Fn::And, Fn::Or, Fn::Equals, and ConditionRef. I have to admit that I'm still not quite a master of the type system enough to see exactly how to do this, though I'm trying to figure it out. @ddgenome or anyone else, if you have thoughts on this, please let me know.

I do believe the change to Fn::If is correct, however. It does require a named condition.

Typing issues when nesting templates

CFTG's type safety starts causing problems when trying to reference one template as a stack inside another. An example of this is if you want to have your core VPC structure in one template, include that as a AWS::CloudFormation::Stack, and then put instances into the VPC's subnets from your main template.

To do this in regular CFN, you would expose the subnet IDs as Outputs in the VPC template, and then reference them with a GetAtt, such as like this:

"SubnetId": {
     "Fn::GetAtt": ["VPCStack", "Outputs.PrivateSubnet2"]
}

However, our implementation of AWS::EC2::Instance expects Subnet ID as follows:

SubnetId:               Token[ResourceRef[`AWS::EC2::Subnet`]]

Our implementation of Fn::GetAtt is typed only to String, so we can't pass it in as something that meets the AWS::EC2::Subnet criteria.

This is an issue throughout the library -- anywhere where you may want to reference something from a parent template, if that resource's parameter is typed, you're out of luck. There's an assumption in the library that you're going to reference something you've defined within the template, and thus you'll have a typed reference to pass in. That's no longer the case when we start nesting and want to reference things with GetAtt

Of course none of this is a problem in CloudFormation itself, since all of this serializes down to simple strings in the JSON output. This is just an issue with our stronger typing.

DynamoDB DependsOn attribute requires a single string, not a list

The AWS::DynamoDB:Table case class derives from Resource, which has a DependsOn field of type Seq[String]. This is incompatible with the CloudFormation format for DynamoDB, which requires a single string for the DependsOn attribute - if an array of strings is given instead, it is ignored.

PolicyStatement Missing Sid Element required by SNS Topic Policy?

When I try to create an SNS Topic Policy that contains multiple policy statements, I get an error from CloudFormation: โ€œInvalid parameter: Every policy statement must have a unique ID.โ€

Here's an example of the topic policy I'd like to create:

val topicPolicy = `AWS::SNS::TopicPolicy`("TopicPolicy",
  PolicyDocument = PolicyDocument(Statement = Seq(
    PolicyStatement(
      Effect = "Allow",
      Action = Seq(
        "sns:Publish"
      ),
      Principal = Option(DefinedPrincipal(Map("Service" โ†’ Seq("cloudformation.amazonaws.com")))),
      Resource = Option(ResourceRef(topic))
    ),
    PolicyStatement(
      Effect = "Allow",
      Action = Seq(
        "sns:Publish"
      ),
      Principal = Option(DefinedPrincipal(Map("AWS" โ†’ Seq(`Fn::Sub`("arn:aws:iam::${AWS::AccountId}:user/bholt"))))),
      Resource = Option(ResourceRef(topic))
    )
  )),
  Topics = Seq(topic)
)

I think this might be because PolicyStatement is missing a Sid field, because if I manually edit the generated JSON and add Sid elements with unique values to each policy statement, the stack creates successfully.

I wondered if someone else is using this successfully, and if so, could share an example of how they do it? If not, is there a reason that Sid is not currently part of PolicyStatement?

Missing Support for OpsWorks

I am willing to implement this, but have a question about how to implement the CustomJson field, as it must serialize to a Json object, rather than a string containing json.

The correct output would be of the following format:

{ "field": { "subObjectField": "value" } }

Rather than

{"field" : " { \"subObjectField\" : \"value\" } "}

As far as I can see there is no other field like this currently implemented.

Make regions and availability zones objects rather than strings

Something like:

sealed trait `AWS::Region`
object `AWS::Region` extends DefaultJsonProtocol {
  case object `AWS::Region::us-east-1` extends `AWS::Region`
  case object `AWS::Region::us-west-1` extends `AWS::Region`
  ...

  implicit val format: JsonFormat[AWSRegions] = new JsonFormat[AWSRegions] {
    override def write(obj: AWSRegions)= JsString(obj.toString)
    override def read(json: JsValue): AWSRegions = {
      json.toString match {
        case "us-east-1"  => `AWS::Region::us-east-1`
        case "us-west-1" => `AWS::Region::us-west-1`
        ...
      }
    }
  }
}

Change `Path` type in IAM resources to be `Token[String]`

AWS::IAM::InstanceProfile and AWS::IAM::ManagedPolicy specify the type of Path to be String and Option[String], respectively. These should be changed to Token[String] and Option[Token[String]].

AWS::IAM::User, AWS::IAM::Role, and AWS::IAM::Group are already using Token[String] as the Path type.

Add additional fields to s3 notification for lambda

Add DependsOn parameter to AWS::ECS::Service and AWS::ECS::Cluster

CloudFormation fails to create an ECS service with the error Unable to assume role and validate the specified targetGroupArn. Please verify that the ECS service role being passed has the proper permissions. when the role does not yet exist.

http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-dependson.html#gatewayattachment indicates that

When you use Auto Scaling or Amazon Elastic Compute Cloud (Amazon EC2) to create container instances for an Amazon ECS cluster, the Amazon ECS service resource must have a dependency on the Auto Scaling group or Amazon EC2 instances, as shown in the following snippet. That way the container instances are available and associated with the Amazon ECS cluster before AWS CloudFormation creates the Amazon ECS service.

Add support for AWS::Logs resources

Add support for the following CloudFormation resources:

  • AWS::Logs::Destination
  • AWS::Logs::LogGroup
  • AWS::Logs::LogStream
  • AWS::Logs::MetricFilter
  • AWS::Logs::SubscriptionFilter

Add support for Redshift

Model currently lacking Redshift support. I will take a stab, should be pretty easy to add aside from the number of properties on the cluster object which Spray may not like so much.

Add support for Application Load Balancers (ELBV2)

Change `AWS::RDS::DBInstance`'s `Option[A]`s to `Option[Token[A]]`

Now that I've used CFTG for a while, it's become pretty obvious that almost everything should be a Token[A] to support parameters, functions, etc.

I propose changing the following parameters of AWS::RDS::DBInstance to support Token types:

  • AllowMajorVersionUpgrade
  • AutoMinorVersionUpgrade
  • AvailabilityZone
  • BackupRetentionPeriod
  • DBSnapshotIdentifier
  • EngineVersion
  • MultiAZ
  • OptionGroupName
  • PreferredBackupWindow
  • PreferredMaintenanceWindow
  • PubliclyAccessible
  • StorageEncrypted

Add support for Fn::Split

The library is missing support for the Fn::Split intrinsic function, which would be useful for e.g. importing a list of subnets from a VPC stack into a stack defining a Lambda that needs to run in that VPC.

I am preparing a pull request that adds support for Fn::Split.

Using existing resources with builders

Hi,

I recently stumbled across your work and I'm busy rewriting my Cfndsl templates to Scala using it. One issue that I have is that I use an existing VPC in my templates, so I have a token (or parameter) for my VPC. The builders provided by cloudformation-template-generator however require a proper AWS::EC2::VPC or similar implicit. (Specifically, withVPC and withSubnet are being issues.)

Is there an easy way to convert my token (or parameter) to a resource type, or will I have to fork and extend the project?

Clean up 24 Methods with `???` Bodies

There's 24 methods within this code-base that will throw.

???

scala> ???
scala.NotImplementedError: an implementation is missing
  at scala.Predef$.$qmark$qmark$qmark(Predef.scala:230)
  ... 30 elided

Reference to 24

$pwd
/.../cloudformation-template-generator
$grep -r 'def read' src/main/ | grep '???' | wc -l
      24

I'm guessing that most of them are due to a non-implemented read that's likely not used in practice.

  implicit def format2: JsonFormat[ResourceRef[_]] = new JsonFormat[ResourceRef[_]] {
    def write(obj: ResourceRef[_]) = AmazonFunctionCall.format.write(obj)

    //TODO: Implement Readers, but this is necessary to get Seq[T] JsonFormat for ResourceRef's
    def read(json: JsValue) = ???
  }

If the read, i.e. JsValue => A method is not needed, then, I would expect that only a JsonWriter instance should be provided.

Using ParameterRef[CidrParameter] as a Token[String]

There are use cases in which you might want to use a ParameterRef within a Fn::Join. This works just fine for String/Int parameters. However if the case of a CidrParameter or IPAddress you end up with a Token[CidrParameter] instead of a Token[String].

Example code:

import com.monsanto.arch.cloudformation.model._
import com.monsanto.arch.cloudformation.model.resource._
import com.monsanto.arch.cloudformation.model.simple.Builders._
import TransportProtocol._
import spray.json._
import DefaultJsonProtocol._
โ€‹
object Broke {
  val vpcCidrBlockParameter = CidrBlockParameter(
    name        = "VPCCIDR",
    Default     = CidrBlock(10,0,0,0,16),
    Description = "The VPC net block (CIDR)"
  )
  val sParameter = StringParameter(
    name        = "Stringy",
    Default     = "nothing",
    Description = "Something"
  )
  val vpcTemplate = withVpc(ParameterRef(vpcCidrBlockParameter)) { implicit vpc =>
    withAZ("us-east-1a") { implicit az =>
      withSubnet("Subnet", CidrBlock(10, 0, 0, 0, 24)) { implicit subnet =>
        val instance = `AWS::EC2::Instance`(
          name = "simple",
          InstanceType = "t2.micro",
          KeyName = "none",
          SubnetId = subnet,
          ImageId = AMIId("blech"),
          Tags = Seq(),
          SecurityGroupIds = Seq(),
          UserData = Some(`Fn::Base64`(`Fn::Join`("", Seq(
            "foo",
            ParameterRef(sParameter), // this is fine
            "bar",
            ParameterRef(vpcCidrBlockParameter), // comment this out and all is cool 

           /* hacky solution
           Token.fromFunction(ParameterRef(vpcCidrBlockParameter)).asInstanceOf[Token[String]]
           */
            "baz"
          ))))
        )
        Template.fromResource(instance)
      }
    }
  }
}

Thanks to @ddgenome for reporting.

RDS | DBSubnetGroup should be able to take SubnetIds as ParameterRef

Currently, DBSubnetGroup expects users to pass in SubnetIds as Seq of ResourceRefs and hence does not support ParameterRef.

I attempted to make code changes to allow for this, but it seems like it's hard to do this without breaking backward compatibility. The main issue is that the output JSON in case of ParameterRef needs to be like:
"SubnetIds": {"Ref": "subnets"}
instead of the usual (when subnets are passed as Seq of ResourceRef):

SubnetIds": [
  {"Ref": "subnet1"},
  {"Ref": "subnet2",
]

Here is what I tried:

  1. Create a new AWS::EC2::Subnet_Parameter_List type that has AWS Type as ListAWS::EC2::Subnet::Id and Rep = Seq[AWS::EC2::Subnet].

  2. Change the type of SubnetIds to Seq[Token[ResourceRef[AWS::EC2::Subnet]]] but this results in incorrect json.
    SubnetIds": [ {"Ref": "subnets"} ]

  3. Change the type of SubnetIds to Token[Seq[ResourceRef[AWS::EC2::Subnet]]] but the implicit conversion from Resource to ResourceRef does not kick in (Token[Seq[Resource]] does not implicit convert to Token[Seq[ResourceRef]]).

  4. Introduce a new ResourcesRef type like:

    case class ResourcesRef[R <: Resource[R]](rs: Seq[R]) {
    val arguments = rs.map(r => ResourceRef(r))
    def serializeArguments = arguments.toJson
    }
    object ResourcesRef extends DefaultJsonProtocol {
    
    implicit def fromResourceRefs[R <: Resource[R]](rs: Seq[ResourceRef[R]]): ResourcesRef[R] = ResourcesRef(rs.map(_.r))
    
    implicit def fromParameterRef[R <: Resource[R]](parameterRef: ParameterRef[Seq[R]]): ResourcesRef[R] = {
    ???
    }
    
    implicit def format[R <: Resource[R]]: JsonFormat[ResourcesRef[R]] = new JsonFormat[ResourcesRef[R]] {
      def write(obj: ResourcesRef[R]) = obj.serializeArguments
    
      //TODO: Implement Readers, but this is necessary to get Seq[T] JsonFormat for ResourceRef's
      def read(json: JsValue) = ???
    }
    }
    

    but as you can see, I can't figure out how to convert ParameterRef to ResourcesRef.

Any guidance on this will be much appreciated.

Scala 2.12 Artifact

It looks like #122 added support for Scala 2.12, but I don't see an artifact published in JCenter. Am I just missing something or is publishing for 2.12 not enabled yet?

Add support for Cognito

Have predictable order in the output JSON

Every time I add or remove objects (resources, parameters, etc.), the output JSON is completely shuffled. After I make a change to the Scala code, I'd like to review the change in the output JSON. The random order makes it very difficult.

Add support for creating Route 53 alias records by hosted zone ID

AWS::Route53::RecordSet currently has generalRecord() and generalRecordByID() to support creating record sets by either the hosted zone name or ID. Alias records, which must be created differently than other record types, can only be created with a hosted zone name. This prevents creating alias records when more than one hosted zone have the same name (for example, internal hosted zones for multiple VPCs that all have the same name like "internal.company.com").

Question - Using ParameterRef where Token[ResourceRef[`AWS::SOME::SERVICE`]] is expected

Hey, I really like the work you've done here. Not an expert in scala so I'm just wondering if there is a better way to do what I need.

Currently the RouteTableId parameter for AWS::EC2::Route is a Token[ResourceRef[AWS::EC2::RouteTable]]. However in my case the default route table is already created in aws and is passed in as a parameter.

So I need to do

AWS::EC2::Route`(
    name = "RouteToMainVpc",
    RouteTableId = ParameterRef(defaultVpcRouteTableIdParameter),
    DestinationCidrBlock = cidrBlock,
    connectionBobber = VPCPeeringRoute(vpcPeeringConnection)
  )

That doesn't work, but if I change the signature of that parameter to Token[String]. Then everything seems to be good. I imagine what I've done is remove the type safety, can you explain how you decide on using Token[String] vs Token[ResourceRef[some_aws_thing]].

Thanks

"Range / Protocol" notation in Ingress rule DSL fails compilation

See guoshimin@cf2ac98

> test
[warn] Credentials file /Users/shimin/.bintray/.credentials does not exist
[info] Compiling 7 Scala sources to /Users/shimin/src/github.com/guoshimin/cloudformation-template-generator/target/scala-2.11/test-classes...
[error] /Users/shimin/src/github.com/guoshimin/cloudformation-template-generator/src/test/scala/com/monsanto/arch/cloudformation/model/TemplateDoc_AT.scala:91: value / is not a member of scala.collection.immutable.Range.Inclusive
[error]               val sshToBastion = ParameterRef(allowSSHFromParameter) ->- (22 to 22) / TCP ->- bastion
[error]                                                                                     ^
[error] one error found
[error] (test:compileIncremental) Compilation failed
[error] Total time: 7 s, completed Aug 11, 2015 9:38:26 AM

Scala 2.10 Support

It would be helpful to build this project for Scala 2.10 to enable more easily using it from sbt. For example, we have Scala services that are assembled to either jars uploaded to S3 (e.g. for AWS Lambda functions) or Docker images published to our private Docker registry. In both cases, the publishing happens from an sbt plugin. It would be great to define a CloudFormation stack as part of the build and have it created or updated by executing something like sbt deploy.

However, since sbt is essentially a version behind Scala itself (sbt 0.13 is compiled with Scala 2.10), it's not easy to include this library as a dependency of an sbt 0.13 plugin. I'm working around it now by including the CloudFormation code as a sub-project that writes the template to a local file. sbt runs the sub-project, reads in the generated file, and then uses the AWS SDK to create or update the CloudFormation stack. This is inconvenient in several ways, as you can imagine.

I tried compiling the library using 2.10, but ran into problems with case classes with more than 22 parameters. Before I try refactoring those case classes, I wanted to get some feedback on the overall goal, and whether, in the end, you're open to supporting Scala 2.10.

Consider cross compiling for 2.10

Hello!

Love this project! Exactly what I was looking for - I wanted to create a SBT plugin for my project which when executing release task - would also auto generate the cloudformation task definition templates. This sbt plugin would glean the necessary information from the build settings to generate the template.

However, more than a quarter of my sbt plugins have not been cross compiled for 2.11.

Would it be possible to compile and release this library against scala 2.10?

Thank you for considering my request!

Using version:

"com.monsanto.arch" % "cloud-formation-template-generator_2.11" % "3.6.0"

`AWS::CloudFormation::Stack` should at least take Map[String, Token[String]]

Right now AWS::CloudFormation::Stack takes [Map[String, String]], which only allows for hard coded parameter values. At the very least, we want values to be a Token[String] so that we can reference parameters to this template that we want to pass through to the nested template.

Even this isn't perfect, however, since we have parameter types that are typed more strongly than string. For example, to pass a CidrBlockParameter through, we'd have to "convert" it to a StringParameter as follows:

ParameterRef(StringParameter(vpcCidrParameter.name))

This seems hacky, especially since the "conversion" here is only to satisfy the type system...the underlying JSON generated is the same. Should see if we can come up with some implicit conversions.

Missing support for Lambda Alias and Version resources

As of 3.3.4 there is no support for the AWS::Lambda::Alias or AWS::Lambda::Version resource types. This is required for many deployment scenarios including mine.

I've implemented this in a fork and will be submitting a PR shortly.

Merge master back into develop?

Seems like at some point (my fault I'm sure) we had a number of direct-to-master commits, should we merge those back into develop and get back to the standard flow? @ddgenome is that the way to fix it?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.