Class: Nagios::ExternalCommands

Inherits:
Object
  • Object
show all
Defined in:
lib/nagios/external_commands.rb,
lib/nagios/external_commands/list.rb

Overview

Class Nagios::ExternalCommands is class implementing sending commands to external commands file in Nagios.

From nagios.cfg file:

This is the file that Nagios checks for external command requests. It is also where the command CGI will write commands that are submitted by users, so it must be writable by the user that the web server is running as (usually ‘nobody’).

Usage

command = Nagios::ExternalCommands.new Nagios::Config.new.parse.command_file

command.write :action => :PROCESS_HOST_CHECK_RESULT, 
  :host_name  => 'myhost', :status_code => 0, :plugin_output => "PING command OK"

Constant Summary collapse

ACTIONS =

External commands list in nagios and format to send this to Nagios. Keys of the Hash are names of commands, values are Array’s of Nagios variables to be sent. Arrays are converted to ERB templates before printing, command name and all variables joined together by semicolons.

Each variable must be defined as attr_accessor, these variables are used in ERB binding.

List of all available nagios external commands, formats and descriptions can be obtained from www.nagios.org/developerinfo/externalcommands As of the time of writing this list is 157 commands for Nagios 3.x.

Example

:PROCESS_SERVICE_CHECK_RESULT => %w{host_name service_description return_code plugin_output} 

converted to template on print:

[timestamp] PROCESS_SERVICE_CHECK_RESULT;<%= host_name %>;<%= service_description %>;<%= return_code %>;<%= plugin_output %>\n
{ 
  :ACKNOWLEDGE_HOST_PROBLEM => %w{host_name sticky notify persistent author comment},
  :ACKNOWLEDGE_SVC_PROBLEM => %w{host_name service_description sticky notify persistent author comment},
  :ADD_HOST_COMMENT => %w{host_name persistent author comment},
  :ADD_SVC_COMMENT => %w{host_name service_description persistent author comment},
  :CHANGE_CONTACT_HOST_NOTIFICATION_TIMEPERIOD => %w{contact_name notification_timeperiod},
  :CHANGE_CONTACT_MODATTR => %w{contact_name value},
  :CHANGE_CONTACT_MODHATTR => %w{contact_name value},
  :CHANGE_CONTACT_MODSATTR => %w{contact_name value},
  :CHANGE_CONTACT_SVC_NOTIFICATION_TIMEPERIOD => %w{contact_name notification_timeperiod},
  :CHANGE_CUSTOM_CONTACT_VAR => %w{contact_name varname varvalue},
  :CHANGE_CUSTOM_HOST_VAR => %w{host_name varname varvalue},
  :CHANGE_CUSTOM_SVC_VAR => %w{host_name service_description varname varvalue},
  :CHANGE_GLOBAL_HOST_EVENT_HANDLER => %w{event_handler_command},
  :CHANGE_GLOBAL_SVC_EVENT_HANDLER => %w{event_handler_command},
  :CHANGE_HOST_CHECK_COMMAND => %w{host_name check_command},
  :CHANGE_HOST_CHECK_TIMEPERIOD => %w{host_name check_timeperod},
  :CHANGE_HOST_CHECK_TIMEPERIOD => %w{host_name timeperiod},
  :CHANGE_HOST_EVENT_HANDLER => %w{host_name event_handler_command},
  :CHANGE_HOST_MODATTR => %w{host_name value},
  :CHANGE_MAX_HOST_CHECK_ATTEMPTS => %w{host_name check_attempts},
  :CHANGE_MAX_SVC_CHECK_ATTEMPTS => %w{host_name service_description check_attempts},
  :CHANGE_NORMAL_HOST_CHECK_INTERVAL => %w{host_name check_interval},
  :CHANGE_NORMAL_SVC_CHECK_INTERVAL => %w{host_name service_description check_interval},
  :CHANGE_RETRY_HOST_CHECK_INTERVAL => %w{host_name service_description check_interval},
  :CHANGE_RETRY_SVC_CHECK_INTERVAL => %w{host_name service_description check_interval},
  :CHANGE_SVC_CHECK_COMMAND => %w{host_name service_description check_command},
  :CHANGE_SVC_CHECK_TIMEPERIOD => %w{host_name service_description check_timeperiod},
  :CHANGE_SVC_EVENT_HANDLER => %w{host_name service_description event_handler_command},
  :CHANGE_SVC_MODATTR => %w{host_name service_description value},
  :CHANGE_SVC_NOTIFICATION_TIMEPERIOD => %w{host_name service_description notification_timeperiod},
  :DELAY_HOST_NOTIFICATION => %w{host_name notification_time},
  :DELAY_SVC_NOTIFICATION => %w{host_name service_description notification_time},
  :DEL_ALL_HOST_COMMENTS => %w{host_name},
  :DEL_ALL_SVC_COMMENTS => %w{host_name service_description},
  :DEL_HOST_COMMENT => %w{comment_id},
  :DEL_HOST_DOWNTIME => %w{downtime_id},
  :DEL_SVC_COMMENT => %w{comment_id},
  :DEL_SVC_DOWNTIME => %w{downtime_id},
  :DISABLE_ALL_NOTIFICATIONS_BEYOND_HOST => %w{host_name},
  :DISABLE_CONTACTGROUP_HOST_NOTIFICATIONS => %w{contactgroup_name},
  :DISABLE_CONTACTGROUP_SVC_NOTIFICATIONS => %w{contactgroup_name},
  :DISABLE_CONTACT_HOST_NOTIFICATIONS => %w{contact_name},
  :DISABLE_CONTACT_SVC_NOTIFICATIONS => %w{contact_name},
  :DISABLE_EVENT_HANDLERS => [],
  :DISABLE_FAILURE_PREDICTION => [],
  :DISABLE_FLAP_DETECTION => [],
  :DISABLE_HOSTGROUP_HOST_CHECKS => %w{hostgroup_name},
  :DISABLE_HOSTGROUP_HOST_NOTIFICATIONS => %w{hostgroup_name},
  :DISABLE_HOSTGROUP_PASSIVE_HOST_CHECKS => %w{hostgroup_name},
  :DISABLE_HOSTGROUP_PASSIVE_SVC_CHECKS => %w{hostgroup_name},
  :DISABLE_HOSTGROUP_SVC_CHECKS => %w{hostgroup_name},
  :DISABLE_HOSTGROUP_SVC_NOTIFICATIONS => %w{hostgroup_name},
  :DISABLE_HOST_AND_CHILD_NOTIFICATIONS => %w{host_name},
  :DISABLE_HOST_CHECK => %w{host_name},
  :DISABLE_HOST_EVENT_HANDLER => %w{host_name},
  :DISABLE_HOST_FLAP_DETECTION => %w{host_name},
  :DISABLE_HOST_FRESHNESS_CHECKS => [],
  :DISABLE_HOST_NOTIFICATIONS => %w{host_name},
  :DISABLE_HOST_SVC_CHECKS => %w{host_name},
  :DISABLE_HOST_SVC_NOTIFICATIONS => %w{host_name},
  :DISABLE_NOTIFICATIONS => [],
  :DISABLE_PASSIVE_HOST_CHECKS => %w{host_name},
  :DISABLE_PASSIVE_SVC_CHECKS => %w{host_name service_description},
  :DISABLE_PERFORMANCE_DATA => [],
  :DISABLE_SERVICEGROUP_HOST_CHECKS => %w{servicegroup_name},
  :DISABLE_SERVICEGROUP_HOST_NOTIFICATIONS => %w{servicegroup_name},
  :DISABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS => %w{servicegroup_name},
  :DISABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS => %w{servicegroup_name},
  :DISABLE_SERVICEGROUP_SVC_CHECKS => %w{servicegroup_name},
  :DISABLE_SERVICEGROUP_SVC_NOTIFICATIONS => %w{servicegroup_name},
  :DISABLE_SERVICE_FLAP_DETECTION => %w{host_name service_description},
  :DISABLE_SERVICE_FRESHNESS_CHECKS => [],
  :DISABLE_SVC_CHECK => %w{host_name service_description},
  :DISABLE_SVC_EVENT_HANDLER => %w{host_name service_description},
  :DISABLE_SVC_FLAP_DETECTION => %w{host_name service_description},
  :DISABLE_SVC_NOTIFICATIONS => %w{host_name service_description},
  :ENABLE_ALL_NOTIFICATIONS_BEYOND_HOST => %w{host_name},
  :ENABLE_CONTACTGROUP_HOST_NOTIFICATIONS => %w{contactgroup_name},
  :ENABLE_CONTACTGROUP_SVC_NOTIFICATIONS => %w{contactgroup_name},
  :ENABLE_CONTACT_HOST_NOTIFICATIONS => %w{contact_name},
  :ENABLE_CONTACT_SVC_NOTIFICATIONS => %w{contact_name},
  :ENABLE_EVENT_HANDLERS => [],
  :ENABLE_FAILURE_PREDICTION => [],
  :ENABLE_FLAP_DETECTION => [],
  :ENABLE_HOSTGROUP_HOST_CHECKS => %w{hostgroup_name},
  :ENABLE_HOSTGROUP_HOST_NOTIFICATIONS => %w{hostgroup_name},
  :ENABLE_HOSTGROUP_PASSIVE_HOST_CHECKS => %w{hostgroup_name},
  :ENABLE_HOSTGROUP_PASSIVE_SVC_CHECKS => %w{hostgroup_name},
  :ENABLE_HOSTGROUP_SVC_CHECKS => %w{hostgroup_name},
  :ENABLE_HOSTGROUP_SVC_NOTIFICATIONS => %w{hostgroup_name},
  :ENABLE_HOST_AND_CHILD_NOTIFICATIONS => %w{host_name},
  :ENABLE_HOST_CHECK => %w{host_name},
  :ENABLE_HOST_EVENT_HANDLER => %w{host_name},
  :ENABLE_HOST_FLAP_DETECTION => %w{host_name},
  :ENABLE_HOST_FRESHNESS_CHECKS => [],
  :ENABLE_HOST_NOTIFICATIONS => %w{host_name},
  :ENABLE_HOST_SVC_CHECKS => %w{host_name},
  :ENABLE_HOST_SVC_NOTIFICATIONS => %w{host_name},
  :ENABLE_NOTIFICATIONS => [],
  :ENABLE_PASSIVE_HOST_CHECKS => %w{host_name},
  :ENABLE_PASSIVE_SVC_CHECKS => %w{host_name service_description},
  :ENABLE_PERFORMANCE_DATA => [],
  :ENABLE_SERVICEGROUP_HOST_CHECKS => %w{servicegroup_name},
  :ENABLE_SERVICEGROUP_HOST_NOTIFICATIONS => %w{servicegroup_name},
  :ENABLE_SERVICEGROUP_PASSIVE_HOST_CHECKS => %w{servicegroup_name},
  :ENABLE_SERVICEGROUP_PASSIVE_SVC_CHECKS => %w{servicegroup_name},
  :ENABLE_SERVICEGROUP_SVC_CHECKS => %w{servicegroup_name},
  :ENABLE_SERVICEGROUP_SVC_NOTIFICATIONS => %w{servicegroup_name},
  :ENABLE_SERVICE_FRESHNESS_CHECKS => [],
  :ENABLE_SVC_CHECK => %w{host_name service_description},
  :ENABLE_SVC_EVENT_HANDLER => %w{host_name service_description},
  :ENABLE_SVC_FLAP_DETECTION => %w{host_name service_description},
  :ENABLE_SVC_NOTIFICATIONS => %w{host_name service_description},
  :PROCESS_FILE => %w{file_name delete},
  :PROCESS_HOST_CHECK_RESULT => %w{host_name status_code plugin_output},
  :PROCESS_SERVICE_CHECK_RESULT => %w{host_name service_description return_code plugin_output},
  :READ_STATE_INFORMATION => [],
  :REMOVE_HOST_ACKNOWLEDGEMENT => %w{host_name},
  :REMOVE_SVC_ACKNOWLEDGEMENT => %w{host_name service_description},
  :RESTART_PROGRAM => [],
  :SAVE_STATE_INFORMATION => [],
  :SCHEDULE_AND_PROPAGATE_HOST_DOWNTIME => %w{host_name start_time end_time fixed trigger_id duration author comment},
  :SCHEDULE_AND_PROPAGATE_TRIGGERED_HOST_DOWNTIME => %w{host_name start_time end_time fixed trigger_id duration author comment},
  :SCHEDULE_FORCED_HOST_CHECK => %w{host_name check_time},
  :SCHEDULE_FORCED_HOST_SVC_CHECKS => %w{host_name check_time},
  :SCHEDULE_FORCED_SVC_CHECK => %w{host_name service_description check_time},
  :SCHEDULE_HOSTGROUP_HOST_DOWNTIME => %w{hostgroup_name start_time end_time fixed trigger_id duration author comment},
  :SCHEDULE_HOSTGROUP_SVC_DOWNTIME => %w{hostgroup_name start_time end_time fixed trigger_id duration author comment},
  :SCHEDULE_HOST_CHECK => %w{host_name check_time},
  :SCHEDULE_HOST_DOWNTIME => %w{host_name start_time end_time fixed trigger_id duration author comment},
  :SCHEDULE_HOST_SVC_CHECKS => %w{host_name check_time},
  :SCHEDULE_HOST_SVC_DOWNTIME => %w{host_name start_time end_time fixed trigger_id duration author comment},
  :SCHEDULE_SERVICEGROUP_HOST_DOWNTIME => %w{servicegroup_name start_time end_time fixed trigger_id duration author comment},
  :SCHEDULE_SERVICEGROUP_SVC_DOWNTIME => %w{servicegroup_name start_time end_time fixed trigger_id duration author comment},
  :SCHEDULE_SVC_CHECK => %w{host_name service_description check_time},
  :SCHEDULE_SVC_DOWNTIME => %w{host_name service_desription start_time end_time fixed trigger_id duration author comment},
  :SEND_CUSTOM_HOST_NOTIFICATION => %w{host_name options author comment},
  :SEND_CUSTOM_SVC_NOTIFICATION => %w{host_name service_description options author comment},
  :SET_HOST_NOTIFICATION_NUMBER => %w{host_name notification_number},
  :SET_SVC_NOTIFICATION_NUMBER => %w{host_name service_description notification_number},
  :SHUTDOWN_PROGRAM => [],
  :START_ACCEPTING_PASSIVE_HOST_CHECKS => [],
  :START_ACCEPTING_PASSIVE_SVC_CHECKS => [],
  :START_EXECUTING_HOST_CHECKS => [],
  :START_EXECUTING_SVC_CHECKS => [],
  :START_OBSESSING_OVER_HOST => %w{host_name},
  :START_OBSESSING_OVER_HOST_CHECKS => [],
  :START_OBSESSING_OVER_SVC => %w{host_name service_description},
  :START_OBSESSING_OVER_SVC_CHECKS => [],
  :STOP_ACCEPTING_PASSIVE_HOST_CHECKS => [],
  :STOP_ACCEPTING_PASSIVE_SVC_CHECKS => [],
  :STOP_EXECUTING_HOST_CHECKS => [],
  :STOP_EXECUTING_SVC_CHECKS => [],
  :STOP_OBSESSING_OVER_HOST => %w{host_name},
  :STOP_OBSESSING_OVER_HOST_CHECKS => [],
  :STOP_OBSESSING_OVER_SVC => %w{host_name service_description},
  :STOP_OBSESSING_OVER_SVC_CHECKS => []
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path) ⇒ ExternalCommands

Constructor for the external command write class.

Example

>> cmd = Nagios::ExternalCommands.new('/var/nagios/rw/nagios.cmd')

Parameters:

  • path (String)

    Full UNIX path to external command file

Raises:

  • (ArgumentError)


34
35
36
37
38
39
# File 'lib/nagios/external_commands.rb', line 34

def initialize path
  raise ArgumentError, "External command file name must be provided" unless path
  raise RuntimeError,  "External command directory holding file #{path} is not writable by this user." unless File.writable? File.dirname path
  
  @path = path
end

Instance Attribute Details

#actionObject

Action to write: one of the keys listed in ::Nagios::ExternalCommands::ACTIONS hash.



45
46
47
# File 'lib/nagios/external_commands.rb', line 45

def action
  @action
end

#authorObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def author
  @author
end

#check_attemptsObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def check_attempts
  @check_attempts
end

#check_commandObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def check_command
  @check_command
end

#check_intervalObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def check_interval
  @check_interval
end

#check_timeObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def check_time
  @check_time
end

#check_timeperiodObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def check_timeperiod
  @check_timeperiod
end

#commentObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def comment
  @comment
end

#comment_idObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def comment_id
  @comment_id
end

#contact_nameObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def contact_name
  @contact_name
end

#contactgroup_nameObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def contactgroup_name
  @contactgroup_name
end

#deleteObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def delete
  @delete
end

#downtime_idObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def downtime_id
  @downtime_id
end

#durationObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def duration
  @duration
end

#end_timeObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def end_time
  @end_time
end

#event_handler_commandObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def event_handler_command
  @event_handler_command
end

#file_nameObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def file_name
  @file_name
end

#fixedObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def fixed
  @fixed
end

#host_nameObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def host_name
  @host_name
end

#hostgroup_nameObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def hostgroup_name
  @hostgroup_name
end

#notification_numberObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def notification_number
  @notification_number
end

#notification_timeObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def notification_time
  @notification_time
end

#notification_timeperiodObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def notification_timeperiod
  @notification_timeperiod
end

#notifyObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def notify
  @notify
end

#optionsObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def options
  @options
end

#pathObject (readonly)

Returns the value of attribute path.



41
42
43
# File 'lib/nagios/external_commands.rb', line 41

def path
  @path
end

#persistentObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def persistent
  @persistent
end

#plugin_outputObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def plugin_output
  @plugin_output
end

#return_codeObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def return_code
  @return_code
end

#service_descriptionObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def service_description
  @service_description
end

#service_desriptionObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def service_desription
  @service_desription
end

#servicegroup_nameObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def servicegroup_name
  @servicegroup_name
end

#start_timeObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def start_time
  @start_time
end

#status_codeObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def status_code
  @status_code
end

#stickyObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def sticky
  @sticky
end

#timeperiodObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def timeperiod
  @timeperiod
end

#trigger_idObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def trigger_id
  @trigger_id
end

#tsObject

Time-stamp - usually time when write is performed, but can be overridden by params in constructor. If given as argument for constructor it should be String of the format: Time.to_i.to_s (i.e number of seconds since epoch).



51
52
53
# File 'lib/nagios/external_commands.rb', line 51

def ts
  @ts
end

#valueObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def value
  @value
end

#varnameObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def varname
  @varname
end

#varvalueObject

Nagios variable used in external command



59
60
61
# File 'lib/nagios/external_commands.rb', line 59

def varvalue
  @varvalue
end

Instance Method Details

#get_bindingObject

Get private binding to use with ERB bindings.



71
72
73
# File 'lib/nagios/external_commands.rb', line 71

def get_binding
  binding()
end

#write(data) ⇒ Object

Send command to Nagios. Prints formatted string to external command file (pipe).

Parameters:

  • data (Hash or Array)

    Data to write to command file pipe. Must include :action and all additional variables



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# File 'lib/nagios/external_commands.rb', line 79

def write data
  case data
  when Hash then data = [data]
  else 
    return { :result => false, :data => "Input data type #{data.class} is not supproted." }
  end

  result, output = true, []

  data.each do |params|
    
    messages = []

    if params.has_key? :action
      messages << "ArgumentError: Action name #{params[:action]} is not implemented" unless ACTIONS.keys.include? params[:action]
    else
      messages << "ArgumentError: Action name must be provided"
    end
    
    # It makes sense to continue only if checks above did not fail
    if messages.empty?
      #
      # Clear all attributes first - so no old data left
      #
      ACTIONS.values.flatten.uniq.each do |att|
        self.instance_variable_set "@#{att}", nil
      end
      #
      # And set it to param's value
      #
      params.each { |k,v| self.instance_variable_set "@#{k}", v }
      #
      # Check that all variable that are used in the template are
      # actually set, not nil's
      #
      ACTIONS[@action].each do |var|
        messages << "ArgumentError, Parameter :#{var} is required, cannot be nil"  if self.instance_variable_get("@#{var}").nil?
      end
      
      # Try to write to file only if none of the above failed
      if messages.empty?
        self.ts = params[:ts] || Time.now.to_i.to_s
        
        format = "[#{ts}] " << ([self.action.to_s] + ACTIONS[self.action].map {|x| "<%= #{x} %>" }).join(';')
        
        begin
          File.open(path, 'a') do |pipe|
            pipe.puts ERB.new(format).result(self.get_binding)
            pipe.close
          end
        rescue e
          messages << e.message
        end
      end
    end
    
    output << { :data => params, :result => messages.empty? , :messages => messages }
    result &&= messages.empty?
  end # data.each

  { :result => result, :data => output }
end