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:
- 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.
- 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:
- 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
- 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?
- Ports below 1024 are off limits
- We are constrained by IP addresses; one IP per server.
From here we could allow the following constraints:
- Environments can use the same ports, EXCEPT for multicast- we don’t want QA and prod replicating data!
- 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`; } |