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 328 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[:identity_file] = config[:identity_file] || File.join(locate_config_value(:vagrant_dir), 'insecure_key') bootstrap.config[:chef_node_name] = locate_config_value(:chef_node_name) || server.ip 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,instance_dir)
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 219 def build_vmx_customize(customize,instance_dir) vmx_params = "" if customize customize.chomp! if customize.end_with?("\n") disks = {} customize.split(/::/).each do |p| kv = p.split('=') k = kv[0].strip v = kv[1].strip if v if k.start_with?('scsi') ss = k.split('.') disks[ss[0]] ||= {} case ss[1] when 'fileName' if v.start_with?('/') disks[ss[0]]['fileName'] = v else v = File.expand_path(v,instance_dir) disks[ss[0]]['fileName'] = v end when 'fileSize' disks[ss[0]]['fileSize'] = v next end end vmx_params += "v.vmx[\"#{k}\"] = \"#{v}\"\n" end end if locate_config_value(:provider).start_with?('vmware') # Create extra disks as unlike virtual box vmware-fusion/workstation # will not create disks automatically based on configuration params disks.each_value do |f| vdiskmgr = %x(which vmware-vdiskmanager) vdiskmgr = "/Applications/VMware Fusion.app/Contents/Library/vmware-vdiskmanager" if vdiskmgr.empty? if File.exist?(vdiskmgr) disk = f['fileName'] %x("#{vdiskmgr}" -c -t 0 -s #{f['fileSize']} -a ide #{disk}) unless File.exist?(f['fileName']) unless File.exist?(disk) ui.error("Disk #{disk} could not be created.") exit 1 end else ui.error("Unable to determine path to vmware-vdiskmanager to create the requested additional disk.") exit 1 end end end end vmx_params end
create_server_def()
click to toggle source
# File lib/chef/knife/vagrant_server_create.rb, line 384 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_parameters => locate_config_value(:vmx_parameters), :inline_config => config[:inline_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 370 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 173 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) write_insecure_key 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 448 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 425 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 363 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 441 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 413 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 417 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 278 def write_vagrantfile # Create folder and write Vagrant file instance_dir = File.join(locate_config_value(:vagrant_dir), @server.name) FileUtils.mkdir_p(instance_dir) additions = [] if @server.use_cachier additions << 'config.cache.auto_detect = true' # enable vagarant-cachier end if @server.inline_config additions << @server.inline_config 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_parameters,instance_dir)} end config.vm.provider :vmware_workstation do |v| v.vmx["memsize"] = "#{@server.memsize}" #{build_vmx_customize(@server.vmx_parameters,instance_dir)} end #{additions.join("\n")} end EOF file instance_file = File.join(instance_dir, 'Vagrantfile') ui.msg("Creating #{instance_file}") File.open(instance_file, 'w') { |f| f.write(file) } end