class Chef::Knife::VagrantServerCreate
Public Instance Methods
bootstrap_node(server,ssh_host)
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 281 def bootstrap_node(server,ssh_host) bootstrap = Chef::Knife::Bootstrap.new bootstrap.name_args = [ssh_host] bootstrap.config[:ssh_user] = config[:ssh_user] 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) || server.ip # Starting from version 1.7 Vagrant replaces the fixed insecure key with a new, # random one the first time it is brought up. If that's the case we need to use # it to bootstrap. msg_pair("Vagrant version", vagrant_version) if config[:identity_file] bootstrap.config[:identity_file] = config[:identity_file] elsif vagrant_version_cmp('1.7') < 0 write_insecure_key bootstrap.config[:identity_file] = File.join(locate_config_value(:vagrant_dir), 'insecure_key') else # Vagrant puts the private key under the provider (i.e. 'virtualbox') so we search for it path = File.join(locate_config_value(:vagrant_dir), server.name, '.vagrant/') Find.find(path) do |f| if File.basename(f) == 'private_key' bootstrap.config[:identity_file] = f end end end bootstrap.config[:distro] = locate_config_value(:distro) || "chef-full" bootstrap.config[:use_sudo] = true unless config[:ssh_user] == 'root' bootstrap.config[:host_key_verify] = config[:host_key_verify] bootstrap.config[:run_list] = config[:run_list] 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[:environment] = locate_config_value(:environment) bootstrap.config[:prerelease] = config[:prerelease] bootstrap.config[:bootstrap_version] = locate_config_value(:bootstrap_version) 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) # Modify global configuration state to ensure hint gets set by # knife-bootstrap Chef::Config[:knife][:hints] ||= {} Chef::Config[:knife][:hints]["vagrant"] ||= {} # Cargo Cult programming FTW? msg_pair("SSH User", bootstrap.config[:ssh_user]) msg_pair("SSH identity file", bootstrap.config[:identity_file]) bootstrap end
build_port_forwards(ports)
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 211 def build_port_forwards(ports) ports.collect { |k, v| "config.vm.network :forwarded_port, host: #{k}, guest: #{v}, host_ip: '127.0.0.1'" }.join("\n") end
build_vb_customize(customize)
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 215 def build_vb_customize(customize) customize.split(/::/).collect { |k| "vb.customize [ #{k} ]" }.join("\n") if customize end
build_vmx_customize(customize)
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 219 def build_vmx_customize(customize) customize.split(/::/).collect { |k| "v.vmx[#{k.split('=')[0]}] = #{k.split('=')[1]}" }.join("\n") if customize end
create_server_def()
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 356 def create_server_def server_def = { :box => locate_config_value(:box), :box_url => locate_config_value(:box_url), :memsize => locate_config_value(:memsize), :share_folders => config[:share_folders], :port_forward => config[:port_forward], :use_cachier => config[:use_cachier], :vb_customize => locate_config_value(:vb_customize), :vmx_customize => locate_config_value(:vmx_customize), :vagrant_config => locate_config_value(:vagrant_config) } # Get specified IP address for new instance or pick an unused one from the subnet pool. server_def[:ip_address] = config[:ip_address] || find_available_ip collision = vagrant_instance_list.detect { |i| i[:ip_address] == server_def[:ip_address] } if collision ui.error("IP address #{server_def[:ip_address]} already in use by instance #{collision[:name]}") exit 1 end # Derive name for vagrant instance from chef node name or IP server_def[:name] = locate_config_value(:chef_node_name) || server_def[:ip_address] # Turn it into and object like thing OpenStruct.new(server_def) end
find_available_ip()
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 342 def find_available_ip subnet = locate_config_value('subnet') IPAddr.new(subnet).to_range().each { |ip| # 192.168.3.0/24 should yield 192.168.3.2 through 192.168.3.254 # 192.168.3.1 cannot be used because virtual box uses it for the router mask = IPAddr::IN4MASK ^ ip.instance_variable_get("@mask_addr") unless [0, 1, mask].include? (ip & mask) or vagrant_instance_list.detect { |i| i[:ip_address] == ip.to_s } return ip.to_s end } ui.error("No unused IP address available in subnet #{subnet}") exit 1 end
run()
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 174 def run $stdout.sync = true validate! @server = create_server_def msg_pair("Instance name", @server.name) msg_pair("Instance IP", @server.ip_address) msg_pair("Box", @server.box || @server.box_url) if vagrant_instance_list.detect { |i| i[:name] == @server.name } ui.error("Instance #{@server.name} already exists") exit 1 end # Create Vagrant file for new instance print "\n#{ui.color("Launching instance", :magenta)}\n" write_vagrantfile cmd = "up --provider #{locate_config_value(:provider)}" vagrant_exec(@server.name, cmd) print "\n#{ui.color("Waiting for sshd", :magenta)}" wait_for_sshd(@server.ip_address) print "\n#{ui.color("Bootstraping instance", :magenta)}\n" bootstrap_node(@server,@server.ip_address).run puts "\n" msg_pair("Instance Name", @server.name) msg_pair("Box", @server.box || @server.box_url) msg_pair("IP Address", @server.ip_address) msg_pair("Environment", locate_config_value(:environment) || '_default') msg_pair("Run List", (config[:run_list] || []).join(', ')) msg_pair("JSON Attributes", config[:json_attributes]) unless !config[:json_attributes] || config[:json_attributes].empty? end
tcp_test_ssh(hostname, ssh_port) { || ... }
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 420 def tcp_test_ssh(hostname, ssh_port) tcp_socket = TCPSocket.new(hostname, ssh_port) readable = IO.select([tcp_socket], nil, nil, 5) if readable Chef::Log.debug("sshd accepting connections on #{hostname}, banner is #{tcp_socket.gets}") yield true else false end rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError sleep 2 false rescue Errno::EPERM, Errno::ETIMEDOUT false # This happens on some mobile phone networks rescue Errno::ECONNRESET sleep 2 false ensure tcp_socket && tcp_socket.close end
tunnel_test_ssh(hostname, &block)
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 397 def tunnel_test_ssh(hostname, &block) gw_host, gw_user = config[:ssh_gateway].split('@').reverse gw_host, gw_port = gw_host.split(':') gateway = Net::SSH::Gateway.new(gw_host, gw_user, :port => gw_port || 22) status = false gateway.open(hostname, config[:ssh_port]) do |local_tunnel_port| status = tcp_test_ssh('localhost', local_tunnel_port, &block) end status rescue SocketError, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, Errno::ENETUNREACH, IOError sleep 2 false rescue Errno::EPERM, Errno::ETIMEDOUT false end
validate!()
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 335 def validate! unless locate_config_value(:box) || locate_config_value(:box_url) ui.error("You need to either specify --box or --box-url") exit 1 end end
wait_for_direct_sshd(hostname, ssh_port)
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 413 def wait_for_direct_sshd(hostname, ssh_port) print(".") until tcp_test_ssh(hostname, ssh_port) { sleep @initial_sleep_delay ||= 2 puts("done") } end
wait_for_sshd(hostname)
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 385 def wait_for_sshd(hostname) config[:ssh_gateway] ? wait_for_tunnelled_sshd(hostname) : wait_for_direct_sshd(hostname, config[:ssh_port]) end
wait_for_tunnelled_sshd(hostname)
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 389 def wait_for_tunnelled_sshd(hostname) print(".") print(".") until tunnel_test_ssh(hostname) { sleep @initial_sleep_delay ||= 2 puts("done") } end
write_vagrantfile()
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 230 def write_vagrantfile additions = [] if @server.use_cachier additions << 'config.cache.auto_detect = true' # enable vagarant-cachier end if @server.vagrant_config additions << @server.vagrant_config.split(/::/) end unless config[:identity_file].nil? additions << 'config.ssh.private_key_path = "' + config[:identity_file] + '"' end file = <<-EOF Vagrant.configure("2") do |config| config.vm.box = "#{@server.box}" config.vm.box_url = "#{@server.box_url}" config.vm.hostname = "#{@server.name}" config.vm.network :private_network, ip: "#{@server.ip_address}" #{build_port_forwards(@server.port_forward)} #{build_shares(@server.share_folders)} config.vm.provider :virtualbox do |vb| vb.customize [ "modifyvm", :id, "--memory", #{@server.memsize} ] #{build_vb_customize(@server.vb_customize)} end config.vm.provider :vmware_fusion do |v| v.vmx["memsize"] = "#{@server.memsize}" #{build_vmx_customize(@server.vmx_customize)} end config.vm.provider :vmware_workstation do |v| v.vmx["memsize"] = "#{@server.memsize}" #{build_vmx_customize(@server.vmx_customize)} end #{additions.join("\n")} end EOF file # Create folder and write Vagrant file instance_dir = File.join(locate_config_value(:vagrant_dir), @server.name) instance_file = File.join(instance_dir, 'Vagrantfile') ui.msg("Creating #{instance_file}") FileUtils.mkdir_p(instance_dir) File.open(instance_file, 'w') { |f| f.write(file) } end