lib/chef/knife/openstack_server_create.rb in knife-openstack-0.10.0 vs lib/chef/knife/openstack_server_create.rb in knife-openstack-1.0.0.rc1
- old
+ new
@@ -16,502 +16,216 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
-require 'chef/knife/openstack_base'
-require 'chef/knife/winrm_base'
+require 'chef/knife/cloud/server/create_command'
+require 'chef/knife/openstack_helpers'
+require 'chef/knife/cloud/openstack_server_create_options'
+require 'chef/knife/cloud/openstack_service'
+require 'chef/knife/cloud/openstack_service_options'
+require 'chef/knife/cloud/exceptions'
class Chef
class Knife
- class OpenstackServerCreate < Knife
- include Knife::OpenstackBase
- include Chef::Knife::WinrmBase
+ class Cloud
+ class OpenstackServerCreate < ServerCreateCommand
+ include OpenstackHelpers
+ include OpenstackServerCreateOptions
+ include OpenstackServiceOptions
- deps do
- require 'fog'
- require 'readline'
- require 'chef/json_compat'
- require 'chef/knife/bootstrap'
- Chef::Knife::Bootstrap.load_deps
- end
- banner "knife openstack server create (options)"
+ banner "knife openstack server create (options)"
- attr_accessor :initial_sleep_delay
+ def before_exec_command
+ super
+ # setup the create options
+ @create_options = {
+ :server_def => {
+ #servers require a name, knife-cloud generates the chef_node_name
+ :name => config[:chef_node_name],
+ :image_ref => service.get_image(locate_config_value(:image)).id,
+ :flavor_ref => service.get_flavor(locate_config_value(:flavor)).id,
+ :security_groups => locate_config_value(:openstack_security_groups),
+ :availability_zone => locate_config_value(:availability_zone),
+ :metadata => locate_config_value(:metadata),
+ :key_name => locate_config_value(:openstack_ssh_key_id)
+ },
+ :server_create_timeout => locate_config_value(:server_create_timeout)
+ }
- option :flavor,
- :short => "-f FLAVOR",
- :long => "--flavor FLAVOR",
- :description => "The flavor name or ID of server (m1.small, m1.medium, etc)",
- :proc => Proc.new { |f| Chef::Config[:knife][:flavor] = f }
+ @create_options[:server_def].merge!({:user_data => locate_config_value(:user_data)}) if locate_config_value(:user_data)
+ @create_options[:server_def].merge!({:nics => locate_config_value(:network_ids).map { |nic| nic_id = { 'net_id' => nic }}}) if locate_config_value(:network_ids)
- option :image,
- :short => "-I IMAGE",
- :long => "--image IMAGE",
- :description => "A regexp matching an image name or an image ID for the server",
- :proc => Proc.new { |i| Chef::Config[:knife][:image] = i }
+ Chef::Log.debug("Create server params - server_def = #{@create_options[:server_def]}")
+ #set columns_with_info map
+ @columns_with_info = [
+ {:label => 'Instance ID', :key => 'id'},
+ {:label => 'Name', :key => 'name'},
+ {:label => 'Public IP', :key => 'addresses', :value_callback => method(:primary_public_ip_address)},
+ {:label => 'Private IP', :key => 'addresses', :value_callback => method(:primary_private_ip_address)},
+ {:label => 'Flavor', :key => 'flavor', :value_callback => method(:get_id)},
+ {:label => 'Image', :key => 'image', :value_callback => method(:get_id)},
+ {:label => 'Keypair', :key => 'key_name'},
+ {:label => 'State', :key => 'state'},
+ {:label => 'Availability Zone', :key => 'availability_zone'}
+ ]
+ end
- 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(',') }
+ def get_id(value)
+ value['id']
+ end
- md = {}
- option :metadata,
- :short => "-M X=1",
- :long => "--metadata X=1",
- :description => "Metadata information for this server (may pass multiple times)",
- :proc => Proc.new { |data| md.merge!({data.split('=')[0]=>data.split('=')[1]}) }
+ # Setup the floating ip after server creation.
+ def after_exec_command
+ Chef::Log.debug("Addresses #{server.addresses}")
+ 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)
- option :chef_node_name,
- :short => "-N NAME",
- :long => "--node-name NAME",
- :description => "The Chef node name for your new node"
+ floating_address = locate_config_value(:openstack_floating_ip)
+ bind_ip = primary_network_ip_address(server.addresses,server.addresses.keys[0])
+ Chef::Log.debug("Floating IP Address requested #{floating_address}")
+ unless (floating_address == '-1') #no floating IP requested
+ addresses = service.connection.addresses
+ #floating requested without value
+ if floating_address.nil?
+ free_floating = addresses.find_index {|a| a.fixed_ip.nil?}
+ begin
+ if free_floating.nil? #no free floating IP found
+ error_message = "Unable to assign a Floating IP from allocated IPs."
+ ui.fatal(error_message)
+ raise CloudExceptions::ServerSetupError, error_message
+ else
+ floating_address = addresses[free_floating].ip
+ end
+ rescue CloudExceptions::ServerSetupError => e
+ cleanup_on_failure
+ raise e
+ end
+ end
- option :network_ids,
- :long => "--network-ids NETWORK_ID_1,NETWORK_ID_2,NETWORK_ID_3",
- :description => "Comma separated list of the UUID(s) of the network(s) for the server to attach",
- :proc => Proc.new { |networks| networks.split(',') }
+ # Pull the port_id for the associate_floating_ip
+ port_id = @service.network.list_ports[:body].flatten.flatten[1]["id"]
+ fixed_ip_address = @service.network.list_ports[:body].flatten.flatten[1]["fixed_ips"].flatten[0]["ip_address"]
- option :floating_ip,
- :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."
+ floating_ip_id = get_floating_ip_id(floating_address)
+ # Associate the floating ip via the neutron/network api
+ @service.network.associate_floating_ip(floating_ip_id, port_id, options = {:fixed_ip_address => fixed_ip_address })
- option :bootstrap_network,
- :long => '--bootstrap-network NAME',
- :default => 'public',
- :description => "Specify network for bootstrapping. Default is 'public'."
+ #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
- option :network,
- :long => "--no-network",
- :boolean => true,
- :default => true,
- :description => "Use first available network for bootstrapping if 'public' and 'private' are unavailable."
+ 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)
- option :private_network,
- :long => "--private-network",
- :description => "Use the private IP for bootstrapping rather than the public IP",
- :boolean => true,
- :default => false
-
- option :ssh_key_name,
- :short => "-S KEY",
- :long => "--ssh-key KEY",
- :description => "The OpenStack SSH keypair id",
- :proc => Proc.new { |key| Chef::Config[:knife][:openstack_ssh_key_id] = key }
-
- option :ssh_port,
- :short => "-p PORT",
- :long => "--ssh-port PORT",
- :description => "The ssh port",
- :default => "22",
- :proc => Proc.new { |key| Chef::Config[:knife][:ssh_port] = key }
-
- option :ssh_user,
- :short => "-x USERNAME",
- :long => "--ssh-user USERNAME",
- :description => "The ssh username",
- :default => "root"
-
- option :ssh_password,
- :short => "-P PASSWORD",
- :long => "--ssh-password PASSWORD",
- :description => "The ssh password"
-
- option :identity_file,
- :short => "-i IDENTITY_FILE",
- :long => "--identity-file IDENTITY_FILE",
- :description => "The SSH identity file used for authentication"
-
- option :prerelease,
- :long => "--prerelease",
- :description => "Install the pre-release chef gems"
-
- option :bootstrap_version,
- :long => "--bootstrap-version VERSION",
- :description => "The version of Chef to install",
- :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_version] = v }
-
- option :distro,
- :short => "-d DISTRO",
- :long => "--distro DISTRO",
- :description => "Bootstrap a distro using a template; default is 'chef-full'",
- :proc => Proc.new { |d| Chef::Config[:knife][:distro] = d },
- :default => "chef-full"
-
- option :template_file,
- :long => "--template-file TEMPLATE",
- :description => "Full path to location of template to use",
- :proc => Proc.new { |t| Chef::Config[:knife][:template_file] = t },
- :default => false
-
- option :run_list,
- :short => "-r RUN_LIST",
- :long => "--run-list RUN_LIST",
- :description => "Comma separated list of roles/recipes to apply",
- :proc => lambda { |o| o.split(/[\s,]+/) },
- :default => []
-
- option :host_key_verify,
- :long => "--[no-]host-key-verify",
- :description => "Verify host key, enabled by default",
- :boolean => true,
- :default => true
-
- option :bootstrap_protocol,
- :long => "--bootstrap-protocol protocol",
- :description => "Protocol to bootstrap Windows servers. options: winrm",
- :default => nil
-
- option :bootstrap_proxy,
- :long => "--bootstrap-proxy PROXY_URL",
- :description => "The proxy server for the node being bootstrapped",
- :proc => Proc.new { |v| Chef::Config[:knife][:bootstrap_proxy] = v }
-
- option :server_create_timeout,
- :long => "--server-create-timeout timeout",
- :description => "How long to wait until the server is ready; default is 600 seconds",
- :default => 600,
- :proc => Proc.new { |v| Chef::Config[:knife][:server_create_timeouts] = v }
-
- option :first_boot_attributes,
- :short => "-j JSON_ATTRIBS",
- :long => "--json-attributes JSON_ATTRIBS",
- :description => "A JSON string to be added to the first run of chef-client",
- :proc => lambda { |o| JSON.parse(o) },
- :default => {}
-
- option :user_data,
- :long => "--user-data USER_DATA",
- :description => "The file path containing user data information for this server",
- :proc => Proc.new { |user_data| open(user_data) { |f| f.read } }
-
- def tcp_test_ssh(hostname, port)
- tcp_socket = TCPSocket.new(hostname, port)
- readable = IO.select([tcp_socket], nil, nil, 5)
- if readable
- Chef::Log.debug("sshd accepting connections on #{hostname} port #{port}, banner is #{tcp_socket.gets}")
- yield
- true
- else
- false
+ msg_pair("Private IP Address", primary_private_ip_address(server.addresses)) if primary_private_ip_address(server.addresses)
+ super
end
- rescue Errno::ETIMEDOUT
- false
- rescue Errno::EPERM
- false
- rescue Errno::ECONNREFUSED
- sleep 2
- false
- rescue Errno::EHOSTUNREACH, Errno::ENETUNREACH
- sleep 2
- false
- rescue Errno::ENETUNREACH
- sleep 2
- false
- ensure
- tcp_socket && tcp_socket.close
- end
- def tcp_test_winrm(hostname, port)
- TCPSocket.new(hostname, port)
- return true
- rescue SocketError
- sleep 2
- false
- rescue Errno::ETIMEDOUT
- false
- rescue Errno::EPERM
- false
- rescue Errno::ECONNREFUSED
- sleep 2
- false
- rescue Errno::EHOSTUNREACH
- sleep 2
- false
- rescue Errno::ENETUNREACH
- sleep 2
- false
- end
+ def before_bootstrap
+ super
- def load_winrm_deps
- require 'winrm'
- require 'em-winrm'
- require 'chef/knife/bootstrap_windows_winrm'
- require 'chef/knife/core/windows_bootstrap_context'
- require 'chef/knife/winrm'
- end
- def run
- $stdout.sync = true
+ # Use SSH password either specified from command line or from openstack server instance
+ config[:ssh_password] = locate_config_value(:ssh_password) || server.password unless config[:openstack_ssh_key_id]
- validate!
- if locate_config_value(:bootstrap_protocol) == 'winrm'
- load_winrm_deps
- else
- # workaround for KNIFE-296 winrm values stomping on ssh values
- # unchanged ssh_user and changed winrm_user, override ssh_user
- if locate_config_value(:ssh_user).eql?(options[:ssh_user][:default]) &&
- !locate_config_value(:winrm_user).eql?(options[:winrm_user][:default])
- config[:ssh_user] = locate_config_value(:winrm_user)
- end
- # unchanged ssh_port and changed winrm_port, override ssh_port
- if locate_config_value(:ssh_port).eql?(options[:ssh_port][:default]) &&
- !locate_config_value(:winrm_port).eql?(options[:winrm_port][:default])
- config[:ssh_port] = locate_config_value(:winrm_port)
- end
- # unset ssh_password and set winrm_password, override ssh_password
- if locate_config_value(:ssh_password).nil? &&
- !locate_config_value(:winrm_password).nil?
- config[:ssh_password] = locate_config_value(:winrm_password)
- end
- # unset identity_file and set kerberos_keytab_file, override identity_file
- if locate_config_value(:identity_file).nil? &&
- !locate_config_value(:kerberos_keytab_file).nil?
- config[:identity_file] = locate_config_value(:kerberos_keytab_file)
- end
- end
- # servers require a name, generate one if not passed
- node_name = get_node_name(config[:chef_node_name])
+ # private_network means bootstrap_network = 'private'
+ config[:bootstrap_network] = 'private' if config[:private_network]
- # define the server to be created
- server_def = {
- :name => node_name,
- :image_ref => image.id,
- :flavor_ref => flavor.id,
- :security_groups => locate_config_value(:security_groups),
- :availability_zone => locate_config_value(:availability_zone),
- :metadata => locate_config_value(:metadata),
- :key_name => locate_config_value(:openstack_ssh_key_id)
- }
- server_def[:user_data] = locate_config_value(:user_data) unless locate_config_value(:user_data).nil?
- unless locate_config_value(:network_ids).nil?
- server_def[:nics] = locate_config_value(:network_ids).map do |nic|
- nic_id = { 'net_id' => nic }
- nic_id
+ # Which IP address to bootstrap
+ unless config[:network] # --no-network
+ bootstrap_ip_address = primary_public_ip_address(server.addresses) ||
+ primary_private_ip_address(server.addresses) ||
+ server.addresses.first[1][0]['addr']
+ Chef::Log.debug("No Bootstrap Network: #{config[:bootstrap_network]}")
+ else
+ bootstrap_ip_address = primary_network_ip_address(server.addresses, config[:bootstrap_network])
+ Chef::Log.debug("Bootstrap Network: #{config[:bootstrap_network]}")
end
- end
- Chef::Log.debug("server_def is: #{server_def}")
- Chef::Log.debug("Name #{node_name}")
- Chef::Log.debug("Availability Zone #{locate_config_value(:availability_zone)}")
- Chef::Log.debug("Image #{locate_config_value(:image)}")
- Chef::Log.debug("Flavor #{locate_config_value(:flavor)}")
- Chef::Log.debug("Requested Floating IP #{locate_config_value(:floating_ip)}")
- Chef::Log.debug("Security Groups #{locate_config_value(:security_groups)}")
- Chef::Log.debug("User Data #{locate_config_value(:user_data)}")
- Chef::Log.debug("Metadata #{locate_config_value(:metadata)}")
- Chef::Log.debug("Creating server #{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
+ Chef::Log.debug("Bootstrap IP Address: #{bootstrap_ip_address}")
+ if bootstrap_ip_address.nil?
+ error_message = "No IP address available for bootstrapping."
+ ui.error(error_message)
+ raise CloudExceptions::BootstrapError, error_message
end
+ config[:bootstrap_ip_address] = bootstrap_ip_address
end
- msg_pair("Instance Name", server.name)
- msg_pair("Instance ID", server.id)
- msg_pair("Availability zone", server.availability_zone)
+ def validate_params!
+ # set param vm_name to a random value if the name is not set by the user (plugin)
+ config[:chef_node_name] = get_node_name(locate_config_value(:chef_node_name), locate_config_value(:chef_node_name_prefix))
- print "\n#{ui.color("Waiting for server", :magenta)}"
+ errors = []
- # wait for it to be ready to do stuff
- server.wait_for(Integer(locate_config_value(:server_create_timeout))) { print "."; ready? }
-
- puts("\n")
-
- msg_pair("Flavor", server.flavor['id'])
- msg_pair("Image", server.image['id'])
- 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)
- msg_pair("Private IP Address", primary_private_ip_address(server.addresses)) if primary_private_ip_address(server.addresses)
-
- 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
+ if locate_config_value(:bootstrap_protocol) == 'winrm'
+ if locate_config_value(:winrm_password).nil?
+ errors << "You must provide Winrm Password."
end
+ elsif locate_config_value(:bootstrap_protocol) != 'ssh'
+ errors << "You must provide a valid bootstrap protocol. options [ssh/winrm]. For linux type images, options [ssh]"
end
- server.associate_address(floating_address)
- # 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("Addresses #{server.addresses}")
- Chef::Log.debug("Public IP Address actual: #{primary_public_ip_address(server.addresses)}") if primary_public_ip_address(server.addresses)
-
- # private_network means bootstrap_network = 'private'
- config[:bootstrap_network] = 'private' if config[:private_network]
-
- unless config[:network] # --no-network
- bootstrap_ip_address = primary_public_ip_address(server.addresses) ||
- primary_private_ip_address(server.addresses) ||
- server.addresses[1][0]['addr']
- Chef::Log.debug("No Bootstrap Network: #{config[:bootstrap_network]}")
- else
- bootstrap_ip_address = primary_network_ip_address(server.addresses, config[:bootstrap_network])
- Chef::Log.debug("Bootstrap Network: #{config[:bootstrap_network]}")
+ errors << "You must provide --image-os-type option [windows/linux]" if ! (%w(windows linux).include?(locate_config_value(:image_os_type)))
+ error_message = ""
+ raise CloudExceptions::ValidationError, error_message if errors.each{|e| ui.error(e); error_message = "#{error_message} #{e}."}.any?
end
- Chef::Log.debug("Bootstrap IP Address: #{bootstrap_ip_address}")
- if bootstrap_ip_address.nil?
- ui.error("No IP address available for bootstrapping.")
- exit 1
+ def is_image_valid?
+ service.get_image(locate_config_value(:image)).nil? ? false : true
end
- if locate_config_value(:bootstrap_protocol) == 'winrm'
- print "\n#{ui.color("Waiting for winrm", :magenta)}"
- print(".") until tcp_test_winrm(bootstrap_ip_address, locate_config_value(:winrm_port))
- bootstrap_for_windows_node(server, bootstrap_ip_address).run
- else
- Chef::Log.debug("Waiting for sshd on IP address: #{bootstrap_ip_address} and port: #{locate_config_value(:ssh_port)}")
- print "\n#{ui.color("Waiting for sshd", :magenta)}"
- print(".") until tcp_test_ssh(bootstrap_ip_address, locate_config_value(:ssh_port)) {
- sleep @initial_sleep_delay ||= 10
- puts("done")
- }
- bootstrap_for_node(server, bootstrap_ip_address).run
+ def is_flavor_valid?
+ service.get_flavor(locate_config_value(:flavor)).nil? ? false : true
end
- 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("SSH Keypair", server.key_name) if server.key_name
- msg_pair("SSH Password", server.password) if (server.password && !server.key_name)
- server.addresses.each do |name,addr|
- msg_pair("Network", name)
- msg_pair(" IP Address", addr[0]['addr'])
- end
- msg_pair("Environment", config[:environment] || '_default')
- msg_pair("Run List", config[:run_list].join(', '))
- end
- def bootstrap_for_windows_node(server, bootstrap_ip_address)
- bootstrap = Chef::Knife::BootstrapWindowsWinrm.new
- bootstrap.name_args = [bootstrap_ip_address]
- bootstrap.config[:winrm_user] = locate_config_value(:winrm_user) || 'Administrator'
- bootstrap.config[:winrm_password] = locate_config_value(:winrm_password)
- bootstrap.config[:winrm_transport] = locate_config_value(:winrm_transport)
- bootstrap.config[:winrm_port] = locate_config_value(:winrm_port)
- bootstrap_common_params(bootstrap, server.name)
- end
+ def is_floating_ip_valid?
+ address = locate_config_value(:openstack_floating_ip)
- def bootstrap_common_params(bootstrap, server_name)
- bootstrap.config[:chef_node_name] = config[:chef_node_name] || server_name
- bootstrap.config[:run_list] = config[:run_list]
- bootstrap.config[:first_boot_attributes] = config[:first_boot_attributes]
- bootstrap.config[:prerelease] = config[:prerelease]
- bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version)
- bootstrap.config[:distro] = locate_config_value(:distro)
- bootstrap.config[:template_file] = locate_config_value(:template_file)
- bootstrap.config[:bootstrap_proxy] = locate_config_value(:bootstrap_proxy)
- bootstrap.config[:environment] = config[:environment]
- bootstrap.config[:encrypted_data_bag_secret] = config[:encrypted_data_bag_secret]
- bootstrap.config[:encrypted_data_bag_secret_file] = config[:encrypted_data_bag_secret_file]
- # let ohai know we're using OpenStack
- Chef::Config[:knife][:hints] ||= {}
- Chef::Config[:knife][:hints]['openstack'] ||= {}
- bootstrap
- end
-
- def bootstrap_for_node(server, bootstrap_ip_address)
- bootstrap = Chef::Knife::Bootstrap.new
- bootstrap.name_args = [bootstrap_ip_address]
- bootstrap.config[:ssh_user] = config[:ssh_user]
- bootstrap.config[:ssh_password] = config[:ssh_password] || server.password unless config[:ssh_key_name]
- bootstrap.config[:ssh_port] = config[:ssh_port]
- bootstrap.config[:identity_file] = config[:identity_file]
- bootstrap.config[:host_key_verify] = config[:host_key_verify]
- bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
- bootstrap_common_params(bootstrap, server.name)
- end
-
- def flavor
- @flavor ||= connection.flavors.find{|f| f.name == locate_config_value(:flavor) || f.id == locate_config_value(:flavor) }
- end
-
- def image
- @image ||= connection.images.find{|img| img.name =~ /#{locate_config_value(:image)}/ || img.id == 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? }
+ if address == '-1' # no floating IP requested
return true
- else
- return false # no floating IPs available
end
- else
- # floating requested with value
- if addresses.find_index { |a| a.ip == address }
- return true
+
+ addresses = service.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
else
- return false # requested floating IP does not exist
+ # 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
end
- end
- def validate!
- super([:image, :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
+ def post_connection_validations
+ errors = []
+ errors << "You have not provided a valid image ID. Please note the options for this value are -I or --image." if !is_image_valid?
+ errors << "You have not provided a valid flavor ID. Please note the options for this value are -f or --flavor." if !is_flavor_valid?
+ errors << "You have either requested an invalid floating IP address or none are available." if !is_floating_ip_valid?
+ error_message = ""
+ raise CloudExceptions::ValidationError, error_message if errors.each{|e| ui.error(e); error_message = "#{error_message} #{e}."}.any?
end
- 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
+ def get_floating_ip_id(floating_address)
+ # required for this method to work
+ floating_ip_id = -1
+ # Figure out the id for the port that the floating ip you requested
+ @service.network.list_floating_ips[:body]["floatingips"].each do |x|
+ if x["floating_ip_address"] == floating_address
+ floating_ip_id = x["id"]
+ end
+ end
+ return floating_ip_id
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
- def get_node_name(chef_node_name)
- return chef_node_name unless chef_node_name.nil?
- # lazy uuids
- chef_node_name = "os-" + rand.to_s.split('.')[1]
end
end
end
end