terraformdsl 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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