munin alternative

May 28th, 2009

just started a new project called ‘monitordatasink’ (im kind of uncreative in such naming things…).
Jut hop over to http://code.google.com/p/monitordatasink/ and have a look yourself. happy monitoring! :)

how to get the client IP in python XMLRPC - the easy way

May 26th, 2009

some time i wrote a post of how to do it the complicated way, so today the easy way:

Python [Show Plain Code]:
  1. import SimpleXMLRPCServer
  2. import os.path
  3. import rrd
  4.  
  5. monitor = None
  6.  
  7. class Monitor:
  8.     def getMyIP(self):
  9.         return "your IP is: %s" % monitor.clientIP
  10.  
  11. class myHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
  12.     def do_POST(self):
  13.         global monitor
  14.         monitor.clientIP, monitor.clientPort = self.client_address
  15.         SimpleXMLRPCServer.SimpleXMLRPCRequestHandler.do_POST(self)
  16.  
  17. server = SimpleXMLRPCServer.SimpleXMLRPCServer(("",8888), myHandler)
  18. monitor = Monitor()
  19. server.register_instance(monitor)
  20. server.serve_forever()

’strict’ typing of function arguments in python

April 2nd, 2009

Sometimes you just need strict variable typing in python. For example if you provide an XML-RPC function, where you have to ensure that the incoming data has the correct type. One solution for this is to write type-checking and converting manually within every function. Since that idea is not very nice and clean, i wrote a function and function decorator that can ensure that the function is always called with the desired types as arguments. To achieve that you need to use a certain naming scheme for the functions arguments: variableType_variableName. So int_a, string_s, list_myList, etc. (see example in code)

code (working example, just run):

Python [Show Plain Code]:
  1. # strictly typed python function arguments example
  2. # Thomas Fischer <thomas{AT}thoamsfischer{DOT}biz>
  3.  
  4. # function that checks the variable name and its type
  5. # to use a certain type for a variable, just write variableype_variablename
  6. # for example: int_number, string_s, list_l
  7. def checkFunctionArgumentTypes(function_pointer, args):
  8.   args = list(args) # we want to assign stuff to it later on
  9.   # now list some built-in types we check for
  10.   arg_types = {‘int’:int, ’str’:str, ‘list’:list, ‘dict’:dict, ‘bool’:bool, ‘unicode’:unicode, ‘tuple’:tuple, ‘buffer’:buffer, ‘xrange’:xrange, ‘int’:int, ‘float’:float, ‘long’:long, ‘complex’:complex, ’set’:set, ‘frozenset’:frozenset}
  11.   # care about default arguments (means args <= len of function arguments)
  12.   arg_num = len(args)
  13.  
  14.   self_exist = False
  15.   if function_pointer.func_code.co_argcount > 0 and function_pointer.func_code.co_varnames[0] == ’self’:
  16.     self_exist = True
  17.  
  18.   for argnum in range(0, arg_num):
  19.     arg_def = None
  20.     if self_exist:
  21.       arg_def = function_pointer.func_code.co_varnames[argnum+1]
  22.     else:
  23.       arg_def = function_pointer.func_code.co_varnames[argnum]
  24.     arg_ext = args[argnum]
  25.     atype = None
  26.     for arg_type in arg_types.keys():
  27.       if arg_def.startswith(arg_type):
  28.         atype = arg_types[arg_type]
  29.         break
  30.     if atype is None:
  31.       # we cannot check the type, since no keyword was found :-/
  32.       # maybe this is fatal for you and you want to return False as well
  33.       continue
  34.     # try to convert the type
  35.     try:
  36.       args[argnum] = atype.__call__(arg_ext)
  37.     except Exception, e:
  38.       res_str = "wrong type for function %s, argument %s (%d.) has to be type ‘%s’ and not ‘%s’" % (function_pointer.__name__, arg_def, argnum, atype, type(arg_ext))
  39.       return False, res_str
  40.   return True, args
  41.  
  42. # some fancy function decorator that acts as a type checking wrapper around the function
  43. def checkArgumentTypes(f):
  44.   def wrapper(*args, **kwargs):
  45.     ok, args = checkFunctionArgumentTypes(f, args)
  46.     if not ok:
  47.       return ok, args
  48.     f(*args, **kwargs)
  49.   return wrapper
  50.  
  51. # magic with python decorators :)
  52. @checkArgumentTypes
  53. def func1(string_s, int_number):
  54.   print "func1 called with:", string_s, type(string_s), int_number, type(int_number)
  55.  
  56. # ok, fits:
  57. print func1(‘test’, 123)
  58.  
  59. # ok, will be converted:
  60. print func1(‘test’, ‘123′)
  61.  
  62. # fails, cannot convert ABC to int:
  63. print func1(‘test’, ‘ABC’)

the result upon run:

func1 called with: test <type 'str'> 123 <type 'int'>
None
func1 called with: test <type 'str'> 123 <type 'int'>
None
(False, "wrong type for function func1, argument int_number (1.) has to be type '<type 'int'>' and not '<type 'str'>'")

this thing makes using XML-RPC much easier :)

clone discs over the network

April 1st, 2009

its easy if you know how:
A is the computer we want to clone, B is the target.
1) download and burn two gentoo installation CDs and boot them on both systems.
2) give the root user a password and start sshd:

passwd
/etc/init.d/sshd start

3) clone discs via dd and ssh: (execute this on A)


dd if=/dev/hda bs=512 | ssh root@<IP of B> "dd of=/dev/hda"

4) thats all. You can view the status of the operation via:


kill -SIGUSR1 `ps | grep dd | awk '{ print $1 }'`

EDIT: better solution (with compression over the network):
on B:


netcat -l -p 11000 | bzip2 -d | dd of=/dev/sda

on A:

bzip2 -c /dev/sda | netcat <IP of B> 11000

script to backup LVM volumes

March 29th, 2009

since i have to backup some volumes from time to time and i dont want to put this imporant task into the hand of backup scripts, i wrote a LVM backup helper script. The script does not execute anything more then readonly/show commands and instead outputs all steps you have to do:

backupvolume.sh:

#!/bin/bash
# this script should help an administrator to backup his volumes
# the script does NOT execute any dangerous ogerations, instead it
# will print them, so the user can execute them by hand

# if you are totally insane you can also copy-paste the script output into a console

# written by thomas fischer thomas{AT}thomasfischer{DOT}biz
VOL=''

if [ -n "$1" ] ; then
 VOL=$1
else
 echo "usage: $0 > /dev/null 2>&1
mkdir -p /mnt/backup-target >> /dev/null 2>&1
echo “mount /dev/$VG/$SNAP_VN /mnt/backup-snapshot”
echo “mount /dev/$VG/$TEMP_VN /mnt/backup-target”

echo “# 4) create the actual backup:”
echo “tar pzcvf /mnt/backup-target/backup.tar.gz /mnt/backup-snapshot/”

echo “# 5) backup done, remove mount and snapshot volume:”

echo “umount /mnt/backup-snapshot”
echo “lvremove /dev/$VG/$SNAP_VN”

echo “# 6) now, download your backup: /mnt/backup-target/backup.tar.bz2 and continue then:”

echo “umount /mnt/backup-snapshot”
echo “lvremove /dev/$VG/$TEMP_VN”

echo “# 7) done!”

this outputs such a nice guide:

# SNIP HERE!
# 1) create temporary volumes:
lvcreate -L107.37G -s -n webserver_snapshot /dev/vg/webserver
lvcreate -L107.37G -n webserver_temp vg
# 2) format the temporary volume:
mke2fs /dev/vg/webserver_temp
# 3) mount the temporary volumes:
mount /dev/vg/webserver_snapshot /mnt/backup-snapshot
mount /dev/vg/webserver_temp /mnt/backup-target
# 4) create the actual backup:
tar pzcvf /mnt/backup-target/backup.tar.bz2 /mnt/backup-snapshot/
# 5) backup done, remove mount and snapshot volume:
umount /mnt/backup-snapshot
lvremove /dev/vg/webserver_snapshot
# 6) now, download your backup: /mnt/backup-target/backup.tar.bz2 and continue then:
umount /mnt/backup-snapshot
lvremove /dev/vg/webserver_temp
# 7) done

that can be checked by the user and copy-pasted on will :)

valve steam down (even the best systems fail)

March 28th, 2009

steam.pngsteamdwk4.jpg

linux custom firefox protocols the easy way

March 25th, 2009

so you have your fancy application and want to add a protocol to firefox in order to link firefox to it?
Under windows thats easy, under linux now as well: the attached wrapper will call any program you set up in firefox. (this can be a security issue, but i need it for testing only)

step 0:
a) download this script as ~/browser-wrapper.py :

#!/usr/bin/env python
from syslog import syslog
import sys
import commands

def main():
  cmdargs = sys.argv[1].split(':')
  cmd = cmdargs[0] + ' ' + ':'.join(cmdargs[1:])
  syslog("browser wrapper calling: %s" % cmd)
  return commands.getstatusoutput(cmd)

if __name__ == "__main__":
  main()

b) chmod +x the script

step 1: let firefox know about this:
(please note that we want to add vncviewer links in this example, so the correct YOUR_APPLICATION_NAME is vncviewer)
a) open about:config in firefox
b) Right Click > New > Boolean : enter
network.protocol-handler.external.YOUR_APPLICATION_NAME
and as boolean value true
c) Right Click > New > String : enter
network.protocol-handler.app.YOUR_APPLICATION_NAME
and as string value the
d) open a new tab in firefox and type:
YOUR_APPLICATION_NAME:test
e) in the upcoming dialog, select the wrapper script again and click ok (firefox bug with the preset value …)

your wrapper should work :)
so everytime you click on an url
YOUR_APPLICATION_NAME:something
the application YOUR_APPLICATION_NAME will be called with argument “something”

SimpleXMLRPCServer and peer IPs

March 23rd, 2009

So python has some really nice and easy functions to setup a XMLRPC server.
For me it just lacks a basic function: find out the caller’s IP address. So i took the default implementation and added a function to insert the client IP into the data. Bit hack-ish but works very well. So your client just adds an argument that contains ‘__CLIENT_IP_ADDRESS__’ as string. This receiving function will see the client IP instead this hardcoded sting.

have fun :)

(side note: they only modification to the original code is marked via XXX)

Python [Show Plain Code]:
  1. class myXMLRPCRequesthandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
  2.   def do_POST(self):
  3.     """Handles the HTTP POST request.
  4.  
  5.     Attempts to interpret all HTTP POST requests as XML-RPC calls,
  6.     which are forwarded to the server’s _dispatch method for handling.
  7.     """
  8.     try:
  9.         # get arguments
  10.         data = self.rfile.read(int(self.headers["content-length"]))
  11.  
  12.         # XXX modification start: special replacement functions
  13.         clientIP, clientPort = self.client_address
  14.         data = data.replace(‘__CLIENT_IP_ADDRESS__’, clientIP)
  15.         # XXX modification end
  16.  
  17.         # In previous versions of SimpleXMLRPCServer, _dispatch
  18.         # could be overridden in this class, instead of in
  19.         # SimpleXMLRPCDispatcher. To maintain backwards compatibility,
  20.         # check to see if a subclass implements _dispatch and dispatch
  21.         # using that method if present.
  22.         response = self.server._marshaled_dispatch(
  23.                 data, getattr(self, ‘_dispatch’, None)
  24.             )
  25.     except: # This should only happen if the module is buggy
  26.         # internal error, report as HTTP server error
  27.         self.send_response(500)
  28.         self.end_headers()
  29.     else:
  30.         # got a valid XML RPC response
  31.         self.send_response(200)
  32.         self.send_header("Content-type", "text/xml")
  33.         self.send_header("Content-length", str(len(response)))
  34.         self.end_headers()
  35.         self.wfile.write(response)
  36.  
  37.         # shut down the connection
  38.         self.wfile.flush()
  39.         self.connection.shutdown(1)
  40.  
  41. class myXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer):
  42.     def __init__(self, addr, requestHandler=myXMLRPCRequesthandler, logRequests=1):
  43.         SimpleXMLRPCServer.SimpleXMLRPCServer.__init__(self, addr, requestHandler, logRequests)
  44.  
  45. # then use myXMLRPCServer class as you would do normally with the SimpleXMLRPCServer class :)

boost::asio

March 23rd, 2009

is really nice :)

just have a look at this fancy code:

  1. #include <iostream>
  2. #include <string>
  3. #include <boost/asio.hpp>
  4. int main(int argc, char* argv[])
  5. {
  6.  boost::asio::ip::tcp::iostream stream("www.google.com", "http");
  7.  if (!stream)
  8.   return 1;
  9.  stream << "GET / HTTP/1.0\r\nHost: www.google.com\r\n\r\n";
  10.  std::string line;
  11.  while(std::getline(stream, line))
  12.   std::cout << line << std::endl;
  13.  return 0;
  14. }

life-sign :)

March 16th, 2009

well, i am very busy working in Britain currently, so not much updates currently :(

packing and unpacking zero terminated strings in python

July 8th, 2008

so i found a problem with the struct module in python: it cannot pack or unpack zero terminated strings! This is pretty bad if you want to parse or generate data that must conform that zero termination c-string idea. So i wrote some wrapper functions for pack and unpack that add the format ‘z’. z means zero terminated string.

What it does simply is:

  • on packing find and add z zero if necessary. Use the correct string size of the found string argument to pack it correctly
  • on unpacking unpack every format as normal, just manually unpack the ‘z’ character format.

This will enable you to write:

Python [Show Plain Code]:
  1. print unpackExt("z", packExt("z", "test1"))
  2. print unpackExt("z", packExt("z", "test1 test2"))
  3. print unpackExt("z", packExt("z", "test1\0test2"))
  4. print unpackExt("ibzi", packExt("ibzi", 200, 3, "test1\0test2", 34))
  5. print unpackExt("ibzizf", packExt("ibzizf", 200, 3, "test1\0test2", 34, "test string", 0.234))

which will result in:

['test1']
['test1 test2']
['test1']
[200, 3, 'test1', 34]
[200, 3, 'test1', 34, 'test string', 0.23399999737739563]

download the script: struct-zerostrings.py

feel free to use, but please report back if you found problems :)

one c macro to rule them all

June 29th, 2008

or how to comment a line using the precompiler: http://www.ddj.com/cpp/184401344

the short version for the impatient:

#ifdef _DEBUG
 #define DEBUGCLASS myClass::getSingleton()
#else
 #define COMMENT SLASH(/)
 #define SLASH(s) /##s
 #define DEBUGCLASS COMMENT
#endif

DEBUGCLASS.dosomething();

how to fully use maxmind’s geolocation DB with php

April 16th, 2008

or: how to use geolocation usefully. This solution tries to solve i.e. the problem of calculating the distance between two country by simply comparing the continent of each. So you can simply use a fitting server on the user’s same continent or such.

application example: geolocatephp.txt

the included php file (use it as you like) (the data is based on this)
geotoolsphp.txt

indentcode.net

March 3rd, 2008

i was really missing the “indent” tool under windows for my c++ source code :-\
and i found no online converter, so i created one in under an hour:


indentcode.net

about mysql…

January 28th, 2008

some small notes from myself:
- never use timestamps in queries and use such queries to select them:

  1. SELECT * form TABLE WHERE timestamp > $begin AND timestamp < $end;

this will result in an overused CPU ! :-\

- also how to loop over entries in sql via stored procedures in sql:

  1. DELIMITER |
  2. DROP PROCEDURE IF EXISTS createstats |
  3. CREATE PROCEDURE createstats()
  4. BEGIN
  5.   DECLARE v_fileid INT;
  6.   declare no_more_rows BOOLEAN DEFAULT FALSE;
  7.   declare cursor1 cursor FOR
  8.   SELECT id FROM files;
  9.   declare continue handler FOR NOT found
  10.   SET no_more_rows = TRUE;
  11.  
  12.   open cursor1;
  13.   LOOP1: loop
  14.     fetch cursor1 INTO v_fileid;
  15.     IF no_more_rows then
  16.       close cursor1;
  17.       leave LOOP1;
  18.     end IF;
  19.  
  20.     INSERT INTO files_tempstats (`fileid`, `dltotal`, `ratecount`, `ratesum`) VALUES (
  21.       v_fileid,
  22.       (SELECT count(`stats`.`value`) FROM `stats` WHERE `stats`.`fileid`=v_fileid),
  23.       (SELECT count(`ratings`.`id`) FROM `ratings` WHERE `ratings`.`fileid`=v_fileid),
  24.       (SELECT sum(`ratings`.`rating`) FROM `ratings` WHERE `ratings`.`fileid`=v_fileid)
  25.     );
  26.   END LOOP LOOP1;
  27. END

great OS-independent Python Editor

January 15th, 2008

Just found the “SPE IDE” = Stani’s Python Editor :)

get it here

YABT (yet another new blog title)

January 8th, 2008

Isaac was so kind to tell me that the meaning of the title wont fit with the amount of number (meaning here).

so i updated it to a more correct form ;)

kcachegrind

January 8th, 2008

very useful to see the call Graph and performance of your program:
screenshots: http://kcachegrind.sourceforge.net/cgi-bin/show.cgi/KcacheGrindShot
how to get it (under gentoo):

emerge -av kcachegrind valgrind

How to use:
Collect data program during program execution

valgrind –tool=callgrind –trace-children=yes –num-callers=8 –collect-jumps=yes –instr-atstart=no ./yourprogram

Then open the output file that is created using kcachegrind!

write your own wireshark protocol dissector

January 4th, 2008

Dissectors in Wireshark will convert the pure data of a packet into a custom protocol with readable data, so you can see values of your protocol instead of just binary data.

How is it done?

First open the file “init.lua” in your wireshark directory and comment out this line:

  1. disable_lua = false; do return end;

to

  1. –disable_lua = false; do return end;

then add to the bottom of the file this line:

  1. dofile("ror.lua")

(ror is the protocol in my case)

After that you should create a file named “ror.lua” and copy+paste the following content:

  1. – dissects the RoR Protocol
  2. packetnum = -1
  3. ror_proto = Proto("ror","ROR","RoR Protocol")
  4. – create a function to dissect it
  5. function ror_proto.dissector(buffer,pinfo,tree)
  6.     pinfo.cols.protocol = "ROR"
  7.         cmd = buffer(0,4):le_uint()
  8.        
  9.         packetnum = pinfo.number
  10.  
  11.         local subtree_packet = tree:add(ror_proto,buffer(),"Rigs of Rods ("..buffer:len()..")")
  12.        
  13.         local subtree_header = subtree_packet:add_le(buffer(0,12), "RoR Header (12)")
  14.        
  15.         cmd_str = "unkown"
  16.         if cmd == 1000 then
  17.                 cmd_str = "MSG2_HELLO"
  18.         elseif cmd == 1001 then
  19.                 cmd_str = "MSG2_VERSION"
  20.         elseif cmd == 1002 then
  21.                 cmd_str = "MSG2_FULL"
  22.         elseif cmd == 1003 then
  23.                 cmd_str = "MSG2_BANNED"
  24.         elseif cmd == 1004 then
  25.                 cmd_str = "MSG2_WELCOME"
  26.         elseif cmd == 1005 then
  27.                 cmd_str = "MSG2_USE_VEHICLE"
  28.         elseif cmd == 1006 then
  29.                 cmd_str = "MSG2_SPAWN"
  30.         elseif cmd == 1007 then
  31.                 cmd_str = "MSG2_BUFFER_SIZE"
  32.         elseif cmd == 1008 then
  33.                 cmd_str = "MSG2_VEHICLE_DATA"
  34.         elseif cmd == 1009 then
  35.                 cmd_str = "MSG2_USER"
  36.         elseif cmd == 1010 then
  37.                 cmd_str = "MSG2_DELETE"
  38.         elseif cmd == 1011 then
  39.                 cmd_str = "MSG2_CHAT"
  40.         elseif cmd == 1012 then
  41.                 cmd_str = "MSG2_FORCE"
  42.         elseif cmd == 1017 then
  43.                 cmd_str = "MSG2_USER_CREDENTIALS"
  44.         elseif cmd == 1019 then
  45.                 cmd_str = "MSG2_TERRAIN_RESP"
  46.         elseif cmd == 1020 then
  47.                 cmd_str = "MSG2_WRONG_PW"
  48.         elseif cmd == 1021 then
  49.                 cmd_str = "MSG2_RCON_LOGIN"
  50.         elseif cmd == 1022 then
  51.                 cmd_str = "MSG2_RCON_LOGIN_FAILED"
  52.         elseif cmd == 1023 then
  53.                 cmd_str = "MSG2_RCON_LOGIN_SUCCESS"
  54.         elseif cmd == 1024 then
  55.                 cmd_str = "MSG2_RCON_LOGIN_NOTAV"
  56.         elseif cmd == 1025 then
  57.                 cmd_str = "MSG2_RCON_COMMAND"
  58.         elseif cmd == 1026 then
  59.                 cmd_str = "MSG2_RCON_COMMAND_FAILED"
  60.         elseif cmd == 1027 then
  61.                 cmd_str = "MSG2_RCON_COMMAND_SUCCESS"
  62.         end
  63.        
  64.         datasize = buffer(8,4):le_uint()
  65.        
  66.         pinfo.cols.info:set("Command: "..cmd_str)
  67.         subtree_header:add_le(buffer(0,4),"command: ".. cmd_str .." (" .. cmd..")")
  68.         subtree_header:add_le(buffer(4,4),"source: " .. buffer(4,4):le_uint())
  69.         subtree_header:add_le(buffer(8,4),"size: " .. buffer(8,4):le_uint())
  70.  
  71.         databegin = 12
  72.         dataend = databegin + datasize
  73.         local subtree_data = subtree_packet:add_le(buffer(databegin,datasize), "RoR Data ("..datasize..")")
  74.        
  75.         if cmd == 1000 then
  76.                 local info = "RoR Version: "..buffer(databegin, datasize):string()
  77.                 subtree_data:add_le(buffer(databegin, datasize), info)
  78.  
  79.         elseif cmd == 1001 then
  80.                 local info = "RoR Version: "..buffer(databegin, datasize):string()
  81.                 subtree_data:add_le(buffer(databegin, datasize), info)
  82.         elseif cmd == 1002 then
  83.                 local info = "Server full! "..buffer(databegin, datasize):string()
  84.                 subtree_data:add_le(buffer(databegin, datasize), info)
  85.         elseif cmd == 1003 then
  86.                 local info = "user banned! "..buffer(databegin, datasize):string()
  87.                 subtree_data:add_le(buffer(databegin, datasize), info)
  88.         elseif cmd == 1004 then
  89.                 local info = "you are welcome. "..buffer(databegin, datasize):string()
  90.                 subtree_data:add_le(buffer(databegin, datasize), info)
  91.         elseif cmd == 1007 then
  92.                 local info = "buffer size for vehicle data: "..buffer(databegin, datasize):le_uint()
  93.                 subtree_data:add_le(buffer(databegin, datasize), info)
  94.         elseif cmd == 1009 then
  95.                 local info = "deprecated rornet_2.0 packet"
  96.                 subtree_data:add_le(buffer(databegin, datasize), info)
  97.         elseif cmd == 1010 then
  98.                 local info = "deleting user! "..buffer(databegin, datasize):string()
  99.                 subtree_data:add_le(buffer(databegin, datasize), info)
  100.         elseif cmd == 1011 then
  101.                 local info = "chat: "..buffer(databegin, datasize):string()
  102.                 subtree_data:add_le(buffer(databegin, datasize), info)
  103.         elseif cmd == 1012 then
  104.                 local info = "force command (yet not used): "..buffer(databegin, datasize):string()
  105.                 subtree_data:add_le(buffer(databegin, datasize), info)
  106.         elseif cmd == 1017 then
  107.                 subtree_data:add_le(buffer(databegin,20),"nickname: ".. buffer(databegin, 20):string())
  108.                 subtree_data:add_le(buffer(databegin+20,40),"SHA1 password: " .. buffer(databegin+20,40):string())
  109.                 subtree_data:add_le(buffer(databegin+60,40),"SHA1 uniqueID: " .. buffer(databegin+60,40):string())
  110.         elseif cmd == 1019 then
  111.                 local info = "using terrain "..buffer(databegin, datasize):string()
  112.                 subtree_data:add_le(buffer(databegin, datasize), info)
  113.         elseif cmd == 1020 then
  114.                 local info = "wrong password!"..buffer(databegin, datasize):string()
  115.                 subtree_data:add_le(buffer(databegin, datasize), info)
  116.         elseif cmd == 1021 then
  117.                 local info = "rcon login, with SHA1 password:"..buffer(databegin, datasize):string()
  118.                 subtree_data:add_le(buffer(databegin, datasize), info)
  119.         elseif cmd == 1022 then
  120.                 local info = "rcon login failed: "..buffer(databegin, datasize):string()
  121.                 subtree_data:add_le(buffer(databegin, datasize), info)
  122.         elseif cmd == 1023 then
  123.                 local info = "rcon login successful: "..buffer(databegin, datasize):string()
  124.                 subtree_data:add_le(buffer(databegin, datasize), info)
  125.         elseif cmd == 1024 then
  126.                 local info = "rcon not available: "..buffer(databegin, datasize):string()
  127.                 subtree_data:add_le(buffer(databegin, datasize), info)
  128.         elseif cmd == 1025 then
  129.                 local info = "rcon command: "..buffer(databegin, datasize):string()
  130.                 subtree_data:add_le(buffer(databegin, datasize), info)
  131.         elseif cmd == 1026 then
  132.                 local info = "rcon command failed: "..buffer(databegin, datasize):string()
  133.                 subtree_data:add_le(buffer(databegin, datasize), info)
  134.         elseif cmd == 1027 then
  135.                 local info = "rcon command successful: "..buffer(databegin, datasize):string()
  136.                 subtree_data:add_le(buffer(databegin, datasize), info)
  137.                
  138.         elseif cmd == 1005 then
  139.                 local info = "Use vehicle: "..buffer(databegin, datasize):string()
  140.                 subtree_data:add_le(buffer(databegin, datasize), info)
  141.         elseif cmd == 1008 then
  142.                 local oobtree = subtree_data:add(buffer(databegin+0,16), "OOB Data (16)")
  143.                 oobtree:add(buffer(databegin+0,4), "Time: "..buffer(databegin+0,4):le_uint())
  144.                 oobtree:add(buffer(databegin+4,4), "Engine Speed: "..buffer(databegin+4,4):le_uint())
  145.                 oobtree:add(buffer(databegin+8,4), "Engine Force: "..buffer(databegin+8,4):le_uint())
  146.                 local flagtree = oobtree:add(buffer(databegin+12,4), "Flags: "..buffer(databegin+12,4):le_uint())
  147.                 –flaghorn = buffer(12,4):le_uint() & 0×00000001
  148.                 –flagtree:add(buffer(12,4), "Horn: "..flaghorn)
  149.                 – todo: all all others
  150.                
  151.                 subtree_data:add(buffer(databegin+16,datasize-16), "Node Data ("..(datasize-16)..")")
  152.                
  153.                
  154.         else
  155.                 local info = "RoR Data ("..buffer:len()..")"..cmd
  156.                 local subtree = tree:add(ror_proto,buffer(),info)
  157.                 pinfo.cols.info:set(info)
  158.         end
  159. end
  160. – load the tcp.port table
  161. tcp_table = DissectorTable.get("tcp.port")
  162. – register our protocol to handle tcp port 12308
  163. tcp_table:add(12000,ror_proto)

i think you should be able to experiment with that now ;)
have fun! :)

custom munin plugins the easy way (or: python rocks, perl sucks)

January 2nd, 2008

i just wrote this little neat python plugin for munin, to be able to track some lighttpd statistics

Python [Show Plain Code]:
  1. #!/bin/env python
  2. import sys
  3. if len(sys.argv) == 2 and sys.argv[1] == "autoconf":
  4.         print "yes"
  5. elif len(sys.argv) == 2 and sys.argv[1] == "config":
  6.         print ‘graph_title Lighttpd Stats’
  7.         print ‘graph_vlabel count’
  8.         print ‘graph_category lighttpd’
  9.  
  10.         print ‘total_accesses.label Total Accesses’
  11.         #print ‘Total_Accesses.draw AREA’
  12.         print ‘total_accesses.type COUNTER’
  13.  
  14.         print ‘total_kbytes.label Total kBytes transferred’
  15.         #print ‘Total_kBytes.draw AREA’
  16.         print ‘total_kbytes.type COUNTER’
  17.  
  18.         print ‘total_uptime.label Total Uptime’
  19.         #print ‘Total_Uptime.draw AREA’
  20.         #print ‘Total_Uptime.type GAUGE’
  21.  
  22.         print ‘total_busyservers.label Total Busy servers’
  23.         #print ‘Total_BusyServers.draw AREA’
  24.         #print ‘Total_BusyServers.type GAUGE’
  25.  
  26.         print ‘graph_args –base 1000′
  27. else:
  28.    import urllib2
  29.    f = urllib2.urlopen(‘http://127.0.0.1/server-status?auto’)
  30.    temp = f.read()
  31.    f.close()
  32.    temp = temp.replace(" ", "_")
  33.    temp = temp.replace(":_", ".value ")
  34.    print temp.lower()

EDIT: got an error in the first version, fixed that in the above one
EDIT2: now its finally working :)