class Anjou::EC2

Constants

DEFAULT_AMI
DEFAULT_INSTANCE_TYPE
DEFAULT_SNAPSHOT_NAME
DEFAULT_USER_DATA
DEFAULT_ZONE
KEY_ID
KEY_PAIR_NAME
Name
SECRET_KEY
SECURITY_GROUP_NAME
USER_VOL_SIZE

Attributes

api[R]

Public Class Methods

new(access_key_id=KEY_ID, secret_access_key=SECRET_KEY) click to toggle source
# File lib/anjou/ec2.rb, line 19
def initialize(access_key_id=KEY_ID, secret_access_key=SECRET_KEY)
  @api = ::AWS::EC2.new(
    access_key_id:     access_key_id,
    secret_access_key: secret_access_key )
end

Public Instance Methods

attach(username, instance, device=nil) click to toggle source
# File lib/anjou/ec2.rb, line 107
def attach(username, instance, device=nil)
  volume = user_volume_for(username)
  guard_volume_available(volume, username)
  device ||= next_device_for(instance)
  volume.attach_to instance, device
end
create_instance( username: nil, ami: DEFAULT_AMI, key_name: KEY_PAIR_NAME, zone: DEFAULT_ZONE, instance_type: DEFAULT_INSTANCE_TYPE, user_data: DEFAULT_USER_DATA ) click to toggle source
# File lib/anjou/ec2.rb, line 25
def create_instance(
  username: nil,
  ami: DEFAULT_AMI,
  key_name: KEY_PAIR_NAME,
  zone: DEFAULT_ZONE,
  instance_type: DEFAULT_INSTANCE_TYPE,
  user_data: DEFAULT_USER_DATA
)
  key_pair = key_pair_for key_name
  raise "Unable to start instance: no such key pair exists! (key_name: #{key_name})" unless key_pair && key_pair.exists?
  @api.instances.create(
    image_id: ami,
    key_pair: key_pair,
    availability_zone: zone,
    instance_type: instance_type,
    user_data: user_data,
    security_groups: security_groups
  ).tap do |instance|
    if username
      instance.tags.Name = name_tag_for username
      instance.tags.owner = username
    end
  end
end
create_user_volume(username: nil, user_vol_size: USER_VOL_SIZE, zone: DEFAULT_ZONE, snapshot: DEFAULT_SNAPSHOT_NAME) click to toggle source
# File lib/anjou/ec2.rb, line 64
def create_user_volume(username: nil, user_vol_size: USER_VOL_SIZE, zone: DEFAULT_ZONE, snapshot: DEFAULT_SNAPSHOT_NAME)

  aws_snapshot = @api.snapshots.tagged('Name').select do |snp|
    snp.tags.to_a.include? ['Name', snapshot]
  end.last

  @api.volumes.create(
    size: user_vol_size,
    availability_zone: zone,
    snapshot: aws_snapshot
  ).tap do |volume|
    if username
      volume.tags.Name = name_tag_for username
      volume.tags.owner = username
    end
  end
end
delete_user_volume(username) click to toggle source
# File lib/anjou/ec2.rb, line 82
def delete_user_volume(username)
  detach(username).delete
end
detach(username) click to toggle source
# File lib/anjou/ec2.rb, line 114
def detach(username)
  user_volume_for(username).tap do |volume|
    volume.attachments.each do |attachment|
      attachment.delete(force: true)
    end
    sleep 1 until volume.status == :available
  end
end
instance_for(username) click to toggle source
# File lib/anjou/ec2.rb, line 50
def instance_for(username)
  @api.instances.tagged('owner').select do |instance|
    instance.tags.to_a.include? ['owner', username]
  end.select{|i| i.status != :terminated }.last
end
instance_status_for(username) click to toggle source
# File lib/anjou/ec2.rb, line 56
def instance_status_for(username)
  instance_for(username).status
end
key_pair_for(key_name) click to toggle source
# File lib/anjou/ec2.rb, line 60
def key_pair_for(key_name)
  @api.key_pairs.select{ |kp| kp.name == key_name }.last
end
next_device_for(instance) click to toggle source
# File lib/anjou/ec2.rb, line 123
def next_device_for(instance)
  '/dev/sda' + (instance.attachments.keys.size + 1).to_s
end
security_groups() click to toggle source
# File lib/anjou/ec2.rb, line 127
def security_groups
  @api.security_groups.to_a.select{ |sg| sg.name == 'Anjou' }
end
user_volume_for(username) click to toggle source
# File lib/anjou/ec2.rb, line 86
def user_volume_for(username)
  @api.volumes.tagged('owner').select do |vol|
    vol.tags.to_a.include? ['owner', username]
  end.first
end
user_volume_status_for(username) click to toggle source
# File lib/anjou/ec2.rb, line 92
def user_volume_status_for(username)
  user_volume_for(username).status
end
wait_for_user_volume(username, status: :available, timeout: 15) click to toggle source

@depricated: this method violates Anjou::EC2's “thin wrapper” contract.

It's a useful method, but it should be implemented elsewhere.
# File lib/anjou/ec2.rb, line 98
def wait_for_user_volume(username, status: :available, timeout: 15)
  seconds = 0
  while user_volume_status_for(username) != status
    raise "Timeout: After #{timeout} seconds, user volume for #{username} is still not #{status}" if seconds >= timeout
    seconds += sleep 1
  end
  status
end

Private Instance Methods

guard_volume_available(volume, username) click to toggle source
# File lib/anjou/ec2.rb, line 137
def guard_volume_available(volume, username)
  volume.status.tap do |status|
    unless status == :available
      raise "user volume for \"#{username}\" is not available (status: #{status})"
    end
  end
end
name_tag_for(username) click to toggle source
# File lib/anjou/ec2.rb, line 133
def name_tag_for(username)
  "anjou-#{username || :generic}"
end