class Chef::Knife::SoftlayerServerCreate

Attributes

cci[R]

Public Instance Methods

apply_tags(instance) click to toggle source
# File lib/chef/knife/softlayer_server_create.rb, line 446
def apply_tags(instance)
  Proc.new do
    chef = Chef::Search::Query.new
    chef.search('node', "name:#{locate_config_value(:chef_node_name) || instance.id}") do |n|
      config[:tags] = [] if config[:tags].nil? # we're going to tag every Chef node with the SL id no matter what
      config[:tags] << "slid=#{instance.id}"
      config[:tags].each do |tag|
        n.tag(tag)
      end
      n.save
    end
  end
end
linux_bootstrap(instance) click to toggle source

@param [Hash] instance @return [Chef::Knife::Bootstrap]

# File lib/chef/knife/softlayer_server_create.rb, line 383
def linux_bootstrap(instance)
  bootstrap = Chef::Knife::Bootstrap.new
  instance.ssh_ip_address = instance.private_ip_address if config[:private_network_only]
  bootstrap.name_args = [instance.ssh_ip_address]
  bootstrap.config[:ssh_user] = config[:ssh_user]
  bootstrap.config[:ssh_password] = config[:ssh_password] if config[:ssh_password]
  bootstrap.config[:identity_file] = config[:identity_file] if config[:identity_file]
  bootstrap.config[:ssh_port] = config[:ssh_port]
  bootstrap.config[:ssh_gateway] = config[:ssh_gateway]
  bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || instance.id
  bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root'
  bootstrap.config[:host_key_verify] = config[:host_key_verify]
  shared_bootstrap(bootstrap)
end
progress(proc) click to toggle source
# File lib/chef/knife/softlayer_server_create.rb, line 423
def progress(proc)
  t = Thread.new { Thread.current[:output] = proc.call }
  i = 0
  while t.alive?
    sleep 0.5
    putc('.')
    i += 1
    putc("\n") if i == 76
    i = 0 if i == 76
  end
  putc("\n")
  t.join
  t[:output]
end
run() click to toggle source

Run the procedure to create a SoftLayer VM and bootstrap it. @return [nil]

# File lib/chef/knife/softlayer_server_create.rb, line 265
def run
  $stdout.sync = true
  config.merge!(slurp_from_file(config[:from_file])) if config[:from_file]

  # TODO: Windows support.
  raise SoftlayerServerCreateError, "#{ui.color("Windows VMs not currently supported.", :red)}" if config[:os_code] =~ /^WIN_/
  raise SoftlayerServerCreateError, "#{ui.color("identity file (-i) option is incompatible with password (-P) option required.", :red)}" if !!config[:identity_file] and !!config[:ssh_password]
  raise SoftlayerServerCreateError, "#{ui.color("--new-global-ip value must be 'v4' or 'v6'.", :red)}" if config[:new_global_ip] and !config[:new_global_ip].to_s.match(/^v[4,6]$/i)

  # TODO: create a pre-launch method for clean up tasks.
  # TODO: create a pre-launch method for clean up tasks.
  config[:vlan] = config[:vlan].to_i if config[:vlan]
  config[:private_vlan] = config[:private_vlan].to_i if config[:private_vlan]
  Fog.credentials[:private_key_path] = config[:identity_file] if config[:identity_file]
  # TODO: create a pre-launch method for clean up tasks.
  # TODO: create a pre-launch method for clean up tasks.

  opts = {
      :flavor => :flavor_id,
      :hostname => :name,
      :domain => nil,
      :cores => :cpu,
      :os_code => nil,
      :ram => nil,
      :block_storage => :disk,
      :local_storage => :ephemeral_storage,
      :datacenter => nil,
      :ssh_keys => :key_pairs,
      :vlan => nil,
      :private_vlan => nil,
      :image_id => nil,
      :private_network_only => nil,
      #:tags => nil,
      :user_data => nil
  }


  opts.keys.each do |opt|
    if opts[opt].nil?
      opts[opt] = config[opt]
    else
      opts[opts.delete(opt)] = config[opt]  # clever shit like this is why I like programming :-]
    end
  end

  # FIXME: make the above deal with nested opts and get rid of this one-off
  opts[:network_components] = [ {"speed" => config[:nic]} ] if !!config[:nic]

  opts.delete_if { |k,v| v.nil? }
  puts ui.color("Launching SoftLayer VM, this may take a few minutes.", :green)
  instance = connection.servers.create(opts)
  if config[:private_network_only] || config[:use_private_network]
    instance.ssh_ip_address = Proc.new {|server| server.private_ip_address }
  end
  progress Proc.new { instance.wait_for(timeout=config[:wait_for_timeout].to_i) { ready? and sshable? } }
  putc("\n")

  if config[:tags]
    puts ui.color("Applying tags to SoftLayer instance.", :green)
    progress Proc.new { instance.add_tags(config[:tags]) }
    putc("\n")
  end


  if config[:new_global_ip] || config[:assign_global_ip]
    if config[:new_global_ip] # <— the value of this will be v4 or v6
      begin
        puts ui.color('Provisioning new Global IP' + config[:new_global_ip].downcase + ', this may take a few minutes.', :green)
        create_global_ip =  Proc.new do
          existing_records = connection(:network).get_global_ip_records.body
          connection(:network).send('create_new_global_ip' + config[:new_global_ip].downcase) or raise SoftlayerServerCreateError, "Unable to create new Global IP Address.";
          sleep 20 # if we look for the new record too quickly it won't be there yet...
          new_record_global_id = (connection(:network).get_global_ip_records.body - existing_records).reduce['id']
          connection(:network).ips.select { |ip| ip.global_id == new_record_global_id }.reduce
        end
        global_ip = progress(create_global_ip) or raise SoftlayerServerCreateError, "Error encountered creating Global IP Address."
        puts ui.color('Global IP Address successfully created.', :green)
      rescue SoftlayerServerCreateError => e
        puts ui.color('We have encountered a problem ordering the requested global IP.  The transaction may not have completed.', :red)
        puts ui.color(e.message, :yellow)
      end
    end

    if config[:assign_global_ip]
      case config[:assign_global_ip].to_s
        #ipv4
        when /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/
          global_ip = connection(:network).ips.by_address(config[:assign_global_ip])
        #ipv6
        when /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/
          global_ip = connection(:network).ips.by_address(config[:assign_global_ip])
        else
          raise SoftlayerServerCreateError, "--assign-global-ip value must be valid IPv4 or IPv6 address"
      end
      global_ip or raise SoftlayerServerCreateError, "Global IP address not found.  Please check the address or id supplied and try again."
      global_ip.reload
    end

    route_global_ip = Proc.new do
      puts ui.color('Routing Global IP Address to Instance.', :green)
      global_ip.route(connection(:network).ips.by_address(instance.public_ip_address)) or raise SoftlayerServerCreateError, "Global IP address failed to route."
      puts ui.color('Global IP Address has been assigned.', :green)
      puts ui.color('Global IP Address will not function without networking rules on the endpoint operating system.  See http://knowledgelayer.softlayer.com/learning/global-ip-addresses for details.', :yellow)
    end
    progress(route_global_ip)

  end

  puts ui.color('Bootstrapping Chef node, this may take a few minutes.', :green)
  linux_bootstrap(instance).run

  puts ui.color("Applying tags to Chef node.", :green)
  progress apply_tags(instance)

end
shared_bootstrap(bootstrap) click to toggle source

@param [Chef::Knife::Bootstrap] bootstrap @return [Chef::Knife::Bootstrap]

# File lib/chef/knife/softlayer_server_create.rb, line 400
def shared_bootstrap(bootstrap)
  bootstrap.config[:run_list] = config[:run_list]
  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[:environment] = locate_config_value(:environment)
  bootstrap.config[:prerelease] = config[:prerelease]
  bootstrap.config[:first_boot_attributes] = locate_config_value(:json_attributes) || {}
  bootstrap.config[:encrypted_data_bag_secret] = locate_config_value(:encrypted_data_bag_secret)
  bootstrap.config[:encrypted_data_bag_secret_file] = locate_config_value(:encrypted_data_bag_secret_file)
  bootstrap.config[:secret] = locate_config_value(:secret)
  bootstrap.config[:secret_file] = locate_config_value(:secret_file)
  bootstrap.config[:tags] = locate_config_value(:tags)
  bootstrap.config[:fqdn] = locate_config_value(:fqdn)
  Chef::Config[:knife][:hints] ||= {}
  Chef::Config[:knife][:hints]['softlayer'] ||= {}
  bootstrap
end
slurp_from_file(path) click to toggle source
# File lib/chef/knife/softlayer_server_create.rb, line 438
def slurp_from_file(path)
  args = JSON.parse(IO.read(path))
  args.keys.each { |key| args[key.gsub('-', '_').to_sym] = args.delete(key) }
  # TODO: Something less ugly than the empty rescue block below.  The :proc Procs/Lambdas aren't idempotent...
  args.keys.each { |key| begin; args[key] = options[key][:proc] ? options[key][:proc].call(args[key]) : args[key]; rescue; end }
  args
end
windows_bootstrap(server, fqdn) click to toggle source
# File lib/chef/knife/softlayer_server_create.rb, line 419
def windows_bootstrap(server, fqdn)
  # TODO: Windows support....
end