Class: EC2Launcher::BlockDeviceBuilder

Inherits:
Object
  • Object
show all
Includes:
BackoffRunner
Defined in:
lib/ec2launcher/block_device_builder.rb

Overview

Helper class to build EC2 block device definitions.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from BackoffRunner

#run_with_backoff, #test_with_backoff

Constructor Details

#initialize(ec2, volume_size = nil) ⇒ BlockDeviceBuilder

Returns a new instance of BlockDeviceBuilder.

Parameters:

  • ec2 (AWS::EC2)

    interface to ec2

  • volume_size (Integer, nil) (defaults to: nil)

    size of new EBS volumes. If set to nil, uses EC2Launcher::Defaults::DEFAULT_VOLUME_SIZE.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/ec2launcher/block_device_builder.rb', line 20

def initialize(ec2, volume_size = nil)
  @ec2 = ec2
  @block_size = volume_size
  @volume_size ||= EC2Launcher::DEFAULT_VOLUME_SIZE

  @block_device_mappings = {}
  @block_device_tags = {}

  begin
    @log = Log4r::Logger['ec2launcher']
  rescue
  end

  @log ||= Log4r::Logger.new 'ec2launcher'
end

Instance Attribute Details

#block_device_mappingsObject (readonly)

Returns the value of attribute block_device_mappings.



14
15
16
# File 'lib/ec2launcher/block_device_builder.rb', line 14

def block_device_mappings
  @block_device_mappings
end

#block_device_tagsObject (readonly)

Returns the value of attribute block_device_tags.



15
16
17
# File 'lib/ec2launcher/block_device_builder.rb', line 15

def block_device_tags
  @block_device_tags
end

Instance Method Details

#generate_block_devices(instance_type, environment, application, clone_host = nil) ⇒ Hash<String, Hash] returns a mapping of device names to device details

Generates the mappings for ephemeral and ebs volumes.

Parameters:

  • instance_type (String)

    type of instance. See EC2Launcher::Defaults::INSTANCE_TYPES.

  • environment (EC2Launcher::Environment)

    current environment

  • application (EC2Launcher::Application)

    current application

  • clone_host (String, nil) (defaults to: nil)

    FQDN of host to clone or nil to skip cloning.

Returns:

  • (Hash<String, Hash] returns a mapping of device names to device details)

    Hash<String, Hash] returns a mapping of device names to device details



45
46
47
48
49
50
51
52
53
# File 'lib/ec2launcher/block_device_builder.rb', line 45

def generate_block_devices(instance_type, environment, application, clone_host = nil)
  block_device_mappings = {}

  build_ephemeral_drives(block_device_mappings, instance_type)
  build_ebs_volumes(block_device_mappings, application.block_devices)
  clone_volumes(block_device_mappings, application, clone_host)

  block_device_mappings
end

#generate_device_tags(hostname, short_hostname, environment_name, block_devices) ⇒ Hash<String, Hash<String, String>] returns a mapping of device names to maps tag names and values.

Generates a mapping of block device names to tags.

Parameters:

  • hostname (String)

    FQDN for new host

  • short_hostname (String)

    short name for host host, without domain name.

  • environment_name (String)

    Name of current environment

  • block (EC2Launcher::DSL::BlockDevice)

    devices for this application

Returns:

  • (Hash<String, Hash<String, String>] returns a mapping of device names to maps tag names and values.)

    Hash<String, Hash<String, String>] returns a mapping of device names to maps tag names and values.



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/ec2launcher/block_device_builder.rb', line 63

def generate_device_tags(hostname, short_hostname, environment_name, block_devices)
  block_device_tags = {}
  unless block_devices.nil?
    base_device_name = "sdf"
    block_devices.each do |block_device|
      build_block_devices(block_device.count, base_device_name) do |device_name, index|
        block_device_tags["/dev/#{device_name}"] = {
          "purpose" => block_device.name,
          "host" => hostname,
          "environment" => environment_name
        }
        
        if block_device.raid_level.nil?
          block_device_tags["/dev/#{device_name}"]["Name"] = "#{short_hostname} #{block_device.name}"
        else
          block_device_tags["/dev/#{device_name}"]["Name"] = "#{short_hostname} #{block_device.name} raid (#{(index + 1).to_s})"
          block_device_tags["/dev/#{device_name}"]["raid_number"] = (index + 1).to_s
        end
      end
    end
  end
  block_device_tags
end

#get_latest_raid_snapshot_mapping(hostname, purpose, count) ⇒ Object



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/ec2launcher/block_device_builder.rb', line 279

def get_latest_raid_snapshot_mapping(hostname, purpose, count)
  @log.info "Retrieving list of snapshots ..."
  result = @ec2.snapshots.tagged("host").tagged_values(hostname).tagged("volumeName").tagged_values("*raid*").tagged("time")

  @log.info "Building list of snapshots to clone (#{purpose}) for '#{hostname}'..."
  host_snapshots = build_snapshot_clone_list(purpose, result)

  # Bucket the snapshots based on volume number e.g. "raid (1)" vs "raid (2)"
  snapshot_buckets = bucket_snapshots_by_volume_number(host_snapshots)

  # Sort the snapshots in each bucket by time
  snapshot_buckets.keys.each do |key|
    snapshot_buckets[key].sort! do |a, b|
      b.tags["time"] <=> a.tags["time"]
    end
  end

  # We need to find the most recent backup time that all snapshots have in common.
  most_recent_date = get_most_recent_common_snapshot_time(snapshot_buckets)

  @log.info "Most recent snapshot: #{most_recent_date}"

  # Find snapshots for the specified date
  snapshot_mapping = { }
  AWS.memoize do
    snapshot_buckets.keys.each do |index|
      found = false
      snapshot_buckets[index].each do |snapshot|
        if snapshot.tags["time"] == most_recent_date
          snapshot_mapping[index] = snapshot
          found = true
          break
        end
      end

      abort("***** ERROR: Unable to find snapshot for #{purpose} (#{index.to_s})") unless found
    end
  end
  snapshot_mapping
end

#get_latest_snapshot_by_purpose(clone_host, purpose) ⇒ Object



329
330
331
332
333
334
335
336
337
338
339
# File 'lib/ec2launcher/block_device_builder.rb', line 329

def get_latest_snapshot_by_purpose(clone_host, purpose)
  @log.info "Retrieving snapshtos for #{clone_host} [#{purpose}]"
  results = @ec2.snapshots.tagged("host").tagged_values(clone_host).tagged("purpose").tagged_values(purpose)
  
  snapshot = nil
  results.each do |s|
    next unless s.status == :completed
    snapshot = s if snapshot.nil? || snapshot.start_time < s.start_time
  end
  snapshot
end

#get_most_recent_common_snapshot_time(snapshot_buckets) ⇒ Object



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/ec2launcher/block_device_builder.rb', line 240

def get_most_recent_common_snapshot_time(snapshot_buckets)
  # We need to find the most recent backup time that all snapshots have in common.
  #
  # For example, we may have the following snapshots for "raid (1)":
  #   volumeName => db1.dev db raid (1), time => 11-06-15 10:00
  #   volumeName => db1.dev db raid (1), time => 11-06-15 09:00
  #   volumeName => db1.dev db raid (1), time => 11-06-14 09:00
  # And the following snapshots for "raid (2)":
  #   volumeName => db1.dev db raid (1), time => 11-06-15 09:00
  #   volumeName => db1.dev db raid (1), time => 11-06-14 09:00
  #
  # In this example, the latest snapshot from "raid (1)" is dated "11-06-15 10:00", but "raid (2)" does not have
  # a matching snapshot (because it hasn't completed yet). Instead, we should use the "11-06-15 09:00" snapshots.
  #
  # We find the most recent date from each bucket and then take the earliest one.
  most_recent_dates = []
  snapshot_buckets.keys().each do |key|
    snapshot = snapshot_buckets[key][0]
    most_recent_dates << snapshot.tags["time"].to_s
  end
  most_recent_dates.sort!
  most_recent_dates[0]
end