terraformdsl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ base_domain = "example.com"
2
+ office_ip = "123.123.123.123"
3
+ db_user = "dbuser"
4
+ db_pass = "<<password>>"
@@ -0,0 +1,8 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require_relative "terraformdsl/version"
4
+
5
+ module TerraformDSL
6
+ class Error < StandardError; end
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,1072 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ require 'json'
4
+
5
+ require_relative './common'
6
+
7
+
8
+ module TerraformDSL::AWS
9
+
10
+
11
+ class Resource
12
+
13
+ def set_parent(resource)
14
+ @parent.nil? or raise "already parent set."
15
+ @parent = resource
16
+ end
17
+
18
+ attr_reader :parent
19
+
20
+ def accept(visitor)
21
+ method = 'on_' + self.class.name.sub(/^.*?AWS::/, '').gsub('::', '_')
22
+ visitor.__send__(method, self) do
23
+ @children.each do |x|
24
+ x.accept(visitor)
25
+ end if @children
26
+ end
27
+ end
28
+
29
+ def attr(attr)
30
+ raise NotImplementedError.new("#{self.class.name}#attr(#{attr.inspect}): not available.")
31
+ end
32
+
33
+ private
34
+
35
+ def add_resource(res, &blk)
36
+ res.set_parent(self)
37
+ (@children ||= []) << res
38
+ res.instance_exec(res, &blk) if blk
39
+ return res
40
+ end
41
+
42
+ def let(*args)
43
+ yield *args
44
+ end
45
+
46
+ end
47
+
48
+
49
+ def self.infra(*args, &blk)
50
+ infra = Infra.new(*args)
51
+ infra.instance_exec(infra, &blk) if blk
52
+ @current_infra = infra
53
+ return infra
54
+ end
55
+
56
+ def self.current_infra
57
+ @current_infra
58
+ end
59
+
60
+
61
+ class Infra < Resource
62
+
63
+ def region(*a, &b); add_resource(Region.new(*a), &b); end
64
+ def global(*a, &b); add_resource(Global.new(*a), &b); end
65
+
66
+ def generate_tf
67
+ visitor = TerraformVisitor.new
68
+ visitor.visit(self)
69
+ tf_str = visitor.output()
70
+ #
71
+ if $_rds_monitoring_role_required
72
+ tf_str << RDS::RDS_MONITORING_ROLE_TF
73
+ end
74
+ #
75
+ return tf_str
76
+ end
77
+
78
+ end
79
+
80
+
81
+ class Global < Resource
82
+
83
+ def Route53(*a, &b); add_resource(Route53.new(*a), &b); end
84
+ def IAM (*a, &b); add_resource(IAM .new(*a), &b); end
85
+
86
+ end
87
+
88
+
89
+ class Region < Resource
90
+
91
+ def initialize(name=nil)
92
+ @name = name
93
+ end
94
+ attr_reader :name
95
+
96
+ def AZ (*a, &b); add_resource(AZ .new(*a), &b); end
97
+ def AMI(*a, &b); add_resource(AMI.new(*a), &b); end
98
+ def VPC(*a, &b); add_resource(VPC.new(*a), &b); end
99
+
100
+ end
101
+
102
+
103
+ class AZ < Resource
104
+
105
+ def initialize(name)
106
+ @name = name
107
+ end
108
+ attr_reader :name
109
+
110
+ end
111
+
112
+
113
+ class AMI < Resource
114
+
115
+ def initialize(name, owners, pattern)
116
+ @name = name
117
+ @owners = [owners].flatten()
118
+ @pattern = pattern
119
+ end
120
+ attr_reader :name, :owners, :pattern
121
+
122
+ def attr(attr); "${data.aws_ami.#{@name}.#{attr}}"; end
123
+
124
+ end
125
+
126
+
127
+ class VPC < Resource
128
+
129
+ def initialize(name, cidr)
130
+ @name = name
131
+ @cidr = cidr
132
+ end
133
+ attr_reader :name, :cidr
134
+
135
+ def attr(attr); "${aws_vpc.#{@name}.#{attr}}"; end
136
+
137
+ def EC2 (*a, &b); add_resource(EC2 .new(*a), &b); end
138
+ def EIP (*a, &b); add_resource(EIP .new(*a), &b); end
139
+ def Subnet(*a, &b); add_resource(Subnet.new(*a), &b); end
140
+ def InternetGateway(*a, &b); add_resource(InternetGateway.new(*a), &b); end
141
+ def RouteTable (*a, &b); add_resource(RouteTable .new(*a), &b); end
142
+ def SecurityGroup (*a, &b); add_resource(SecurityGroup .new(*a), &b); end
143
+ def RDS_SubnetGroup(*a, &b); add_resource(RDS::SubnetGroup.new(*a), &b); end
144
+ def RDS_ParameterGroup(*a, &b); add_resource(RDS::ParameterGroup.new(*a), &b); end
145
+ def RDS_OptionGroup(*a, &b); add_resource(RDS::OptionGroup.new(*a), &b); end
146
+ def RDS_Instance (*a, &b); add_resource(RDS::Instance .new(*a), &b); end
147
+ def RDS_ReadReplica(*a, &b); add_resource(RDS::ReadReplica.new(*a), &b); end
148
+
149
+ end
150
+
151
+
152
+ class Subnet < Resource
153
+
154
+ def initialize(name, cidr, az, route_table=nil)
155
+ @name = name
156
+ @cidr = cidr
157
+ @az = az
158
+ @route_table = route_table
159
+ end
160
+ attr_reader :name, :cidr, :az, :route_table
161
+
162
+ def attr(attr); "${aws_subnet.#{@name}.#{attr}}"; end
163
+
164
+ end
165
+
166
+
167
+ class InternetGateway < Resource
168
+
169
+ def initialize(name)
170
+ @name = name
171
+ end
172
+ attr_reader :name
173
+
174
+ def attr(attr); "${aws_internet_gateway.#{@name}.#{attr}}"; end
175
+
176
+ end
177
+
178
+
179
+ class RouteTable < Resource
180
+
181
+ def initialize(name)
182
+ @name = name
183
+ end
184
+ attr_reader :name
185
+
186
+ def attr(attr); "${aws_route_table.#{@name}.#{attr}}"; end
187
+
188
+ def Route(*a, &b); add_resource(Route.new(*a), &b); end
189
+
190
+ end
191
+
192
+
193
+ class Route < Resource
194
+
195
+ def initialize(cidr, gateway: nil, ec2: nil, nat: nil, egress_only: nil, network_interface: nil)
196
+ @cidr = cidr
197
+ @gateway = gateway
198
+ @ec2 = ec2
199
+ @nat = nat
200
+ @egress_only = egress_only
201
+ @network_interface = network_interface
202
+ end
203
+ attr_reader :cidr, :gateway, :ec2, :nat, :egress_only, :network_interface
204
+
205
+ def attr(attr)
206
+ @name or raise "#{self.class.name}#attr() is not available without name."
207
+ "${aws_route_table.#{@name}.#{attr}}"
208
+ end
209
+
210
+ end
211
+
212
+
213
+ class SecurityGroup < Resource
214
+
215
+ def initialize(name, desc)
216
+ @name = name
217
+ @desc = desc
218
+ end
219
+ attr_reader :name, :desc
220
+
221
+ def attr(attr); "${aws_security_group.#{@name}.#{attr}}"; end
222
+
223
+ def Ingress(*a, &b); add_resource(Ingress.new(*a), &b); end
224
+ def Egress (*a, &b); add_resource(Egress .new(*a), &b); end
225
+
226
+ end
227
+
228
+
229
+ class Ingress < Resource
230
+
231
+ PROTOCOLS = [:tcp, :udp, :icmp, :any]
232
+
233
+ def initialize(protocol, port, destination)
234
+ PROTOCOLS.include?(protocol) or
235
+ raise ArgumentError.new("#{protocol.inspect}: unknown protocol for Ingress.")
236
+ @protocol = protocol
237
+ @port = port
238
+ @destination = destination
239
+ end
240
+ attr_reader :protocol, :port, :destination
241
+
242
+ end
243
+
244
+
245
+ class Egress < Resource
246
+
247
+ PROTOCOLS = [:tcp, :udp, :icmp, :any]
248
+
249
+ def initialize(protocol, port, destination)
250
+ PROTOCOLS.include?(protocol) or
251
+ raise ArgumentError.new("#{protocol.inspect}: unknown protocol for Egress.")
252
+ @protocol = protocol
253
+ @port = port
254
+ @destination = destination
255
+ end
256
+ attr_reader :protocol, :port, :destination
257
+
258
+ end
259
+
260
+
261
+ class EC2 < Resource
262
+
263
+ def initialize(name, type, ami, subnet, security_group, key_name)
264
+ @name = name
265
+ @type = type
266
+ @ami = ami
267
+ @subnet = subnet
268
+ @security_group = security_group
269
+ @key_name = key_name
270
+ end
271
+ attr_reader :name, :type, :ami, :subnet, :security_group, :key_name
272
+
273
+ def cpu_credit
274
+ case @type
275
+ when /^t[2-9]\./ ; "unlimited"
276
+ else ; nil
277
+ end
278
+ end
279
+
280
+ def attr(attr); "${aws_instance.#{@name}.#{attr}}"; end
281
+
282
+ end
283
+
284
+
285
+ class EIP < Resource
286
+
287
+ def initialize(name, ec2)
288
+ @name = name
289
+ @ec2 = ec2
290
+ end
291
+ attr_reader :name, :ec2
292
+
293
+ def attr(attr); "${aws_eip.#{@name}.#{attr}}"; end
294
+
295
+ end
296
+
297
+
298
+ module RDS
299
+
300
+ RDS_MONITORING_ROLE_NAME = "rds-monitoring-role"
301
+ RDS_MONITORING_ROLE_TF = <<END
302
+ resource "aws_iam_role" "rds-monitoring-role" {
303
+ name = "rds-monitoring-role"
304
+ path = "/"
305
+ assume_role_policy = <<POLICY
306
+ {
307
+ "Version": "2012-10-17",
308
+ "Statement": [
309
+ {
310
+ "Sid": "",
311
+ "Effect": "Allow",
312
+ "Principal": {
313
+ "Service": "monitoring.rds.amazonaws.com"
314
+ },
315
+ "Action": "sts:AssumeRole"
316
+ }
317
+ ]
318
+ }
319
+ POLICY
320
+ }
321
+
322
+ resource "aws_iam_policy_attachment" "AmazonRDSEnhancedMonitoringRole-policy-attachment" {
323
+
324
+ name = "AmazonRDSEnhancedMonitoringRole-policy-attachment"
325
+ policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
326
+ groups = []
327
+ users = []
328
+ roles = ["rds-monitoring-role"]
329
+ }
330
+
331
+ END
332
+
333
+
334
+ class SubnetGroup < Resource
335
+
336
+ def initialize(name, subnets=[])
337
+ subnets.all? {|x| x.is_a?(Subnet) } or
338
+ raise TypeError.new("RDS::SubnetGroup(#{name.inspect}): 2nd argument should be an array of Subnet, but got: #{subnets.inspect}")
339
+ @name = name
340
+ @subnets = subnets
341
+ end
342
+ attr_reader :name, :subnets
343
+
344
+ def attr(attr); "${aws_db_subnet_group.#{@name}.#{attr}}"; end
345
+
346
+ end
347
+
348
+
349
+ class ParameterGroup < Resource
350
+
351
+ def initialize(name, family, parameters={})
352
+ @name = name
353
+ @family = family
354
+ @parameters = parameters
355
+ end
356
+ attr_reader :name, :family, :parameters
357
+
358
+ def attr(attr); "${aws_db_parameter_group.#{@name}.#{attr}}"; end
359
+
360
+ end
361
+
362
+
363
+ class OptionGroup < Resource
364
+
365
+ def initialize(name, engine, version)
366
+ @name = name
367
+ @engine = engine
368
+ @version = version
369
+ @options = {}
370
+ end
371
+ attr_reader :name, :engine, :version, :options
372
+
373
+ def attr(attr); "${aws_db_option_group.#{@name}.#{attr}}"; end
374
+
375
+ def add_option(name, kvs={})
376
+ @options[name] = kvs
377
+ nil
378
+ end
379
+
380
+ end
381
+
382
+
383
+ class Instance < Resource
384
+
385
+ def initialize(name, machine_type)
386
+ @name = name
387
+ @machine_type = machine_type
388
+ @master_instance = nil
389
+ @database = {}
390
+ @network = {}
391
+ @flags = {}
392
+ @storage = {}
393
+ @encryption = {}
394
+ @backup = {}
395
+ @monitoring = {}
396
+ @maintenance = {}
397
+ end
398
+ attr_reader :name, :machine_type, :master_instance
399
+ attr_reader :database, :network, :flags, :storage, :encryption, :backup, :monitoring, :maintenance
400
+
401
+ def database=(engine: nil, version: nil, license: nil,
402
+ name: nil, port: 5432, user: nil, password: nil,
403
+ parameter_group: nil, option_group: nil)
404
+ @database = {engine: engine, version: version, license: license,
405
+ name: name, port: port, user: user, password: password,
406
+ parameter_group: parameter_group, option_group: option_group}
407
+ end
408
+
409
+ def network=(subnet_group: nil, security_group: [], az: nil, public_access: nil, multi_az: nil)
410
+ @network = {subnet_group: subnet_group, security_group: security_group,
411
+ az: az, public_access: public_access, multi_az: multi_az}
412
+ end
413
+
414
+ def storage=(type: nil, size: nil)
415
+ @storage = {type: type, size: size}
416
+ end
417
+
418
+ def encryption=(enable: nil)
419
+ @encryption = {enable: enable}
420
+ end
421
+
422
+ def backup=(days: 7, window: nil)
423
+ @backup = {days: days, window: window}
424
+ end
425
+
426
+ def monitoring=(interval: nil, role: nil)
427
+ if interval && interval > 0
428
+ role ||= RDS_MONITORING_ROLE_NAME
429
+ end
430
+ @monitoring = {interval: interval, role: role}
431
+ end
432
+
433
+ def maintenance=(auto_upgrade: true, maintenace_window: nil)
434
+ @maintenance = {auto_upgrade: auto_upgrade,
435
+ maintenace_window: maintenace_window}
436
+ end
437
+
438
+ def attr(attr); "${aws_db_instance.#{@name}.#{attr}}"; end
439
+
440
+ end
441
+
442
+
443
+ class ReadReplica < Instance
444
+
445
+ def initialize(name, machine_type, master_instance)
446
+ super(name, machine_type)
447
+ @master_instance = master_instance
448
+ end
449
+
450
+ def database=(port: nil)
451
+ @database = {}
452
+ @database[:port] = port unless port.nil?
453
+ end
454
+
455
+ def network=(region: nil, subnet_group: nil, az: nil, public_access: nil, multi_az: nil)
456
+ @network = {region: region, subnet_group: subnet_group,
457
+ az: az, public_access: public_access, multi_az: multi_az}
458
+ end
459
+
460
+ def storage=(type: nil, size: nil)
461
+ @storage = {type: type, size: size}
462
+ end
463
+
464
+ def encryption=(enable: nil)
465
+ @encryption = {enable: enable}
466
+ end
467
+
468
+ def monitoring=(interval: nil, role: nil)
469
+ if interval && interval > 0
470
+ role ||= RDS_MONITORING_ROLE_NAME
471
+ end
472
+ @monitoring = {interval: interval, role: role}
473
+ end
474
+
475
+ def maintenance=(auto_upgrade: true, maintenace_window: nil)
476
+ @maintenace = {auto_upgrade: auto_upgrade,
477
+ maintenace_window: maintenace_window}
478
+ end
479
+
480
+ def attr(attr); "${aws_db_instance.#{@name}.#{attr}}"; end
481
+
482
+ end
483
+
484
+
485
+ end
486
+
487
+
488
+ class Route53 < Resource
489
+
490
+ RECORD_TYPES = [
491
+ :A, :AAAA, :CAA, :CNAME, :MX, :NAPTR, :NS,
492
+ :PTR, :SOA, :SPF, :SRV, :TXT,
493
+ ]
494
+
495
+ def initialize()
496
+ end
497
+
498
+ def Zone (*a, &b); add_resource(Zone.new(*a) , &b); end
499
+ def PrivateZone(*a, &b); add_resource(PrivateZone.new(*a), &b); end
500
+
501
+
502
+ class Zone < Resource
503
+
504
+ def initialize(name, domain)
505
+ @name = name
506
+ @domain = domain
507
+ end
508
+ attr_reader :name, :domain
509
+
510
+ def attr(attr); "${aws_route53_zone.#{@name}.#{attr}}"; end
511
+
512
+ def Record(*a, &b); add_resource(Record.new(*a), &b); end
513
+
514
+ end
515
+
516
+
517
+ class PrivateZone < Resource
518
+
519
+ def initialize(name, domain, vpc)
520
+ @name = name
521
+ @domain = domain
522
+ @vpc = vpc
523
+ end
524
+ attr_reader :name, :domain, :vpc
525
+
526
+ def attr(attr); "${aws_route53_zone.#{@name}.#{attr}}"; end
527
+
528
+ def Record(*a, &b); add_resource(Record.new(*a), &b); end
529
+
530
+ end
531
+
532
+
533
+ class Record < Resource
534
+
535
+ def initialize(type, name, values, opts={})
536
+ RECORD_TYPES.include?(type) or
537
+ raise "#{type.inspect}: unknown record type."
538
+ @type = type
539
+ @name = name
540
+ @values = [values].flatten
541
+ @opts = opts
542
+ end
543
+ attr_reader :type, :name, :values, :opts
544
+
545
+ def attr(attr); "${aws_route53_record.#{@name}.#{attr}}"; end
546
+
547
+ end
548
+
549
+
550
+ end
551
+
552
+
553
+ class IAM < Resource
554
+
555
+ def initialize()
556
+ end
557
+
558
+ def Role (*a, &b); add_resource(Role.new(*a) , &b); end
559
+ def PolicyAttachment(*a, &b); add_resource(PolicyAttachment.new(*a), &b); end
560
+
561
+
562
+ class Role < Resource
563
+
564
+ def initialize(name, path, policy)
565
+ @name = name
566
+ @path = path
567
+ @policy = policy
568
+ end
569
+ attr_reader :name, :path, :policy
570
+
571
+ def attr(attr); "${aws_iam_role.#{@name}.#{attr}}"; end
572
+
573
+ end
574
+
575
+
576
+ class PolicyAttachment < Resource
577
+
578
+ def initialize(name, groups=[], users=[], roles=[])
579
+ @name = name
580
+ @groups = groups
581
+ @users = users
582
+ @roles = roles
583
+ end
584
+ attr_reader :name, :groups, :users, :roles
585
+
586
+ def attr(attr); "${aws_policy_role.#{@name}.#{attr}}"; end
587
+
588
+ end
589
+
590
+
591
+ end
592
+
593
+
594
+ class Visitor
595
+
596
+ def visit(resource)
597
+ resource.accept(self)
598
+ end
599
+
600
+ end
601
+
602
+
603
+ class TerraformVisitor < Visitor
604
+
605
+ def initialize
606
+ @buf = []
607
+ end
608
+
609
+ def output
610
+ return @buf.join("")
611
+ end
612
+
613
+ def on_Infra(infra)
614
+ yield
615
+ end
616
+
617
+ def on_Global(global)
618
+ yield
619
+ end
620
+
621
+ def on_Region(region)
622
+ @buf << <<END
623
+ provider "aws" {
624
+ #access_key = "${var.access_key}"
625
+ #secret_key = "${var.secret_key}"
626
+ region = "#{region.name}"
627
+ }
628
+
629
+ END
630
+ yield
631
+ end
632
+
633
+ def on_AZ(az)
634
+ yield
635
+ end
636
+
637
+ def on_AMI(ami)
638
+ owners = ami.owners.map {|x| "\"#{x}\"" }
639
+ @buf << <<END
640
+ data "aws_ami" "#{ami.name}" {
641
+ most_recent = true
642
+ owners = [#{owners.join(', ')}]
643
+ filter {
644
+ name = "name"
645
+ values = ["#{ami.pattern}"]
646
+ }
647
+ }
648
+
649
+ END
650
+ yield
651
+ end
652
+
653
+ def on_VPC(vpc)
654
+ @buf << <<END
655
+ resource "aws_vpc" "#{vpc.name}" {
656
+ cidr_block = "#{vpc.cidr}"
657
+ enable_dns_support = true
658
+ enable_dns_hostnames = true
659
+ tags {
660
+ Name = "#{vpc.name}"
661
+ }
662
+ }
663
+
664
+ END
665
+ yield
666
+ end
667
+
668
+ def on_InternetGateway(gw)
669
+ @buf << <<END
670
+ resource "aws_internet_gateway" "#{gw.name}" {
671
+ vpc_id = "#{gw.parent.attr(:id)}"
672
+ tags {
673
+ Name = "#{gw.name}"
674
+ }
675
+ }
676
+
677
+ END
678
+ yield
679
+ end
680
+
681
+ def on_Subnet(subnet)
682
+ @buf << <<END
683
+ resource "aws_subnet" "#{subnet.name}" {
684
+ vpc_id = "#{subnet.parent.attr(:id)}"
685
+ availability_zone = "#{subnet.az.name}"
686
+ cidr_block = "#{subnet.cidr}"
687
+ tags {
688
+ Name = "#{subnet.name}"
689
+ }
690
+ }
691
+
692
+ END
693
+ if subnet.route_table
694
+ @buf << <<END
695
+ resource "aws_route_table_association" "#{subnet.route_table.name}-#{subnet.name}" {
696
+ route_table_id = "#{subnet.route_table.attr(:id)}"
697
+ subnet_id = "#{subnet.attr(:id)}"
698
+ }
699
+
700
+ END
701
+ end
702
+ yield
703
+ end
704
+
705
+ def on_RouteTable(route_table)
706
+ @buf << <<END
707
+ resource "aws_route_table" "#{route_table.name}" {
708
+ vpc_id = "#{route_table.parent.attr(:id)}"
709
+ tags {
710
+ Name = "#{route_table.name}"
711
+ }
712
+ END
713
+ yield
714
+ @buf << <<END
715
+ }
716
+
717
+ END
718
+ end
719
+
720
+ def on_Route(route)
721
+ @buf << <<END
722
+ route {
723
+ cidr_block = "#{route.cidr || '0.0.0.0/0'}"
724
+ gateway_id = "#{route.gateway.attr(:id)}"
725
+ }
726
+ END
727
+ yield
728
+ end
729
+
730
+ def on_SecurityGroup(sg)
731
+ @buf << <<END
732
+ resource "aws_security_group" "#{sg.name}" {
733
+ name = "#{sg.name}"
734
+ description = "#{sg.desc}"
735
+ vpc_id = "#{sg.parent.attr(:id)}"
736
+ tags {
737
+ Name = "#{sg.name}"
738
+ }
739
+ END
740
+ yield
741
+ @buf << <<END
742
+ }
743
+
744
+ END
745
+ end
746
+
747
+ def on_Ingress(ingress, &blk)
748
+ _on_anygress('ingress', ingress, &blk)
749
+ end
750
+
751
+ def on_Egress(egress, &blk)
752
+ _on_anygress('egress', egress, &blk)
753
+ end
754
+
755
+ def _on_anygress(kind, x, &blk)
756
+ port = x.port || "-1"
757
+ protocol = x.protocol
758
+ protocol = "-1" if protocol == :any || protocol.nil?
759
+ cidrs = []
760
+ secgrps = []
761
+ flag_self = false
762
+ [x.destination].flatten.each {|t|
763
+ case t
764
+ when nil ; cidrs << "0.0.0.0/0"
765
+ when :any ; cidrs << "0.0.0.0/0"
766
+ when :self ; flag_self = true
767
+ when /^\d+\./ ; cidrs << t
768
+ when EC2 ; cidrs << "#{t.attr(:private_ip)}/32"
769
+ when SecurityGroup; secgrps << t.attr(:id)
770
+ when /^\w[-\w]*$/ ; cidrs << "${aws_instance.#{t}.private_ip}/32"
771
+ else ; cidrs << t
772
+ end
773
+ }
774
+ cidrs_s = cidrs.map {|s| "\"#{s}\"" }.join(", ")
775
+ secgrps_s = secgrps.map {|s| "\"#{s}\"" }.join(", ")
776
+ @buf << " #{kind} {\n"
777
+ @buf << " from_port = \"#{port}\"\n"
778
+ @buf << " to_port = \"#{port}\"\n"
779
+ @buf << " protocol = \"#{protocol}\"\n"
780
+ @buf << " cidr_blocks = [#{cidrs_s}]\n" if ! cidrs_s.empty?
781
+ @buf << " security_groups = [#{secgrps_s}]\n" if ! secgrps.empty?
782
+ @buf << " self = true\n" if flag_self
783
+ @buf << " }\n"
784
+ yield
785
+ end
786
+ private :_on_anygress
787
+
788
+ def on_EC2(ec2)
789
+ sg_s = [ec2.security_group].flatten.collect {|sg|
790
+ "\"#{sg.attr(:id)}\""
791
+ }.join(", ")
792
+ @buf << <<END
793
+ resource "aws_instance" "#{ec2.name}" {
794
+ instance_type = "#{ec2.type}"
795
+ ami = "#{ec2.ami.attr(:image_id)}"
796
+ subnet_id = "#{ec2.subnet.attr(:id)}"
797
+ vpc_security_group_ids = [#{sg_s}]
798
+ key_name = "#{ec2.key_name}"
799
+ END
800
+ if ec2.cpu_credit
801
+ @buf << <<END
802
+ credit_specification {
803
+ cpu_credits = "#{ec2.cpu_credit}"
804
+ }
805
+ END
806
+ end
807
+ @buf << <<END
808
+ tags {
809
+ Name = "#{ec2.name}"
810
+ }
811
+ }
812
+
813
+ END
814
+ yield
815
+ end
816
+
817
+ def on_EIP(eip)
818
+ @buf << <<END
819
+ resource "aws_eip" "#{eip.name}" {
820
+ vpc = true
821
+ instance = "#{eip.ec2.attr(:id)}"
822
+ tags {
823
+ Name = "#{eip.name}"
824
+ }
825
+ }
826
+
827
+ END
828
+ yield
829
+ end
830
+
831
+ def on_RDS_SubnetGroup(subnetgrp)
832
+ grp = subnetgrp
833
+ ids = grp.subnets.map {|x| "\"#{x.attr(:id)}\"" }
834
+ @buf << <<END
835
+ resource "aws_db_subnet_group" "#{grp.name}" {
836
+ name = "#{grp.name}"
837
+ subnet_ids = [#{ids.join(', ')}]
838
+ tags {
839
+ Name = "#{grp.name}"
840
+ }
841
+ }
842
+
843
+ END
844
+ yield
845
+ end
846
+
847
+ def on_RDS_ParameterGroup(parametergrp)
848
+ grp = parametergrp
849
+ @buf << <<END
850
+ resource "aws_db_parameter_group" "#{grp.name}" {
851
+ name = "#{grp.name}"
852
+ family = "#{grp.family}"
853
+ END
854
+ grp.parameters.each do |k, v|
855
+ pending_reboot = false
856
+ if k.end_with?('!')
857
+ pending_reboot = true
858
+ k = k.sub(/!$/, '')
859
+ end
860
+ @buf << " parameter {\n"
861
+ @buf << " name = \"#{k}\"\n"
862
+ @buf << " value = \"#{v}\"\n"
863
+ @buf << " apply_method = \"pending-reboot\"\n" if pending_reboot
864
+ @buf << " }\n"
865
+ end
866
+ @buf << <<END
867
+ }
868
+
869
+ END
870
+ yield
871
+ end
872
+
873
+ def on_RDS_OptionGroup(optiongrp)
874
+ grp = optiongrp
875
+ @buf << <<END
876
+ resource "aws_db_option_group" "#{grp.name}" {
877
+ name = "#{grp.name}"
878
+ engine_name = "#{grp.engine}"
879
+ major_engine_version = "#{grp.version}"
880
+ END
881
+ grp.options.each do |name, kvs|
882
+ @buf << <<END
883
+ option {
884
+ option_name = "#{name}"
885
+ END
886
+ kvs.each do |k, v|
887
+ @buf << <<END
888
+ option_settings {
889
+ name = "#{k}"
890
+ value = "#{v}"
891
+ }
892
+ END
893
+ end if kvs
894
+ @buf << <<END
895
+ }
896
+ END
897
+ end
898
+ @buf << <<END
899
+ }
900
+
901
+ END
902
+ yield
903
+ end
904
+
905
+ def on_RDS_Instance(instance)
906
+ x = instance
907
+ storage_type = {general: 'gp2', iops: 'io1', magnetic: 'standard'}
908
+ d = x.backup ? x.backup[:window] : nil
909
+ backup_window = d ? "#{d[:start]}-#{d[:start].sub(/:00$/, ':30')}" : nil
910
+ sg = (x.master_instance || x).network[:security_group] \
911
+ &.map {|g| "\"#{g.attr(:id)}\"" }&.join(", ")
912
+ monitoring_role_arn = \
913
+ case x.monitoring[:role]
914
+ when nil ; nil
915
+ when String ; "${aws_iam_role.#{x.monitoring[:role]}.arn}"
916
+ when IAM::Role; "#{x.monitoring[:role].attr(:arn)}"
917
+ else ; raise "#{x.monitoring[:role].inspect}: unexpected value"
918
+ end
919
+ if x.monitoring[:role] == RDS::RDS_MONITORING_ROLE_NAME
920
+ $_rds_monitoring_role_required = true
921
+ end
922
+ str = <<END
923
+ resource "aws_db_instance" "#{x.name}" {
924
+ allocated_storage = "#{x.storage[:size].to_i}"
925
+ auto_minor_version_upgrade = "#{x.maintenance[:auto_upgrade]}"
926
+ availability_zone = "#{x.network[:az].name}"
927
+ backup_retention_period = "#{x.backup[:days]}"
928
+ backup_window = "#{backup_window}"
929
+ copy_tags_to_snapshot = "true"
930
+ db_subnet_group_name = "#{x.master_instance ? nil : x.network[:subnet_group].name}"
931
+ #enabled_cloudwatch_logs_exports = ""
932
+ engine = "#{x.database[:engine]}"
933
+ engine_version = "#{x.database[:version]}"
934
+ #final_snapshot_identifier = ""
935
+ #iam_database_authentication_enabled = ""
936
+ identifier = "#{x.name}"
937
+ #identifier_prefix = ""
938
+ instance_class = "#{x.machine_type}"
939
+ iops = "#{x.storage[:iops]}"
940
+ kms_key_id = "#{x.encryption[:kms_key_id]}"
941
+ license_model = "#{x.database[:license]}"
942
+ maintenance_window = "#{x.maintenance[:window]}"
943
+ monitoring_interval = "#{x.monitoring[:interval]}"
944
+ monitoring_role_arn = "#{monitoring_role_arn}"
945
+ multi_az = "#{x.network[:multi_az]}"
946
+ name = "#{x.database[:name]}"
947
+ option_group_name = "#{x.database[:option_group]&.name}"
948
+ parameter_group_name = "#{(x.master_instance || x).database[:parameter_group]&.name}"
949
+ password = "#{x.database[:password]}"
950
+ port = "#{x.database[:port]}"
951
+ publicly_accessible = "#{x.network[:public_access]}"
952
+ replicate_source_db = "#{x.master_instance&.attr(:id)}"
953
+ #skip_final_snapshot = ""
954
+ #snapshot_identifier = ""
955
+ storage_encrypted = "#{x.encryption[:enable]}"
956
+ storage_type = "#{storage_type[x.storage[:type]]}"
957
+ #timezone = "UTC"
958
+ username = "#{x.database[:user]}"
959
+ vpc_security_group_ids = [#{sg}]
960
+ #s3_import = ""
961
+ #tags = {
962
+ # Name = "#{x.name}"
963
+ #}
964
+ }
965
+
966
+ END
967
+ str = str.gsub(/^.*""\n/, '')
968
+ @buf << str
969
+ yield
970
+ end
971
+
972
+ def on_RDS_ReadReplica(instance, &block)
973
+ on_RDS_Instance(instance, &block)
974
+ end
975
+
976
+ def on_Route53(route53)
977
+ yield
978
+ end
979
+
980
+ def on_Route53_Zone(zone)
981
+ @buf << <<END
982
+ resource "aws_route53_zone" "#{zone.name}" {
983
+ name = "#{zone.domain}"
984
+ tags {
985
+ Name = "#{zone.name}"
986
+ }
987
+ }
988
+
989
+ END
990
+ yield
991
+ end
992
+
993
+ def on_Route53_PrivateZone(zone)
994
+ @buf << <<END
995
+ resource "aws_route53_zone" "#{zone.name}" {
996
+ name = "#{zone.domain}"
997
+ vpc {
998
+ vpc_id = "#{zone.vpc.attr(:id)}"
999
+ }
1000
+ tags {
1001
+ Name = "#{zone.name}"
1002
+ }
1003
+ }
1004
+
1005
+ END
1006
+ yield
1007
+ end
1008
+
1009
+ def on_Route53_Record(record)
1010
+ values_s = record.values.flatten.collect {|x|
1011
+ case x
1012
+ when String; "\"#{x}\""
1013
+ when EIP ; "\"#{x.attr(:public_ip)}\""
1014
+ when EC2 ; "\"#{x.attr(:private_ip)}\""
1015
+ else
1016
+ raise TypeError.new("#{x.inspect}: ip address (string, EIP or EC2) expected")
1017
+ end
1018
+ }.join(", ")
1019
+ record_name = record.name.gsub(/[^-\w]/, '_')
1020
+ @buf << <<END
1021
+ resource "aws_route53_record" "#{record.parent.name}-#{record_name}-#{record.type}" {
1022
+ zone_id = "#{record.parent.attr(:zone_id)}"
1023
+ type = "#{record.type}"
1024
+ name = "#{record.name}"
1025
+ ttl = "#{record.opts[:ttl] || 5}"
1026
+ records = [#{values_s}]
1027
+ }
1028
+
1029
+ END
1030
+ yield
1031
+ end
1032
+
1033
+ def on_IAM(route53)
1034
+ yield
1035
+ end
1036
+
1037
+ def on_IAM_Role(role)
1038
+ json_str = JSON.pretty_generate(role.policy)#.sub(/\n\z/, '')
1039
+ @buf << <<END
1040
+ resource "aws_iam_role" "#{role.name}" {
1041
+ name = "#{role.name}"
1042
+ path = "#{role.path}"
1043
+ assume_role_policy = <<POLICY
1044
+ #{json_str}
1045
+ POLICY
1046
+ }
1047
+
1048
+ END
1049
+ yield
1050
+ end
1051
+
1052
+ def on_IAM_PolicyAttachment(pa)
1053
+ groups_str = pa.groups.map {|x| "\"#{x.name}\"" }.join(', ')
1054
+ users_str = pa.users.map {|x| "\"#{x.name}\"" }.join(', ')
1055
+ roles_str = pa.roles.map {|x| "\"#{x.name}\"" }.join(', ')
1056
+ @buf << <<END
1057
+ resource "aws_iam_policy_attachment" "#{pa.name}-policy-attachment" {
1058
+ name = "#{pa.name}-policy-attachment"
1059
+ policy_arn = "arn:aws:iam::aws:policy/service-role/#{pa.name}"
1060
+ groups = [#{groups_str}]
1061
+ users = [#{users_str}]
1062
+ roles = [#{roles_str}]
1063
+ }
1064
+
1065
+ END
1066
+ yield
1067
+ end
1068
+
1069
+ end
1070
+
1071
+
1072
+ end