You are here

function nagios_check_requirements in Nagios Monitoring 7

Same name and namespace in other branches
  1. 8 nagios.module \nagios_check_requirements()
  2. 5 nagios.module \nagios_check_requirements()
  3. 6 nagios.module \nagios_check_requirements()

Check all Drupal requirements are satisfied.

Calls hook_requirements on all modules to gather info.

Return value

array

File

./nagios.module, line 661

Code

function nagios_check_requirements() {

  // Load .install files
  include_once DRUPAL_ROOT . '/' . './includes/install.inc';
  module_load_include('inc', 'update', 'update.compare');
  drupal_load_updates();

  // Get the run-time requirements and status information.
  // module_invoke_all('requirements', 'runtime') returns an array that isn't
  // keyed by the module name, eg we might get a key 'ctools_css_cache'.
  // We have no way of knowing which module set this, and we can't guess based
  // on the name, as removing everything that begins with 'ctools_' might remove
  // data from other ctools sub-modules that we want to still monitor.
  // The only safe way is to use module_invoke, calling each module in turn.
  $project_data = _nagios_update_get_projects();
  $nagios_ignored_modules = variable_get('nagios_ignored_modules', []);
  $nagios_ignored_themes = variable_get('nagios_ignored_themes', []);

  /** @var array $nagios_ignored_projects */
  $nagios_ignored_projects = $nagios_ignored_modules + $nagios_ignored_themes;
  $enabled_modules = [];
  foreach ($project_data as $project) {
    foreach ($project['includes'] as $key => $val) {
      if (!isset($nagios_ignored_projects[$key])) {
        $enabled_modules[] = $key;
      }
    }
  }

  // Copied from update_requirements(). Get available update data for projects.
  $data = [];

  // TODO: The TRUE param should be made configurable when writing a drush
  // command, so we don't rely on cached data.
  if ($available = _nagios_update_get_available(TRUE)) {
    $data = _nagios_update_calculate_project_data($available);
  }

  // Remove from the update data array the projects ignored.
  foreach ($nagios_ignored_projects as $key => $value) {
    unset($data[$key]);
  }

  // Cycle through enabled modules for requirements checks.
  $reqs = [];
  $module_data = [];
  foreach ($enabled_modules as $module_name_outer) {
    $requirements_data = module_invoke($module_name_outer, 'requirements', 'runtime');

    /** @noinspection UnnecessaryEmptinessCheckInspection */
    if (is_array($requirements_data) && count($requirements_data)) {

      // Intercept the Update Status module to respect our Ignore behaviour.
      // Note, if $data is empty then there's no available update data and Update Status will handle that for us.
      if ($module_name_outer == 'update' && !empty($data)) {

        // Don't want the 'update_contrib' section reported by 'update' module,
        // because that one contains *ALL* modules, even the ones ignored by
        // nagios module.
        unset($requirements_data['update_contrib']);

        // Now we need to loop through all modules again to reset 'update_contrib'.
        foreach ($enabled_modules as $module_name) {

          // Double check we're not processing a core module.
          if (!array_key_exists($module_name, $project_data['drupal']['includes'])) {

            // If the module is a sub-module (eg views_ui) then we need to set the status key.
            // Without this,  _update_requirement_check() will return severity = 2.
            if (isset($data[$module_name]['status']) && is_numeric($data[$module_name]['status'])) {

              // Within this clause, only contrib modules are processed. Get update
              // status for the current one, and store data as it would be left
              // by update_requirements() function.
              $contrib_req = _update_requirement_check($data[$module_name], 'contrib');
              $contrib_req['name'] = $module_name;

              // If module up to date, set a severity of -1 for sorting purposes.
              if (!isset($contrib_req['severity'])) {
                $contrib_req['severity'] = -1;
              }

              // Build an array of required contrib updates.
              if ($contrib_req) {
                $module_data[] = $contrib_req;
              }
            }
          }
        }

        // Sort our finished array by severity so we can set Nagios status accordingly.
        usort($module_data, '_nagios_updates_sort_by_severity');

        // Add the 'worst case' to requirements.
        $requirements_data['update_contrib'] = array_pop($module_data);
      }
      $reqs += $requirements_data;
    }
  }

  // Check the requirements as to the most severe status
  $descriptions = [];
  $severity = REQUIREMENT_OK;
  $min_severity = variable_get('nagios_min_report_severity', NAGIOS_STATUS_WARNING);
  foreach ($reqs as $key => $requirement) {
    if (isset($requirement['severity'])) {

      // Once a day, the update_core cache expires. The update_core requirement severity is
      // then REQUIREMENT_WARNING and the reason is UPDATE_UNKNOWN. In order to avoid an unnecessary
      // nagios state change, calculate a grace time that lasts for one planned cron duration. During
      // grace time, use the requirement info from cache.
      if ($key == 'update_core' || $key == 'update_contrib') {
        $grace_time = FALSE;
        if ($requirement['severity'] == REQUIREMENT_WARNING && $requirement['reason'] == UPDATE_UNKNOWN) {
          $grace_seconds = 60 * variable_get('nagios_cron_duration', 60);
          $expire = db_query("SELECT expire FROM {cache_update} WHERE cid = :cid", [
            ':cid' => 'update_available_releases',
          ])
            ->fetchField();
          if ($expire && time() < $expire + $grace_seconds) {
            $grace_time = TRUE;
          }
        }
        if ($grace_time) {
          $requirement = cache_get('nagios_update_core_requirement');
        }
        else {
          cache_set('nagios_update_core_requirement', $requirement);
        }
      }
      if ($requirement['severity'] >= $min_severity) {
        if ($requirement['severity'] > $severity) {
          $severity = $requirement['severity'];
        }
        $descriptions[] = $requirement['title'];
      }
    }
  }
  if (empty($descriptions)) {
    $desc = t('No information.');
  }
  else {
    $desc = join(', ', $descriptions);
  }

  // Create a status to pass back, and a text description too
  switch ($severity) {
    case REQUIREMENT_OK:
    case REQUIREMENT_INFO:
      $data = [
        'status' => NAGIOS_STATUS_OK,
        'type' => 'state',
        'text' => t('No known issues at this time.'),
      ];
      break;
    case REQUIREMENT_WARNING:
      $data = [
        'status' => NAGIOS_STATUS_WARNING,
        'type' => 'state',
        'text' => t('@desc', [
          '@desc' => $desc,
        ]),
      ];
      break;
    case REQUIREMENT_ERROR:
      $data = [
        'status' => NAGIOS_STATUS_CRITICAL,
        'type' => 'state',
        'text' => t('@desc', [
          '@desc' => $desc,
        ]),
      ];
      break;
    default:
      $data = [
        'status' => NAGIOS_STATUS_UNKNOWN,
        'type' => 'state',
        'text' => t('severity is @severity', [
          '@severity' => $severity,
        ]),
      ];
      break;
  }
  return [
    'key' => 'ADMIN',
    'data' => $data,
  ];
}