Class: PoolParty::Remote::Ec2

Inherits:
RemoterBase show all
Defined in:
lib/poolparty/net/remoter_bases/ec2/ec2.rb

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from RemoterBase

#after_launched, available_bases, #before_shutdown, #cloud, describe_instance, describe_instances, inherited, #initialize, #key_name, #keypair, launch_instance!, #launch_instance!, #remoter_base_options, symbol, terminate_instance!, #terminate_youngest_instance!, #to_hash, #to_s

Methods included from Pinger

included

Methods included from PoolParty::Remote

#are_any_nodes_exceeding_minimum_runtime?, #are_too_few_instances_running?, #are_too_many_instances_running?, available, #commands, #execute!, #list_of_instances, #list_of_nodes_exceeding_minimum_runtime, #netssh, #nodes, #remote_rsync_command, #remote_ssh_array, #remote_ssh_string, #rsync, #rsync_command, #rsync_storage_files_to, #rsync_storage_files_to_command, #rsync_to, #rsync_to_command, #run_command_on, #run_command_on_command, #run_command_on_instance_number, #run_local, #run_remote, #scp_array, #scp_to_command, #simplest_run_remote, #ssh_array, #ssh_command, #ssh_into, #ssh_into_instance_number, #ssh_options, #ssh_string, #target_host

Constructor Details

This class inherits a constructor from PoolParty::Remote::RemoterBase

Class Method Details

.ec2(o) ⇒ Object



141
142
143
144
145
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 141

def self.ec2(o)
  @ec2 ||= EC2::Base.new( :access_key_id => o[:access_key], 
                          :secret_access_key => o[:secret_access_key]
                        )
end

.launch_new_instance!(o) ⇒ Object

Requires a hash of options



67
68
69
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 67

def self.launch_new_instance!(o)
  new(o).launch_new_instance!
end

Instance Method Details

#after_install_tasks_for(o) ⇒ Object



271
272
273
274
275
276
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 271

def after_install_tasks_for(o)
  [
    # "cd /var/poolparty && wget http://rubyforge.org/frs/download.php/43666/amazon-ec2-0.3.1.gem -O amazon-ec2.gem 2>&1",
    # "/usr/bin/gem install --no-ri --no-rdoc amazon-ec2.gem 2>&1"
  ]
end

#after_launch_instance(inst) ⇒ Object



170
171
172
173
174
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 170

def after_launch_instance(inst)
  if inst
    associate_address(inst)
  end
end

#associate_address(instance = nil) ⇒ Object

Associate an address with the instance using ec2 Get the next_unused_elastic_ip and if there is one, associate the instance to the public ip



180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 180

def associate_address(instance=nil)
  if ip = next_unused_elastic_ip
    vputs "Associating #{instance.instance_id} with #{ip}"
    ec2.associate_address(:instance_id => instance.instance_id, :public_ip => ip)
    
    # Try for 10 minutes to pint port 22 
    500.times do |i|
      dprint "."
      if ping_port(ip, 22)
        instance[:ip] = ip
        return true
      end
      sleep(2)
    end 
  end
end

#aws_keysObject

Class method helpers



160
161
162
163
164
165
166
167
168
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 160

def aws_keys
  unless @access_key && @secret_access_key
    aws_keys = {}
    aws_keys = YAML::load( File.open('/etc/poolparty/aws_keys.yml') ) rescue 'No aws_keys.yml file.   Will try to use enviornment variables'
    @access_key ||= aws_keys[:access_key] || ENV['AMAZON_ACCESS_KEY_ID'] || ENV['AWS_ACCESS_KEY']
    @secret_access_key ||= aws_keys[:secret_access_key] || ENV['AMAZON_SECRET_ACCESS_KEY'] || ENV['AWS_SECRET_ACCESS_KEY']
  end
  [@access_key, @secret_access_key]
end

#create_keypairObject

Help create a keypair for the cloud This is a helper to create the keypair and add them to the cloud for you



227
228
229
230
231
232
233
234
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 227

def create_keypair
  return false unless keypair
  unless ::File.exists?( new_keypair_path )
    FileUtils.mkdir_p ::File.dirname( new_keypair_path )
    vputs "Creating keypair: #{keypair} in #{new_keypair_path}"
    Kernel.system "ec2-add-keypair #{keypair} > #{new_keypair_path} && chmod 600 #{new_keypair_path}"
  end
end

#create_snapshotObject

wrapper for remote base to perform a snapshot backup for the ebs volume



237
238
239
240
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 237

def create_snapshot
  return nil if ebs_volume_id.nil?
  ec2.create_snapshot(:volume_id => ebs_volume_id)
end

#custom_install_tasks_for(o) ⇒ Object

Hook TODO#: Change this so they match with the cap tasks



262
263
264
265
266
267
268
269
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 262

def custom_install_tasks_for(o)        
  [
    # "if [ -z $(grep -v '#' /etc/hosts | grep '#{o.name}') ]; then echo \"$(curl http://169.254.169.254/latest/meta-data/public-ipv4) #{o.name}\" >> /etc/hosts; fi",
    "if [ -z \"$(grep -v '#' /etc/hosts | grep '#{o.name}')\" ]; then echo '127.0.0.1 #{o.name}' >> /etc/hosts; fi",
    "hostname #{o.name}",
    "echo #{o.name} > /etc/hostname"
  ]
end

#custom_minimum_runnable_optionsObject



256
257
258
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 256

def custom_minimum_runnable_options
  [:ami, :availability_zone, :security_group]
end

#describe_instance(o = {}) ⇒ Object

Describe an instance’s status



97
98
99
100
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 97

def describe_instance(o={})
  return describe_instances.first if o.empty? || o[:instance_id].nil?
  describe_instances.detect {|a| a[:name] == o[:instance_id] || a[:ip] == o[:instance_id] || a[:instance_id] == o[:instance_id] }
end

#describe_instances(o = {}) ⇒ Object



102
103
104
105
106
107
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 102

def describe_instances(o={})
  ec2_instants = EC2ResponseObject.describe_instances(ec2.describe_instances)
  insts = ec2_instants.select_with_hash(o) if !o.empty?
  ec2_remote_instances = ec2_instants.collect{|i| Ec2RemoteInstance.new(i)}
  ec2_remote_instances.sort {|a,b| a[:ami_launch_index] <=> b[:ami_launch_index] }
end

#ec2(o = {}) ⇒ Object

return or create a new base EC2 connection object that will actually connect to ec2



136
137
138
139
140
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 136

def ec2(o={})
  @ec2 ||= EC2::Base.new( :access_key_id => o[:access_key] || get_access_key, 
                          :secret_access_key => o[:secret_access_key] || get_secret_access_key
                        )
end

#get_access_key(n = nil) ⇒ Object



278
279
280
281
282
283
284
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 278

def get_access_key(n=nil)
  if n.nil?
    dsl_options[:access_key] ||= Default.access_key
  else
    self.access_key = n
  end
end

#get_descriptions(o = {}) ⇒ Object



155
156
157
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 155

def get_descriptions(o={})
  self.class.get_descriptions(o)
end

#get_instances_description(o = {}) ⇒ Object

Get the ec2 description for the response in a hash format



148
149
150
151
152
153
154
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 148

def get_instances_description(o={})
  #TODO: only use keypair.full_filepath
  set_vars_from_options dsl_options.merge(o)
  key_hash = {:keypair => self.keypair_name}
  out = EC2ResponseObject.get_descriptions(ec2(dsl_options).describe_instances)
  out = keypair_name ? out.select_with_hash(key_hash) : out
end

#get_secret_access_key(n = nil) ⇒ Object



286
287
288
289
290
291
292
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 286

def get_secret_access_key(n=nil)
  if n.nil?
    dsl_options[:secret_access_key] ||= Default.secret_access_key
  else
    self.secret_access_key = n
  end
end

#has_cert_and_key?Boolean

Returns:

  • (Boolean)


242
243
244
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 242

def has_cert_and_key?
  pub_key && private_key
end

#launch_new_instance!(o = {}) ⇒ Object

TODO: Fix the key_name issue Start a new instance with the given options



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 73

def launch_new_instance!(o={})
  set_vars_from_options o
  keypair_name ||= o[:keypair_name] || keypair || (clouds[o[:cloud_name]].keypair.basename if o[:cloud_name])
  raise "You must pass a keypair to launch an instance, or else you will not be able to login. options = #{o.inspect}" if !keypair_name 
  o.merge!( dsl_options.merge(:key_name=>keypair_name, :group_id => security_group) )
  instance = ec2(o).run_instances(o)
  
  begin
    h = EC2ResponseObject.describe_instance(instance)
    #h = instance.instancesSet.item.first
  rescue Exception => e
    vputs "There was an error:\n\t#{e.inspect}"
    h = EC2ResponseObject.describe_instance(instance) rescue instance
    # h = instance
  end
  Ec2RemoteInstance.new(h)
end

#next_unused_elastic_ipObject

Get the next usable elastic ip First, get the list of addresses from ec2 that the client has access to, then select only the ones that are not associated with an instance. If the cloud has set elastic_ips to use, then, using the intersection of the unused ips and those, find the first one available and return that, otherwise, return the first elastic ip available



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 204

def next_unused_elastic_ip
  if elastic_ips.empty?
    nil
  else
    # [{"instanceId"=>nil, "publicIp"=>"174.129.212.93"}, {"instanceId"=>nil, "publicIp"=>"174.129.212.94"}]
    if addressesSet = ec2(dsl_options).describe_addresses(:public_ip => elastic_ips)["addressesSet"]
      begin
        empty_addresses = addressesSet["item"].select {|i| i["instanceId"].nil? }
        ips = empty_addresses.map {|addr| addr["publicIp"]}
        if elastic_ips
          ips_to_use = elastic_ips & ips
          ips_to_use.first
        end
      rescue Exception => e
        puts "Error: #{e}"
        nil
      end
    end
  end
end

#private_keyObject

Private key



252
253
254
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 252

def private_key
  @private_key ||= ENV["EC2_PRIVATE_KEY"] ? ENV["EC2_PRIVATE_KEY"] : nil
end

#pub_keyObject

The keys are used only for puppet certificates and are only used for EC2. Public key



248
249
250
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 248

def pub_key
  @pub_key ||= ENV["EC2_CERT"] ? ENV["EC2_CERT"] : nil
end

#reset_base!Object



294
295
296
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 294

def reset_base!
  @describe_instances = @cached_descriptions = nil
end

#terminate_instance!(o = {}) ⇒ Object

Terminate an instance by id



92
93
94
# File 'lib/poolparty/net/remoter_bases/ec2/ec2.rb', line 92

def terminate_instance!(o={})
  ec2(o).terminate_instances(:instance_id => o[:instance_id])
end