class AwsRegion::AwsInstance
Class to handle EC2 Instances
Attributes
Public Class Methods
# File lib/aws_region.rb, line 478 def initialize(region, options = {}) @tags = {} @region = region if options.has_key?(:instance) @_instance = options[:instance] @id = @_instance[:instance_id] @public_ip = @_instance[:public_ip_address] @private_ip = @_instance[:private_ip_address] else resp = @region.ec2.run_instances(options[:template]) raise "Error creating instance using options" if resp.nil? or resp[:instances].length <= 0 @_instance = resp[:instances][0] @id = @_instance[:instance_id] @tags = options[:tags] self.add_tags(@tags) self.wait instance = @region.ec2.describe_instances(:instance_ids => [@id])[0][0].instances[0] @public_ip = instance[:public_ip_address] @private_ip = instance[:private_ip_address] raise "could not get ip address" if @public_ip.nil? && @private_ip.nil? self.inject_into_environment end @_instance.tags.each do |t| @tags[t[:key].to_sym] = t[:value] end end
Public Instance Methods
Add an instance to an elastic lb @param lb_name [String] - Name of elastic load balancer
# File lib/aws_region.rb, line 565 def add_to_lb(lb_name) @region.elb.register_instances_with_load_balancer({:load_balancer_name => lb_name, :instances => [{:instance_id => @id}]}) end
Connects using ssh to an ec2 instance
# File lib/aws_region.rb, line 617 def connect if self.state(use_cached_state = false) != "running" log "Cannot connect, instance: #{@region.region}://#{@id} due to its state: #{self.state}" return end ip = (self.public_ip && self.public_ip.strip() != "") ? self.public_ip : self.private_ip log "Connecting: ssh -i ~/.ssh/aws/#{@tags[:key]} #{@tags[:user]}@#{ip}" exec "ssh -i ~/.ssh/aws/#{@tags[:key]} #{@tags[:user]}@#{ip}" end
# File lib/aws_region.rb, line 626 def eject_from_environment if @tags.has_key?(:elastic_lb) log "Removing instance: #{@id} from '#{@tags[:elastic_lb]}' load balancer" self.remove_from_lb(tags[:elastic_lb]) end if @tags.has_key?(:security_groups_foreign) self.revoke_sg_ingress(@tags[:security_groups_foreign].split(",")) end end
construct hash for authorize/revoke ingress and has_sg_rule? @param group_id_port [String] - security_group:port like “sg_xxxxxx:8080” @return [Hash] - Hash for ec2 call for security group management
# File lib/aws_region.rb, line 740 def get_simple_sg_options(group_id_port) security_group_id, port = group_id_port.split(':') port = port.to_s.to_i raise "no security group id" unless security_group_id.to_s.length > 0 raise "no, or invalid port" unless port.to_s.to_i > 0 {:group_id => security_group_id, :ip_permissions => [ :ip_protocol => "tcp", :from_port => port, :to_port => port, :ip_ranges => [:cidr_ip => "#{self.public_ip}/32"] ] } end
Does a security group allow ingress on a port for the public IP of this instance @param group_port [String] - security_group:port like “sg_xxxxxx:8080” @return [Boolean] true if the security group allows ingress for the public IP of this instance on a certain port
# File lib/aws_region.rb, line 682 def has_sg_rule?(group_port) options = get_simple_sg_options(group_port) options_cidr_ip = options[:ip_permissions][0][:ip_ranges][0][:cidr_ip] group_id = options[:group_id] raise "missing security group_id" if group_id.nil? sg = @region.ec2.describe_security_groups(:group_ids => [group_id]).data.security_groups[0] sg.ip_permissions.each do |p| if p.ip_protocol == "tcp" && p.from_port == options[:ip_permissions][0][:from_port] && p.to_port == options[:ip_permissions][0][:to_port] p[:ip_ranges].each do |ipr| return true if ipr.cidr_ip == options_cidr_ip end end end false end
# File lib/aws_region.rb, line 636 def inject_into_environment if @tags.has_key?(:elastic_ip) @region.ec2.associate_address({:instance_id => @id, :public_ip => @tags[:elastic_ip]}) log "Associated ip: #{@tags[:elastic_ip]} with instance: #{@id}" elsif @tags.has_key?(:elastic_ip_allocation_id) @region.ec2.associate_address({:instance_id => @id, :allocation_id => @tags[:elastic_ip_allocation_id]}) log "Associated allocation id: #{@tags[:elastic_ip_allocation_id]} with instance: #{@id}" end if @tags.has_key?(:mount_points) mounts = @tags[:mount_points].split(";") mounts.each do |mnt| (volume_id,device) = mnt.split(",") log "Mounting volume: #{volume_id} on #{device}" self.mount(volume_id, device) end end if @tags.has_key?(:security_group_ids) self.set_security_groups(@tags[:security_group_ids].split(",")) end if @tags.has_key?(:security_groups_foreign) self.authorize_sg_ingress(@tags[:security_groups_foreign].split(",")) end # if any of the above fails, we probably do not want it in the lb if @tags.has_key?(:elastic_lb) self.add_to_lb(@tags[:elastic_lb]) log "Adding instance: #{@id} to '#{@tags[:elastic_lb]}' load balancer" end end
# File lib/aws_region.rb, line 731 def mount(volume_id, device) @region.ec2.attach_volume({:instance_id => @id, :volume_id => volume_id, :device => device}) end
Remove instance from elastic lb @param instance [AwsInstance] Instance to remove from lb @param lb_name [String] Lb name from which the instance is to be removed @return [Aws::PageableResponse]
# File lib/aws_region.rb, line 574 def remove_from_lb(lb_name) lb = @region.elb.describe_load_balancers({:load_balancer_names => [lb_name]}) if lb and lb[:load_balancer_descriptions].length > 0 lb[:load_balancer_descriptions][0][:instances].each do |lb_i| if lb_i[:instance_id] == @id @elb.deregister_instances_from_load_balancer({:load_balancer_name => lb_name, :instances => [{:instance_id => @id}]}) sleep 30 end end end end
revoke security group ingress for public ip of this instance on port @param groups [Array] - each element is String: “security_group_id:port”. For example: [“sg-0xxxxx:80”, “sg-0xxxxx:8443”, “sg-0yyyyy:3000”]
# File lib/aws_region.rb, line 717 def revoke_sg_ingress(groups) # revoke the public ip of this instance for ingress on port for security group # groups is array of strings: security_group_id:port raise "no public ip" unless @public_ip.to_s.match /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ groups.each do |gp| options = get_simple_sg_options(gp) if has_sg_rule?(gp) @region.ec2.revoke_security_group_ingress options log "removed #{self.public_ip} from security group for :port #{gp}" else log "not removing #{self.public_ip} rule #{gp} because it does not exist" end end end
# File lib/aws_region.rb, line 674 def set_security_groups(groups) # only works on instances in a vpc @region.ec2.modify_instance_attribute({:instance_id => @id, :groups => groups}) end
Start an EC2 instance @param wait [Boolean] - When true, will wait for instance to move into “running” state before returning
# File lib/aws_region.rb, line 526 def start(wait=false) if self.state(use_cached_state = false) != "stopped" log "Instance cannot be started - #{@region.region}://#{@id} is in the state: #{self.state}" return end log "Starting instance: #{@region.region}://#{@id}" @region.ec2.start_instances({:instance_ids => [@id]}) if wait begin sleep 10 log "Starting instance: #{@region.region}://#{@id} - state: #{self.state}" end while self.state(use_cached_state = false) != "running" end if @tags.has_key?("elastic_ip") @region.ec2.associate_address({:instance_id => @id, :public_ip => @tags['elastic_ip']}) log "Associated ip: #{@tags['elastic_ip']} with instance: #{@id}" elsif @tags.has_key?("elastic_ip_allocation_id") @region.ec2.associate_address({:instance_id => @id, :allocation_id => @tags['elastic_ip_allocation_id']}) log "Associated allocation id: #{@tags['elastic_ip_allocation_id']} with instance: #{@id}" end if @tags.has_key?("elastic_lb") self.add_to_lb(@tags["elastic_lb"]) log "Adding instance: #{@id} to '#{@tags['elastic_lb']}' load balancer" end end
Determine the state of an ec2 instance @param use_cached_state [Boolean] - When true will use a cached version of the state rather than querying EC2 directly
# File lib/aws_region.rb, line 508 def state(use_cached_state=true) if !use_cached_state response = @region.ec2.describe_instances({instance_ids: [@id]}) response[:reservations].each do |res| res[:instances].each do |inst| if inst[:instance_id] == @id return inst[:state][:name].strip() end end end return "" else @_instance.state[:name].strip() end end
Stops an ec2 instance @param wait [Boolean] - When true, will wait for the instance to be completely stopped before returning
# File lib/aws_region.rb, line 595 def stop(wait=false) if self.state(use_cached_state = false) != "running" log "Instance cannot be stopped - #{@region.region}://#{@id} is in the state: #{self.state}" return end self.eject_from_environment if @tags.has_key?("elastic_lb") log "Removing instance: #{@id} from '#{@tags['elastic_lb']}' load balancer" remove_from_lb(tags["elastic_lb"]) end log "Stopping instance: #{@region.region}://#{@id}" @region.ec2.stop_instances({:instance_ids => [@id]}) while self.state(use_cached_state = false) != "stopped" sleep 10 log "Stopping instance: #{@region.region}://#{@id} - state: #{self.state}" end if wait if self.state(use_cached_state = false) == "stopped" log "Instance stopped: #{@region.region}://#{@id}" end end
Terminates ec2 instance
# File lib/aws_region.rb, line 588 def terminate() eject_from_environment @region.ec2.terminate_instances({:instance_ids => [@id]}) end
# File lib/aws_region.rb, line 665 def wait(options = {:timeout => 300, :desired_status => "running"}) t0 = Time.now.to_i begin sleep 10 log "Waiting on instance: #{@region.region}://#{@id} - current state: #{self.state}" return if Time.now.to_i - t0 > options[:timeout] end while self.state(use_cached_state = false) != options[:desired_status] end