Module: Chef::MonitWrapper::Status

Includes:
Chef::Mixin::ShellOut
Included in:
StartStop
Defined in:
libraries/status.rb

Overview

Tools to detect service status from Monit's summary command output. Methods in this module are automatically available in resources and providers.

Instance Method Summary collapse

Instance Method Details

#get_monit_summaryHash

Parses the output of the monit summary command.

Returns:

  • (Hash)

    a mapping from service names to their statuses. Example return value: { 'sshd' => 'Running', 'my-service' => 'Not monitored' }.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'libraries/status.rb', line 30

def get_monit_summary
  monit_executable = node['monit']['executable']
  unless File.exists?(monit_executable)
    Chef::Log.warn("Monit is not installed at #{monit_executable} -- " \
                   "assuming no Monit-controlled processes are running")
    return {}
  end
  p = shell_out("#{node['monit']['executable']} summary")
  unless p.exitstatus == 0
    Chef::Log.fatal("Command '#{p.command}' failed with exit status #{p.exitstatus}\n" +
                    "stdout:\n#{p.stdout}\nstderr:\n#{p.stderr}")
    raise
  end

  parse_monit_summary(p.stdout)
end

#get_stable_monit_service_status(service_name) ⇒ Object

Wait until the service status is considered "stable".

Returns:

  • the new status of the given service

See Also:



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'libraries/status.rb', line 58

def get_stable_monit_service_status(service_name)
  start_time = Time.now
  timeout_sec = 120
  logged_message = false
  status = get_monit_summary[service_name]
  until monit_status_stable?(status)
    if Time.now - start_time >= timeout_sec
      raise "Timed out waiting to get the status of #{service_name} " +
            "(currently #{status.inspect})"
    end
    unless logged_message
      Chef::Log.info('Waiting for Monit to initialize the status of service ' +
                     "#{service_name} for up to #{timeout_sec} seconds")
      logged_message = true
    end
    sleep(1)
    status = get_monit_summary[service_name]
  end
  status
end

#monit_service_exists_and_running?(service_name) ⇒ Boolean

Returns true if the given service is registered with Monit and is running.

Parameters:

  • service_name (String)

    service name

Returns:

  • (Boolean)

    true if the given service is registered with Monit and is running.



100
101
102
# File 'libraries/status.rb', line 100

def monit_service_exists_and_running?(service_name)
  monit_service_registered?(service_name) && monit_service_running?(service_name)
end

#monit_service_registered?(service_name) ⇒ Boolean

Determines whether the given process is registered with Monit. This is done by looking at whether the given service name appears in the output of monit summary.

Parameters:

  • service_name (String)

    service name

Returns:

  • (Boolean)

    true if the given service is registered with Monit.



51
52
53
# File 'libraries/status.rb', line 51

def monit_service_registered?(service_name)
  get_monit_summary.include?(service_name)
end

#monit_service_running?(service_name, options = {}) ⇒ Boolean

Detects if the given service is running.

Parameters:

  • service_name (String)

    service name

  • options (Hash) (defaults to: {})

    a hash with the the optional key :verbose. When :verbose is set to true, additional logging is enabed.

Returns:

  • (Boolean)

    true if the given service is running.



84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'libraries/status.rb', line 84

def monit_service_running?(service_name, options = {})
  is_verbose = options.delete(:verbose)
  raise "Unrecognized options: #{options}" unless options.empty?
  service_status = get_stable_monit_service_status(service_name)
  is_running = service_status =~ /^Running\b/
  if is_verbose
    Chef::Log.info(
      "Monit service #{service_name} is #{is_running ? 'running' : 'not running'} " +
      "(status: #{service_status.inspect})"
    )
  end
  is_running
end

#monit_status_stable?(status) ⇒ Boolean (protected)

Determines if the given Monit service status is considered "stable", i.e. not likely to change without external influence. Currently this means it is not "Initializing", "... pending", or "Does not exist", but this definition may change in the future.

Returns:

  • (Boolean)

    true if the given service status is considered "stable".



110
111
112
113
114
115
116
117
118
# File 'libraries/status.rb', line 110

def monit_status_stable?(status)
  !status.nil? &&
    status !~ / pending$/ &&
    ![
      'Does not exist',
      'Initializing',
      'PPID changed'
    ].include?(status)
end

#parse_monit_summary(monit_summary_stdout) ⇒ Object (protected)

Parses the output of the monit summary command and returns it in the form of a hash mapping service name to its status.



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'libraries/status.rb', line 122

def parse_monit_summary(monit_summary_stdout)
  process_name_to_status = {}
  monit_summary_stdout.split("\n").each do |line|
    # The process status can include letters, spaces, and dashes.
    if line =~ /^Process\s+'(\S+)'\s+([A-Za-z -]+)$/
      process_name_to_status[$1] = $2.strip
    end
  end
  Chef::Log.debug(
    "Raw 'monit summary' stdout:\n" \
    "#{monit_summary_stdout.split("\n").map {|line| "    #{line}" }.join("\n")}\n" \
    "Parsed 'monit summary' output:\n" +
    process_name_to_status.to_s)
  process_name_to_status
end