7 use OpenSRF::AppSession;
8 use OpenSRF::EX qw(:try);
11 my $opt_osrf_config = '/openils/conf/opensrf_core.xml';
13 # For storing the list of supposedly active services
15 # For storing our list of routers to check
19 'osrf-config=s' => \$opt_osrf_config,
22 # If we can't bootstrap then something is horribly wrong!
23 # Probably "ejabberd isn't running"
25 OpenSRF::System->bootstrap_client(config_file => $opt_osrf_config);
27 print "Bootstrap failed\n";
31 # This gets the list of supposedly active services
32 sub prep_service_list {
33 # Using settings directly, as I don't know how to ask with pre-existing classes
34 my $session = OpenSRF::AppSession->create('opensrf.settings');
38 print "Settings Connect Failed\n";
41 # This xpath is "Find every instace of an appname node under an activeapps node, anywhere"
42 # It should grab every app configured to run on any drone
43 # If your config contains apps that are not run on real drones you will get errors ;)
44 my $req = $session->request('opensrf.settings.xpath.get', '//activeapps/appname');
45 my $list = $req->recv;
47 if(UNIVERSAL::isa($list,"Error")) {
48 print "Active Apps List Failed\n";
53 # Quick and dirty de-dupe
54 my %u_list = map { ($_ => 1) } @{$list->content};
56 @services = keys(%u_list);
62 # This gets the list of supposedly active routers
63 # This relies on the bootstrap being accurate in that regard
64 sub prep_routers_list {
65 # First, we grab our (hopefully) cached config
66 my $config = OpenSRF::Utils::Config->current;
68 foreach(@{$config->bootstrap->routers}) {
69 # And make entries for each router
71 $router->{name} = $_->{name};
72 $router->{domain} = $_->{domain};
73 # If we don't have a services list assume all active ones (aka, private router)
74 $router->{services} = \@services unless $_->{services};
75 # Otherwise, make note of what we are supposed to be running (aka, public router)
76 $router->{services} = $_->{services}->{service} if $_->{services};
77 # And tack it onto the list
78 push @routers, $router;
82 # This does the actual checking of routers/services
85 my $conf = OpenSRF::Utils::Config->current;
86 foreach my $router (@routers) {
87 # HACK WARNING - This changes the router we will be querying
88 # This basically edits the cached bootstrap file. This is not guaranteed to keep working.
89 # This does NOT change what domain we are querying from
90 $conf->bootstrap->router_name($router->{name});
91 $conf->bootstrap->domain($router->{domain});
92 # Assume things failed unless they didn't.
94 # First, check the router to see what it claims to have active services-wise
95 my $session = OpenSRF::AppSession->create('router');
97 $failed = 0 if $session->connect;
101 if($session->state != $session->CONNECTED || $failed) {
102 $router->{online} = 0;
105 # Yay router commands! This should give us all services with at least one listener
106 my $req = $session->request('opensrf.router.info.class.list');
107 my $class_list = $req->recv;
110 if(UNIVERSAL::isa($class_list,"Error")) {
112 $session->disconnect;
113 $router->{online} = 0;
117 # If we got an answer then this router is online!
118 $router->{online} = 1;
119 # Counters and storage for services checks
120 $router->{checked} = 0;
122 $router->{failed} = [];
123 # Quick reference of what the router told us it has
124 my %online_services = map { ($_ => 1) } @{$class_list->content};
125 foreach my $service (@{$router->{services}}) {
126 # This skips services not in the active list. Mainly for routers with explicit lists (aka, public routers) that not all may be configured to run.
127 next unless grep { $service eq $_ } @services;
128 # Assume we did not pass until proven otherwise
130 $router->{checked} += 1;
131 if($online_services{$service}) {
132 # Check the service, even if a listener is registered it may be dead
133 my $session2 = OpenSRF::AppSession->create($service);
137 if($session2->state == $session2->CONNECTED) {
138 # To my knowledge, EVERY service should have atomic echo available
139 my $req2 = $session2->request('opensrf.system.echo.atomic','Test');
140 my $testresult = $req2->recv;
141 if(!UNIVERSAL::isa($testresult,"Error")) {
142 # If we got back what we passed in the service is working! Ish. Not a flawless test.
143 $passed = 1 if @{$testresult->content}[0] eq 'Test';
147 $session2->disconnect;
151 # Looks like it works, make note!
152 $router->{pass} += 1;
154 # Doesn't work! Save for later reporting.
155 push @{$router->{failed}}, $service;
159 $session->disconnect;
163 # This outputs the result for Nagios
166 my $checked_services = 0;
170 # Assume all is good until proven otherwise
172 foreach my $router (@routers) {
173 # If the router isn't online then we don't need to look at services - We didn't check any!
174 if(!$router->{online}) {
175 push @down_routers, $router->{domain};
178 # Otherwise increment our counters as needed
179 $checked_services += $router->{checked};
180 $up_services += $router->{pass};
181 foreach (@{$router->{failed}}) {
182 # Keep track of any down services for reporting in a minute
183 push @down_services, $router->{domain} . ':' . $_;
187 # Down routers are really bad. Chances are there will only ever be one here (public), but join with commas anyway.
188 print "Router(s) Offline: " . join(', ', @down_routers) . "\n";
190 } elsif ($checked_services != $up_services) {
191 # Non-responsive services are also really bad
192 print "Service(s) not responding\n";
195 # But if we have nothing then things are good!
196 print "Routers/Services OK\n";
198 # If there are down services then spit them out as additional information.
199 print "$_\n" foreach (@down_services);
200 # And return our response code
204 # CHEAT - We need SettingsClient to have cached stuff
206 OpenSRF::Utils::SettingsClient->new()->config_value('none');
208 print "Settings Fetch Failed\n";
211 # And run all of the above functions
217 # This code should NEVER run, as the only way out of output_result is an exit statement
218 print "What? I shouldn't have reached here.";