Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added basic support for an openstack cloud provider. #332

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
source "http://rubygems.org"

gem 'chef', "~> 10.16"
gem 'fog', "~> 1.2"
gem 'excon', "~> 0.21.0" # v0.22 breaks EC2 calls
gem 'fog', "~> 1.19"
gem 'excon', "~> 0.31.0" # v0.22 breaks EC2 calls
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment no longer valid

gem 'formatador', "~> 0.2"
gem 'gorillib', "~> 0.5.0"
gem 'rbvmomi'
Expand Down
24 changes: 13 additions & 11 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ GEM
multi_json (>= 1.1)
diff-lcs (1.2.5)
erubis (2.7.0)
excon (0.21.0)
excon (0.31.0)
ffi (1.9.0)
fog (1.10.1)
fog (1.19.0)
builder
excon (~> 0.20)
excon (~> 0.31.0)
formatador (~> 0.2.0)
mime-types
multi_json (~> 1.0)
net-scp (~> 1.1)
net-ssh (>= 2.1.3)
nokogiri (~> 1.5.0)
nokogiri (~> 1.5)
ruby-hmac
formatador (0.2.4)
git (1.2.5)
Expand Down Expand Up @@ -82,24 +82,26 @@ GEM
rb-kqueue (>= 0.2)
lumberjack (1.0.3)
method_source (0.8.1)
mime-types (1.23)
mime-types (2.0)
mini_portile (0.5.2)
mixlib-authentication (1.3.0)
mixlib-log
mixlib-cli (1.3.0)
mixlib-config (1.1.2)
mixlib-log (1.6.0)
mixlib-shellout (1.1.0)
moneta (0.6.0)
multi_json (1.7.7)
net-scp (1.1.1)
multi_json (1.8.2)
net-scp (1.1.2)
net-ssh (>= 2.6.5)
net-ssh (2.6.7)
net-ssh (2.7.0)
net-ssh-gateway (1.2.0)
net-ssh (>= 2.6.5)
net-ssh-multi (1.1)
net-ssh (>= 2.1.4)
net-ssh-gateway (>= 0.99.0)
nokogiri (1.5.10)
nokogiri (1.6.1)
mini_portile (~> 0.5.0)
ohai (6.16.0)
ipaddress
mixlib-cli
Expand Down Expand Up @@ -175,8 +177,8 @@ DEPENDENCIES
chef (~> 10.16)
chef-zero
diff-lcs (~> 1.2.5)
excon (~> 0.21.0)
fog (~> 1.2)
excon (~> 0.31.0)
fog (~> 1.19)
formatador (~> 0.2)
gorillib (~> 0.5.0)
guard (~> 1)
Expand Down
17 changes: 13 additions & 4 deletions lib/chef/knife/cluster_launch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ class ClusterLaunch < Knife
:boolean => true,
:default => false

option :wait_ssh,
:long => "--[no-]wait-ssh",
:description => "Wait for the target machine to open an ssh port",
:boolean => true,
:default => false

def _run
load_ironfan
die(banner) if @name_args.empty?
Expand Down Expand Up @@ -110,10 +116,13 @@ def _run
def perform_after_launch_tasks(computer)
# Try SSH
unless config[:dry_run]
Ironfan.step(computer.name, 'trying ssh', :white)
# FIXME: This is EC2-specific, abstract it
address = computer.machine.vpc_id.nil? ? computer.machine.public_hostname : computer.machine.public_ip_address
nil until tcp_test_ssh(address){ sleep @initial_sleep_delay ||= 10 }
if config[:wait_ssh]
Ironfan.step(computer.name, 'trying ssh', :white)
# FIXME: This is EC2-specific, abstract it
address = computer.machine.vpc_id.nil? ? computer.machine.public_hostname : computer.machine.public_ip_address
Ironfan.step('address: ', address, :red)
nil until tcp_test_ssh(address){ sleep @initial_sleep_delay ||= 10 }
end
end

# Run Bootstrap
Expand Down
1 change: 1 addition & 0 deletions lib/ironfan/dsl/cloud.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ def self.receive(obj, &block)
when :virtualbox then VirtualBox
when :vsphere then Vsphere
when :rds then Rds
when :openstack then OpenStack
else raise "Unsupported cloud #{obj[:name]}"
end
end
Expand Down
172 changes: 172 additions & 0 deletions lib/ironfan/dsl/openstack.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
require 'digest/md5'

module Ironfan
class Dsl

class Compute < Ironfan::Dsl
def openstack(*attrs,&block) cloud(:openstack,*attrs,&block); end
end

class OpenStack < Cloud
magic :availability_zones, Array, :default => ['nova']
magic :backing, String, :default => 'ebs'
magic :bits, Integer, :default => ->{ flavor_info[:bits] }
magic :bootstrap_distro, String, :default => ->{ image_info[:bootstrap_distro] }
magic :chef_client_script, String
magic :default_availability_zone, String, :default => ->{ availability_zones.first }
#collection :elastic_load_balancers, Ironfan::Dsl::Ec2::ElasticLoadBalancer, :key_method => :name
magic :ebs_optimized, :boolean, :default => false
magic :flavor, String, :default => 't1.micro'
#collection :iam_server_certificates, Ironfan::Dsl::Ec2::IamServerCertificate, :key_method => :name
magic :image_id, String
magic :image_name, String
magic :keypair, String
magic :monitoring, String
magic :mount_ephemerals, Hash, :default => {}
magic :permanent, :boolean, :default => false
magic :placement_group, String
magic :provider, Whatever, :default => Ironfan::Provider::OpenStack
magic :elastic_ip, String
magic :auto_elastic_ip, String
magic :allocation_id, String
magic :region, String, :default => ->{ default_region }
collection :security_groups, Ironfan::Dsl::OpenStack::SecurityGroup, :key_method => :name
magic :ssh_user, String, :default => ->{ image_info[:ssh_user] }
magic :ssh_identity_dir, String, :default => ->{ Chef::Config.openstack_key_dir }
magic :subnet, String
magic :validation_key, String, :default => ->{ IO.read(Chef::Config.validation_key) rescue '' }
magic :vpc, String

def domain; vpc.nil? ? 'standard' : 'vpc'; end

def image_info
bit_str = "#{self.bits.to_i}-bit" # correct for legacy image info.
keys = [region, bit_str, backing, image_name]
info = Chef::Config[:openstack_image_info][ keys ]
ui.warn("Can't find image for #{[region, bit_str, backing, image_name].inspect}") if info.blank?
return info || {}
end

def image_id
result = read_attribute(:image_id) || image_info[:image_id]
end

def ssh_key_name(computer)
keypair ? keypair.to_s : computer.server.cluster_name
end

def default_region
default_availability_zone ? default_availability_zone.gsub(/^(\w+-\w+-\d)[a-z]/, '\1') : nil
end

def to_display(style,values={})
return values if style == :minimal

values["Flavor"] = flavor
values["AZ"] = default_availability_zone
return values if style == :default

values["Public IP"] = elastic_ip if elastic_ip
values
end

def flavor_info
if not Chef::Config[:openstack_flavor_info].has_key?(flavor)
ui.warn("Unknown machine image flavor '#{flavor}'")
list_flavors
return nil
end
Chef::Config[:openstack_flavor_info][flavor]
end

def implied_volumes
result = []
if backing == 'ebs'
result << Ironfan::Dsl::Volume.new(:name => 'root') do
device '/dev/sda1'
fstype 'ext4'
keep false
mount_point '/'
end
end
return result unless (mount_ephemerals and (flavor_info[:ephemeral_volumes] > 0))

layout = { 0 => ['/dev/sdb','/mnt'],
1 => ['/dev/sdc','/mnt2'],
2 => ['/dev/sdd','/mnt3'],
3 => ['/dev/sde','/mnt4'] }
( 0 .. (flavor_info[:ephemeral_volumes]-1) ).each do |idx|
dev, mnt = layout[idx]
ephemeral = Ironfan::Dsl::Volume.new(:name => "ephemeral#{idx}") do
attachable 'ephemeral'
fstype 'ext3'
device dev
mount_point mnt
mount_options 'defaults,noatime'
tags({:bulk => true, :local => true, :fallback => true})
end
ephemeral_attrs = mount_ephemerals.clone
if ephemeral_attrs.has_key?(:disks)
disk_attrs = mount_ephemerals[:disks][idx] || { }
ephemeral_attrs.delete(:disks)
ephemeral_attrs.merge!(disk_attrs)
end
ephemeral.receive! ephemeral_attrs
result << ephemeral
end
result
end

def receive_provider(obj)
if obj.is_a?(String)
write_attribute :provider, Gorillib::Inflector.constantize(Gorillib::Inflector.camelize(obj.gsub(/\./, '/')))
else
super(obj)
end
end

class SecurityGroup < Ironfan::Dsl
field :name, String
field :group_authorized, Array, :default => []
field :group_authorized_by, Array, :default => []
field :range_authorizations, Array, :default => []

def authorize_port_range(range, cidr_ip = '0.0.0.0/0', ip_protocol = 'tcp')
range = (range .. range) if range.is_a?(Integer)
range_authorizations << [range, cidr_ip, ip_protocol]
range_authorizations.compact!
range_authorizations.uniq!
end

def authorized_by_group(other_name)
group_authorized_by << other_name.to_s
group_authorized_by.compact!
group_authorized_by.uniq!
end

def authorize_group(other_name)
group_authorized << other_name.to_s
group_authorized.compact!
group_authorized.uniq!
end
end
end
end
end

Chef::Config[:openstack_flavor_info] ||= {}
Chef::Config[:openstack_flavor_info].merge!({
# 32-or-64: m1.small, m1.medium, t1.micro, c1.medium
't1.micro' => { :price => 0.02, :bits => 64, :ram => 686, :cores => 1, :core_size => 0.25, :inst_disks => 0, :inst_disk_size => 0, :ephemeral_volumes => 0 },
'm1.small' => { :price => 0.08, :bits => 64, :ram => 1740, :cores => 1, :core_size => 1, :inst_disks => 1, :inst_disk_size => 160, :ephemeral_volumes => 1 },
'm1.medium' => { :price => 0.165, :bits => 64, :ram => 3840, :cores => 2, :core_size => 1, :inst_disks => 1, :inst_disk_size => 410, :ephemeral_volumes => 1 },
'c1.medium' => { :price => 0.17, :bits => 64, :ram => 1740, :cores => 2, :core_size => 2.5, :inst_disks => 1, :inst_disk_size => 350, :ephemeral_volumes => 1 },
#
'm1.large' => { :price => 0.32, :bits => 64, :ram => 7680, :cores => 2, :core_size => 2, :inst_disks => 1, :inst_disk_size => 850, :ephemeral_volumes => 2, },
'm2.xlarge' => { :price => 0.45, :bits => 64, :ram => 18124, :cores => 2, :core_size => 3.25, :inst_disks => 1, :inst_disk_size => 420, :ephemeral_volumes => 1, },
'c1.xlarge' => { :price => 0.64, :bits => 64, :ram => 7168, :cores => 8, :core_size => 2.5, :inst_disks => 1, :inst_disk_size => 1690, :ephemeral_volumes => 4, },
'm1.xlarge' => { :price => 0.66, :bits => 64, :ram => 15360, :cores => 4, :core_size => 2, :inst_disks => 1, :inst_disk_size => 1690, :ephemeral_volumes => 4, },
})

Chef::Config[:openstack_image_info] ||= {}

4 changes: 2 additions & 2 deletions lib/ironfan/dsl/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -279,10 +279,10 @@ def to_machine_manifest
bootstrap_distro: cloud.bootstrap_distro,
chef_client_script: cloud.chef_client_script,
default_availability_zone: cloud.default_availability_zone,
elastic_load_balancers: cloud.elastic_load_balancers,
elastic_load_balancers: cloud.respond_to?(:elastic_load_balancers) ? cloud.elastic_load_balancers : nil,
ebs_optimized: cloud.ebs_optimized,
flavor: cloud.flavor,
iam_server_certificates: cloud.iam_server_certificates,
iam_server_certificates: cloud.respond_to?(:iam_server_certificates) ? cloud.iam_server_certificates : nil,
image_id: cloud.image_id,
image_name: cloud.image_name,
keypair: cloud.keypair,
Expand Down
12 changes: 12 additions & 0 deletions lib/ironfan/headers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ class SecurityGroup < Ironfan::Dsl; end
class ElasticLoadBalancer < Ironfan::Dsl; end
class IamServerCertificate < Ironfan::Dsl; end
end

class OpenStack < Cloud
class SecurityGroup < Ironfan::Dsl; end
end

class VirtualBox < Cloud; end
class Vsphere < Cloud; end
class Rds < Cloud
Expand Down Expand Up @@ -65,6 +70,13 @@ class SecurityGroup < Ironfan::Provider::Resource; end
class ElasticLoadBalancer < Ironfan::Provider::Resource; end
class IamServerCertificate < Ironfan::Provider::Resource; end
end

class OpenStack < Ironfan::IaasProvider
class Machine < Ironfan::IaasProvider::Machine; end
class Keypair < Ironfan::Provider::Resource; end
class SecurityGroup < Ironfan::Provider::Resource; end
end

class VirtualBox < Ironfan::IaasProvider
class Machine < Ironfan::IaasProvider::Machine; end
end
Expand Down
1 change: 1 addition & 0 deletions lib/ironfan/provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def self.receive(obj, &block)
case obj[:name]
when :chef then Chef
when :ec2 then Ec2
when :openstack then OpenStack
when :vsphere then Vsphere
when :virtualbox then VirtualBox
when :rds then Rds
Expand Down
Loading