check_passenger 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +24 -0
 - data/Gemfile +4 -0
 - data/LICENSE.txt +21 -0
 - data/README.md +29 -0
 - data/Rakefile +8 -0
 - data/TODO.md +12 -0
 - data/bin/check_passenger +101 -0
 - data/check_passenger.gemspec +29 -0
 - data/lib/check_passenger.rb +13 -0
 - data/lib/check_passenger/check.rb +96 -0
 - data/lib/check_passenger/nagios_check.rb +66 -0
 - data/lib/check_passenger/parser.rb +120 -0
 - data/lib/check_passenger/passenger_status.rb +29 -0
 - data/lib/check_passenger/status_output_error.rb +10 -0
 - data/lib/check_passenger/version.rb +3 -0
 - data/test/passenger-status +82 -0
 - data/test/sample_output_1.txt +76 -0
 - data/test/sample_output_2.txt +64 -0
 - data/test/test_check.rb +122 -0
 - data/test/test_helper.rb +9 -0
 - data/test/test_nagios_check.rb +72 -0
 - data/test/test_parser.rb +166 -0
 - data/test/test_passenger_status.rb +32 -0
 - metadata +158 -0
 
    
        data/.gitignore
    ADDED
    
    | 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            *.gem
         
     | 
| 
      
 2 
     | 
    
         
            +
            *.rbc
         
     | 
| 
      
 3 
     | 
    
         
            +
            .bundle
         
     | 
| 
      
 4 
     | 
    
         
            +
            .config
         
     | 
| 
      
 5 
     | 
    
         
            +
            .yardoc
         
     | 
| 
      
 6 
     | 
    
         
            +
            Gemfile.lock
         
     | 
| 
      
 7 
     | 
    
         
            +
            InstalledFiles
         
     | 
| 
      
 8 
     | 
    
         
            +
            _yardoc
         
     | 
| 
      
 9 
     | 
    
         
            +
            coverage
         
     | 
| 
      
 10 
     | 
    
         
            +
            doc/
         
     | 
| 
      
 11 
     | 
    
         
            +
            lib/bundler/man
         
     | 
| 
      
 12 
     | 
    
         
            +
            pkg
         
     | 
| 
      
 13 
     | 
    
         
            +
            rdoc
         
     | 
| 
      
 14 
     | 
    
         
            +
            spec/reports
         
     | 
| 
      
 15 
     | 
    
         
            +
            test/tmp
         
     | 
| 
      
 16 
     | 
    
         
            +
            test/version_tmp
         
     | 
| 
      
 17 
     | 
    
         
            +
            tmp
         
     | 
| 
      
 18 
     | 
    
         
            +
            *.bundle
         
     | 
| 
      
 19 
     | 
    
         
            +
            *.so
         
     | 
| 
      
 20 
     | 
    
         
            +
            *.o
         
     | 
| 
      
 21 
     | 
    
         
            +
            *.a
         
     | 
| 
      
 22 
     | 
    
         
            +
            mkmf.log
         
     | 
| 
      
 23 
     | 
    
         
            +
            *.sublime-workspace
         
     | 
| 
      
 24 
     | 
    
         
            +
            *.sublime-project
         
     | 
    
        data/Gemfile
    ADDED
    
    
    
        data/LICENSE.txt
    ADDED
    
    | 
         @@ -0,0 +1,21 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            The MIT License (MIT)
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            Copyright (c) 2014 Alvaro Redondo
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy
         
     | 
| 
      
 6 
     | 
    
         
            +
            of this software and associated documentation files (the "Software"), to deal
         
     | 
| 
      
 7 
     | 
    
         
            +
            in the Software without restriction, including without limitation the rights
         
     | 
| 
      
 8 
     | 
    
         
            +
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         
     | 
| 
      
 9 
     | 
    
         
            +
            copies of the Software, and to permit persons to whom the Software is
         
     | 
| 
      
 10 
     | 
    
         
            +
            furnished to do so, subject to the following conditions:
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be included in all
         
     | 
| 
      
 13 
     | 
    
         
            +
            copies or substantial portions of the Software.
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         
     | 
| 
      
 16 
     | 
    
         
            +
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         
     | 
| 
      
 17 
     | 
    
         
            +
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         
     | 
| 
      
 18 
     | 
    
         
            +
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         
     | 
| 
      
 19 
     | 
    
         
            +
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         
     | 
| 
      
 20 
     | 
    
         
            +
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         
     | 
| 
      
 21 
     | 
    
         
            +
            SOFTWARE.
         
     | 
    
        data/README.md
    ADDED
    
    | 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # CheckPassenger
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            TODO: Write a gem description
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
            ## Installation
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            Add this line to your application's Gemfile:
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                gem 'check_passenger'
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            And then execute:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                $ bundle
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            Or install it yourself as:
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                $ gem install check_passenger
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            TODO: Write usage instructions here
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            ## Contributing
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            1. Fork it ( https://github.com/[my-github-username]/check_passenger/fork )
         
     | 
| 
      
 26 
     | 
    
         
            +
            2. Create your feature branch (`git checkout -b my-new-feature`)
         
     | 
| 
      
 27 
     | 
    
         
            +
            3. Commit your changes (`git commit -am 'Add some feature'`)
         
     | 
| 
      
 28 
     | 
    
         
            +
            4. Push to the branch (`git push origin my-new-feature`)
         
     | 
| 
      
 29 
     | 
    
         
            +
            5. Create a new Pull Request
         
     | 
    
        data/Rakefile
    ADDED
    
    
    
        data/TODO.md
    ADDED
    
    | 
         @@ -0,0 +1,12 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Release
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            - README page.
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            # Other
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            - Option `all` to monitor all counters for all applications and globally,
         
     | 
| 
      
 9 
     | 
    
         
            +
              without possibility to raise alerts.
         
     | 
| 
      
 10 
     | 
    
         
            +
            - PerfDatum class.
         
     | 
| 
      
 11 
     | 
    
         
            +
            - Option to set TTL used to estimate live processes.
         
     | 
| 
      
 12 
     | 
    
         
            +
            - Option to set TTL of cached data.
         
     | 
    
        data/bin/check_passenger
    ADDED
    
    | 
         @@ -0,0 +1,101 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            #!/usr/bin/env ruby
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            lib = File.expand_path('../lib', File.dirname(__FILE__))
         
     | 
| 
      
 4 
     | 
    
         
            +
            $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            require 'thor'
         
     | 
| 
      
 7 
     | 
    
         
            +
            require 'check_passenger'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'tmpdir'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
            class CheckPassengerCLI < Thor
         
     | 
| 
      
 11 
     | 
    
         
            +
              include CheckPassenger::NagiosCheck
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              class_option :app_name, aliases: 'n', banner: 'Limit check to application with APP_NAME'
         
     | 
| 
      
 14 
     | 
    
         
            +
              class_option :cache, aliases: 'C', type: :boolean,
         
     | 
| 
      
 15 
     | 
    
         
            +
                            banner: 'Cache data to avoid fast successive calls to passenger-status'
         
     | 
| 
      
 16 
     | 
    
         
            +
              class_option :debug, aliases: 'D', type: :boolean, banner: 'Debug mode'
         
     | 
| 
      
 17 
     | 
    
         
            +
              class_option :dump, aliases: 'd', type: :boolean, banner: 'Dump passenger-status output on error'
         
     | 
| 
      
 18 
     | 
    
         
            +
              class_option :include_all, aliases: 'a', type: :boolean,
         
     | 
| 
      
 19 
     | 
    
         
            +
                            banner: 'Also include counter for all running apps'
         
     | 
| 
      
 20 
     | 
    
         
            +
              class_option :passenger_status_path, aliases: 'p', banner: 'Path to passenger-status command'
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              desc 'memory', 'Check Passenger memory'
         
     | 
| 
      
 23 
     | 
    
         
            +
              option :warn, banner: 'Memory usage threshold to raise warning status', aliases: 'w'
         
     | 
| 
      
 24 
     | 
    
         
            +
              option :crit, banner: 'Memory usage threshold to raise critical status', aliases: 'c'
         
     | 
| 
      
 25 
     | 
    
         
            +
              def memory
         
     | 
| 
      
 26 
     | 
    
         
            +
                run_check do
         
     | 
| 
      
 27 
     | 
    
         
            +
                  CheckPassenger::Check.memory(options)
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
              end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
              desc 'processes', 'Check Passenger processes'
         
     | 
| 
      
 32 
     | 
    
         
            +
              option :warn, aliases: 'w', banner: 'Process count threshold to raise warning status'
         
     | 
| 
      
 33 
     | 
    
         
            +
              option :crit, aliases: 'c', banner: 'Process count threshold to raise critical status'
         
     | 
| 
      
 34 
     | 
    
         
            +
              def processes
         
     | 
| 
      
 35 
     | 
    
         
            +
                run_check do
         
     | 
| 
      
 36 
     | 
    
         
            +
                  CheckPassenger::Check.process_count(options)
         
     | 
| 
      
 37 
     | 
    
         
            +
                end
         
     | 
| 
      
 38 
     | 
    
         
            +
              end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
              desc 'live_processes', 'Check Passenger live processes'
         
     | 
| 
      
 41 
     | 
    
         
            +
              option :warn, aliases: 'w', banner: 'Live process count threshold to raise warning status'
         
     | 
| 
      
 42 
     | 
    
         
            +
              option :crit, aliases: 'c', banner: 'Live process count threshold to raise critical status'
         
     | 
| 
      
 43 
     | 
    
         
            +
              def live_processes
         
     | 
| 
      
 44 
     | 
    
         
            +
                run_check do
         
     | 
| 
      
 45 
     | 
    
         
            +
                  CheckPassenger::Check.live_process_count(options)
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
              end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              private
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
              def dump_passenger_status_output(exception = nil)
         
     | 
| 
      
 52 
     | 
    
         
            +
                passenger_status_output = nil
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                if exception and exception.respond_to?(:passenger_status_output)
         
     | 
| 
      
 55 
     | 
    
         
            +
                  passenger_status_output = exception.passenger_status_output
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                if passenger_status_output.nil? and CheckPassenger::Check.parsed_data
         
     | 
| 
      
 59 
     | 
    
         
            +
                  passenger_status_output = CheckPassenger::Check.parsed_data.passenger_status_output
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                if passenger_status_output
         
     | 
| 
      
 63 
     | 
    
         
            +
                  filename = 'passenger_status_output_dump-%s.txt' % Time.now.strftime('%Y%m%d%H%M%S')
         
     | 
| 
      
 64 
     | 
    
         
            +
                  dump_path = File.expand_path(filename, Dir.tmpdir)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  File.open(dump_path, 'wb') { |file| file.write passenger_status_output }
         
     | 
| 
      
 66 
     | 
    
         
            +
                  return dump_path
         
     | 
| 
      
 67 
     | 
    
         
            +
                else
         
     | 
| 
      
 68 
     | 
    
         
            +
                  return nil
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
              def run_check
         
     | 
| 
      
 73 
     | 
    
         
            +
                if options[:include_all] and options[:app_name]
         
     | 
| 
      
 74 
     | 
    
         
            +
                  raise ArgumentError, 'Data for all apps can only be included when monitoring a global counter'
         
     | 
| 
      
 75 
     | 
    
         
            +
                end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                output_status, output_data = yield
         
     | 
| 
      
 78 
     | 
    
         
            +
                nagios_output(output_status, output_data)
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
              rescue StandardError => e
         
     | 
| 
      
 81 
     | 
    
         
            +
                if options[:debug] or options[:dump]
         
     | 
| 
      
 82 
     | 
    
         
            +
                  if dump_path = dump_passenger_status_output(e)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    message = e.message + ' -- passenger-status output dumped to %s' % dump_path
         
     | 
| 
      
 84 
     | 
    
         
            +
                    e = e.class.new(message)
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                if options[:debug]
         
     | 
| 
      
 89 
     | 
    
         
            +
                  raise e
         
     | 
| 
      
 90 
     | 
    
         
            +
                else
         
     | 
| 
      
 91 
     | 
    
         
            +
                  case e
         
     | 
| 
      
 92 
     | 
    
         
            +
                  when CheckPassenger::StatusOutputError
         
     | 
| 
      
 93 
     | 
    
         
            +
                    nagios_error('Passenger UNKNOWN - An error occurred while parsing passenger-status output: %s' % e.message)
         
     | 
| 
      
 94 
     | 
    
         
            +
                  else
         
     | 
| 
      
 95 
     | 
    
         
            +
                    nagios_error('Passenger UNKNOWN - %s (%s)' % [e.message, e.class.to_s])
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
      
 99 
     | 
    
         
            +
            end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
            CheckPassengerCLI.start(ARGV)
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # coding: utf-8
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            lib = File.expand_path('../lib', __FILE__)
         
     | 
| 
      
 4 
     | 
    
         
            +
            $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            require 'check_passenger/version'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            Gem::Specification.new do |spec|
         
     | 
| 
      
 9 
     | 
    
         
            +
              spec.name          = 'check_passenger'
         
     | 
| 
      
 10 
     | 
    
         
            +
              spec.version       = CheckPassenger::VERSION
         
     | 
| 
      
 11 
     | 
    
         
            +
              spec.authors       = ['Alvaro Redondo']
         
     | 
| 
      
 12 
     | 
    
         
            +
              spec.email         = ['alvaro@redondo.name']
         
     | 
| 
      
 13 
     | 
    
         
            +
              spec.summary       = %q{Nagios check to monitor Passenger processes and memory}
         
     | 
| 
      
 14 
     | 
    
         
            +
              # spec.description   = %q{TODO: Write a longer description. Optional.}
         
     | 
| 
      
 15 
     | 
    
         
            +
              spec.homepage      = ''
         
     | 
| 
      
 16 
     | 
    
         
            +
              spec.license       = 'MIT'
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
              spec.files         = `git ls-files -z`.split("\x0")
         
     | 
| 
      
 19 
     | 
    
         
            +
              spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
         
     | 
| 
      
 20 
     | 
    
         
            +
              spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
         
     | 
| 
      
 21 
     | 
    
         
            +
              spec.require_paths = ['lib']
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
              spec.add_development_dependency 'bundler', '~> 1.6'
         
     | 
| 
      
 24 
     | 
    
         
            +
              spec.add_development_dependency 'rake'
         
     | 
| 
      
 25 
     | 
    
         
            +
              spec.add_development_dependency 'minitest'
         
     | 
| 
      
 26 
     | 
    
         
            +
              spec.add_development_dependency 'minitest-reporters'
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
              spec.add_dependency 'thor', '~> 0.19.1'
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,96 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'tmpdir'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module CheckPassenger
         
     | 
| 
      
 4 
     | 
    
         
            +
              class Check
         
     | 
| 
      
 5 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 6 
     | 
    
         
            +
                  include CheckPassenger::NagiosCheck
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  attr_reader :parsed_data
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  COUNTER_LABELS = {
         
     | 
| 
      
 11 
     | 
    
         
            +
                    live_process_count: '%d live processes',
         
     | 
| 
      
 12 
     | 
    
         
            +
                    memory: '%dMB memory used',
         
     | 
| 
      
 13 
     | 
    
         
            +
                    process_count: '%d processes'
         
     | 
| 
      
 14 
     | 
    
         
            +
                  }
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def check_counter(counter_name, options = {})
         
     | 
| 
      
 17 
     | 
    
         
            +
                    load_parsed_data(options)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    output_data = []
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    counter = parsed_data.send(counter_name.to_sym, options[:app_name])
         
     | 
| 
      
 21 
     | 
    
         
            +
                    output_status = nagios_status(counter, options)
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    data = {
         
     | 
| 
      
 24 
     | 
    
         
            +
                      text: 'Passenger %s %s - %s' %
         
     | 
| 
      
 25 
     | 
    
         
            +
                            [
         
     | 
| 
      
 26 
     | 
    
         
            +
                              options[:app_name] || parsed_data.passenger_version,
         
     | 
| 
      
 27 
     | 
    
         
            +
                              output_status.to_s.upcase,
         
     | 
| 
      
 28 
     | 
    
         
            +
                              COUNTER_LABELS[counter_name.to_sym] % counter
         
     | 
| 
      
 29 
     | 
    
         
            +
                            ],
         
     | 
| 
      
 30 
     | 
    
         
            +
                      counter: counter_name.to_s, value: counter,
         
     | 
| 
      
 31 
     | 
    
         
            +
                      warn: options[:warn], crit: options[:crit],
         
     | 
| 
      
 32 
     | 
    
         
            +
                      min: 0, max: nil
         
     | 
| 
      
 33 
     | 
    
         
            +
                    }
         
     | 
| 
      
 34 
     | 
    
         
            +
                    if !options[:app_name] and [:process_count, :live_process_count].include?(counter_name.to_sym)
         
     | 
| 
      
 35 
     | 
    
         
            +
                      data[:max] = parsed_data.max_pool_size
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end
         
     | 
| 
      
 37 
     | 
    
         
            +
                    output_data << data
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    if !options[:app_name] and options[:include_all]
         
     | 
| 
      
 40 
     | 
    
         
            +
                      parsed_data.application_names.each do |app_name|
         
     | 
| 
      
 41 
     | 
    
         
            +
                        counter = parsed_data.send(counter_name.to_sym, app_name)
         
     | 
| 
      
 42 
     | 
    
         
            +
                        output_data << {
         
     | 
| 
      
 43 
     | 
    
         
            +
                          text: '%s %s' % [app_name, COUNTER_LABELS[counter_name.to_sym] % counter],
         
     | 
| 
      
 44 
     | 
    
         
            +
                          counter: counter_name.to_s, value: counter
         
     | 
| 
      
 45 
     | 
    
         
            +
                        }
         
     | 
| 
      
 46 
     | 
    
         
            +
                      end
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                    return [output_status, output_data]
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  def method_missing(method, *args)
         
     | 
| 
      
 53 
     | 
    
         
            +
                    if COUNTER_LABELS.keys.include?(method)
         
     | 
| 
      
 54 
     | 
    
         
            +
                      check_counter(method, *args)
         
     | 
| 
      
 55 
     | 
    
         
            +
                    else
         
     | 
| 
      
 56 
     | 
    
         
            +
                      super
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  def respond_to?(method)
         
     | 
| 
      
 61 
     | 
    
         
            +
                    return true if COUNTER_LABELS.keys.include?(method)
         
     | 
| 
      
 62 
     | 
    
         
            +
                    super
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                  private
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                  def load_parsed_data(options)
         
     | 
| 
      
 68 
     | 
    
         
            +
                    @parsed_data = options[:parsed_data]
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                    if @parsed_data.nil? and options[:cache]
         
     | 
| 
      
 71 
     | 
    
         
            +
                      cache_file_path = File.expand_path('check_passenger_cache.dump', Dir.tmpdir)
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                      if File.exist?(cache_file_path) and (Time.now - File.mtime(cache_file_path) < CACHE_TTL)
         
     | 
| 
      
 74 
     | 
    
         
            +
                        File.open(cache_file_path, 'rb') { |file| @parsed_data = Marshal.load(file.read) }
         
     | 
| 
      
 75 
     | 
    
         
            +
                      end
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    if @parsed_data.nil?
         
     | 
| 
      
 79 
     | 
    
         
            +
                      @parsed_data = Parser.new(passenger_status(options[:passenger_status_path]).run)
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                      if options[:cache]
         
     | 
| 
      
 82 
     | 
    
         
            +
                        File.open(cache_file_path, 'wb') { |file| file.write Marshal.dump(@parsed_data) }
         
     | 
| 
      
 83 
     | 
    
         
            +
                      end
         
     | 
| 
      
 84 
     | 
    
         
            +
                    end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                    @parsed_data
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
             
     | 
| 
      
 89 
     | 
    
         
            +
                  def passenger_status(passenger_status_path = nil)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    @passenger_status ||= PassengerStatus
         
     | 
| 
      
 91 
     | 
    
         
            +
                    @passenger_status.path = passenger_status_path
         
     | 
| 
      
 92 
     | 
    
         
            +
                    @passenger_status
         
     | 
| 
      
 93 
     | 
    
         
            +
                  end
         
     | 
| 
      
 94 
     | 
    
         
            +
                end
         
     | 
| 
      
 95 
     | 
    
         
            +
              end
         
     | 
| 
      
 96 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,66 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module CheckPassenger
         
     | 
| 
      
 2 
     | 
    
         
            +
              module NagiosCheck
         
     | 
| 
      
 3 
     | 
    
         
            +
                EXIT_CODES = { ok: 0, warn: 1, crit: 2 }
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                private
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def nagios_error(message)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  puts message
         
     | 
| 
      
 9 
     | 
    
         
            +
                  exit 3
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def nagios_output(status, data)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  unless [:ok, :warn, :crit].include?(status)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    raise ArgumentError, 'Invalid status provided: %s' % status.to_s
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  data = [data] unless data.is_a?(Array)
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  data.each do |line|
         
     | 
| 
      
 20 
     | 
    
         
            +
                    raise ArgumentError, 'No status text provided' unless line.has_key?(:text)
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                    if line[:counter] and line[:value]
         
     | 
| 
      
 23 
     | 
    
         
            +
                      puts '%s|%s=%d;%s;%s;%s;%s' % [
         
     | 
| 
      
 24 
     | 
    
         
            +
                        line[:text],
         
     | 
| 
      
 25 
     | 
    
         
            +
                        line[:counter], line[:value],
         
     | 
| 
      
 26 
     | 
    
         
            +
                        line[:warn], line[:crit],
         
     | 
| 
      
 27 
     | 
    
         
            +
                        line[:min], line[:max]
         
     | 
| 
      
 28 
     | 
    
         
            +
                      ]
         
     | 
| 
      
 29 
     | 
    
         
            +
                    else
         
     | 
| 
      
 30 
     | 
    
         
            +
                      puts line[:text]
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
                  end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                  exit EXIT_CODES[status]
         
     | 
| 
      
 35 
     | 
    
         
            +
                end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                def nagios_range_to_condition(nagios_range)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  case nagios_range
         
     | 
| 
      
 39 
     | 
    
         
            +
                  when /^(-?\d+)$/
         
     | 
| 
      
 40 
     | 
    
         
            +
                    lambda { |n| !(0 .. $1.to_i).include?(n) }
         
     | 
| 
      
 41 
     | 
    
         
            +
                  when /^(-?\d+):~?$/
         
     | 
| 
      
 42 
     | 
    
         
            +
                    lambda { |n| n < $1.to_i }
         
     | 
| 
      
 43 
     | 
    
         
            +
                  when /^~?:(-?\d+)$/
         
     | 
| 
      
 44 
     | 
    
         
            +
                    lambda { |n| n > $1.to_i }
         
     | 
| 
      
 45 
     | 
    
         
            +
                  when /^(-?\d+):(-?\d+)$/
         
     | 
| 
      
 46 
     | 
    
         
            +
                    lambda { |n| !($1.to_i .. $2.to_i).include?(n) }
         
     | 
| 
      
 47 
     | 
    
         
            +
                  when /^@(-?\d+):(-?\d+)$/
         
     | 
| 
      
 48 
     | 
    
         
            +
                    lambda { |n| ($1.to_i .. $2.to_i).include?(n) }
         
     | 
| 
      
 49 
     | 
    
         
            +
                  else
         
     | 
| 
      
 50 
     | 
    
         
            +
                    raise ArgumentError, 'Cannot process Nagios range: %s' % nagios_range
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                def nagios_status(counter, options = {})
         
     | 
| 
      
 55 
     | 
    
         
            +
                  status = :ok
         
     | 
| 
      
 56 
     | 
    
         
            +
                  [:warn, :crit].each do |level|
         
     | 
| 
      
 57 
     | 
    
         
            +
                    status = level if options[level] && number_outside_range?(counter, options[level])
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
                  status
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                def number_outside_range?(number, nagios_range)
         
     | 
| 
      
 63 
     | 
    
         
            +
                  nagios_range_to_condition(nagios_range).call(number)
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,120 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module CheckPassenger
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Parser
         
     | 
| 
      
 3 
     | 
    
         
            +
                UNIT_MULTIPLIERS = { 's' => 1, 'm' => 60, 'h' => 3_600, 'd' => 86_400 }
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                attr_reader :max_pool_size, :passenger_status_output, :passenger_version
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def initialize(passenger_status_output)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @passenger_status_output = passenger_status_output
         
     | 
| 
      
 9 
     | 
    
         
            +
                  parse_passenger_status_output
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def application_names
         
     | 
| 
      
 13 
     | 
    
         
            +
                  @application_data.map { |app_data| app_data[:name] }
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                def live_process_count(app_name = nil)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  if app_name
         
     | 
| 
      
 18 
     | 
    
         
            +
                    app_data = application_data(app_name)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    app_data[:live_process_count]
         
     | 
| 
      
 20 
     | 
    
         
            +
                  else
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @application_data.inject(0) { |sum, e| sum + e[:live_process_count] }
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def memory(app_name = nil)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  if app_name
         
     | 
| 
      
 27 
     | 
    
         
            +
                    app_data = application_data(app_name)
         
     | 
| 
      
 28 
     | 
    
         
            +
                    app_data[:memory]
         
     | 
| 
      
 29 
     | 
    
         
            +
                  else
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @application_data.inject(0) { |sum, e| sum + e[:memory] }
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                def process_count(app_name = nil)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  if app_name
         
     | 
| 
      
 36 
     | 
    
         
            +
                    app_data = application_data(app_name)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    app_data[:process_count]
         
     | 
| 
      
 38 
     | 
    
         
            +
                  else
         
     | 
| 
      
 39 
     | 
    
         
            +
                    @process_count
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
                end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                private
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                def application_data(app_name)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  if app_name
         
     | 
| 
      
 47 
     | 
    
         
            +
                    data = @application_data.select { |d| d[:name].include?(app_name) }
         
     | 
| 
      
 48 
     | 
    
         
            +
                    if data.size == 0
         
     | 
| 
      
 49 
     | 
    
         
            +
                      raise ArgumentError, 'Could not find an application by "%s"' % app_name
         
     | 
| 
      
 50 
     | 
    
         
            +
                    elsif data.size > 1
         
     | 
| 
      
 51 
     | 
    
         
            +
                      raise ArgumentError, 'More than one application match "%s"' % app_name
         
     | 
| 
      
 52 
     | 
    
         
            +
                    else
         
     | 
| 
      
 53 
     | 
    
         
            +
                      return data.first
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
                  else
         
     | 
| 
      
 56 
     | 
    
         
            +
                    return @application_data
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
                end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                def is_process_alive?(last_used)
         
     | 
| 
      
 61 
     | 
    
         
            +
                  life_to_seconds(last_used) < LIVE_PROCESS_TTL_IN_SECONDS
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                def life_to_seconds(last_used)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  last_used.split(/\s+/).inject(0) do |sum, part|
         
     | 
| 
      
 66 
     | 
    
         
            +
                    if part =~ /^(\d+)([a-z])$/
         
     | 
| 
      
 67 
     | 
    
         
            +
                      unless UNIT_MULTIPLIERS.has_key?($2)
         
     | 
| 
      
 68 
     | 
    
         
            +
                      raise StatusOutputError.new(
         
     | 
| 
      
 69 
     | 
    
         
            +
                          'Unknown time unit "%s" in "%s"' % [$2, last_used],
         
     | 
| 
      
 70 
     | 
    
         
            +
                          passenger_status_output
         
     | 
| 
      
 71 
     | 
    
         
            +
                        )
         
     | 
| 
      
 72 
     | 
    
         
            +
                      end
         
     | 
| 
      
 73 
     | 
    
         
            +
                      sum + $1.to_i * UNIT_MULTIPLIERS[$2]
         
     | 
| 
      
 74 
     | 
    
         
            +
                    else
         
     | 
| 
      
 75 
     | 
    
         
            +
                      sum
         
     | 
| 
      
 76 
     | 
    
         
            +
                    end
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
                end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                def parse_application_data(output)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  output.split("\n\n").map do |app_output|
         
     | 
| 
      
 82 
     | 
    
         
            +
                    app_data = {}
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                    app_output =~ /App root: +([^\n]+)/
         
     | 
| 
      
 85 
     | 
    
         
            +
                    raise StatusOutputError.new('Could not find app name', passenger_status_output) unless $1
         
     | 
| 
      
 86 
     | 
    
         
            +
                    app_data[:name] = $1.strip
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                    app_data[:process_count] = app_output.scan(/PID *: *\d+/).size
         
     | 
| 
      
 89 
     | 
    
         
            +
                    app_data[:memory] = app_output.scan(/Memory *: *(\d+)M/).inject(0.0) { |s, m| s + m[0].to_f }
         
     | 
| 
      
 90 
     | 
    
         
            +
                    app_data[:live_process_count] = (
         
     | 
| 
      
 91 
     | 
    
         
            +
                      app_output.scan(/Last used *: *([^\n]+)/).select { |m| is_process_alive?(m[0]) }
         
     | 
| 
      
 92 
     | 
    
         
            +
                    ).size
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                    app_data
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                def parse_passenger_status_output
         
     | 
| 
      
 99 
     | 
    
         
            +
                  passenger_status_output =~ /^(.*?)-+ +Application groups +-+[^\n]*\n(.*)$/m
         
     | 
| 
      
 100 
     | 
    
         
            +
                  raise StatusOutputError.new('Did not find "Application groups" section', passenger_status_output) unless $1
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                  generic_data = $1
         
     | 
| 
      
 103 
     | 
    
         
            +
                  application_data = $2
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                  generic_data =~ /Version *: *([.\d]+)/
         
     | 
| 
      
 106 
     | 
    
         
            +
                  raise StatusOutputError.new('Could not find Passenger version', passenger_status_output) unless $1
         
     | 
| 
      
 107 
     | 
    
         
            +
                  @passenger_version = $1
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                  generic_data =~ /Max pool size *: *(\d+)/
         
     | 
| 
      
 110 
     | 
    
         
            +
                  raise StatusOutputError.new('Could not find max pool size', passenger_status_output) unless $1
         
     | 
| 
      
 111 
     | 
    
         
            +
                  @max_pool_size = $1.to_i
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                  generic_data =~ /Processes *: *(\d+)/
         
     | 
| 
      
 114 
     | 
    
         
            +
                  raise StatusOutputError.new('Could not find process count', passenger_status_output) unless $1
         
     | 
| 
      
 115 
     | 
    
         
            +
                  @process_count = $1.to_i
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                  @application_data = parse_application_data(application_data)
         
     | 
| 
      
 118 
     | 
    
         
            +
                end
         
     | 
| 
      
 119 
     | 
    
         
            +
              end
         
     | 
| 
      
 120 
     | 
    
         
            +
            end
         
     |