diff --git a/src/main/scala/com/monsanto/arch/cloudformation/model/resource/Route53.scala b/src/main/scala/com/monsanto/arch/cloudformation/model/resource/Route53.scala index 5f4a5a3e..a53757fe 100644 --- a/src/main/scala/com/monsanto/arch/cloudformation/model/resource/Route53.scala +++ b/src/main/scala/com/monsanto/arch/cloudformation/model/resource/Route53.scala @@ -7,7 +7,45 @@ import spray.json._ * Created by Ryan Richt on 2/28/15 */ -class `AWS::Route53::RecordSet` private ( +trait Route53RecordSetBaseFields { + def name: String + def RecordName: Token[String] + def RecordType: Route53RecordType + def HostedZoneName: Option[Token[String]] + def HostedZoneId: Option[Token[String]] + def ResourceRecords: Option[Seq[Token[String]]] + def TTL: Option[Token[String]] + def AliasTarget: Option[Route53AliasTarget] + def Condition: Option[ConditionRef] +} + +object Route53RecordSetBaseFields { + import DefaultJsonProtocol._ + def writeField[T: JsonFormat](t: T) = { + + val writer = implicitly[JsonFormat[T]] + writer match { + case _: OptionFormat[_] if t == None => None + case _ => Some(writer.write(t)) + } + } + + def writeCoreFields(p: Route53RecordSetBaseFields) = { + Map( + "name" -> writeField(p.name), + "Name" -> writeField(p.RecordName), + "Type" -> writeField(p.RecordType), + "HostedZoneName" -> writeField(p.HostedZoneName), + "HostedZoneId" -> writeField(p.HostedZoneId), + "ResourceRecords" -> writeField(p.ResourceRecords), + "TTL" -> writeField(p.TTL), + "AliasTarget" -> writeField(p.AliasTarget), + "Condition" -> writeField(p.Condition) + ) + } +} + +class `AWS::Route53::RecordSet` protected ( val name: String, val RecordName: Token[String], // The subdomain, with a . after it. val RecordType: Route53RecordType, @@ -17,36 +55,17 @@ class `AWS::Route53::RecordSet` private ( val TTL: Option[Token[String]] = None, val AliasTarget: Option[Route53AliasTarget] = None, override val Condition: Option[ConditionRef] = None - ) extends Resource[`AWS::Route53::RecordSet`]{ + ) extends Resource[`AWS::Route53::RecordSet`] with Route53RecordSetBaseFields{ def when(newCondition: Option[ConditionRef] = Condition) = new `AWS::Route53::RecordSet`(name, RecordName, RecordType, HostedZoneName, HostedZoneId, ResourceRecords, TTL, AliasTarget, newCondition) } object `AWS::Route53::RecordSet` extends DefaultJsonProtocol { - - private def writeField[T: JsonFormat](t: T) = { - val writer = implicitly[JsonFormat[T]] - writer match { - case _: OptionFormat[_] if t == None => None - case _ => Some(writer.write(t)) - } - } - // Because we dont want the default case class apply method without our checks implicit val format: JsonFormat[`AWS::Route53::RecordSet`] = new JsonFormat[`AWS::Route53::RecordSet`]{ def write(p: `AWS::Route53::RecordSet`) = { JsObject( - Map( - "name" -> writeField(p.name), - "Name" -> writeField(p.RecordName), - "Type" -> writeField(p.RecordType), - "HostedZoneName" -> writeField(p.HostedZoneName), - "HostedZoneId" -> writeField(p.HostedZoneId), - "ResourceRecords" -> writeField(p.ResourceRecords), - "TTL" -> writeField(p.TTL), - "AliasTarget" -> writeField(p.AliasTarget), - "Condition" -> writeField(p.Condition) - ).filter(_._2.isDefined).mapValues(_.get) + Route53RecordSetBaseFields.writeCoreFields(p).filter(_._2.isDefined).mapValues(_.get) ) } @@ -83,6 +102,77 @@ object `AWS::Route53::RecordSet` extends DefaultJsonProtocol { ) = new `AWS::Route53::RecordSet`(name, RecordName, Route53RecordType.A, Some(HostedZoneName), None, None, None, Some(AliasTarget), Condition) } +class `Custom::RemoteRecordSet` private ( + override val name: String, + val ServiceToken: Token[String], + val DestinationRole: Token[String], + val RecordName: Token[String], // The subdomain, with a . after it. + val RecordType: Route53RecordType, + val HostedZoneName: Option[Token[String]], // The parent domain, with a . after it. Must be route 53 managed already. + val HostedZoneId: Option[Token[String]], // the id of the hosted zone + val ResourceRecords: Option[Seq[Token[String]]] = None, + val TTL: Option[Token[String]] = None, + val AliasTarget: Option[Route53AliasTarget] = None, + override val Condition: Option[ConditionRef] = None + ) extends Resource[`Custom::RemoteRecordSet`] with Route53RecordSetBaseFields{ + + override def when(newCondition: Option[ConditionRef] = Condition) = + new `Custom::RemoteRecordSet`(name, ServiceToken, DestinationRole, RecordName, RecordType, HostedZoneName, HostedZoneId, ResourceRecords, TTL, AliasTarget, newCondition) +} + +object `Custom::RemoteRecordSet` { + import DefaultJsonProtocol._ + import Route53RecordSetBaseFields.writeField + implicit val format: JsonFormat[`Custom::RemoteRecordSet`] = new JsonFormat[`Custom::RemoteRecordSet`]{ + def write(p: `Custom::RemoteRecordSet`) = { + JsObject( + (Route53RecordSetBaseFields.writeCoreFields(p) + + ("ServiceToken" -> writeField(p.ServiceToken)) + + ("DestinationRole" -> writeField(p.DestinationRole)) + ).filter(_._2.isDefined).mapValues(_.get) + ) + } + + def read(json: JsValue) = ??? + } + + + def generalRecord( + name: String, + ServiceToken: Token[String], + DestinationRole: Token[String], + RecordName: Token[String], // The subdomain, with a . after it. + RecordType: Route53RecordType, + HostedZoneName: Token[String], // The parent domain, with a . after it. Must be route 53 managed already. + ResourceRecords: Seq[Token[String]], + TTL: Token[String], + Condition: Option[ConditionRef] = None + ) = new `Custom::RemoteRecordSet`(name, ServiceToken, DestinationRole, RecordName, RecordType, Some(HostedZoneName), None, Some(ResourceRecords), Some(TTL), Condition = Condition) + + def generalRecordByID( + name: String, + ServiceToken: Token[String], + DestinationRole: Token[String], + RecordName: Token[String], // The subdomain, with a . after it. + RecordType: Route53RecordType, + HostedZoneID: Token[String], + ResourceRecords: Seq[Token[String]], + TTL: Token[String], + Condition: Option[ConditionRef] = None + ) = new `Custom::RemoteRecordSet`(name, ServiceToken, DestinationRole, RecordName, RecordType, None, Some(HostedZoneID), Some(ResourceRecords), Some(TTL), Condition = Condition) + + + def aliasRecord( + name: String, + ServiceToken: Token[String], + DestinationRole: Token[String], + RecordName: Token[String], // The subdomain, with a . after it. + HostedZoneName: Token[String], // The parent domain, with a . after it. Must be route 53 managed already. + AliasTarget: Route53AliasTarget, + Condition: Option[ConditionRef] = None + ) = new `Custom::RemoteRecordSet`(name, ServiceToken, DestinationRole, RecordName, Route53RecordType.A, Some(HostedZoneName), None, None, None, Some(AliasTarget), Condition) +} + case class `AWS::Route53::HostedZone`( name: String, Name: Token[String], diff --git a/src/test/scala/com/monsanto/arch/cloudformation/model/resource/Route53_UT.scala b/src/test/scala/com/monsanto/arch/cloudformation/model/resource/Route53_UT.scala new file mode 100644 index 00000000..685c29f4 --- /dev/null +++ b/src/test/scala/com/monsanto/arch/cloudformation/model/resource/Route53_UT.scala @@ -0,0 +1,26 @@ +package com.monsanto.arch.cloudformation.model.resource + +import com.monsanto.arch.cloudformation.model.{Template, `Fn::GetAtt`, ResourceRef} +import org.scalatest.{FunSpec, Matchers} +import spray.json +import spray.json._ + +class Route53_UT extends FunSpec with Matchers { + + describe("Custom::RemoteRecordSet"){ + it ("should serialize as expected") { + val record = `Custom::RemoteRecordSet`.generalRecord( + "TestRecord", + "TestServiceToken", + "TestDestinationRole", + "etcd.internal.agro.services", + Route53RecordType.CNAME, + "test", + Seq("cnn.com"), + "60") + + val expectedJson = """{"AWSTemplateFormatVersion":"2010-09-09","Description":"","Resources":{"TestRecord":{"Properties":{"DestinationRole":"TestDestinationRole","Name":"etcd.internal.agro.services","ServiceToken":"TestServiceToken","HostedZoneName":"test","ResourceRecords":["cnn.com"],"TTL":"60","Type":"CNAME"},"Type":"Custom::RemoteRecordSet"}}}""".parseJson + Template.fromResource(record).toJson should be (expectedJson) + } + } +}