lib/rubber/recipes/rubber/instances.rb in axtro-rubber-1.0.2.8 vs lib/rubber/recipes/rubber/instances.rb in axtro-rubber-1.2.0
- old
+ new
@@ -3,11 +3,17 @@
desc <<-DESC
Create a new EC2 instance with the given ALIAS and ROLES
DESC
required_task :create do
instance_alias = get_env('ALIAS', "Instance alias (e.g. web01)", true)
- r = get_env('ROLES', "Instance roles (e.g. web,app,db:primary=true)", true)
+
+ env = rubber_cfg.environment.bind(nil, instance_alias)
+ default_roles = env.instance_roles
+ r = get_env("ROLES", "Instance roles (e.g. web,app,db:primary=true)", true, default_roles)
+
+ create_spot_instance = ENV.delete("SPOT_INSTANCE") || env.cloud_providers[env.cloud_provider].spot_instance
+
if r == '*'
instance_roles = rubber_cfg.environment.known_roles
instance_roles = instance_roles.collect {|role| role == "db" ? "db:primary=true" : role }
else
instance_roles = r.split(",")
@@ -27,11 +33,11 @@
end
# Add in roles that the given set of roles depends on
ir = Rubber::Configuration::RoleItem.expand_role_dependencies(ir, get_role_dependencies)
- create_instance(instance_alias, ir)
+ create_instance(instance_alias, ir, create_spot_instance)
end
desc <<-DESC
Refresh the host data for a EC2 instance with the given ALIAS.
This is useful to run when rubber:create fails after instance creation
@@ -81,10 +87,14 @@
instance = rubber_instances[instance_alias]
fatal "Instance does not exist: #{instance_alias}" unless instance
instance.roles = (instance.roles + ir).uniq
rubber_instances.save()
+ logger.info "Roles for #{instance_alias} are now:"
+ logger.info instance.role_names.sort.join("\n")
+ logger.info ''
+ logger.info "Run 'cap rubber:bootstrap' if done adding roles"
end
desc <<-DESC
Removes the given ROLES from the instance named ALIAS
DESC
@@ -103,10 +113,12 @@
instance = rubber_instances[instance_alias]
fatal "Instance does not exist: #{instance_alias}" unless instance
instance.roles = (instance.roles - ir).uniq
rubber_instances.save()
+ logger.info "Roles for #{instance_alias} are now:"
+ logger.info instance.role_names.sort.join("\n")
end
desc <<-DESC
List all your EC2 instances
DESC
@@ -142,11 +154,11 @@
set :print_ip_command, "ifconfig eth0 | awk 'NR==2 {print $2}' | awk -F: '{print $2}'"
# Creates a new ec2 instance with the given alias and roles
# Configures aliases (/etc/hosts) on local and remote machines
- def create_instance(instance_alias, instance_roles)
+ def create_instance(instance_alias, instance_roles, create_spot_instance=false)
fatal "Instance already exists: #{instance_alias}" if rubber_instances[instance_alias]
role_names = instance_roles.collect{|x| x.name}
env = rubber_cfg.environment.bind(role_names, instance_alias)
@@ -155,16 +167,49 @@
security_groups = get_assigned_security_groups(instance_alias, role_names)
ami = env.cloud_providers[env.cloud_provider].image_id
ami_type = env.cloud_providers[env.cloud_provider].image_type
availability_zone = env.availability_zone
- logger.info "Creating instance #{ami}/#{ami_type}/#{security_groups.join(',') rescue 'Default'}/#{availability_zone || 'Default'}"
- instance_id = cloud.create_instance(ami, ami_type, security_groups, availability_zone)
+ if create_spot_instance
+ spot_price = env.cloud_providers[env.cloud_provider].spot_price.to_s
+
+ logger.info "Creating spot instance request for instance #{ami}/#{ami_type}/#{security_groups.join(',') rescue 'Default'}/#{availability_zone || 'Default'}"
+ request_id = cloud.create_spot_instance_request(spot_price, ami, ami_type, security_groups, availability_zone)
+
+ print "Waiting for spot instance request to be fulfilled"
+ max_wait_time = env.cloud_providers[env.cloud_provider].spot_instance_request_timeout || (1.0 / 0) # Use the specified timeout value or default to infinite.
+ instance_id = nil
+ while instance_id.nil? do
+ print "."
+ sleep 2
+ max_wait_time -= 2
+
+ request = cloud.describe_spot_instance_requests(request_id).first
+ instance_id = request[:instance_id]
+
+ if max_wait_time < 0 && instance_id.nil?
+ cloud.destroy_spot_instance_request(request[:id])
+
+ print "\n"
+ print "Failed to fulfill spot instance in the time specified. Falling back to on-demand instance creation."
+ break
+ end
+ end
+
+ print "\n"
+ end
+
+ if !create_spot_instance || (create_spot_instance && max_wait_time < 0)
+ logger.info "Creating instance #{ami}/#{ami_type}/#{security_groups.join(',') rescue 'Default'}/#{availability_zone || 'Default'}"
+ instance_id = cloud.create_instance(ami, ami_type, security_groups, availability_zone)
+ end
+
logger.info "Instance #{instance_id} created"
instance_item = Rubber::Configuration::InstanceItem.new(instance_alias, env.domain, instance_roles, instance_id, security_groups)
+ instance_item.spot_instance_request_id = request_id if create_spot_instance
rubber_instances.add(instance_item)
rubber_instances.save()
print "Waiting for instance to start"
@@ -178,10 +223,11 @@
logger.info "Instance running, fetching hostname/ip data"
instance_item.external_host = instance[:external_host]
instance_item.external_ip = instance[:external_ip]
instance_item.internal_host = instance[:internal_host]
instance_item.zone = instance[:zone]
+ instance_item.platform = instance[:platform]
rubber_instances.save()
# setup amazon elastic ips if configured to do so
setup_static_ips
@@ -194,10 +240,17 @@
# Connect to newly created instance and grab its internal ip
# so that we can update all aliases
task :_get_ip, :hosts => instance_item.external_ip do
- instance_item.internal_ip = capture(print_ip_command).strip
+ # There's no good way to get the internal IP for a Windows host, so just set it to the external
+ # and let the router handle mapping to the internal network.
+ if instance_item.windows?
+ instance_item.internal_ip = instance_item.external_ip
+ else
+ instance_item.internal_ip = capture(print_ip_command).strip
+ end
+
rubber_instances.save()
end
# even though instance is running, sometimes ssh hasn't started yet,
# so retry on connect failure