niedziela, 13 stycznia 2013

How set up WOL (Wake On Lan) on Thin Client with ubuntu

I set up small home server using HP TERMINAL HP T5000 (Thin Client). I installed Ubuntu server on it. It works great - but recently I realized that I need to have this server up only for very limited number of scenarios i.e. when I'm working on one of my PCs (so I want to have access to server resources e.g. samba, cups, DNS server etc) or I'm downloading something from the internet using transmission-daemon. To optimize my server power consumption I decided to set up Wake On Lan on my ubuntu and wrote 2 simple scripts in ruby.

How to set up WOL on ubuntu?
Log in as administrator.
Install ethtool:
sudo apt-get install ethtool
Change to the startup script directory and start editing a new file:
cd /etc/init.d/
nano wakeonlanconfig
Paste, or type this into the file, replacing eth0 with your network device, repeat the ethtool line as many times for your devices before the exit line:
ethtool -s eth0 wol g
Set the permissions of the file:
chmod a+x wakeonlanconfig
Make the script run on startup:
update-rc.d -f wakeonlanconfig defaults
You should see something like:
 Adding system startup for /etc/init.d/wakeonlanconfig ...
   /etc/rc0.d/K20wakeonlanconfig -> ../init.d/wakeonlanconfig
   /etc/rc1.d/K20wakeonlanconfig -> ../init.d/wakeonlanconfig
   /etc/rc6.d/K20wakeonlanconfig -> ../init.d/wakeonlanconfig
   /etc/rc2.d/S20wakeonlanconfig -> ../init.d/wakeonlanconfig
   /etc/rc3.d/S20wakeonlanconfig -> ../init.d/wakeonlanconfig
   /etc/rc4.d/S20wakeonlanconfig -> ../init.d/wakeonlanconfig
   /etc/rc5.d/S20wakeonlanconfig -> ../init.d/wakeonlanconfig
Now finish by running it, and making sure there are no errors.
Now when the server can be started remotely I want to present you 2 scrips which I wrote in ruby to make my life easier.

First for client machines.
All I need to do in this script is checking state of my server and if it is down send magic packet to power it on.
  require 'Win32/Console/ANSI'
rescue LoadError
  raise 'You must gem install win32console to use color on Windows'

require 'logger'
require 'net/ping'
require File.dirname(__FILE__) + "/wakeonlan.rb"

class String
    def red; colorize(self, "\e[1m\e[31m"); end
    def green; colorize(self, "\e[1m\e[32m"); end
    def dark_green; colorize(self, "\e[32m"); end
    def yellow; colorize(self, "\e[1m\e[33m"); end
    def blue; colorize(self, "\e[1m\e[34m"); end
    def dark_blue; colorize(self, "\e[34m"); end
    def pur; colorize(self, "\e[1m\e[35m"); end
    def colorize(text, color_code)  "#{color_code}#{text}\e[0m" end

log = + '/logs/log.txt', 'monthly')
log.debug "Script has been started"

puts "Ping ubuntu server"
log.debug "Ping ubuntu server"
p ='my_server_IP', 'http').ping?

if !p
 puts "Getting server up"
 log.debug "Getting server up"
 puts "Sending magic packet to ubuntu server"
 wol.wake("my_server_mac_address", "broadcast", "my_server_IP")
 # args: MAC_address Broadcast IP_address
 puts "Server is running".dark_green
 log.debug "Server is running"
Below I present code for WakeOnLan class which I used in above code:
# K.Kodama 2003-04-20 revised/bug fix
# K.Kodama 2000-05-10
# This program is distributed freely 
# in the sense of GNU General Public License or ruby's.

require "socket"

class WakeOnLan
 attr :socket
 def initialize
 def close; @socket.close; @socket=""; end
 def wake(mac_addr, broadcast="", ip_addr="")
  if broadcast==""; # Set broadcast. Assume that standard IP-class.
   if c<=127; ips[1]="255";end # class A:1--127
   if c<=191; ips[2]="255";end # class B:128--191
   if c<=223; ips[3]="255";end # class C:192--223
   # class D:224--239 multicast
  3.times{ @socket.send(wol_magic,0,broadcast,"discard") }

if $0 == __FILE__
Sample for WakeOnLan class.
Use as: ruby wakeonlan.rb [broadcast_address] < data_text
line format of data_text: ip-address  hostname  MAC-address
Data sample:  wake-pc  100:110:120:130:140:150
Note.  To check WOL packet, use tcpdump -x.

 if ARGV.size>=1; broadcast=ARGV[0]; ARGV.clear; else broadcast=""; end
 while gets
  wol.wake(hw, broadcast, ip)

Second for server.
I'm checking here state of network i.e. if any of my PCs is working. In case when all my PCs are offline server could be turn off but before I'll send halt command I have to check status of transmission-daemon - check if there are any elements being downloaded at the moment. If all conditions passed server is going to be shut down.
require 'net/ping'
require 'logger'
require 'transmission_api'

class TorrentStatus
 attr_accessor :all_torrents_finished
 def initialize()
  @transmission_api =
   :username => "my_user",
   :password => "password",
   :url      => "http://myserver:9091/transmission/rpc"
  torrents = @transmission_api.all

  @all_torrents_finished = true
   #puts "#{t["name"]} - [#{t["percentDone"]}]"
   @all_torrents_finished &= (t["percentDone"] == 1)

class LanStatus
 def initialize()
  @interfaces = ["","192.168.zzz.yyy"]
 def active_computers_in_network?
  active = false
   active |=

log = + '/logs/shutdown_log.txt')
log.debug "Script has been started"

puts "Checking system state"
log.debug "Checking system state"
print " * Torrent status "
torrent_status =
all_torrents_finished = torrent_status.all_torrents_finished
puts "- [#{all_torrents_finished ? "idle" : "active"}]"

log.debug " * Torrent status - [#{all_torrents_finished ? "idle" : "active"}]"

print " * Lan status"
lan_status =
active_computers_in_network = lan_status.active_computers_in_network?
puts "- [#{active_computers_in_network ? "active" : "inactive"}]"

log.debug " * Lan status - [#{active_computers_in_network ? "active" : "inactive"}]"

if (all_torrents_finished && !active_computers_in_network)
 puts "Sending HALT command to system"
 log.debug "Sending HALT command to system"
 system "sudo shutdown -h now"
There was still problem how to make it automated process. From the server side i use cron to schedule job which will execute in every 5 minutes and run ruby script. To read more about setting cron please read this post.
I added to crontab below entry:
0/5 * * * * ruby /home/luke/scripts/shut_down.rb
All my clients work under windows system and they are not attached to domain. So i just added ruby script to logon scripts. To add logon script for Windows 7 Home Premium: I've created a script at C:\Windows\System32\repl\import\scripts\start.bat Which executes command:
ruby /path_to_my_script/login.rb
Then I invoked from command line
net user USERNAME /scriptpath:start.bat

Brak komentarzy:

Prześlij komentarz