|
|
Line 1: |
Line 1: |
− | == Region Init Script == | + | == OpenSim Init Scripts == |
− | 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.
| + | |
| | | |
− | <source lang="ruby">
| + | There is now a forge project for [http://forge.opensimulator.org/gf/linuxservice|Linux Service Scripts for OpenSim] that contains init scripts for running OpenSim. |
− | #!/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
| + | |
− | </source>
| + | |
− | | + | |
− | == Grid Init Script ==
| + | |
− | '''WARNING''' this is untested, so it may blow up on you.
| + | |
− | <source lang="ruby">
| + | |
− | #!/usr/bin/ruby
| + | |
− | | + | |
− | # Start or stop OpenSim
| + | |
− | #
| + | |
− | # Sean Dague <sdague@gmail.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
| + | |
− | </source>
| + | |