Adventures in C#
Yesterday I bravely went forth into the weird world of windows programming. Recognizing the need to familiarize myself with at least *one* language and toolset that works on both Linux and Windows I decided to check out the Mono project. Since I immediately understood that the initial threshold would be far too high and tedious for me to get past, I enlisted the help of a comrade-in-arms, Martin Almström, to teach me the basics.
For our first C# project (well, mine anyways, he's a C# guru, working on a 5MLoC project for the Swedish emergency dispatch center), we decided to write a file transfer tool (toy really), where I wrote a client that connected to his server. His server-program would feed my client a file and my client would write that file to disk.
At first, it was very confusing. The idiots at microsoft just had to re-use perfectly valid C keywords but give them totally different semantic meaning. "hey! 'static', I know... err.. no, I don't". It's also quite funny to write in a language where "int" can actually be null (but only if you really ask for it). Add to that the fact that I've never written anything in a OOO (object-oriented only) language before, and the chaos is complete.
After a while though, I started seeing the nifty things about it. It's not as fast as a proper C program (and the closed-source compiler has no clue about optimizations). The source-code has the overhead of all the OOO languages, so "Hello world" requires about 10 lines of code (steep learning curve). It does have some nice features though, such as builtin-accessor-method-enforcement and "interfaces", which seem to work similar to how the linux kernel driver API works, but on a higher level.
To make a long story short, we managed to get the program to transfer the file properly, although not very efficiently. The best speed we reached was 2Mbit/sec (on a local gigabit lan). I blame myself, tbh. I have no clue how to optimally use the Stream objects in C# and was probably doing it wrong, but getting something *real* to work the first day has to be seen as quite a huge success ;-)
The upsides:
* monodevelop is a really nice IDE.
* The executable files load and run nearly as fast as C code.
* The executables are "portable" (well, you need the mono runtime to run them under Linux, but it's the easiest way I've found so far of making windows programs from Linux).
* It's fun hacking side-to-side with a friend.
* It's fun learning new languages.
The downsides:
* It's hard to find info on how to use the compiler from the command-line.
* The mono runtime is quite large.
* monodevelop sets the "runtime options" for new projects to "MONO/.NET 1.1", which means there's a lot of things you don't have (apparently, I'm no expert).
* It seems hard to link C programs to mono apps, making many of my libs useless (well, in need of rewrite, anyways).
Next time we'll probably write a GUI program, which I've never done. My secret plan is to learn this stuff well enough to write a git GUI for windows.
Object oriented configuration
Ok, so I've been having this idea for quite some time (close to 3 years), but for some reason it has never really interested me all that much; Partially because it's such a radical change, and partially because, at least for a transition period, one would have to support both the new and the old configuration style syntax (perhaps indefinitely).
Since objects in nagios inherit a lot of stuff implicitly in Nagios, it's quite hard to follow how that works.
Since the only *real* object in Nagios is the "host", it doesn't make sense to treat any other object as a *true* object.
I strongly feel that groupings are something that should belong to the user interface only. They should not be so overloaded as they are today ("Oh, you want to view all hosts in areaX together? Sure, make a hostgroup", "Oh, you want to add a service to all hosts of typeX? Sure, make a hostgroup", "Oh, you want to view all hosts of typeX? Sure, make a hostgroup").
Because of this, I hereby propose to create a new configuration file format for Nagios that will
a) Make it easy to assign several services to similar types of hosts.
b) Make it easy to find all hosts of a certain type and group them in (insert-ui-of-choice-here).
c) Save quite a lot on typing.
d) Be a lot clearer regarding its inheritance than the current template system.
e) Make it possible for the community to share host type configuration profiles.
f) Make it possible to add hosts without restarting Nagios.
"Ooh, this bugger sets his goals high", you might think, but the answer to all of the above are actually extremely simple: Object oriented configuration, with object inheritance.
So how would that work? Well, since I can't explain what a nose looks like without getting caught up in all sorts of weird stuff, I'll just show an example here instead.
define host {
host_name foo_host
alias This is the Foo Host
address foo_host.example.com
type win2k3-fileserver
}
define host_type {
host_type_name win2k3-fileserver
extends = windows-server
# this applies to both the host and the services
contact_groups = fileserver-admins
service_template {
check_interval 15
retry_interval 3
max_check_attempts 5
}
services {
define service {
service_description Disk E
check_command check_nt_disk!E
}
define service {
service_description Disk F
check_command check_nt_disk!F
}
}
# Oops, this host has one disk that no other fileserver has,
# so we define it separately, but we use the service_template
# from that profile anyway
define service {
use win2k3-fileserver::service_template
host_name foo_host
service_description Disk G
check_command check_nt_disk!G
}
The best thing is that this could (potentially) be written as a module, although that would (currently) be exceedingly difficult, since the module would then have to take care of preventing core Nagios from detecting errors in the configuration (unless one forces some objects to pre-exist in the regular config files, I dunno). I'm sure it's doable, but it won't be pretty ![]()
Community ideas
Once again, I'm awestruck with the power of the thinktank of the world. Last weekend (3-4 Oct) I was at Opensource Days in Copenhagen, Denmark. I was giving a presentation about Nagios (which was quite well received), and included a brief demonstration of some of the addons we've done and ship with our products.
As I was demoing the network map thingie we have and excusing myself for the pretty poor maps we're using (due to copyright issues while shipping such maps with a commercially supported product), a member of the audience named Einar Petersen asked me why we just didn't pull stuff from the Open Streetmaps project. I was so amazed that there was a site like this that I didn't know what to answer.
Once again, the community has outsmarted the corporation ![]()
Thoughts on external commands
Yesterday I had the opportunity to take a look at how external commands are implemented, as I need some way to let merlin decide if commands submitted to the pipe should be applied to the Nagios daemon that receives it as well as the ones we're supposed to propagate it to.
First I started taking a look at how to undo the action of each of the external commands, but there are 100+ of the damn buggers so I quickly gave this up.
I noticed that I can pass "custom" external commands that get sent to neb-modules only that Nagios has no idea about, if I prepend an underscore to the command as written to the pipe. While this is all fine and well, I think I have a better idea.
Imagine the extcmd api working something like this instead:
struct extcmd {
int command_id;
char *command_name;
int command_args;
int (*handler)(struct extcmd *, char **, int);
};
/* set an external command handler */
int set_extcmd_handler(struct extcmd *cmd, int overwrite);
When a command is read, it gets looked up in a hash table, its arguments are parsed into an argument vector with at least "command_args" entries (giving the additional bonus that Nagios can now log a warning if the argument doesn't have at least the minimum number of arguments, which it couldn't do before) and the handler is run for that command. A handler could be defined like this:
int extcmd_handler(struct extcmd *cmd, char **argv, int argc);
If that was the case, all I'd have to do in my NEB-modules would be to register a new handler for the commands I don't want Nagios to handle by itself and it would get called instead of the default handler. Nifty, eh? ![]()
11/11/08 01:50:52 pm, 