class Kitchen::Driver::Softlayer
Softlayer
driver for Kitchen
. rubocop:disable Metrics/LineLength
Public Instance Methods
create(state)
click to toggle source
rubocop:disable Metrics/AbcSize
# File lib/kitchen/driver/softlayer.rb, line 82 def create(state) config_server_name config[:disable_ssl_validation] && disable_ssl_validation config[:fqdn] = "#{config[:server_name]}.#{config[:domain]}" debug "fqdn: #{config[:fqdn]}" debug "server_name: #{config[:server_name]}" debug "server_name_prefix: #{config[:server_name_prefix]}" server = create_server if config[:fqdn].include?(config[:default_name]) || !find_server(config[:fqdn]) state[:server_id] = server.id info "Softlayer instance <#{state[:server_id]}> created." server.wait_for do print '.' ready? end info "\n(server ready)" tag_server(server) # set state[:hostname] to be able to setup ssh using Fog::SSH state[:hostname] = if config[:ssh_via_hostname] config[:server_name] elsif config[:alternate_ip] config[:alternate_ip] else get_ip(server) end setup_ssh(server, state) wait_for_ssh_key_access(state) rescue Fog::Errors::Error, Excon::Errors::Error => ex raise ActionFailed, ex.message end
destroy(state)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 112 def destroy(state) return if state[:server_id].nil? config[:disable_ssl_validation] && disable_ssl_validation server = compute.servers.get(state[:server_id]) server.destroy unless server.nil? || server.id.nil? wait_for_server_to_delete(state) if config[:destroy_wait] info "Softlayer instance <#{state[:server_id]}> destroyed." state.delete(:server_id) state.delete(:server_name) end
Private Instance Methods
compute()
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 168 def compute @compute_connection ||= Fog::Compute.new( provider: :softlayer, softlayer_username: config[:softlayer_username], softlayer_api_key: config[:softlayer_api_key], softlayer_default_datacenter: config[:softlayer_datacenter], softlayer_default_domain: config[:softlayer_domain] ) end
config_server_name()
click to toggle source
Set the proper server name in the config
# File lib/kitchen/driver/softlayer.rb, line 127 def config_server_name return if config[:server_name] config[:server_name] = if config[:server_name_prefix] server_name_prefix(config[:server_name_prefix]) else config[:default_name] = default_name config[:default_name].to_s end end
create_server()
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 227 def create_server server_def = init_configuration # TODO: figure out network options # if config[:network_ref] # networks = [].concat([config[:network_ref]]) # server_def[:nics] = networks.flatten.map do |net| # { 'net_id' => find_network(net).id } # end # end %i[ username password port domain fqdn cpu ram disk flavor_id bare_metal os_code image_id ephemeral_storage network_components account_id single_tenant global_identifier tags user_data uid vlan private_vlan provision_script ].each do |c| server_def[c] = optional_config(c) if config[c] end debug "server_def: #{server_def}" compute.servers.create(server_def) end
default_name()
click to toggle source
Generate what should be a unique server name up to 63 total chars Base name: 15 Username: 15 Hostname: 23 Random string: 7 Separators: 3
¶ ↑
Total: 63
# File lib/kitchen/driver/softlayer.rb, line 299 def default_name [ instance.name.gsub(/\W/, '')[0..14], (Etc.getlogin || 'nologin').gsub(/\W/, '')[0..14], Socket.gethostname.gsub(/\W/, '')[0..22], Array.new(7) { rand(36).to_s(36) }.join ].join('-') end
disable_ssl_validation()
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 387 def disable_ssl_validation require 'excon' Excon.defaults[:ssl_verify_peer] = false end
find_image(image_name)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 196 def find_image(image_name) id = nil images = compute.images.all images.each do |image| if image.name == image_name id = image.id debug "Found public image #{id} for name #{image_name}" end end images = compute.images.private images.each do |image| if image.name == image_name id = image.id debug "Found private image #{id} for name #{image_name}" end end raise "No image found with name #{image_name}" if id.nil? id end
find_network(vlan)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 216 def find_network(vlan) debug "Looking for network for vlan number #{vlan}" response = network.list_networks response.body.each do |r| next unless r['vlanNumber'] == vlan debug "Found network id #{r['id']} for vlan number #{r['vlanNumber']}" return r['id'] end raise "No network found for vlan number #{r['vlanNumber']}" end
find_server(fqdn)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 186 def find_server(fqdn) s = nil srvs = compute.servers.all.select { |x| x.fqdn == fqdn } unless srvs.empty? s = srvs[0] info "Server with fqdn #{fqdn} already created" end s end
get_ip(server)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 342 def get_ip(server) pub, priv = get_public_private_ips(server) pub, priv = parse_ips(pub, priv) pub[config[:public_ip_order].to_i] || priv[config[:private_ip_order].to_i] || raise(ActionFailed, 'Could not find an IP') return priv[0] if config[:use_private_ip_with_public_network] && !config[:private_network_only] return priv[0] if config[:private_network_only] pub[0] end
get_public_private_ips(server)
click to toggle source
TODO: code has support for multiple ips but not used.
# File lib/kitchen/driver/softlayer.rb, line 336 def get_public_private_ips(server) pub = server.public_ip priv = server.private_ip [pub, priv] end
init_configuration()
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 267 def init_configuration { name: config[:server_name], key_pairs: [compute.key_pairs.by_label(config[:key_name])], datacenter: config[:datacenter], hourly_billing_flag: config[:hourly_billing_flag], private_network_only: config[:private_network_only] } end
network()
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 178 def network @network_connection ||= Fog::Network.new( provider: :softlayer, softlayer_username: config[:softlayer_username], softlayer_api_key: config[:softlayer_api_key] ) end
optional_config(c)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 277 def optional_config(c) case c when :vlan find_network(config[c]) when :private_vlan find_network(config[c]) when :image_id return config[c] if config[c].match?('^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}') find_image(config[c]) else config[c] end end
parse_ips(pub, priv)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 353 def parse_ips(pub, priv) pub = Array(pub) priv = Array(priv) if config[:use_ipv6] [pub, priv].each { |n| n.select! { |i| IPAddr.new(i).ipv6? } } else [pub, priv].each { |n| n.select! { |i| IPAddr.new(i).ipv4? } } end [pub, priv] end
server_name_prefix(server_name_prefix)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 308 def server_name_prefix(server_name_prefix) # Generate what should be a unique server name with given prefix # of up to 63 total chars # # Provided prefix: variable, max 54 # Separator: 1 # Random string: 8 # =================== # Max: 63 # if server_name_prefix.length > 54 warn 'Server name prefix too long, truncated to 54 characters' server_name_prefix = server_name_prefix[0..53] end server_name_prefix.gsub!(/\W/, '') if server_name_prefix.empty? warn 'Server name prefix empty or invalid; using fully generated name' default_name else random_suffix = ('a'..'z').to_a.sample(8).join server_name_prefix + '-' + random_suffix end end
setup_ssh(server, state)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 364 def setup_ssh(server, state) tcp_check(state) info "Using Softlayer keypair <#{config[:key_name]}>" info "Using private SSH key <#{config[:ssh_key]}>" state[:ssh_key] = config[:ssh_key] # we don't call this as key_name must be set. do_ssh_setup(state, config, server) unless config[:key_name] end
tag_server(server)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 392 def tag_server(server) server.add_tags(config[:tags]) end
tcp_check(state)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 373 def tcp_check(state) # allow driver config to bypass SSH tcp check -- because # it doesn't respect ssh_config values that might be required if config[:no_ssh_tcp_check] sleep(config[:no_ssh_tcp_check_sleep]) else debug("wait_for_sshd hostname: #{state[:hostname]},username: #{config[:username]},port: #{config[:port]}") wait_for_sshd(state[:hostname], config[:username], port: config[:port]) end info '(ssh ready)' end
wait_for_server_to_delete(state)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 138 def wait_for_server_to_delete(state) ((config[:destroy_timeout].to_i / 15).floor).times do info 'Deleting server in softlayer' sleep 15 server = compute.servers.get(state[:server_id]) return if server.nil? || server.id.nil? end raise "#{config[:destroy_timeout]} seconds went by and server not deleted by softlayer" end
wait_for_ssh_key_access(state)
click to toggle source
# File lib/kitchen/driver/softlayer.rb, line 148 def wait_for_ssh_key_access(state) new_state = build_ssh_args(state) new_state[2][:number_of_password_prompts] = 0 info 'Checking ssh key authentication' (config[:ssh_timeout].to_i).times do ssh = Fog::SSH.new(*new_state) begin ssh.run([%(uname -a)]) rescue StandardError => e info "Server not yet accepting SSH key: #{e.message}" sleep 1 else info 'SSH key authetication successful' return end end raise "#{config[:ssh_timeout]} seconds went by and we couldn't connect, somethings broken" end