Archive for May, 2010

Port Conventions

Over the past few years I’ve been doing a lot of work with JBoss and tomcat. One issue we’ve always had is bringing some level of sanity to ports that are in use. My current situation is somewhat abnormal; we have 12 applications, each with two instances, each with 7 ports- that’s a total of 168 ports that we need to keep track of. Now, multiply that by tomcat, apache and nagios’ configurations. Now multiply that by Dev, QA, ITL, PRJ, Preprod and Prod environments on segregated hardware. Even though a LOT of these ports can overlap, that’s a LOT to keep track of in a flat file or spreadsheet. We also require a certain level of flexibility:

  1. Port Expansion: I mentioned there were 7 ports we use; originally there were only 6, but I enabled SNMP to better trend JVM usage (24 JVMs use a lot of RAM). As we add more features, more ports could be needed.
  2. Application Expansion: We originally started out with 9 instances, and after 5 months added another three. More will be possible in the future.

The required flexibility makes numbering conventions difficult. The solution we came up with is to key the information and use it to build the port number. In order to do that, we had to make a few assumptions:

  1. Environments are sequestered to their own hardware, however they’re on the same networks- i.e. dev and qa instances will never be on the same physical server, but will share multicast ranges
  2. There will not be more than 5 instances in a cluster- any more than that would put theoretical ports out the 65536 range; besides, replication shouldn’t be past 4 nodes, right?
  3. Ports below 1024 are off limits
  4. We are constrained by IP addresses; one IP per server.

From here we could allow the following constraints:

  1. Environments can use the same ports, EXCEPT for multicast- we don’t want QA and prod replicating data!
  2. All multicast should use 1 for their Instance ID

With that in mind, port numbers will be laid out with the following structure: XYYZZ

X = Instance ID (e.g. 1-4)
YY = application ID (Helium,Hydrogen,Lithium, etc )
ZZ = Port Type (jmx, ajp, snmp, etc)


1 Instance1
2 Instance2
3 Instance3
4 Instance4


01 Hydrogen
02 Helium
03 Lithium
04 Beryllium
05 Boron
06 Carbon
07 Nitrogen
08 Oxygen
09 Fluorine
10 Neon
11 Sodium
12 Magnesium


01 Shutdown
02 JMX
03 HTTP
04 AJP
05 SNMP
06 REPL
07 MCASTDEV
08 MCASTQA
09 MCASTUAT
10 MCASTPREPROD
11 MCASTPROD

This allows us to define the following:

  • Hydrogen AJP for instance 1 is 10104 (1+01+04)
  • Oxygen SNMP for instance 4 is 40805 (4+08+05)
  • Sodium Multicast for Prod 3 is 11111 (1+11+11) (remember, all multicast use 1 for their instance)

Other than the Multicast port kludge, this way seems to work pretty well. Numbers are easy to parse visually and can be maintained with a centralized key on the wiki. Anyone have any suggestions or examples of how they’ve solved this problem?

Nagios LDAP Contact Creator Script

The Following is an ugly little perl script I’ve whipped up for generating contact entries for Nagios; each file is read via a cfg_dir command in the nagios.cfg. This script is set to run nightly, capturing any new users and updating users and groups automagically.

Let me know if you find it useful.

 
#!/usr/bin/perl
# read your ldap repo and generation nagios config files for contacts
# and contact_groups
use strict;
use Net::LDAP;
use Data::Dumper;
 
# Set all your custom configs here:
my $ldaphostname='ldap.example.int';
my $groupdn='ou=People,ou=Groups,dc=example,dc=int';
my $peopledn='ou=People,ou=active,ou=Users,dc=example,dc=int';
my $contactdir='/etc/nagios/contacts';
 
my $ldap = new Net::LDAP ($ldaphostname);
$ldap->bind() || die "failed to bind";
 
#search for groups
my $mesg = $ldap->search(
        base => $groupdn,
        filter => "(objectclass=posixgroup)",
        attrs => ['cn','memberuid'],
        );
 
#loop through each entry
while (my $group= $mesg->pop_entry() ){
 
    #set the name of the group
    my $cn=$group->get_value('cn');
 
    #create a comma-separated list of group members
    my $members=$group->get_value('memberuid', asref => 1);
    $members= join( ',', @$members);
 
    # create our configuration block
    my $contactinfo="
        # We only have one contact in this simple configuration file,
        # so there is no need to create more than one contact group.
 
        define contactgroup{
            contactgroup_name       $cn
            alias                   $cn
            members                 $members
            }\n";
 
    # write this block to a file named after the group cn
    print `echo "$contactinfo" > $contactdir/group_$cn.cfg`;
}
 
#search for users
my $mesg = $ldap->search(
            base => $peopledn,
            filter => "(objectclass=person)",
            attrs => ['uid','cn','mail','description'],
           );
 
#loop through each entry
while (my $user= $mesg->pop_entry() ){
 
    my ($pager,$addr);
    # grab the four fields we're interested in
    my $uid=$user->get_value('uid');
    my $cn=$user->get_value('cn');
    my $mail=$user->get_value('mail');
    my $desc=$user->get_value('description');
 
# Note that I store the user's SMS address and Instant Messenger
# addresses in the description field in the following format:
# SMS:1234445555@some.url;
# IM:morgajel@yahoo,morgajel@gtalk;
# for those interested, you can send email to an sms address 
# with help from <a href="http://sms411.net/how-to-send-email-to-a-phone">http://sms411.net/how-to-send-email-to-a-phone</a>
    #strip pager info out of desc and format it
    #(note it's in sms format):
    if ($desc =~/SMS:([^;]+);?/){
        $pager= "        pager           $1\n";
    }
    # strip addresses out of desc and format them:
    if ($desc =~/IM:([^;]+);?/){
        my @multiple_addr=split(/,/,$1);
        my $count=1;
        # break each address out into an addressX line
        # (for informational purposes);
        foreach my $addr (@multiple_addr){
            $addr=$addr."        address$count        $addr\n";
            $count=$count+1 ;
        }
    }
 
    #generate the first half of the contact info
    my $contactinfo="
    define contact{
        contact_name    $uid              ; Short name of user
        use             generic-contact
        alias           $cn               ; Full name of user
        email           $mail
$pager
$addr
    }";
 
    # write this block to a file named after the user uid
    `echo "$contactinfo" > $contactdir/$uid.cfg`;
}
Go to Top