Module: Admiral::Util::OpsWorks

Included in:
Tasks::OpsWorks
Defined in:
lib/admiral-opsworks/util.rb

Instance Method Summary collapse

Instance Method Details

#all_availability_zonesObject



34
35
36
37
# File 'lib/admiral-opsworks/util.rb', line 34

def all_availability_zones
  ec2 = AWS::EC2.new
  ec2.availability_zones.map(&:name)
end

#attach_ebs_volumes(instance_id, volume_ids) ⇒ Object



48
49
50
51
52
53
# File 'lib/admiral-opsworks/util.rb', line 48

def attach_ebs_volumes(instance_id, volume_ids)
  volume_ids.each do |volume_id|
    puts "[admiral] Attaching EBS volume #{volume_id} to instance #{instance_id}"
    opsworks.assign_volume({:volume_id => volume_id, :instance_id => instance_id})
  end
end

#create_instance(stack_id, layer_id, az) ⇒ Object



66
67
68
69
70
71
72
# File 'lib/admiral-opsworks/util.rb', line 66

def create_instance(stack_id, layer_id, az)
  opsworks.create_instance({:stack_id => stack_id,
                            :layer_ids => [layer_id],
                            :instance_type => ENV['INSTANCE_TYPE'] || 't2.small',
                            :install_updates_on_boot => !ENV['SKIP_INSTANCE_PACKAGE_UPDATES'],
                            :availability_zone => az})
end

#detach_ebs_volumes(instance_id) ⇒ Object



55
56
57
58
59
60
61
62
63
64
# File 'lib/admiral-opsworks/util.rb', line 55

def detach_ebs_volumes(instance_id)
  response = opsworks.describe_volumes(:instance_id => instance_id)
  volume_ids = response[:volumes].map { |v| v[:volume_id] }
  volume_ids.each do |volume_id|
    puts "[admiral] Detaching EBS volume #{volume_id} from instance #{instance_id}"
    opsworks.unassign_volume(:volume_id => volume_id)
  end

  volume_ids
end

#get_all_instances(layer_id) ⇒ Object



39
40
41
42
# File 'lib/admiral-opsworks/util.rb', line 39

def get_all_instances(layer_id)
  response = opsworks.describe_instances({:layer_id => layer_id})
  response[:instances]
end

#instance_online?(instance_id) ⇒ Boolean

Returns:

  • (Boolean)


11
12
13
14
# File 'lib/admiral-opsworks/util.rb', line 11

def instance_online?(instance_id)
  response = opsworks.describe_instances(:instance_ids => [instance_id])
  response[:instances].first[:status] == "online"
end

#instance_status(instance_id) ⇒ Object



16
17
18
19
20
21
22
23
24
25
# File 'lib/admiral-opsworks/util.rb', line 16

def instance_status(instance_id)
  begin
    response = opsworks.describe_instances(:instance_ids => [instance_id])
  rescue AWS::OpsWorks::Errors::ResourceNotFoundException
    return "nonexistent"
  end
  response[:instances].first[:status].tap do |status|
    raise "Instance #{instance_id} has a failed status #{status}" if status =~ /fail|error/i
  end
end

#opsworksObject



7
8
9
# File 'lib/admiral-opsworks/util.rb', line 7

def opsworks
  AWS::OpsWorks::Client.new(region: 'us-east-1') # opsworks command-and-control is us-east-1 ONLY ;)
end

#ssh_to_instance(instance, ssh_key_name, username = 'ec2-user') ⇒ Object



44
45
46
# File 'lib/admiral-opsworks/util.rb', line 44

def ssh_to_instance(instance, ssh_key_name, username = 'ec2-user')
  Kernel.exec "ssh -i ~/.ssh/#{ssh_key_name}.pem #{username}@#{instance[:public_ip]}"
end

#update_instances(stack_id, layer_id, count) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/admiral-opsworks/util.rb', line 74

def update_instances(stack_id, layer_id, count)
  azs = all_availability_zones
  existing_instances = get_all_instances(layer_id)
  count_to_create = count.to_i - existing_instances.size
  new_instances = (1..count_to_create).map do |i|
    instance = create_instance(stack_id, layer_id, azs[(existing_instances.size + i) % azs.size])
    puts "[admiral] Created instance #{instance[:instance_id]}; now starting up."
    opsworks.start_instance(:instance_id => instance[:instance_id])
    instance
  end

  new_instances.each do |instance|
    wait_for_instance(instance[:instance_id], "online")
  end

  puts "Replacing existing instances.." if existing_instances.size > 0

  existing_instances.each do |instance|
    puts "[admiral] Stopping instance #{instance[:hostname]}, id: #{instance[:instance_id]}"
    opsworks.stop_instance({:instance_id => instance[:instance_id]})
    wait_for_instance(instance[:instance_id], "stopped")
    ebs_volume_ids = detach_ebs_volumes(instance[:instance_id])

    puts "[admiral] Creating replacement instance"
    replacement = create_instance(stack_id, layer_id, instance[:availability_zone])
    attach_ebs_volumes(replacement[:instance_id], ebs_volume_ids)

    puts "[admiral] Starting new instance, id: #{replacement[:instance_id]}"
    opsworks.start_instance(:instance_id => replacement[:instance_id])
    wait_for_instance(replacement[:instance_id], "online")

    puts "[admiral] Deleting old instance #{instance[:hostname]}, #{instance[:instance_id]}"
    opsworks.delete_instance(:instance_id => instance[:instance_id])
  end
end

#wait_for_instance(instance_id, status) ⇒ Object



27
28
29
30
31
32
# File 'lib/admiral-opsworks/util.rb', line 27

def wait_for_instance(instance_id, status)
  while (ins_status = instance_status(instance_id)) != status
    puts "[admiral] Waiting for #{instance_id} instance to become #{status}. Current status: #{ins_status}"
    sleep 10
  end
end