I wrote a Ruby script to call ssh-copy-id to distribute my public key to a list of hosts. It took me a while to make it work. The code is simple: read the password, and call ssh-copy-id for each host to copy the public key. Of course, the code doesn't consider all scenarios like the key is already copied, and wrong password. The tricky parts are "cp_out.readlines" and "Process.wait(pid)". If you don't read all the data from cp_out (comment out cp_out.readlines), the spawned process won't return.
#!/usr/bin/env ruby
require 'rubygems'
require 'pty'
require 'expect'
require 'io/console'
hosts_file = ARGV[0] || "hosts"
print "Password:"
password = $stdin.noecho(&:gets)
password.chomp!
puts
$expect_verbose = true
File.open(hosts_file).each do |host|
host.chomp!
print "Copying id to #{host} ... "
begin
PTY.spawn("ssh-copy-id #{host}") do |cp_out, cp_in, pid|
begin
pattern = /#{host}'s password:/
cp_out.expect(pattern, 10) do |m|
cp_in.printf("#{password}\n")
end
cp_out.readlines
rescue Errno::EIO
ensure
Process.wait(pid)
end
end
rescue PTY::ChildExited => e
puts "Exited: #{e.status}"
end
status = $?
if status == 0
puts "Done!"
else
puts "Failed with exit code #{status}!"
end
end