UNPKG

9.13 kBtext/coffeescriptView Raw
1fs = require 'fs'
2vm = require 'vm'
3path = require 'path'
4CoffeeScript = require 'coffee-script'
5
6class CloudFormationTemplateContext
7 constructor: ->
8 @_resources = {}
9 @_parameters = {}
10 @_mappings = null
11 @_outputs = {}
12 @_description = null
13 @_conditions = null
14 @Params = {}
15 @Resources = {}
16 @Mappings = {}
17 @Conditions = {}
18 @AWS =
19 AutoScaling:
20 AutoScalingGroup: null
21 LaunchConfiguration: null
22 ScalingPolicy: null
23 LifecycleHook: null
24 ScheduledAction: null
25 Trigger: null
26 CloudFormation:
27 Authentication: null
28 CustomResource: null
29 Stack: null
30 WaitCondition: null
31 WaitConditionHandle: null
32 CloudFront:
33 Distribution: null
34 CloudWatch:
35 Alarm: null
36 CodeDeploy:
37 Application: null
38 DeploymentConfig: null
39 DeploymentGroup: null
40 CodePipeline:
41 Pipeline: null
42 CustomActionType: null
43 Config:
44 ConfigRule: null
45 ConfigurationRecorder: null
46 DeliveryChannel: null
47 DirectoryService:
48 MicrosoftAD: null
49 SimpleAD: null
50 CloudTrail:
51 Trail: null
52 DataPipeline:
53 Pipeline: null
54 DynamoDB:
55 Table: null
56 EC2:
57 CustomerGateway: null
58 DHCPOptions: null
59 EIP: null
60 EIPAssociation: null
61 Instance: null
62 InternetGateway: null
63 NetworkAcl: null
64 NetworkAclEntry: null
65 NetworkInterface: null
66 PlacementGroup: null
67 Route: null
68 RouteTable: null
69 SecurityGroup: null
70 SecurityGroupIngress: null
71 SecurityGroupEgress: null
72 Subnet: null
73 SubnetNetworkAclAssociation: null
74 SubnetRouteTableAssociation: null
75 SpotFleet: null
76 Volume: null
77 VolumeAttachment: null
78 VPC: null
79 VPCDHCPOptionsAssociation: null
80 VPCEndpoint: null
81 VPCGatewayAttachment: null
82 VPNConnection: null
83 VPNGateway: null
84 ECS:
85 Cluster: null
86 Service: null
87 TaskDefinition: null
88 ElastiCache:
89 CacheCluster: null
90 ParameterGroup: null
91 ReplicationGroup: null
92 SecurityGroup: null
93 SecurityGroupIngress: null
94 SubnetGroup: null
95 ElasticBeanstalk:
96 Application: null
97 ApplicationVersion: null
98 Environment: null
99 ConfigurationTemplate: null
100 ElasticLoadBalancing:
101 LoadBalancer: null
102 EFS:
103 FileSystem: null
104 MountTarget: null
105 IAM:
106 AccessKey: null
107 Group: null
108 InstanceProfile: null
109 ManagedPolicy: null
110 Policy: null
111 Role: null
112 User: null
113 UserToGroupAddition: null
114 Kinesis:
115 Stream: null
116 KMS:
117 Key: null
118 Logs:
119 Destination: null
120 LogGroup: null
121 LogStream: null
122 MetricFilter: null
123 SubscriptionFilter: null
124 Lambda:
125 EventSourceMapping: null
126 Function: null
127 Permission: null
128 OpsWorks:
129 App: null
130 Instance: null
131 Layer: null
132 Stack: null
133 Redshift:
134 Cluster: null
135 ClusterParameterGroup: null
136 ClusterSecurityGroup: null
137 ClusterSubnetGroup: null
138 RDS:
139 DBCluster: null
140 DBClusterParameterGroup: null
141 DBInstance: null
142 DBParameterGroup: null
143 DBSubnetGroup: null
144 DBSecurityGroup: null
145 DBSecurityGroupIngress: null
146 EventSubscription: null
147 OptionGroup: null
148 Route53:
149 RecordSet: null
150 RecordSetGroup: null
151 HostedZone: null
152 HealthCheck: null
153 SDB:
154 Domain: null
155 S3:
156 Bucket: null
157 BucketPolicy: null
158 SNS:
159 Topic: null
160 TopicPolicy: null
161 SQS:
162 Queue: null
163 QueuePolicy: null
164 SSM:
165 Document: null
166 WAF:
167 ByteMatchSet: null
168 IPSet: null
169 Rule: null
170 SqlInjectionMatchSet: null
171 WebACL: null
172 WorkSpaces:
173 Workspace: null
174 @Param =
175 String: (name, arg1, arg2) => @_paramByType 'String', name, arg1, arg2
176 Number: (name, arg1, arg2) => @_paramByType 'Number', name, arg1, arg2
177 CommaDelimitedList: (name, arg1, arg2) => @_paramByType 'CommaDelimitedList', name, arg1, arg2
178 AWS: (type, name, arg1, arg2) => @_paramByType "AWS::#{type}", name, arg1, arg2
179 AWSList: (type, name, arg1, arg2) => @_paramByType "List<AWS::#{type}>", name, arg1, arg2
180 @_buildCall null, null, 'AWS', @AWS
181
182 _paramByType: (type, name, arg1, arg2) =>
183 result = {}
184 if not arg1?
185 result[name] = {}
186 else if not arg2?
187 result[name] = if typeof arg1 is 'string' then Description: arg1 else arg1
188 else
189 result[name] = arg2
190 result[name].Description = arg1
191 result[name].Type = type
192 @_set result, @_parameters
193 @Params[name] = Ref: name
194
195 _buildCall: (parent, lastKey, awsType, leaf) =>
196 if leaf?
197 for key, val of leaf
198 @_buildCall leaf, key, "#{awsType}::#{key}", val
199 return
200 parent[lastKey] = (name, props) =>
201 @_resourceByType awsType, name, props
202
203 # todo: this cheesy forward decl thing shouldn't be necessary
204 DeclareResource: (name) =>
205 @Resources[name] ?= Ref: name
206
207 _resourceByType: (type, name, props) =>
208 result = {}
209 if props?.Metadata? or props?.Properties? or props?.DependsOn? or props?.UpdatePolicy? or props?.CreationPolicy? or props?.Condition?
210 result[name] = props
211 result[name].Type = type
212 else
213 result[name] =
214 Type: type
215 Properties: props
216 @_set result, @_resources
217 @DeclareResource name
218
219 _set: (source, target) ->
220 for key, val of source
221 target[key] = val
222
223 Mapping: (name, map) =>
224 @_mappings ?= {}
225 result = {}
226 result[name] = map
227 @_set result, @_mappings
228
229 Output: (name, args...) =>
230 result = {}
231 if args.length is 1
232 result[name] =
233 Value: args[0]
234 if args.length is 2
235 result[name] =
236 Description: args[0]
237 Value: args[1]
238 @_set result, @_outputs
239
240 Condition: (name, intrinsicfn) =>
241 @_conditions ?= {}
242 result = {}
243 result[name] = intrinsicfn
244 @_set result, @_conditions
245
246 Description: (d) => @_description = d
247
248 Tag: (key, val) ->
249 Key: key
250 Value: val
251
252 #utility functions
253 Join: (delimiter, args...) ->
254 if args.length is 1 and (args[0] instanceof Array)
255 'Fn::Join': [ delimiter, args[0] ]
256 else
257 'Fn::Join': [ delimiter, args ]
258 FindInMap: (args...) ->
259 'Fn::FindInMap': args
260 GetAtt: (args...) ->
261 'Fn::GetAtt': args
262 Base64: (arg) ->
263 'Fn::Base64': arg
264 GetAZs: (arg) ->
265 'Fn::GetAZs': arg
266 Select: (index, args...) ->
267 if args.length is 1 and (args[0] instanceof Array)
268 'Fn::Select': [index, args[0]]
269 else
270 'Fn::Select': [index, args]
271 And: (condition, conditions...) ->
272 if conditions.length is 1 and (conditions[0] instanceof Array)
273 'Fn::And': [condition, conditions[0]]
274 else
275 'Fn::And': [condition, conditions]
276 Equals: (value_1, value_2) ->
277 'Fn::Equals': [ value_1, value_2 ]
278 If: (condition, value_if_true, value_if_false) ->
279 'Fn::If': [condition, value_if_true, value_if_false]
280 Not: (condition) ->
281 'Fn::Not': [condition]
282 Or: (condition, conditions...) ->
283 if conditions.length is 1 and (conditions[0] instanceof Array)
284 'Fn::Or': [condition, conditions[0]]
285 else
286 'Fn::Or': [condition, conditions]
287 AccountId: Ref: 'AWS::AccountId'
288 NotificationARNs: Ref: 'AWS::NotificationARNs'
289 NoValue: Ref: 'AWS::NoValue'
290 Region: Ref: 'AWS::Region'
291 StackId: Ref: 'AWS::StackId'
292 StackName: Ref: 'AWS::StackName'
293 InitScript: (arg) ->
294 existsSyncFunc = if fs.existsSync? then fs.existsSync else path.existsSync
295 if not existsSyncFunc(arg)
296 text = arg
297 else
298 text = fs.readFileSync(arg).toString()
299 chunks = []
300 #todo: fix this abhoration of regex
301 pattern = /((.|\n)*?)%{([^}?]+)}?((.|\n)*)/
302 match = text.match pattern
303 while match
304 chunks.push match[1]
305 compiled = CoffeeScript.compile match[3], {bare: true}
306 chunks.push eval compiled
307 text = match[4]
308 match = text.match pattern
309 chunks.push text if text and text.length > 0
310 @Base64 @Join '', chunks
311
312module.exports.CloudFormationTemplateContext = CloudFormationTemplateContext
313
314module.exports = (func) ->
315 context = new CloudFormationTemplateContext
316 func.apply context, [context]
317 template = AWSTemplateFormatVersion: '2010-09-09'
318 template.Description = context._description if context._description?
319 template.Parameters = context._parameters
320 template.Mappings = context._mappings if context._mappings?
321 template.Resources = context._resources
322 template.Outputs = context._outputs
323 template.Conditions = context._conditions if context._conditions?
324 template
325
326require('pkginfo')(module, 'version')