class SyncWrap::AmazonEC2
Amazon EC2 host provider. Supports importing, creating, and terminating hosts.
Synopsis¶ ↑
Add the following to your sync.rb
ec2 = AmazonEC2.new( space )
Then add profiles via profile, as needed.
Attributes
The json configuration file path, parsed and passed to AWS::config. This file should contain a json object with the minimal required keys: access_key_id, secret_access_key. A relative path is interpreted relative to the :sync_file_path option if provided on construction. (default: private/aws.json)
Public Class Methods
# File lib/syncwrap/amazon_ec2.rb, line 53 def initialize( space, opts = {} ) super() @profiles = {} @space = space @aws_config = 'private/aws.json' opts = opts.dup sync_file_path = opts.delete( :sync_file_path ) opts.each { |name, val| send( name.to_s + '=', val ) } # Look up aws_config (i.e. default private/aws.json) relative to # the sync file path. if @aws_config if sync_file_path @aws_config = File.expand_path( @aws_config, sync_file_path ) end if File.exist?( @aws_config ) aws_configure( @aws_config ) else @aws_config = relativize( @aws_config ) warn "WARNING: #{aws_config} not found. EC2 provider operations not available." @aws_config = nil end end end
Public Instance Methods
Create new hosts and append host definitions to the sync_file. If a block is given, each new host is yielded before appending.
# File lib/syncwrap/amazon_ec2.rb, line 126 def create_hosts( count, profile, name, sync_file ) require_configured! profile = get_profile( profile ) if profile.is_a?( Symbol ) profile = profile.dup # FIXME: Support profile overrides? Also add some targeted CLI # overrides (like for :availability_zone)? if profile[ :user_data ] == :ec2_user_sudo profile[ :user_data ] = no_tty_sudoer( 'ec2-user' ) end dname = profile.delete( :default_name ) name ||= dname count.times do hname = if count == 1 raise "Host #{name} already exists!" if space.get_host( name ) name else find_name( name ) end props = aws_create_instance( hname, profile ) host = space.host( props ) yield( host ) if block_given? append_host_definitions( [ host ], nil, sync_file ) host[ :just_created ] = true # Need to use a host prop for this since context(s) do not # exist yet. Note it is set after append_host_definitions, to # avoid permanently writing this property to the sync_file. end end
Create a temporary host using the specified profile, yield to block for provisioning, then create a machine image and terminate the host. If block returns false, then the image will not be created nor will the host be terminated. On success, returns image_id (ami-*) and name.
# File lib/syncwrap/amazon_ec2.rb, line 164 def create_image_from_profile( profile_key, sync_file ) require_configured! profile = get_profile( profile_key ).dup tag = profile[ :tag ] profile[ :tag ] = tag = tag.call if tag.is_a?( Proc ) opts = {} opts[ :name ] = profile_key.to_s opts[ :name ] += ( '-' + tag ) if tag opts[ :description ] = profile[ :description ] if image_name_exist?( profile[ :region ], opts[ :name ] ) raise "Image name #{opts[:name]} (profile-tag) already exists." end hname = nil loop do hname = SecureRandom::hex(4) break unless space.get_host( hname ) end create_hosts( 1, profile, hname, sync_file ) host = space.host( hname, imaging: true ) success = yield( host ) if success image_id = create_image( host, opts ) terminate_hosts( [ hname ], false, sync_file, false ) [ image_id, opts[ :name ] ] end end
# File lib/syncwrap/amazon_ec2.rb, line 104 def get_profile( key ) @profiles[ key ] or raise "Profile #{key} not registered" end
# File lib/syncwrap/amazon_ec2.rb, line 108 def import_hosts( regions, sync_file ) require_configured! hlist = import_host_props( regions ) unless hlist.empty? hlist.map! do |props| props[:name] ||= props[:id].to_s Host.new( space, props ) end time = Time.now.utc cmt = "\n# Import of AWS #{regions.join ','} on #{time.iso8601}" append_host_definitions( hlist, cmt, sync_file ) end end
Define a host profile by Symbol key and Hash value.
Profiles may inherit properties from a :base_profile, either specified by that key, or the :default profile. The base_profile must be defined in advance (above in the sync file). When merging profile to any base_profile, the :roles property is concatenated via set union. All other properties are overwritten.
FIXME: All other profile properties are as currently defined by aws_create_instance.
# File lib/syncwrap/amazon_ec2.rb, line 90 def profile( key, profile ) profile = profile.dup base = profile.delete( :base_profile ) || :default base_profile = @profiles[ base ] if base_profile profile = base_profile.merge( profile ) if base_profile[ :roles ] && profile[ :roles ] profile[ :roles ] = ( base_profile[ :roles ] | profile[ :roles ] ) end end @profiles[ key ] = profile end
# File lib/syncwrap/amazon_ec2.rb, line 197 def terminate_hosts( names, delete_attached_storage, sync_file, do_wait = true ) require_configured! names.each do |name| host = space.get_host( name ) raise "Host #{name} not found in Space, sync file." unless host raise "Host #{name} missing :id" unless host[:id] raise "Host #{name} missing :region" unless host[:region] aws_terminate_instance( host, delete_attached_storage, do_wait ) delete_host_definition( host, sync_file ) end end