Init Script

From OpenSimulator

Revision as of 11:06, 25 January 2009 by SeanDague (Talk | contribs)

Jump to: navigation, search

Region Init Script

The following is an init script that I wrote for starting, stopping, and monitoring OpenSim on Linux systems. It makes some assumptions, and is only going to work (unmoddified) if you stay with those assumptions:

  • Your opensim instance is in /opt/opensim/staging/bin (that's an easy change)
  • You are only running 1 OpenSim.exe process per machine (that's not easy to change)
  • You are using mysql (that's easy to change)
  • Production mono is in /usr/local/bin (that's easy to change)

While it may not be suitable for all environments, it has been very useful for the environments that I run.

#!/usr/bin/ruby
 
# Start or stop OpenSim
#
# Sean Dague <sdague@gmail.com>
 
### BEGIN INIT INFO
# Provides:          opensim
# Required-Start:    $local_fs $remote_fs $syslog $named $network $time $mysql
# Required-Stop:     $local_fs $remote_fs $syslog $named $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: start and stop opensim
# Description:       opensim init script
### END INIT INFO
 
require "rexml/document"
require "open-uri"
include REXML
 
OpenSimPath = "/opt/opensim/staging/bin"
Dir.chdir(OpenSimPath)
 
@host = "localhost"
@port = 9000
@uuid = "0"
 
def parse_config
    # first we figure out the external hostname of a region on the box
    Dir.new("#{OpenSimPath}/Regions").find do |f|
        if f =~ /\.xml$/
            doc = Document.new(File.new("#{OpenSimPath}/Regions/#{f}"))
 
            if doc.root.elements['Config'].attributes['external_host_name']
                @host = doc.root.elements['Config'].attributes['external_host_name']
            else
                @host = doc.root.elements['Config'].elements['external_host_name'].text
            end
 
            if doc.root.elements['Config'].attributes['sim_UUID']
                @uuid = doc.root.elements['Config'].attributes['sim_UUID'].gsub(/-/,'')
            else
                @uuid = doc.root.elements['Config'].elements['sim_UUID'].text.gsub(/-/,'')
            end
 
            break
        end
    end
    # then we figure out the external port from opensim.ini
    open("#{OpenSimPath}/OpenSim.ini") do |f|
        f.each do |line|
            if line =~ /^\s*http_listener_port/
                (key, equal, port) = line.split
                if port
                    @port = port
                end
            end
        end
    end
end
 
def alive?
    begin
        open("http://#{@host}:#{@port}/index.php?method=regionImage#{@uuid}") do |f|
            resp = f.read
            return true
        end
    rescue => e
    end
    return false
end
 
def pidof(item)
    IO.popen("ps auxw | grep #{item} | grep -v grep") do |line|
        line.each do |l|
            return l.split[1].to_i
        end
    end
    return nil
end
 
def opensim_pid
    return pidof("OpenSim.exe")
end
 
def status
    if alive?
        puts "OK"
        exit 0
    else
        puts "FAILED"
        exit 1
    end
end
 
def start
    if alive?
        puts "OpenSim already running"
        exit 0
    end
    if opensim_pid != nil
        # opensim process is running, but not responding, we're hung
        stop
        # this really is needed otherwise you get a wedge
        system("/etc/init.d/mysql restart")
        sleep 10
        # purge the addin cache, this may have been the reason for the hang
        system("rm -rf addin-db-*")
    end
    system("screen -wipe")
    system("screen -d -S opensim -m /usr/local/bin/mono --debug OpenSim.exe")
 
    20.times do |t|
        if alive?
            return
        end
        sleep 5
    end
 
    puts "FAILED to start region"
    exit 1
end
 
def stop
    if opensim_pid == nil
        puts "OpenSim not running"
        exit 0
    end
    system("screen -wipe")
    system("screen -S opensim -X eval 'stuff \"shutdown\015\"'")
    puts "Shutting down... waiting 30 seconds"
    30.times do |i|
        if opensim_pid == nil
            return 
        end
        $stderr.write "."
        sleep 1
    end
 
    pid = opensim_pid
    if pid
        puts "Process not responding, forcing shutdown"
        Process.kill(9, pid)
    end
 
end
 
def main
    parse_config
 
    mode = ARGV[0]
 
    if mode == "start"
        start
    elsif mode == "stop"
        stop
    elsif mode == "status"
        status
    elsif mode == "process"
        puts opensim_pid
    elsif mode == "restart"
        puts "called restart"
    else
        puts "unknown"
    end
end
 
main

Grid Init Script

WARNING this is untested, so it may blow up on you.

#!/usr/bin/ruby
 
# Start or stop OpenSim
#
# Sean Dague <japh@us.ibm.com>
 
### BEGIN INIT INFO
# Provides:          opensim-grid
# Required-Start:    $local_fs $remote_fs $syslog $named $network $time $mysql
# Required-Stop:     $local_fs $remote_fs $syslog $named $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: start and stop opensim-grid
# Description:       opensim-grid init script
### END INIT INFO
 
require "rexml/document"
require "open-uri"
include REXML
 
OpenSimPath = "/opt/opensim/staging/bin"
Dir.chdir(OpenSimPath)
 
@host = "localhost"
@gridport = nil
@userport = nil
@invport = nil
@assetport = nil
@messageport = nil
 
GridExe = "OpenSim.Grid.GridServer.exe"
UserExe = "OpenSim.Grid.UserServer.exe"
AssetExe = "OpenSim.Grid.AssetServer.exe"
InventoryExe = "OpenSim.Grid.InventoryServer.exe"
MessagingExe = "OpenSim.Grid.MessagingServer.exe"
 
def parse_config
    # Grid 
    begin 
        doc = Document.new(File.new("#{OpenSimPath}/GridServer_Config.xml"))
        @gridport = doc.root.elements['Config'].attributes['http_port']
    rescue => e
    end
 
    # User 
    begin
        doc = Document.new(File.new("#{OpenSimPath}/UserServer_Config.xml"))
        @userport = doc.root.elements['Config'].attributes['http_port']
    rescue => e
    end
 
    # Inventory 
    begin
        doc = Document.new(File.new("#{OpenSimPath}/InventoryServer_Config.xml"))
        @invport = doc.root.elements['Config'].attributes['http_port']
    rescue => e
    end
 
    # Asset 
    begin
        doc = Document.new(File.new("#{OpenSimPath}/AssetServer_Config.xml"))
        @assetport = doc.root.elements['Config'].attributes['http_port']
    rescue => e
    end
 
    # Messaging 
    begin
        doc = Document.new(File.new("#{OpenSimPath}/MessagingServer_Config.xml"))
        @messageport = doc.root.elements['Config'].attributes['http_port']
    rescue => e
    end
end
 
def grid_alive?
    if not @gridport
        return false
    end
    # we actually only care if we cause an exception, which means the grid server is bust
    begin
        xml = open("http://#{@host}:#{@gridport}/sims/fc036b80fed84b3096a50569b60da265").read
        return true
    rescue => e
        return false
    end
end
 
def user_alive?
    if not @userport
       return false 
    end
    # we actually only care if we cause an exception, which means the grid server is bust
    begin
        xml = open("http://#{@host}:#{@userport}/get_grid_info").read
        return true
    rescue => e
        return false
    end
end
 
def asset_alive?
    if not @assetport
        return false
    end
    begin
        # fetch the moon
        xml = open("http://#{@host}:#{@assetport}/assets/ec4b9f0b-d008-45c6-96a4-01dd947ac621").read
        # we need to check that we got something, because everything returns success, even if it didn't work
        if xml.size > 0
            return true
        else
            return false
        end
    rescue => e
        return false
    end
end
 
def inv_alive?
    if not @userport
       return false 
    end
    return true
    # THERE IS CURRENTLY NO EASY CALL FOR INV SERVER
    # we actually only care if we cause an exception, which means the grid server is bust
    begin
        xml = open("http://#{@host}:#{@port}/get_grid_info").read
        return true
    rescue => e
        return false
    end
end
 
def message_alive?
    if not @messageport
        return false
    end
    return true
end
 
 
def pidof(item)
    IO.popen("ps auxw | grep #{item} | grep -v grep") do |line|
        line.each do |l|
            return l.split[1].to_i
        end
    end
    return nil
end
 
def grid_pid
    return pidof(GridExe)
end
def user_pid
    return pidof(UserExe)
end
def asset_pid
    return pidof(AssetExe)
end
def inv_pid
    return pidof(InventoryExe)
end
def message_pid
    return pidof(MessagingExe)
end
 
def failme(msg="")
    puts "FAIL - #{msg}"
    exit 1
end
 
def status
    if @gridport and (not grid_alive?)
        failme("Grid server not responding")
    end
    if @userport and (not user_alive?)
        failme("User server not responding")
    end
    if @assetport and (not asset_alive?)
        failme("Asset server not responding")
    end
    if @invport and (not inv_alive?)
        failme("Inventory server not responding")
    end
    if @messageport and (not message_alive?)
        failme("Grid server not responding")
    end
    puts "OK"
    exit 0
end
 
def start_service(name, exe)
    if pidof(exe) != nil
        puts("#{exe} already running")
        return
    end
    system("screen -d -S #{name} -m /usr/local/bin/mono --debug #{exe}")
end
 
def start
    # Grid
    start_service("grid", GridExe)
    10.times do |d|
        if grid_alive?
            break
        end
        sleep 2
    end
    if not grid_alive?
        failme("Grid server did not start")
    end
 
    # User
    start_service("user", UserExe)
    10.times do |d|
        if user_alive?
            break
        end
        sleep 2
    end
    if not user_alive?
        failme("User server did not start")
    end
 
    # Asset
    start_service("asset", AssetExe)
    10.times do |d|
        if asset_alive?
            break
        end
        sleep 2
    end
    if not asset_alive?
        failme("Asset server did not start")
    end
 
    # Inventory
    start_service("inventory", InventoryExe)
    10.times do |d|
        if inv_alive?
            break
        end
        sleep 2
    end
    if not inv_alive?
        failme("Inventory server did not start")
    end
 
    # sleep an extra 2 because we didn't sleep at all here
    sleep 2
    # Messaging
    start_service("messaging", MessagingExe)
    10.times do |d|
        if message_alive?
            break
        end
        sleep 2
    end
    if not message_alive?
        failme("Messaging server did not start")
    end
end
 
def stop_service(name, exe)
    if pidof(exe) == nil
        puts "WARNING - #{exe} not running"
    end
    system("screen -S #{name} -X eval 'stuff \"shutdown\015\"'")
    puts "Shutting down... waiting 30 seconds"
    30.times do |i|
        if pidof(exe) == nil
            # just puts out a newline
            puts ""
            return 
        end
        $stderr.write "."
        sleep 1
    end
 
    pid = pidof(exe)
    if pid
        puts "Process not responding, forcing shutdown"
        Process.kill(9, pid)
    end
end
 
def stop
    stop_service("messaging",MessagingExe)
    stop_service("inventory",InventoryExe)
    stop_service("asset",AssetExe)
    stop_service("user",UserExe)
    stop_service("grid",GridExe)
end
 
def process
    puts "Grid #{grid_pid}"
    puts "User #{user_pid}"
    puts "Asset #{asset_pid}"
    puts "Inventory #{inv_pid}"
    puts "Messaging #{message_pid}"
end
 
def main
    parse_config
 
    mode = ARGV[0]
 
    if mode == "start"
        start
    elsif mode == "stop"
        stop
    elsif mode == "status"
        status
    elsif mode == "process"
        process
    elsif mode == "restart"
        puts "called restart"
    else
        puts "unknown"
    end
end
 
main
Personal tools
General
About This Wiki