class Chef::Knife::RackspaceServerCreate
Attributes
initial_sleep_delay[RW]
Public Instance Methods
bootstrap_common_params(bootstrap, server)
click to toggle source
# File lib/chef/knife/rackspace_server_create.rb, line 606 def bootstrap_common_params(bootstrap, server) bootstrap.config[:environment] = config[:environment] bootstrap.config[:run_list] = config[:run_list] if version_one? bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.id else bootstrap.config[:chef_node_name] = config[:chef_node_name] || server.name end bootstrap.config[:prerelease] = locate_config_value(:prerelease) bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version) bootstrap.config[:bootstrap_template] = locate_config_value(:bootstrap_template) bootstrap.config[:first_boot_attributes] = locate_config_value(:first_boot_attributes) bootstrap.config[:bootstrap_proxy] = locate_config_value(:bootstrap_proxy) bootstrap.config[:encrypted_data_bag_secret] = locate_config_value(:secret) bootstrap.config[:encrypted_data_bag_secret_file] = locate_config_value(:secret_file) bootstrap.config[:secret] = locate_config_value(:secret) bootstrap.config[:secret_file] = locate_config_value(:secret_file) Chef::Config[:knife][:hints] ||= {} Chef::Config[:knife][:hints]["rackspace"] ||= {} bootstrap end
bootstrap_for_node(server, bootstrap_ip_address)
click to toggle source
# File lib/chef/knife/rackspace_server_create.rb, line 590 def bootstrap_for_node(server, bootstrap_ip_address) bootstrap = Chef::Knife::Bootstrap.new bootstrap.name_args = [bootstrap_ip_address] bootstrap.config[:ssh_user] = locate_config_value(:ssh_user) || "root" bootstrap.config[:ssh_password] = server.password bootstrap.config[:ssh_port] = locate_config_value(:ssh_port) bootstrap.config[:identity_file] = locate_config_value(:identity_file) bootstrap.config[:host_key_verify] = locate_config_value(:host_key_verify) bootstrap.config[:bootstrap_vault_file] = locate_config_value(:bootstrap_vault_file) if locate_config_value(:bootstrap_vault_file) bootstrap.config[:bootstrap_vault_json] = locate_config_value(:bootstrap_vault_json) if locate_config_value(:bootstrap_vault_json) bootstrap.config[:bootstrap_vault_item] = locate_config_value(:bootstrap_vault_item) if locate_config_value(:bootstrap_vault_item) # bootstrap will run as root...sudo (by default) also messes up Ohai on CentOS boxes bootstrap.config[:use_sudo] = true unless locate_config_value(:ssh_user) == "root" bootstrap_common_params(bootstrap, server) end
bootstrap_for_windows_node(server, bootstrap_ip_address)
click to toggle source
# File lib/chef/knife/rackspace_server_create.rb, line 629 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) || server.password bootstrap.config[:winrm_transport] = locate_config_value(:winrm_transport) bootstrap.config[:winrm_port] = locate_config_value(:winrm_port) bootstrap.config[:distro] = locate_config_value(:distro) || "windows-chef-client-msi" bootstrap_common_params(bootstrap, server) end
encode_file(file)
click to toggle source
# File lib/chef/knife/rackspace_server_create.rb, line 342 def encode_file(file) begin filename = File.expand_path(file) content = File.read(filename) rescue Errno::ENOENT => e ui.error "Unable to read source file - #{filename}" exit 1 end Base64.encode64(content) end
files()
click to toggle source
# File lib/chef/knife/rackspace_server_create.rb, line 353 def files return {} unless Chef::Config[:knife][:file] files = [] Chef::Config[:knife][:file].each do |arg| dest, src = parse_file_argument(arg) Chef::Log.debug("Inject file #{src} into #{dest}") files << { path: dest, contents: encode_file(src), } end files end
load_winrm_deps()
click to toggle source
# File lib/chef/knife/rackspace_server_create.rb, line 301 def load_winrm_deps require "winrm" require "chef/knife/winrm" require "chef/knife/bootstrap_windows_winrm" require "chef/knife/core/windows_bootstrap_context" end
parse_file_argument(arg)
click to toggle source
# File lib/chef/knife/rackspace_server_create.rb, line 333 def parse_file_argument(arg) dest, src = arg.split("=") unless dest && src ui.error "Unable to process file arguments #{arg}. The --file option requires both the destination on the remote machine as well as the local source be supplied using the form DESTINATION-PATH=SOURCE-PATH" exit 1 end [dest, src] end
run()
click to toggle source
# File lib/chef/knife/rackspace_server_create.rb, line 390 def run $stdout.sync = true server_create_options = { metadata: locate_config_value(:rackspace_metadata), disk_config: locate_config_value(:rackspace_disk_config), user_data: user_data, config_drive: locate_config_value(:rackspace_config_drive) || false, personality: files, key_name: locate_config_value(:rackspace_ssh_keypair), name: get_node_name(config[:chef_node_name] || config[:server_name]), networks: get_networks(locate_config_value(:rackspace_networks), locate_config_value(:rackconnect_v3_network_id)), } # Maybe deprecate this option at some point config[:bootstrap_network] = "private" if locate_config_value(:private_network) flavor_id = locate_config_value(:flavor) flavor = connection.flavors.get(flavor_id) if !flavor ui.error("Invalid Flavor ID: #{flavor_id}") exit 1 else server_create_options[:flavor_id] = flavor.id end # This is somewhat a hack, but Rackspace's API returns '0' for flavors # that must be backed by a CBS volume. # # In the case we are trying to create one of these flavors, we should # swap out the image_id argument with the boot_image_id argument. if flavor.disk == 0 server_create_options[:image_id] = "" server_create_options[:boot_volume_id] = locate_config_value(:boot_volume_id) server_create_options[:boot_image_id] = locate_config_value(:image) server_create_options[:boot_volume_size] = locate_config_value(:boot_volume_size) if server_create_options[:boot_image_id] && server_create_options[:boot_volume_id] ui.error("Please specify either --boot-volume-id (-B) or --image (-I)") exit 1 end else server_create_options[:image_id] = locate_config_value(:image) unless server_create_options[:image_id] ui.error("Please specify an Image ID for the server with --image (-I)") exit 1 end end if locate_config_value(:bootstrap_protocol) == "winrm" load_winrm_deps end server = connection.servers.new(server_create_options) if version_one? server.save else server.save(networks: server_create_options[:networks]) end rackconnect_wait = locate_config_value(:rackconnect_wait) rackspace_servicelevel_wait = locate_config_value(:rackspace_servicelevel_wait) msg_pair("Instance ID", server.id) msg_pair("Host ID", server.host_id) msg_pair("Name", server.name) msg_pair("Flavor", server.flavor.name) msg_pair("Image", server.image.name) if server.image msg_pair("Boot Image ID", server.boot_image_id) if server.boot_image_id msg_pair("Metadata", server.metadata.all) msg_pair("ConfigDrive", server.config_drive) msg_pair("UserData", locate_config_value(:rackspace_user_data)) msg_pair("RackConnect Wait", rackconnect_wait ? "yes" : "no") msg_pair("RackConnect V3", locate_config_value(:rackconnect_v3_network_id) ? "yes" : "no") msg_pair("ServiceLevel Wait", rackspace_servicelevel_wait ? "yes" : "no") msg_pair("SSH Key", locate_config_value(:rackspace_ssh_keypair)) # wait for it to be ready to do stuff begin server.wait_for(Integer(locate_config_value(:server_create_timeout))) do print "." Chef::Log.debug("#{progress}%") if rackconnect_wait && rackspace_servicelevel_wait Chef::Log.debug("rackconnect_automation_status: #{metadata.all["rackconnect_automation_status"]}") Chef::Log.debug("rax_service_level_automation: #{metadata.all["rax_service_level_automation"]}") ready? && metadata.all["rackconnect_automation_status"] == "DEPLOYED" && metadata.all["rax_service_level_automation"] == "Complete" elsif rackconnect_wait Chef::Log.debug("rackconnect_automation_status: #{metadata.all["rackconnect_automation_status"]}") ready? && metadata.all["rackconnect_automation_status"] == "DEPLOYED" elsif rackspace_servicelevel_wait Chef::Log.debug("rax_service_level_automation: #{metadata.all["rax_service_level_automation"]}") ready? && metadata.all["rax_service_level_automation"] == "Complete" else ready? end end rescue Fog::Errors::TimeoutError ui.error("Timeout waiting for the server to be created") msg_pair("Progress", "#{server.progress}%") msg_pair("rackconnect_automation_status", server.metadata.all["rackconnect_automation_status"]) msg_pair("rax_service_level_automation", server.metadata.all["rax_service_level_automation"]) Chef::Application.fatal! "Server didn't finish on time" end msg_pair("Metadata", server.metadata) print "\n#{ui.color("Waiting server", :magenta)}" puts("\n") if locate_config_value(:rackconnect_v3_network_id) print "\n#{ui.color("Setting up RackconnectV3 network and IPs", :magenta)}" setup_rackconnect_network!(server) while server.ipv4_address == "" server.reload sleep 5 end end if server_create_options[:networks] && locate_config_value(:rackspace_networks) msg_pair("Networks", locate_config_value(:rackspace_networks).sort.join(", ")) end msg_pair("Public DNS Name", public_dns_name(server)) msg_pair("Public IP Address", ip_address(server, "public")) msg_pair("Private IP Address", ip_address(server, "private")) msg_pair("Password", server.password) msg_pair("Metadata", server.metadata.all) bootstrap_ip_address = ip_address(server, locate_config_value(:bootstrap_network)) 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 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 print "\n#{ui.color("Waiting for sshd", :magenta)}" tcp_test_ssh(server, bootstrap_ip_address) bootstrap_for_node(server, bootstrap_ip_address).run end puts "\n" msg_pair("Instance ID", server.id) msg_pair("Host ID", server.host_id) msg_pair("Name", server.name) msg_pair("Flavor", server.flavor.name) msg_pair("Image", server.image.name) if server.image msg_pair("Boot Image ID", server.boot_image_id) if server.boot_image_id msg_pair("Metadata", server.metadata) msg_pair("Public DNS Name", public_dns_name(server)) msg_pair("Public IP Address", ip_address(server, "public")) msg_pair("Private IP Address", ip_address(server, "private")) msg_pair("Password", server.password) msg_pair("Environment", config[:environment] || "_default") msg_pair("Run List", config[:run_list].join(", ")) end
setup_rackconnect_network!(server)
click to toggle source
# File lib/chef/knife/rackspace_server_create.rb, line 556 def setup_rackconnect_network!(server) auth_token = connection.authenticate tenant_id = connection.endpoint_uri.path.split("/").last region = connection.region uri = URI("https://#{region}.rackconnect.api.rackspacecloud.com/v3/#{tenant_id}/public_ips") Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http| begin req = Net::HTTP::Post.new(uri.request_uri) req["X-Auth-Token"] = auth_token req["Content-Type"] = "application/json" req.body = JSON.dump("cloud_server" => { "id" => server.id }) http.use_ssl = true http.request req rescue StandardError => e puts "HTTP Request failed (#{e.message})" end end end
tcp_test_ssh(server, bootstrap_ip)
click to toggle source
# File lib/chef/knife/rackspace_server_create.rb, line 308 def tcp_test_ssh(server, bootstrap_ip) return true if locate_config_value(:tcp_test_ssh).nil? limit = locate_config_value(:retry_ssh_limit).to_i count = 0 begin Net::SSH.start(bootstrap_ip, "root", password: server.password ) do |ssh| Chef::Log.debug("sshd accepting connections on #{bootstrap_ip}") break end rescue count += 1 if count <= limit print "." sleep locate_config_value(:retry_ssh_every).to_i tcp_test_ssh(server, bootstrap_ip) else ui.error "Unable to SSH into #{bootstrap_ip}" exit 1 end end end
tcp_test_winrm(hostname, port)
click to toggle source
# File lib/chef/knife/rackspace_server_create.rb, line 368 def tcp_test_winrm(hostname, port) tcp_socket = TCPSocket.new(hostname, port) 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 tcp_socket && tcp_socket.close end
user_data()
click to toggle source
# File lib/chef/knife/rackspace_server_create.rb, line 576 def user_data file = locate_config_value(:rackspace_user_data) return unless file begin filename = File.expand_path(file) content = File.read(filename) rescue Errno::ENOENT => e ui.error "Unable to read source file - #{filename}" exit 1 end content end