I don't know any internet-cafe software that would do this and I think something like Puppet or Chef would be an overkill. You can build a very simple setup based on SSH that would work.
Lets say you have 20 clients (10.0.0.101 to 10.0.0.120) and 1 management station (10.0.0.1).
All of the following steps can be tested out initially on 1 client only to test things out. The initial setup will need to be performed manually on all the clients.
Step 1: Make it more secure (Optional?)
Make a firewall rule on all of the clients to only accept new connections from 10.0.0.1
Maybe you can open anther question about this. I can also provide some help with the iptables
but I don't have experience with the new Ubuntu firewall rules.
Step 2: Establish a connection
You would need to have SSH service running on all the clients.
- Create a separate non-root account on the management station station.
- Run
ssh-keygen
to get an SSH key-pair. Don't provide any password.
- Create a separate account on the clients. Takkat mentioned how to exclude it from the Gnome Login window.
Add the account to sudoers (e.g. with sudo visudo
). Add this line:
aptaccount1 ALL=(silktree) NOPASSWD: /usr/bin/apt-get
NOPASSWD is important because you will need the installations to run without asking you for a password for every client.
Now you can test. From your management workstation run:
ssh 10.0.0.101 sudo apt-get update
Step 3: Connect to all in parallel
Now here is where my contribution comes in. I used this script for about 3 years and am really happy with it. It runs an ssh command in parallel to many nodes printing the output and/or errors nicely.
You would need to install ruby on the management station apt-get install ruby
and put all your clients hosts in a list into /etc/managed-clients like this:
n01
n02
n03
n04
And also on the management station add to /etc/hosts
:
10.0.0.101 n01
10.0.0.102 n02
10.0.0.103 n03
10.0.0.103 n04
Then save this script into /usr/local/bin/on-all-nodes-run
#!/usr/bin/ruby
CLIENTS_FILE = "/etc/managed-clients"
require "open3"
# Non-interactive, no password asking, and seasonable timeouts
SSH_OPTIONS = ["-o PreferredAuthentications=publickey,hostbased,gssapi,gssapi-with-mic",
"-o ForwardX11=no",
"-o BatchMode=yes",
"-o SetupTimeOut=5",
"-o ServerAliveInterval=5",
"-o ServerAliveCountMax=2"
].join(" ")
SSH = "/usr/bin/ssh #{SSH_OPTIONS}"
MKDIR = "/bin/mkdir"
raise "Pleae give this command at least one argument" if ARGV.size < 1
COMMAND = ARGV[0..-1].join(' ')
output_o = {}
output_e = {}
IO_CONNECTIONS_TO_REMOTE_PROCESSES = {}
def on_all_nodes(&block)
nodes = []
File.open(CLIENTS_FILE) do |f|
while line = f.gets
i = line.split(' ').first
nodes.push(i)
end
end
nodes.sort.each {|n| block.call(n)}
end
# Create processes
on_all_nodes do |node|
stdin, stdout, stderr = Open3.popen3("#{SSH} #{node} \"#{COMMAND}\"")
IO_CONNECTIONS_TO_REMOTE_PROCESSES[node] = [stdin, stdout, stderr]
end
has_remote_errors = false
# Collect results
on_all_nodes do |node|
stdin, stdout, stderr = IO_CONNECTIONS_TO_REMOTE_PROCESSES[node]
stdin.close
e_thread = Thread.new do
while line = stderr.gets
line.chomp!
STDERR.puts "#{node} ERROR: #{line}"
has_remote_errors = true
end
end
o_thread = Thread.new do
while line = stdout.gets
line.chomp!
puts "#{node} : #{line}"
end
end
# Let the threads finish
t1 = nil
t2 = nil
while [t1, t2].include? nil
if t1.nil?
t1 = e_thread.join(0.1) # Gives 1/10 of a second to STDERR
end
if t2.nil?
t2 = o_thread.join(0.1) # Give 1/10 of a second to STDOUT
end
end
end
exit(1) if has_remote_errors
The code has been reviewed for good coding style and there are some screenshots here:
https://codereview.stackexchange.com/questions/1180/ruby-script-on-all-nodes-run-for-teaching
but I never got time to introduce these suggestions. The code works well as is.
Test like this:
on-all-nodes-run echo hi
n01 : hi
n02 : hi
n03 ERROR: Timeout, server not responding.
n04 : hi
Step 4: Install software in parallel
Now you should be able to install and upgrade software like this (sorry, I only have the show
example with aptitude but it should be possible to do the same with apt-get
):
on-all-nodes-run sudo aptitude show pbzip2 \| grep State
n01 : State: not installed
n02 : State: not installed
n03 ERROR: Timeout, server not responding.
n04 : State: not installed
on-all-nodes-run echo "Yes" \| sudo apt-get install pbzip2
...
on-all-nodes-run sudo aptitude show pbzip2 \| grep State
n01 : State: installed
n02 : State: installed
n03 ERROR: Timeout, server not responding.
n04 : State: installed
Final note
If you have more than 10-20 clients then in addition to the script above you should find a way to re-provision the hard-drives with something like Perceus. That way you can save yourself some time (adding new client, etc...) and ensure that everything is the same across all the clients. In practice I use on-all-nodes-run
100s of times per year. I re-image with Perceus all the clients a few times a year.