geoengineer 0.1.4 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/README.md +1 -0
  5. data/lib/geoengineer/cli/geo_cli.rb +1 -0
  6. data/lib/geoengineer/cli/terraform_commands.rb +35 -0
  7. data/lib/geoengineer/environment.rb +1 -0
  8. data/lib/geoengineer/resource.rb +31 -0
  9. data/lib/geoengineer/resources/aws_alb.rb +2 -0
  10. data/lib/geoengineer/resources/aws_alb_listener.rb +16 -6
  11. data/lib/geoengineer/resources/aws_alb_target_group.rb +19 -7
  12. data/lib/geoengineer/resources/aws_customer_gateway.rb +4 -0
  13. data/lib/geoengineer/resources/aws_emr_cluster.rb +20 -0
  14. data/lib/geoengineer/resources/aws_iam_role.rb +1 -0
  15. data/lib/geoengineer/resources/aws_kinesis_stream.rb +10 -7
  16. data/lib/geoengineer/resources/aws_lambda_function.rb +4 -5
  17. data/lib/geoengineer/resources/aws_nat_gateway.rb +6 -7
  18. data/lib/geoengineer/resources/aws_network_interface.rb +22 -0
  19. data/lib/geoengineer/resources/aws_placement_group.rb +25 -0
  20. data/lib/geoengineer/resources/aws_route53_record.rb +45 -4
  21. data/lib/geoengineer/resources/aws_route53_zone.rb +34 -7
  22. data/lib/geoengineer/resources/aws_route_table.rb +1 -1
  23. data/lib/geoengineer/resources/aws_s3_bucket_object.rb +24 -0
  24. data/lib/geoengineer/resources/aws_vpn_connection.rb +17 -9
  25. data/lib/geoengineer/resources/aws_vpn_connection_route.rb +50 -14
  26. data/lib/geoengineer/resources/aws_waf_ipset.rb +35 -0
  27. data/lib/geoengineer/resources/aws_waf_rule.rb +26 -0
  28. data/lib/geoengineer/resources/aws_waf_web_acl.rb +26 -0
  29. data/lib/geoengineer/utils/aws_clients.rb +15 -0
  30. data/lib/geoengineer/utils/has_validations.rb +1 -0
  31. data/lib/geoengineer/version.rb +1 -1
  32. data/spec/resource_spec.rb +56 -0
  33. data/spec/resources/aws_alb_listener_spec.rb +6 -1
  34. data/spec/resources/aws_alb_spec.rb +7 -0
  35. data/spec/resources/aws_alb_target_group_spec.rb +22 -0
  36. data/spec/resources/aws_emr_cluster_spec.rb +23 -0
  37. data/spec/resources/aws_kinesis_stream_spec.rb +26 -11
  38. data/spec/resources/aws_network_interface_spec.rb +32 -0
  39. data/spec/resources/aws_placement_group_spec.rb +29 -0
  40. data/spec/resources/aws_route53_zone_spec.rb +19 -3
  41. data/spec/resources/aws_s3_bucket_object_spec.rb +4 -0
  42. data/spec/resources/aws_waf_ipset_spec.rb +65 -0
  43. data/spec/resources/aws_waf_rule_spec.rb +36 -0
  44. data/spec/resources/aws_waf_web_acl_spec.rb +36 -0
  45. data/spec/spec_helper.rb +1 -1
  46. metadata +23 -2
  47. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ebcdcd4573207cc095eeb99bcc20771ddae9f2fa
4
- data.tar.gz: d34079a107d98e72ebb3206395d6982a63238efc
3
+ metadata.gz: 10c2741c5361a9ab218a96c9de280f01ea20c9a5
4
+ data.tar.gz: d18876526519536af82c08f15128c20fab9047c5
5
5
  SHA512:
6
- metadata.gz: '0092827fe84c1e9325ec4511133f7d80299bbd9d67a96e47ac62c84c11fc7e5c792e298ecbc78442d9ab219c9d5168a16eb12b2b162b2df53f138e28bc308e55'
7
- data.tar.gz: ddd2677004c40b506e3336fa0882236a8c231181aa1f9ce405816b8de95ec446a02eee7e687c5ab2dec3dc741bc9bc4c9b8f8a72655103bf3764b1155ad54918
6
+ metadata.gz: ff50a5841f091791bf99ce86b57d5bd74b6f20ae4dbac98b1a096271c3ed54475959bcb2f1801028f9aadcb7839cf60b15630f149d010f409872624375c1e76b
7
+ data.tar.gz: e67c59d14db3bebc2414d6cf245a5070c78fd43e62a098a92f9682fa47f9f491771ede031eb5242d18d20562b84369b17dd43e6595b2ed7e8c96d8667a0f49c1
Binary file
data.tar.gz.sig CHANGED
Binary file
data/README.md CHANGED
@@ -61,6 +61,7 @@ environment("staging") {
61
61
  account_id "1"
62
62
  subnet "1"
63
63
  vpc_id "1"
64
+ allow_destroy true ## Defaults to false. Set to true to support `geo destroy ...`
64
65
  }
65
66
 
66
67
  # Create the first_project to be in the `staging` environment
@@ -189,6 +189,7 @@ class GeoCLI
189
189
  def add_commands
190
190
  plan_cmd
191
191
  apply_cmd
192
+ destroy_cmd
192
193
  graph_cmd
193
194
  status_cmd
194
195
  end
@@ -22,6 +22,7 @@ module GeoCLI::TerraformCommands
22
22
  def terraform_plan
23
23
  plan_commands = [
24
24
  "cd #{@tmpdir}",
25
+ "terraform init",
25
26
  "terraform refresh",
26
27
  "terraform plan --refresh=false -parallelism=#{terraform_parallelism}" \
27
28
  " -state=#{@terraform_state_file} -out=#{@plan_file} #{@no_color}"
@@ -30,6 +31,17 @@ module GeoCLI::TerraformCommands
30
31
  shell_exec(plan_commands.join(" && "), true)
31
32
  end
32
33
 
34
+ def terraform_plan_destroy
35
+ plan_destroy_commands = [
36
+ "cd #{@tmpdir}",
37
+ "terraform refresh",
38
+ "terraform plan -destroy --refresh=false -parallelism=#{terraform_parallelism}" \
39
+ " -state=#{@terraform_state_file} -out=#{@plan_file} #{@no_color}"
40
+ ]
41
+
42
+ shell_exec(plan_destroy_commands.join(" && "), true)
43
+ end
44
+
33
45
  def terraform_apply
34
46
  apply_commands = [
35
47
  "cd #{@tmpdir}",
@@ -39,6 +51,15 @@ module GeoCLI::TerraformCommands
39
51
  shell_exec(apply_commands.join(" && "), true)
40
52
  end
41
53
 
54
+ def terraform_destroy
55
+ destroy_commands = [
56
+ "cd #{@tmpdir}",
57
+ "terraform apply -parallelism=#{terraform_parallelism}" \
58
+ " #{@plan_file} #{@no_color}"
59
+ ]
60
+ shell_exec(destroy_commands.join(" && "), true)
61
+ end
62
+
42
63
  def plan_cmd
43
64
  command :plan do |c|
44
65
  c.syntax = 'geo plan [<geo_files>]'
@@ -64,4 +85,18 @@ module GeoCLI::TerraformCommands
64
85
  c.action init_action(:apply, &action)
65
86
  end
66
87
  end
88
+
89
+ def destroy_cmd
90
+ command :destroy do |c|
91
+ c.syntax = 'geo destroy [<geo_files>]'
92
+ c.description = 'Destroy an execution plan'
93
+ action = lambda do |args, options|
94
+ create_terraform_files
95
+ return puts "Plan Broken" if terraform_plan_destroy.exitstatus.nonzero?
96
+ return puts "Rejecting Plan" unless yes?("Apply the above plan? [YES/NO]")
97
+ terraform_destroy
98
+ end
99
+ c.action init_action(:destroy, &action)
100
+ end
101
+ end
67
102
  end
@@ -72,6 +72,7 @@ class GeoEngineer::Environment
72
72
 
73
73
  def resource(type, id, &block)
74
74
  return find_resource(type, id) unless block_given?
75
+
75
76
  resource = create_resource(type, id, &block)
76
77
  resource.environment = self
77
78
  resource
@@ -114,6 +114,37 @@ class GeoEngineer::Resource
114
114
  self
115
115
  end
116
116
 
117
+ def duplicate(new_id, &block)
118
+ parent = @project || @environment
119
+ return unless parent
120
+
121
+ duplicated = duplicate_resource(parent, self, new_id)
122
+ duplicated.reset
123
+ duplicated.instance_exec(duplicated, &block) if block_given?
124
+ duplicated.execute_lifecycle(:after, :initialize)
125
+
126
+ duplicated
127
+ end
128
+
129
+ def duplicate_resource(parent, progenitor, new_id)
130
+ parent.resource(progenitor.type, new_id) do
131
+ # We want to set all attributes from the parent, EXCEPT _geo_id and _terraform_id
132
+ # Which should be set according to the init logic
133
+ progenitor.attributes.each do |key, value|
134
+ self[key] = value unless %w(_geo_id _terraform_id).include?(key)
135
+ end
136
+
137
+ progenitor.subresources.each do |subresource|
138
+ duplicated_subresource = GeoEngineer::SubResource.new(self, subresource.type) do
139
+ subresource.attributes.each do |key, value|
140
+ self[key] = value
141
+ end
142
+ end
143
+ self.subresources << duplicated_subresource
144
+ end
145
+ end
146
+ end
147
+
117
148
  def _json_file(attribute, path, binding_obj = nil)
118
149
  raise "file #{path} not found" unless File.file?(path)
119
150
 
@@ -29,6 +29,8 @@ class GeoEngineer::Resources::AwsAlb < GeoEngineer::Resource
29
29
 
30
30
  def self._fetch_remote_resources(provider)
31
31
  albs = AwsClients.alb(provider).describe_load_balancers['load_balancers'].map(&:to_h)
32
+ return [] if albs.empty?
33
+
32
34
  tags = AwsClients.alb(provider)
33
35
  .describe_tags({ resource_arns: albs.map { |alb| alb[:load_balancer_arn] } })
34
36
  .tag_descriptions
@@ -4,23 +4,33 @@
4
4
  # {https://www.terraform.io/docs/providers/aws/r/alb_listener.html Terraform Docs}
5
5
  ########################################################################
6
6
  class GeoEngineer::Resources::AwsAlbListener < GeoEngineer::Resource
7
- validate -> { validate_required_attributes([:load_balancer_arn, :port, :default_action]) }
7
+ validate -> {
8
+ validate_required_attributes([:_load_balancer_name, :load_balancer_arn, :port, :default_action])
9
+ }
8
10
  validate -> {
9
11
  validate_subresource_required_attributes(:default_action, [:target_group_arn, :type])
10
12
  }
11
13
 
14
+ # Since we can't know the ARN until the ALB exists, it is not a good candidate for the
15
+ # _geo_id - instead we use the ALB name, which is also unique per region
16
+ after :initialize, -> { _geo_id -> { "#{_load_balancer_name}::#{port}" } }
12
17
  after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
13
- after :initialize, -> { _geo_id -> { "#{load_balancer_arn}::#{port}" } }
14
18
 
15
19
  def short_type
16
20
  "alb_listener"
17
21
  end
18
22
 
19
- def self._merge_attributes(listener)
23
+ def support_tags?
24
+ false
25
+ end
26
+
27
+ def self._merge_attributes(listener, alb)
20
28
  listener.merge(
21
29
  {
22
- _geo_id: "#{listener[:load_balancer_arn]}::#{listener[:port]}",
23
- _terraform_id: listener[:listener_arn]
30
+ _geo_id: "#{alb[:load_balancer_name]}::#{listener[:port]}",
31
+ _terraform_id: listener[:listener_arn],
32
+ load_balancer_arn: alb[:load_balancer_arn],
33
+ load_balancer_name: alb[:load_balancer_name]
24
34
  }
25
35
  )
26
36
  end
@@ -33,7 +43,7 @@ class GeoEngineer::Resources::AwsAlbListener < GeoEngineer::Resource
33
43
  .describe_listeners({ load_balancer_arn: alb[:load_balancer_arn] })
34
44
  .listeners
35
45
  .map(&:to_h)
36
- .map { |listener| _merge_attributes(listener) }
46
+ .map { |listener| _merge_attributes(listener, alb) }
37
47
  end.flatten.compact
38
48
  end
39
49
  end
@@ -10,21 +10,33 @@ class GeoEngineer::Resources::AwsAlbTargetGroup < GeoEngineer::Resource
10
10
  validate -> { validate_subresource_required_attributes(:stickiness, [:type]) }
11
11
 
12
12
  after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
13
- after :initialize, -> { _geo_id -> { "#{vpc_id}::#{protocol}::#{port}" } }
13
+ after :initialize, -> { _geo_id -> { NullObject.maybe(tags)[:Name] } }
14
14
 
15
15
  def short_type
16
16
  "alb_target_group"
17
17
  end
18
18
 
19
- def self._fetch_remote_resources(provider)
20
- target_groups = AwsClients.alb(provider).describe_target_groups.target_groups.map(&:to_h)
21
- target_groups.map do |group|
22
- group.merge(
19
+ def self._merge_attributes(target_groups, tags)
20
+ target_groups.map do |target_group|
21
+ target_tags = tags.find { |desc| desc[:resource_arn] == target_group[:target_group_arn] }
22
+ target_group.merge(
23
23
  {
24
- _geo_id: "#{group[:vpc_id]}::#{group[:protocol]}::#{group[:port]}",
25
- _terraform_id: group[:target_group_arn]
24
+ _terraform_id: target_group[:target_group_arn],
25
+ _geo_id: (target_tags || {})[:tags]&.find { |tag| tag[:key] == "Name" }&.dig(:value)
26
26
  }
27
27
  )
28
28
  end
29
29
  end
30
+
31
+ def self._fetch_remote_resources(provider)
32
+ target_groups = AwsClients.alb(provider).describe_target_groups.target_groups
33
+ return [] if target_groups.empty?
34
+
35
+ tags = AwsClients.alb(provider)
36
+ .describe_tags({ resource_arns: target_groups.map(&:target_group_arn) })
37
+ .tag_descriptions
38
+ .map(&:to_h)
39
+
40
+ _merge_attributes(target_groups.map(&:to_h), tags)
41
+ end
30
42
  end
@@ -10,6 +10,10 @@ class GeoEngineer::Resources::AwsCustomerGateway < GeoEngineer::Resource
10
10
  after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
11
11
  after :initialize, -> { _geo_id -> { NullObject.maybe(tags)[:Name] } }
12
12
 
13
+ def gateway_type(val = nil)
14
+ val ? self["type"] = val : self["type"]
15
+ end
16
+
13
17
  def self._fetch_remote_resources(provider)
14
18
  AwsClients.ec2(provider)
15
19
  .describe_customer_gateways['customer_gateways']
@@ -0,0 +1,20 @@
1
+ ########################################################################
2
+ # AwsEmr is the +aws_emr_cluster+ terrform resource,
3
+ #
4
+ # {https://www.terraform.io/docs/providers/aws/r/emr_cluster.html}
5
+ ########################################################################
6
+ class GeoEngineer::Resources::AwsEmrCluster < GeoEngineer::Resource
7
+ validate -> { validate_required_attributes([:name]) }
8
+ validate -> { validate_has_tag(:Name) }
9
+
10
+ after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
11
+ after :initialize, -> { _geo_id -> { name } }
12
+
13
+ def self._fetch_remote_resources(provider)
14
+ AwsClients.emr(provider).list_clusters['clusters'].map(&:to_h).map do |cluster|
15
+ cluster[:_terraform_id] = cluster[:id]
16
+ cluster[:_geo_id] = cluster[:name]
17
+ cluster
18
+ end
19
+ end
20
+ end
@@ -19,6 +19,7 @@ class GeoEngineer::Resources::AwsIamRole < GeoEngineer::Resource
19
19
 
20
20
  attributes = {}
21
21
  attributes['arn'] = arn if arn
22
+ attributes['force_detach_policies'] = force_detach_policies || 'false'
22
23
  attributes['assume_role_policy'] = _normalize_json(assume_role_policy) if assume_role_policy
23
24
 
24
25
  tfstate[:primary][:attributes] = attributes
@@ -19,14 +19,17 @@ class GeoEngineer::Resources::AwsKinesisStream < GeoEngineer::Resource
19
19
  tfstate
20
20
  end
21
21
 
22
+ def self._stream_description(stream_name)
23
+ AwsClients.kinesis
24
+ .describe_stream({ stream_name: stream_name })
25
+ .stream_description
26
+ .to_h
27
+ end
28
+
22
29
  def self._all_streams(provider)
23
- streams = []
24
- AwsClients.kinesis(provider).list_streams[:stream_names].each do |stream_name|
25
- AwsClients.kinesis.describe_stream({ stream_name: stream_name }).map(&:to_h).map do |stream|
26
- streams << stream[:stream_description]
27
- end
28
- end
29
- streams
30
+ AwsClients.kinesis(provider)
31
+ .list_streams[:stream_names]
32
+ .map { |s| self._stream_description(s) }
30
33
  end
31
34
 
32
35
  def self._fetch_remote_resources(provider)
@@ -32,13 +32,12 @@ class GeoEngineer::Resources::AwsLambdaFunction < GeoEngineer::Resource
32
32
  tfstate
33
33
  end
34
34
 
35
- def support_tags?
36
- false
37
- end
38
-
39
35
  def self._fetch_remote_resources(provider)
40
36
  AwsClients.lambda(provider).list_functions['functions'].map(&:to_h).map do |function|
41
- function.merge({ _terraform_id: function[:function_name] })
37
+ function.merge({
38
+ _terraform_id: function[:function_name],
39
+ _geo_id: function[:function_name]
40
+ })
42
41
  end
43
42
  end
44
43
  end
@@ -4,7 +4,7 @@
4
4
  # {https://www.terraform.io/docs/providers/aws/r/nat_gateway.html Terraform Docs}
5
5
  ########################################################################
6
6
  class GeoEngineer::Resources::AwsNatGateway < GeoEngineer::Resource
7
- validate -> { validate_required_attributes([:subnet_id, :allocation_id]) }
7
+ validate -> { validate_required_attributes(%i(subnet_id allocation_id)) }
8
8
 
9
9
  after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
10
10
  after :initialize, -> { _geo_id -> { "#{allocation_id}::#{subnet_id}" } }
@@ -18,12 +18,11 @@ class GeoEngineer::Resources::AwsNatGateway < GeoEngineer::Resource
18
18
  # AWS SDK has `nat_gateway_addresses` as an array, but you should only be able to
19
19
  # have exactly 1 elastic IP association. This logic should cover the bases...
20
20
  allocation = gateway[:nat_gateway_addresses].find { |addr| addr.key?(:allocation_id) }
21
- gateway.merge(
22
- {
23
- _terraform_id: gateway[:nat_gateway_id],
24
- _geo_id: "#{allocation[:allocation_id]}::#{gateway[:subnet_id]}"
25
- }
26
- )
21
+
22
+ gateway[:_terraform_id] = gateway[:nat_gateway_id]
23
+ gateway[:_geo_id] = "#{allocation[:allocation_id]}::#{gateway[:subnet_id]}"
24
+
25
+ gateway
27
26
  end
28
27
  end
29
28
  end
@@ -0,0 +1,22 @@
1
+ ########################################################################
2
+ # AwsNetworkInterface is the +aws_network_interface+ terrform resource,
3
+ #
4
+ # {https://www.terraform.io/docs/providers/aws/r/network_interface.html Terraform Docs}
5
+ ########################################################################
6
+ class GeoEngineer::Resources::AwsNetworkInterface < GeoEngineer::Resource
7
+ validate -> { validate_required_attributes([:subnet_id]) }
8
+
9
+ after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
10
+ after :initialize, -> { _geo_id -> { Array(private_ips).join(',') } }
11
+
12
+ def self._fetch_remote_resources(provider)
13
+ interfaces = AwsClients.ec2(provider).describe_network_interfaces
14
+
15
+ interfaces['network_interfaces'].map(&:to_h).map do |interface|
16
+ addresses = interface[:private_ip_addresses].collect { |a| a[:private_ip_address] }
17
+ interface[:_terraform_id] = interface[:network_interface_id]
18
+ interface[:_geo_id] = addresses.join(',')
19
+ interface
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ ########################################################################
2
+ # AwsPlacementGroup is the +aws_placement_group+ terrform resource,
3
+ #
4
+ # {https://www.terraform.io/docs/providers/aws/r/placement_group.html Terraform Docs}
5
+ ########################################################################
6
+ class GeoEngineer::Resources::AwsPlacementGroup < GeoEngineer::Resource
7
+ validate -> { validate_required_attributes([:name, :strategy]) }
8
+
9
+ after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
10
+ after :initialize, -> { _geo_id -> { name } }
11
+
12
+ def support_tags?
13
+ false
14
+ end
15
+
16
+ def self._fetch_remote_resources(provider)
17
+ pgs = AwsClients.ec2(provider).describe_placement_groups['placement_groups']
18
+ pgs.map(&:to_h).map do |group|
19
+ group[:_terraform_id] = group[:group_name]
20
+ group[:_geo_id] = group[:group_name]
21
+ group[:name] = group[:group_name]
22
+ group
23
+ end
24
+ end
25
+ end
@@ -3,6 +3,8 @@
3
3
  #
4
4
  # {https://www.terraform.io/docs/providers/aws/r/route53_record.html Terraform Docs}
5
5
  ########################################################################
6
+
7
+ # Note: Currently, 'name' must be the fully qualified domain name.
6
8
  class GeoEngineer::Resources::AwsRoute53Record < GeoEngineer::Resource
7
9
  validate -> { validate_required_attributes([:zone_id, :name, :type]) }
8
10
  validate -> { validate_required_attributes([:ttl, :records]) unless self.alias }
@@ -13,7 +15,26 @@ class GeoEngineer::Resources::AwsRoute53Record < GeoEngineer::Resource
13
15
  end
14
16
  }
15
17
 
16
- after :initialize, -> { _terraform_id -> { "#{zone_id}_#{name}_#{type}" } }
18
+ after :initialize, -> { _terraform_id -> { NullObject.maybe(remote_resource)._terraform_id } }
19
+ after :initialize, -> { _geo_id -> { "#{zone_id}_#{self.name&.downcase}_#{record_type}" } }
20
+
21
+ def to_terraform_state
22
+ tfstate = super
23
+ tfstate[:primary][:attributes] = {
24
+ 'id' => _terraform_id,
25
+ 'name' => name,
26
+ 'type' => record_type
27
+ }
28
+ tfstate
29
+ end
30
+
31
+ def record_type(val = nil)
32
+ val ? self["type"] = val : self["type"]
33
+ end
34
+
35
+ def fqdn
36
+ self["name"].downcase
37
+ end
17
38
 
18
39
  def support_tags?
19
40
  false
@@ -28,9 +49,29 @@ class GeoEngineer::Resources::AwsRoute53Record < GeoEngineer::Resource
28
49
  end
29
50
 
30
51
  def self._fetch_records_for_zone(provider, zone)
31
- records = AwsClients.route53(provider).list_resource_record_sets({ hosted_zone_id: zone[:id] })
32
- records.resource_record_sets.map(&:to_h).map do |record|
33
- record.merge({ _terraform_id: "#{record[:zone_id]}_#{record[:name]}_#{record[:type]}" })
52
+ zone_id = zone[:id].gsub(%r{^/hostedzone/}, '')
53
+ response = AwsClients.route53(provider).list_resource_record_sets({ hosted_zone_id: zone_id })
54
+
55
+ records = []
56
+ response.each do |page|
57
+ records += page.resource_record_sets.map(&:to_h).map do |record|
58
+ name = _fetch_name(record, zone)
59
+ id = "#{zone_id}_#{name}_#{record[:type]}"
60
+ record.merge({ fqdn: name, _terraform_id: id, _geo_id: id })
61
+ end
62
+ end
63
+
64
+ records
65
+ end
66
+
67
+ def self._fetch_name(record, zone)
68
+ # Need to trim the trailing dot, as well as convert ASCII 42 (Octal 52) to
69
+ # the wildcard star. Route53 uses that for wildcard records.
70
+ name = record[:name].downcase.gsub(/\.$/, '').gsub(/^\\052/, '*')
71
+ zone_name = zone[:name].gsub(/\.$/, '')
72
+ if name !~ /#{zone_name}$/
73
+ name = name.empty? ? zone_name : "#{name}.#{zone_name}"
34
74
  end
75
+ name
35
76
  end
36
77
  end