Class: Terrafying::Aws::Ops

Inherits:
Object
  • Object
show all
Defined in:
lib/terrafying/aws.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(region) ⇒ Ops

Returns a new instance of Ops.



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/terrafying/aws.rb', line 16

def initialize(region)
  half_jitter = lambda { |c|
    sleep_time = 0.5 * (2**c.retries)
    Kernel.sleep(Kernel.rand((sleep_time / 2)..sleep_time))
  }

  ::Aws.config.update({
    region: region,
    retry_limit: 7,
    retry_backoff: half_jitter
  })

  @autoscaling_client = ::Aws::AutoScaling::Client.new
  @ec2_resource = ::Aws::EC2::Resource.new
  @ec2_client = ::Aws::EC2::Client.new
  @elb_client = ::Aws::ElasticLoadBalancingV2::Client.new
  @route53_client = ::Aws::Route53::Client.new
  @s3_client = ::Aws::S3::Client.new
  @sts_client = ::Aws::STS::Client.new

  @region = region
end

Instance Attribute Details

#regionObject (readonly)

Returns the value of attribute region.



14
15
16
# File 'lib/terrafying/aws.rb', line 14

def region
  @region
end

Instance Method Details

#account_idObject



39
40
41
# File 'lib/terrafying/aws.rb', line 39

def 
  @account_id_cache ||= @sts_client.get_caller_identity.
end

#all_security_groupsObject



43
44
45
# File 'lib/terrafying/aws.rb', line 43

def all_security_groups
  @all_security_groups ||= @ec2_resource.security_groups.to_a
end

#ami(name, owners = ["self"]) ⇒ Object



248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/terrafying/aws.rb', line 248

def ami(name, owners=["self"])
  @ami ||= {}
  @ami[name] ||=
    begin
      STDERR.puts "looking for an image with prefix '#{name}'"
      resp = @ec2_client.describe_images({owners: owners})
      if resp.images.count < 1
        raise "no images were found"
      end
      m = resp.images.select { |a| /^#{name}/.match(a.name) }
      if m.count == 0
        raise "no image with name '#{name}' was found"
      end
      m.sort { |x,y| y.creation_date <=> x.creation_date }.shift.image_id
    end
end

#asgs_by_tags(expectedTags = {}) ⇒ Object



494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
# File 'lib/terrafying/aws.rb', line 494

def asgs_by_tags(expectedTags = {})
  asgs = []
  next_token = nil

  loop do
    resp = @autoscaling_client.describe_auto_scaling_groups({ next_token: next_token })

    asgs = asgs + resp.auto_scaling_groups.select { |asg|
      matches = asg.tags.select { |tag|
        expectedTags[tag.key.to_sym] == tag.value ||
          expectedTags[tag.key] == tag.value
      }

      matches.count == expectedTags.count
    }

    if resp.next_token
      next_token = resp.next_token
    else
      break
    end
  end

  asgs
end

#availability_zonesObject



265
266
267
268
269
270
271
272
273
274
# File 'lib/terrafying/aws.rb', line 265

def availability_zones
  @availability_zones ||=
    begin
      STDERR.puts "looking for AZs in the current region"
      resp = @ec2_client.describe_availability_zones({})
      resp.availability_zones.map { |zone|
        zone.zone_name
      }
    end
end

#elastic_ip(alloc_id) ⇒ Object



323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/terrafying/aws.rb', line 323

def elastic_ip(alloc_id)
  @ips ||= {}
  @ips[alloc_id] ||=
    begin
      STDERR.puts "looking for an elastic ip with allocation_id '#{alloc_id}'"
      ips = @ec2_client.describe_addresses(
        {
          filters: [
            {
              name: "allocation-id",
              values: [alloc_id],
            },
          ],
        }
      ).addresses
      case
      when ips.count == 1
        ips.first
      when ips.count < 1
        raise "No elastic ip with allocation_id '#{alloc_id}' was found."
      when ips.count > 1
        raise "More than one elastic ip with allocation_id '#{alloc_id}' was found: " + ips.join(', ')
      end
    end
end

#endpoint_service_by_lb_arn(arn) ⇒ Object



442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
# File 'lib/terrafying/aws.rb', line 442

def endpoint_service_by_lb_arn(arn)
  @endpoint_services_by_lb_arn ||= {}
  @endpoint_services_by_lb_arn[arn] ||=
    begin
      resp = @ec2_client.describe_vpc_endpoint_service_configurations

      services = resp.service_configurations.select { |service|
        service.network_load_balancer_arns.include?(arn)
      }

      case
      when services.count == 1
        services.first
      when services.count < 1
        raise "No endpoint service with lb arn '#{arn}' was found."
      when services.count > 1
        raise "More than one endpoint service with lb arn '#{arn}' was found: " + services.join(', ')
      end
    end
end

#endpoint_service_by_name(service_name) ⇒ Object



415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
# File 'lib/terrafying/aws.rb', line 415

def endpoint_service_by_name(service_name)
  @endpoint_service ||= {}
  @endpoint_service[service_name] ||=
    begin
      resp = @ec2_client.describe_vpc_endpoint_service_configurations(
        {
          filters: [
            {
              name: "service-name",
              values: [service_name],
            },
          ],
        }
      )

      endpoint_services = resp.service_configurations
      case
      when endpoint_services.count == 1
        endpoint_services.first
      when endpoint_services.count < 1
        raise "No endpoint service with name '#{service_name}' was found."
      when endpoint_services.count > 1
        raise "More than one endpoint service with name '#{service_name}' was found: " + endpoint_services.join(', ')
      end
    end
end

#hosted_zone(fqdn) ⇒ Object



349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/terrafying/aws.rb', line 349

def hosted_zone(fqdn)
  @hosted_zones ||= {}
  @hosted_zones[fqdn] ||=
    begin
      STDERR.puts "looking for a hosted zone with fqdn '#{fqdn}'"
      hosted_zones = @route53_client.list_hosted_zones_by_name({ dns_name: fqdn }).hosted_zones.select { |zone|
        zone.name == "#{fqdn}."
      }
      case
      when hosted_zones.count == 1
        hosted_zones.first
      when hosted_zones.count < 1
        raise "No hosted zone with fqdn '#{fqdn}' was found."
      when hosted_zones.count > 1
        raise "More than one hosted zone with name '#{fqdn}' was found: " + hosted_zones.join(', ')
      end
    end
end

#hosted_zone_by_tag(tag) ⇒ Object



368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/terrafying/aws.rb', line 368

def hosted_zone_by_tag(tag)
  @hosted_zones ||= {}
  @hosted_zones[tag] ||=
    begin
      STDERR.puts "looking for a hosted zone with tag '#{tag}'"
      @aws_hosted_zones ||= @route53_client.list_hosted_zones.hosted_zones.map do |zone|
        {
          zone: zone,
          tags: @route53_client.list_tags_for_resource({resource_type: "hostedzone", resource_id: zone.id.split('/')[2]}).resource_tag_set.tags
        }
      end

      hosted_zones = @aws_hosted_zones.select do |z|
        z[:tags].any? do |aws_tag|
          tag.any? { |k, v| aws_tag.key = String(k) && aws_tag.value == v }
        end
      end

      case
      when hosted_zones.count == 1
        hosted_zones.first[:zone]
      when hosted_zones.count < 1
        raise "No hosted zone with tag '#{tag}' was found."
      when hosted_zones.count > 1
        raise "More than one hosted zone with tag '#{tag}' was found: " + hosted_zones.join(', ')
      end
    end
end

#instance_profile(name) ⇒ Object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/terrafying/aws.rb', line 97

def instance_profile(name)
  @instance_profiles ||= {}
  @instance_profiles[name] ||=
    begin
      resource = ::Aws::IAM::Resource.new
      STDERR.puts "Looking up id of instance profile '#{name}'"
      # unfortunately amazon don't let us filter for profiles using
      # a name filter, for now we have enumerate and filter manually
      coll = resource.instance_profiles
      profiles = []
      profiles = coll.select {|p| p.instance_profile_name =~ /#{name}/}

      case
      when profiles.count == 1
        profiles.first.instance_profile_id
      when profiles.count < 1
        raise "No instance profile with name '#{name}' was found."
      when profiles.count > 1
        raise "More than one instance profile with name '#{name}' found: " + profiles.join(', ')
      end
    end
end

#lb_by_name(name) ⇒ Object



463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
# File 'lib/terrafying/aws.rb', line 463

def lb_by_name(name)
  @lbs ||= {}
  @lbs[name] ||=
    begin
      load_balancers = @elb_client.describe_load_balancers({ names: [name] }).load_balancers

      case
      when load_balancers.count == 1
        load_balancers.first
      when load_balancers.count < 1
        raise "No load balancer with name '#{name}' was found."
      when load_balancers.count > 1
        raise "More than one load balancer with name '#{name}' was found: " + load_balancers.join(', ')
      end
    end
end

#list_objects(bucket) ⇒ Object



406
407
408
409
410
411
412
413
# File 'lib/terrafying/aws.rb', line 406

def list_objects(bucket)
  @list_objects ||= {}
  @list_objects[bucket] ||=
    begin
      resp = @s3_client.list_objects_v2({ bucket: bucket })
      resp.contents
    end
end

#route_table(name) ⇒ Object



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
# File 'lib/terrafying/aws.rb', line 297

def route_table(name)
  @route_tables ||= {}
  @route_tables[name] ||=
    begin
      STDERR.puts "looking for a route table with name '#{name}'"
      route_tables = @ec2_client.describe_route_tables(
        {
          filters: [
            {
              name: "tag:Name",
              values: [name],
            },
          ],
        }
      ).route_tables
      case
      when route_tables.count == 1
        route_tables.first.route_table_id
      when route_tables.count < 1
        raise "No route table with name '#{name}' was found."
      when route_tables.count > 1
        raise "More than one route table with name '#{name}' was found: " + route_tables.join(', ')
      end
    end
end

#route_table_for_subnet(subnet_id) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/terrafying/aws.rb', line 120

def route_table_for_subnet(subnet_id)
  @route_table_for_subnet ||= {}
  @route_table_for_subnet[subnet_id] ||=
    begin
      resp = @ec2_client.describe_route_tables(
        {
          filters: [
            { name: "association.subnet-id", values: [ subnet_id ] },
          ],
        })

      route_tables = resp.route_tables

      case
      when route_tables.count == 1
        route_tables.first
      when route_tables.count < 1
        raise "No route table for subnet '#{subnet_id}' was found."
      when profiles.count > 1
        raise "More than route table for subnet '#{subnet_id}' found: " + route_tables.join(', ')
      end
    end
end

#route_table_for_vpc(vpc_id) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/terrafying/aws.rb', line 144

def route_table_for_vpc(vpc_id)
  @route_table_for_vpc ||= {}
  @route_table_for_vpc[vpc_id] ||=
    begin
      resp = @ec2_client.describe_route_tables(
        {
          filters: [
            { name: "association.main", values: [ "true" ] },
            { name: "vpc-id", values: [ vpc_id ] },
          ],
        })

      route_tables = resp.route_tables

      case
      when route_tables.count == 1
        route_tables.first
      when route_tables.count < 1
        raise "No route table for vpc '#{vpc_id}' was found."
      when profiles.count > 1
        raise "More than route table for vpc '#{vpc_id}' found: " + route_tables.join(', ')
      end
    end
end

#s3_object(bucket, key) ⇒ Object



397
398
399
400
401
402
403
404
# File 'lib/terrafying/aws.rb', line 397

def s3_object(bucket, key)
  @s3_objects ||= {}
  @s3_objects["#{bucket}-#{key}"] ||=
    begin
      resp = @s3_client.get_object({ bucket: bucket, key: key })
      resp.body.read
    end
end

#security_group(name) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/terrafying/aws.rb', line 47

def security_group(name)
  @security_groups ||= {}
  @security_groups[name] ||=
    begin
      STDERR.puts "Looking up id of security group '#{name}'"
      groups = all_security_groups.select { |g| g.group_name == name }.take(2)
      case
      when groups.count == 1
        groups.first.id
      when groups.count < 1
        raise "No security group with name '#{name}' was found."
      when groups.count > 1
        raise "More than one security group with name '#{name}' found: " + groups.join(', ')
      end
    end
end

#security_group_by_tags(tags) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/terrafying/aws.rb', line 81

def security_group_by_tags(tags)
  @security_groups_by_tags ||= {}
  @security_groups_by_tags[tags] ||=
    begin
      groups = all_security_groups.select { |g| g.tags.any? { |t| t.key == tags.keys && t.value == tags.values } }.take(2)
      case
      when groups.count == 1
        groups.first.id
      when groups.count < 1
        raise "No security group with tags '#{tags}' was found."
      when groups.count > 1
        raise "More than one security group with tags '#{tags}' found: " + groups.join(', ')
      end
    end
end

#security_group_in_vpc(vpc_id, name) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/terrafying/aws.rb', line 64

def security_group_in_vpc(vpc_id, name)
  @security_groups_in_vpc ||= {}
  @security_groups_in_vpc[vpc_id + name] ||=
    begin
      STDERR.puts "Looking up id of security group '#{name}'"
      groups = all_security_groups.select { |g| g.vpc_id == vpc_id && g.group_name == name }.take(2)
      case
      when groups.count == 1
        groups.first.id
      when groups.count < 1
        raise "No security group with name '#{name}' was found."
      when groups.count > 1
        raise "More than one security group with name '#{name}' found: " + groups.join(', ')
      end
    end
end

#security_groups(*names) ⇒ Object



169
170
171
# File 'lib/terrafying/aws.rb', line 169

def security_groups(*names)
  names.map{|n| security_group(n)}
end

#security_groups_in_vpc(vpc_id, *names) ⇒ Object



173
174
175
# File 'lib/terrafying/aws.rb', line 173

def security_groups_in_vpc(vpc_id, *names)
  names.map{|n| security_group_in_vpc(vpc_id, n)}
end

#subnet(name) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/terrafying/aws.rb', line 177

def subnet(name)
  @subnets ||= {}
  @subnets[name] ||=
    begin
      STDERR.puts "Looking up id of subnet '#{name}'"
      subnets = @ec2_resource.subnets(
        {
          filters: [
            {
              name: "tag:Name",
              values: [name],
            },
          ],
        }).limit(2)
      case
      when subnets.count == 1
        subnets.first.id
      when subnets.count < 1
        raise "No subnet with name '#{name}' was found."
      when subnets.count > 1
        raise "More than one subnet with this name '#{name}' found : " + subnets.join(', ')
      end
    end
end

#subnet_by_id(id) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/terrafying/aws.rb', line 202

def subnet_by_id(id)
  @subnets_by_id ||= {}
  @subnets_by_id[id] ||=
    begin
      resp = @ec2_client.describe_subnets(
        {
          subnet_ids: [id],
        })
      subnets = resp.subnets
      case
      when subnets.count == 1
        subnets.first
      when subnets.count < 1
        raise "No subnet with id '#{id}' was found."
      when subnets.count > 1
        raise "More than one subnet with this id '#{id}' found : " + subnets.join(', ')
      end
    end
end

#subnets(*names) ⇒ Object



222
223
224
# File 'lib/terrafying/aws.rb', line 222

def subnets(*names)
  names.map{|n| subnet(n)}
end

#subnets_for_vpc(vpc_id) ⇒ Object



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/terrafying/aws.rb', line 226

def subnets_for_vpc(vpc_id)
  @subnets_for_vpc ||= {}
  @subnets_for_vpc[vpc_id] ||=
    begin
      resp = @ec2_client.describe_subnets(
        {
          filters: [
            { name: "vpc-id", values: [ vpc_id ] },
          ],
        })

      subnets = resp.subnets

      case
      when subnets.count >= 1
        subnets
      when subnets.count < 1
        raise "No subnets found for '#{vpc_id}'."
      end
    end
end

#target_groups_by_lb(arn) ⇒ Object



480
481
482
483
484
485
486
487
488
489
490
491
492
# File 'lib/terrafying/aws.rb', line 480

def target_groups_by_lb(arn)
  @target_groups ||= {}
  @target_groups[arn] ||=
    begin
      resp = @elb_client.describe_target_groups(
        {
          load_balancer_arn: arn,
        }
      )

      resp.target_groups
    end
end

#vpc(name) ⇒ Object



276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/terrafying/aws.rb', line 276

def vpc(name)
  @vpcs ||= {}
  @vpcs[name] ||=
    begin
      STDERR.puts "looking for a VPC with name '#{name}'"
      resp = @ec2_client.describe_vpcs({})
      matching_vpcs = resp.vpcs.select { |vpc|
        name_tag = vpc.tags.select { |tag| tag.key == "Name" }.first
        name_tag && name_tag.value == name
      }
      case
      when matching_vpcs.count == 1
        matching_vpcs.first
      when matching_vpcs.count < 1
        raise "No VPC with name '#{name}' was found."
      when matching_vpcs.count > 1
        raise "More than one VPC with name '#{name}' was found: " + matching_vpcs.join(', ')
      end
    end
end