Ad Widget

Collapse

Подскажите, можно ли отключить для элемента данных проверку на "поддерживаемость"?

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • BashkirovVM
    Junior Member
    • Jun 2011
    • 14

    #1

    Подскажите, можно ли отключить для элемента данных проверку на "поддерживаемость"?

    Предистория. Есть радиооборудование, которое опрашивается по SNMP. Положительный результат запроса приходит только при наличии зарегистрированного клиента или канала. При отсутствии регистрации (выключили клиента, плохие условия приема и т.п.) приходит ответ что запрос не поддерживается и zabbix помечает "Элемент данных" как "Неподдерживаемый" и следующий рас его опросит уже по времени из глобальных настроек. Можно сделать так, что бы опрос велся в любом случае по графику из настроек "Элемента данных"?
  • Semiadmin
    Senior Member
    • Oct 2014
    • 1625

    #2
    Вариант решения для версии 3.4. Делаете тип вашего айтема text или character. Для него делаете зависимый айтем числового типа с регуляркой в препроцессинге, извлекающей число, если основной айтем его получает. Т.о., основной айтем никогда не станет неподдерживаемым, т.к. он текстовый и не обидится на сообщение об ошибке. Зависимый в этом случае будет становиться неподдерживаемым, но будет восстанавливаться сразу при получении основным числа, а не по времени из глобальных настроек.

    Comment

    • Jimson
      Senior Member
      • Jan 2008
      • 1327

      #3
      Это не решение, от слова совсем. Надо учитывать что
      1) ваш зависимый элемент данных не будет возвращать "тоже значение" для COUNTER, и как следствие элемент данных delta не упадет в ноль, а превратится в тыкву
      2) интервалы "восстановления" неподдерживаемых элементов данных снижать до нескольких минут нельзя, если общее число собираемых данных достаточно велико, а восстановление через 15 минут элементов данных для описываемой ситуации никого не устроит

      По вопросу автора. Есть две ситуации когда элемент данных может стать недоступен, вы не указали какая у вас
      1) SNMP OID пропадают из snmp агента, при опросе он вернет что "такой OID не найден". Это самая сложная ситуация, решить ее средствами zabbix невозможно в принципе, придется сдорово переписывать SNMP пуллер. Я решаю это ситуацию с помощью проксирования snmp. Поднимается snmpd (net-snmp), в конфигурации прописываются что и откуда проксировать, затем пишем небольшой скрипт, который цепляется к этой проксе как agentx, и этот скрипт подменяет поведение snmp агента для определенных OID

      2) Агент дает ошибку, или просто не отвечает. Это так же происходит если оборудование занято чем то другим и просто скипает обработку входящих snmp запросов. Это можно решить, например, вот так.

      P.S. пример agentx
      Code:
      #!/usr/bin/perl
      
      use feature 'switch';
      use strict;
      use warnings;
      use Getopt::Long qw( :config no_posix_default no_ignore_case bundling_override require_order );
      use POSIX qw( setsid );
      use Unix::Syslog qw( :subs :macros );
      use NetSNMP::OID;
      use NetSNMP::agent;
      use NetSNMP::ASN qw( ASN_COUNTER );
      use NetSNMP::default_store (':all');
      use NetSNMP::agent::default_store;
      use SNMP;
      
      $SNMP::auto_init_mib = 0;
      $SNMP::use_long_names = 1;
      $SNMP::use_numeric = 1;
      
      netsnmp_ds_set_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_MIBDIRS, '/');
      netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_READ_CONFIGS, 1);
      netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1);
      netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_SNMPVERSION, 129);
      netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1);
      
      my $agent = undef;
      my $running = 1;
      
      sub shutdown ();
      sub daemonize ();
      sub syserrors (;$);
      sub setstate ($$;@);
      sub usage (;$@);
      
      # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      my %opt = (
          ident           => 'agentx-fake-counter',
          pidfile         => '/var/run/agentx-fake-counter.pid',
          master          => '/var/agentx/master',
          nmsHost         => '172.17.11.1',
          nmsCommunity    => 'public'
      );
      
      GetOptions(
          \%opt,
          'ident|n=s',
          'pidfile|p=s',
          'master|m=s',
          'oid|o=s',
          'host|h=s',
          'community|c=s',
          'debug|d'
      ) or usage();
      
      daemonize() unless $opt{debug};
      
      my $rootOID = new NetSNMP::OID($opt{oid}) || usage "Can't parse OID:%s", $opt{oid};
      my %cache = ();
      
      syslog LOG_INFO, "Start OID %s host %s", $rootOID, $opt{host};
      setstate $rootOID, "";
      
      $SIG{'INT'}  = \&shutdown;
      $SIG{'QUIT'} = \&shutdown;
      $SIG{'TERM'} = \&shutdown;
      
      netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET, $opt{master});
      
      $agent = new NetSNMP::agent('Name' => $opt{ident}, 'AgentX' => 1);
      $agent->register($opt{ident}, $rootOID, \&agentxHandler);
      NetSNMP::agent::snmp_enable_syslog_ident($opt{ident}, LOG_LOCAL0) unless $opt{debug};
      
      my $counter = 0;
      while ($running) {
          $agent->agent_check_and_process(1);
          setstate $rootOID, "processed %u requests", $counter;
      }
      $agent->shutdown();
      unlink $opt{pidfile};
      # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      
      
      ############################################################################################
      # function agentxHandler()
      #   parameters:
      #               $handler
      #               $registration_info  object
      #               $request_info       object
      #               $requests           object
      #   return
      #               none
      #
      #   The handler subroutine will be called when a SNMP request received by
      # the agent for anything below the registered OID.
      #
      sub agentxHandler {
          my ($handler, $registration_info, $request_info, $requests) = @_;
          my ($request, $oid, $index, $sess, $vb, $value) = ();
          for ( $request = $requests; $request; $request = $request->next() ) {
              $oid = $request->getOID();
              $index = ($oid->to_array())[$oid->length() - 1] if $oid > $rootOID;
              if ( defined $index and $rootOID + $index == $oid or $rootOID == $oid ) {
                  $sess = new SNMP::Session(
                      DestHost        => $opt{host},
                      Community       => $opt{community},
                      Version         => 2,
                      Retries         => 0,
                      Timeout         => 1000000
                  );
                  $vb = new SNMP::Varbind([$rootOID, $index]);
                  if ( $request_info->getMode() == MODE_GET ) {
                      $value = $sess->get($vb);
                      if ( $sess->{ErrorNum} or $vb->type =~ /^NOSUCH/i ) {
                          if ( exists $cache{$oid} ) {
                              $request->setValue(ASN_COUNTER, $cache{$oid});
                          } elsif ( $sess->{ErrorNum} ) {
                              $request->setError($request_info, SNMP_ERR_GENERR);
                          }
                          next;
                      }
                  } elsif ( $request_info->getMode() == MODE_GETNEXT ) {
                      $value = $sess->getnext($vb);
                      next if $sess->{ErrorNum} or $vb->type =~ /^NOSUCH/i;
                      $oid = new NetSNMP::OID( $vb->name );
                      next unless $rootOID + ($oid->to_array())[$oid->length() - 1] == $oid or $rootOID == $oid;
                      $request->setOID($oid);
                  }
                  $cache{$oid} = $value;
                  $request->setValue(ASN_COUNTER, $value);
              } else {
                  $request->setError($request_info, SNMP_ERR_NOSUCHNAME);
                  syslog LOG_ERR, "Bad request OID:%s", $oid;
              }
              $counter++;
          }
      }
      
      ############################################################################################
      # function shutdown()
      #   parameters: none
      #   return:     none
      #
      sub shutdown () {
          $running = 0;
          syslog LOG_WARNING, "Got signal. Exiting.";
      }
      
      ############################################################################################
      # function daemonize()
      #   parameters: none
      #   return:     none
      #
      $SIG{CHLD} = 'IGNORE';
      sub daemonize () {
          chdir '/' or usage "Can't chdir to /: $!";
          open(STDIN, '/dev/null') or usage "Can't read /dev/null: $!";
          open(STDOUT, '>> /dev/null') or usage "Can't write to /dev/null: $!";
          defined(my $pid = fork) or usage "Can't fork: $!";
          if ($pid) {
              # parent
              open(PID, "> $opt{pidfile}") or usage "Couldn't open %s for writing: $!", $opt{pidfile};
              print PID "$pid\n" or usage "Couldn't write pid to %s: $!", $opt{pidfile};
              close(PID) or usage "Couldn't close %s: $!", $opt{pidfile};
              exit;
          }
          # child
          setsid() or usage "can't start a new session: $!";
          close(STDIN) or usage "Can't close STDIN: $!";
          close(STDOUT) or usage "Can't close STDOUT: $!";
          close(STDERR) or usage "Can't close STDERR: $!";
          openlog $opt{ident}, LOG_PID, LOG_LOCAL0;
      }
      
      sub setstate ($$;@) {
          $0 = sprintf("%s: %s [%s]", $opt{ident}, shift, sprintf(shift, @_));
      }
      
      sub usage (;$@) {
          my ($msg, @params) = @_;
          print STDERR sprintf($msg, @params) . "\n" if $msg;
          print STDERR "Who are you? Goodbye!\n";
          exit 1;
      }
      Я бы переписал это, для начала не стоит использовать NetSNMP для запроса значения с snmp агента, реализация модуля очень кривая, приходится в частности пересоздавать объект/сокет на каждый запрос, иначе это поделие тупо виснет в недрах net-snmp, возможно стоит просто использовать Net::SNMP, а от NetSNMP использовать только реализацию agentx.

      Comment

      • Semiadmin
        Senior Member
        • Oct 2014
        • 1625

        #4
        Originally posted by Jimson
        Это не решение, от слова совсем. Надо учитывать что
        1) ваш зависимый элемент данных не будет возвращать "тоже значение" для COUNTER, и как следствие элемент данных delta не упадет в ноль, а превратится в тыкву
        2) интервалы "восстановления" неподдерживаемых элементов данных снижать до нескольких минут нельзя, если общее число собираемых данных достаточно велико, а восстановление через 15 минут элементов данных для описываемой ситуации никого не устроит
        Преобразования типа simple change или change per second в условиях задачи не обсуждались, но ваша идея насчет тыквы заинтриговала. Проверил, превращения не получилось. Кстати, регулярку в препроцессинг можно не ставить, и без нее работает.
        Что касается изменения глобальной настройки Refresh unsupported items, то никто этого и не предлагал. На зависимые айтемы она не влияет.

        Comment

        • Jimson
          Senior Member
          • Jan 2008
          • 1327

          #5
          В unsupported у вас уйдет элемент данных типа SNMP, именно об этом был задан вопрос, и этот элемент данных у вас будет основным.
          Я без понятия что вы проверяли, но как то слабо верится что зависимый элемент данных в ситуации когда основной ушел в unsupported, продолжит вычисляться и что то сохранять в бд.
          И это уже не говоря о том что в ситуации когда SNMP данные по какой то причине отсутствуют (я писал об этом несколько лет назад в теме на которую сослался выше) может требоваться совершенно разная реакция, например, если это уровни сигналов то вероятнее я захочу сохранять что то вроде -10 dB, в не получать "разрыв графика" на 15/30/45/etc минут. Есть и более "странные", с точки зрения реализации, snmp агенты, как пример местоположении (gps) ушедшего в оффлайн устройства snmp agent центрального узла может вернуть "нулевое", и в такой ситуации у zabbix просто не существует механизма верификации, в базу запишутся нули. По идее препроцессинг должен решить эти проблемы, но пока там недостаточно функционала.

          Comment

          • Semiadmin
            Senior Member
            • Oct 2014
            • 1625

            #6
            Видимо, мы с вами по-разному смотрим на задачу. Я вижу задачу так, как она сформулирована: есть некий собираемый с заданным интервалом айтем, который иногда вместо числа получает текст в виде сообщения об ошибке. Надо сделать так, чтобы, став неподдерживаемым, он восстановился раньше времени, указанного в Refresh unsupported items. Неважно, SNMP это, Zabbix agent или ODBC. Вы же рассказываете о разнообразных проблемах SNMP мониторинга.

            Comment

            • Jimson
              Senior Member
              • Jan 2008
              • 1327

              #7
              Originally posted by Semiadmin
              Я вижу задачу так, как она сформулирована: есть некий собираемый с заданным интервалом айтем, который иногда вместо числа получает текст в виде сообщения об ошибке.
              Нет никакого "текста". Речь идет про штатное поведение SNMP агента, которое обязан обработать код пулера, и он это делает, результатом будет перевод элемента данных zabbix в состояние unsupported, и не важно какой тип данных выбран для вашего SNMP элемента данных.
              Смотрите код в src/zabbix_server/poller/checks_snmp.c

              Comment

              • Semiadmin
                Senior Member
                • Oct 2014
                • 1625

                #8
                да, вы правы, для snmp трюк не пройдет, нужен внешний скрипт.

                Comment

                Working...