lib/chef/knife/openstack_server_create.rb in knife-openstack-0.6.2 vs lib/chef/knife/openstack_server_create.rb in knife-openstack-0.7.0
- old
+ new
@@ -1,9 +1,9 @@
#
# Author:: Seth Chisamore (<schisamo@opscode.com>)
# Author:: Matt Ray (<matt@opscode.com>)
-# Copyright:: Copyright (c) 2011-2012 Opscode, Inc.
+# Copyright:: Copyright (c) 2011-2013 Opscode, Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
@@ -47,28 +47,27 @@
:short => "-I IMAGE_ID",
:long => "--image IMAGE_ID",
:description => "The image ID for the server",
:proc => Proc.new { |i| Chef::Config[:knife][:image] = i }
- # option :security_groups,
- # :short => "-G X,Y,Z",
- # :long => "--groups X,Y,Z",
- # :description => "The security groups for this server",
- # :default => ["default"],
- # :proc => Proc.new { |groups| groups.split(',') }
+ option :security_groups,
+ :short => "-G X,Y,Z",
+ :long => "--groups X,Y,Z",
+ :description => "The security groups for this server",
+ :default => ["default"],
+ :proc => Proc.new { |groups| groups.split(',') }
option :chef_node_name,
:short => "-N NAME",
:long => "--node-name NAME",
:description => "The Chef node name for your new node"
option :floating_ip,
- :short => "-a",
- :long => "--floating-ip",
- :boolean => true,
- :default => false,
- :description => "Request to associate a floating IP address to the new OpenStack node. Assumes IPs have been allocated to the project."
+ :short => "-a [IP]",
+ :long => "--floating-ip [IP]",
+ :default => "-1",
+ :description => "Request to associate a floating IP address to the new OpenStack node. Assumes IPs have been allocated to the project. Specific IP is optional."
option :private_network,
:long => "--private-network",
:description => "Use the private IP for bootstrapping rather than the public IP",
:boolean => true,
@@ -146,11 +145,11 @@
rescue Errno::EPERM
false
rescue Errno::ECONNREFUSED
sleep 2
false
- rescue Errno::EHOSTUNREACH
+ rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH
sleep 2
false
rescue Errno::ENETUNREACH
sleep 2
false
@@ -161,83 +160,96 @@
def run
$stdout.sync = true
validate!
- connection = Fog::Compute.new(
- :provider => 'OpenStack',
- :openstack_username => Chef::Config[:knife][:openstack_username],
- :openstack_api_key => Chef::Config[:knife][:openstack_password],
- :openstack_auth_url => Chef::Config[:knife][:openstack_auth_url],
- :openstack_tenant => Chef::Config[:knife][:openstack_tenant]
- )
-
#servers require a name, generate one if not passed
node_name = get_node_name(config[:chef_node_name])
server_def = {
:name => node_name,
:image_ref => locate_config_value(:image),
:flavor_ref => locate_config_value(:flavor),
- # :security_group => locate_config_value(:security_groups),
- :key_name => Chef::Config[:knife][:openstack_ssh_key_id],
- :personality => [{
- "path" => "/etc/chef/ohai/hints/openstack.json",
- "contents" => ''
- }]
+ :security_groups => locate_config_value(:security_groups),
+ :key_name => locate_config_value(:openstack_ssh_key_id)
}
Chef::Log.debug("Name #{node_name}")
Chef::Log.debug("Image #{locate_config_value(:image)}")
Chef::Log.debug("Flavor #{locate_config_value(:flavor)}")
- # Chef::Log.debug("Groups #{locate_config_value(:security_groups)}")
+ Chef::Log.debug("Requested Floating IP #{locate_config_value(:floating_ip)}")
+ Chef::Log.debug("Security Groups #{locate_config_value(:security_groups)}")
Chef::Log.debug("Creating server #{server_def}")
- server = connection.servers.create(server_def)
+ begin
+ server = connection.servers.create(server_def)
+ rescue Excon::Errors::BadRequest => e
+ response = Chef::JSONCompat.from_json(e.response.body)
+ if response['badRequest']['code'] == 400
+ if response['badRequest']['message'] =~ /Invalid flavorRef/
+ ui.fatal("Bad request (400): Invalid flavor specified: #{server_def[:flavor_ref]}")
+ exit 1
+ else
+ ui.fatal("Bad request (400): #{response['badRequest']['message']}")
+ exit 1
+ end
+ else
+ ui.fatal("Unknown server error (#{response['badRequest']['code']}): #{response['badRequest']['message']}")
+ raise e
+ end
+ end
+
msg_pair("Instance Name", server.name)
msg_pair("Instance ID", server.id)
- # msg_pair("Security Groups", server.groups.join(", "))
- msg_pair("SSH Keypair", server.key_name)
print "\n#{ui.color("Waiting for server", :magenta)}"
# wait for it to be ready to do stuff
server.wait_for { print "."; ready? }
puts("\n")
msg_pair("Flavor", server.flavor['id'])
msg_pair("Image", server.image['id'])
- msg_pair("Public IP Address", server.public_ip_address['addr']) if server.public_ip_address
+ msg_pair("SSH Identity File", config[:identity_file])
+ msg_pair("SSH Keypair", server.key_name) if server.key_name
+ msg_pair("SSH Password", server.password) if (server.password && !server.key_name)
+ Chef::Log.debug("Addresses #{server.addresses}")
+ msg_pair("Public IP Address", primary_public_ip_address(server.addresses)) if primary_public_ip_address(server.addresses)
- if config[:floating_ip]
- associated = false
- connection.addresses.each do |address|
- if address.instance_id.nil?
- server.associate_address(address.ip)
- #a bit of a hack, but server.reload takes a long time
- server.addresses['public'].push({"version"=>4,"addr"=>address.ip})
- associated = true
- msg_pair("Floating IP Address", address.ip)
- break
+ floating_address = locate_config_value(:floating_ip)
+ Chef::Log.debug("Floating IP Address requested #{floating_address}")
+ unless (floating_address == '-1') #no floating IP requested
+ addresses = connection.addresses
+ #floating requested without value
+ if floating_address.nil?
+ free_floating = addresses.find_index {|a| a.fixed_ip.nil?}
+ if free_floating.nil? #no free floating IP found
+ ui.error("Unable to assign a Floating IP from allocated IPs.")
+ exit 1
+ else
+ floating_address = addresses[free_floating].ip
end
end
- unless associated
- ui.error("Unable to associate floating IP.")
- exit 1
- end
+ server.associate_address(floating_address)
+ #a bit of a hack, but server.reload takes a long time
+ (server.addresses['public'] ||= []) << {"version"=>4,"addr"=>floating_address}
+ msg_pair("Floating IP Address", floating_address)
end
- Chef::Log.debug("Public IP Address actual #{server.public_ip_address['addr']}") if server.public_ip_address
- msg_pair("Private IP Address", server.private_ip_address['addr']) if server.private_ip_address
+ Chef::Log.debug("Addresses #{server.addresses}")
+ Chef::Log.debug("Public IP Address actual: #{primary_public_ip_address(server.addresses)}") if primary_public_ip_address(server.addresses)
+ msg_pair("Private IP Address", primary_private_ip_address(server.addresses)) if primary_private_ip_address(server.addresses)
+
#which IP address to bootstrap
- bootstrap_ip_address = server.public_ip_address['addr'] if server.public_ip_address
+ bootstrap_ip_address = primary_public_ip_address(server.addresses) if primary_public_ip_address(server.addresses)
if config[:private_network]
- bootstrap_ip_address = server.private_ip_address['addr']
+ bootstrap_ip_address = primary_private_ip_address(server.addresses)
end
- Chef::Log.debug("Bootstrap IP Address #{bootstrap_ip_address}")
+
+ Chef::Log.debug("Bootstrap IP Address: #{bootstrap_ip_address}")
if bootstrap_ip_address.nil?
ui.error("No IP address available for bootstrapping.")
exit 1
end
@@ -253,44 +265,84 @@
puts "\n"
msg_pair("Instance Name", server.name)
msg_pair("Instance ID", server.id)
msg_pair("Flavor", server.flavor['id'])
msg_pair("Image", server.image['id'])
- # msg_pair("Security Groups", server.groups.join(", "))
- msg_pair("SSH Keypair", server.key_name)
- msg_pair("Public IP Address", server.public_ip_address['addr']) if server.public_ip_address
- msg_pair("Private IP Address", server.private_ip_address['addr']) if server.private_ip_address
+ msg_pair("SSH Keypair", server.key_name) if server.key_name
+ msg_pair("SSH Password", server.password) if (server.password && !server.key_name)
+ msg_pair("Public IP Address", primary_public_ip_address(server.addresses)) if primary_public_ip_address(server.addresses)
+ msg_pair("Private IP Address", primary_private_ip_address(server.addresses)) if primary_private_ip_address(server.addresses)
msg_pair("Environment", config[:environment] || '_default')
msg_pair("Run List", config[:run_list].join(', '))
end
def bootstrap_for_node(server, bootstrap_ip_address)
bootstrap = Chef::Knife::Bootstrap.new
bootstrap.name_args = [bootstrap_ip_address]
bootstrap.config[:run_list] = config[:run_list]
bootstrap.config[:ssh_user] = config[:ssh_user]
+ bootstrap.config[:ssh_password] = server.password
bootstrap.config[:identity_file] = config[:identity_file]
bootstrap.config[:host_key_verify] = config[:host_key_verify]
bootstrap.config[:chef_node_name] = server.name
bootstrap.config[:prerelease] = config[:prerelease]
bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
bootstrap.config[:distro] = locate_config_value(:distro)
bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
bootstrap.config[:template_file] = locate_config_value(:template_file)
bootstrap.config[:environment] = config[:environment]
+ # let ohai know we're using OpenStack
+ Chef::Config[:knife][:hints] ||= {}
+ Chef::Config[:knife][:hints]['openstack'] ||= {}
bootstrap
end
- def ami
- @ami ||= connection.images.get(locate_config_value(:image))
+ def flavor
+ @flavor ||= connection.flavors.get(locate_config_value(:flavor))
end
+ def image
+ @image ||= connection.images.get(locate_config_value(:image))
+ end
+
+ def is_floating_ip_valid
+ address = locate_config_value(:floating_ip)
+ if address == '-1' #no floating IP requested
+ return true
+ end
+ addresses = connection.addresses
+ return false if addresses.empty? #no floating IPs
+ #floating requested without value
+ if address.nil?
+ if addresses.find_index {|a| a.fixed_ip.nil?}
+ return true
+ else
+ return false #no floating IPs available
+ end
+ end
+ #floating requested with value
+ if addresses.find_index {|a| a.ip == address}
+ return true
+ else
+ return false #requested floating IP does not exist
+ end
+ end
+
def validate!
+ super([:image, :openstack_username, :openstack_password, :openstack_auth_url])
- super([:image, :openstack_ssh_key_id, :openstack_username, :openstack_password, :openstack_auth_url])
+ if flavor.nil?
+ ui.error("You have not provided a valid flavor ID. Please note the options for this value are -f or --flavor.")
+ exit 1
+ end
- if ami.nil?
- ui.error("You have not provided a valid image ID. Please note the short option for this value recently changed from '-i' to '-I'.")
+ if image.nil?
+ ui.error("You have not provided a valid image ID. Please note the options for this value are -I or --image.")
+ exit 1
+ end
+
+ if !is_floating_ip_valid
+ ui.error("You have either requested an invalid floating IP address or none are available.")
exit 1
end
end
#generate a random name if chef_node_name is empty