Переменная Perl ASCII в десятичную с помощью . после каждой буквы

Я делаю плагин Perl для Nagios для балансировщика нагрузки F5. Мне нужно преобразовать имя пула в десятичный формат, соответствующий OID для SNMP.

my ( $PoolName )         = $ARGV[1];
my ( $rootOIDPoolStatus ) = '1.3.6.1.4.1.3375.2.2.5.5.2.1.2';

Например, $PoolName равно "/Common/Atlassian", и мне нужно преобразовать его в /.C.o.m.m.o.n./.A.t.l.a.s.s.i.a.n, а затем в 47.67.111.109.109.111.110.47.65.116.108.97.115.115.105.97.110.

Как только это будет преобразовано, они будут объединены в одну переменную.

my ( $PoolStatus ) = "$rootOIDPoolStatus.$OIDPoolName"

Я разрабатывал чужие Perl-плагины для Nagios, и это то, что делает кто-то другой, но я не мог заставить его работать, независимо от того, какие комбинации я делал. Их $name будет моим $PoolName

sub to_oid($) {
    my $oid;
    my ($name) = $_[0];
    return "" if ( ! $name );
    $oid = ( length $name ) . '.' . ( join '.', ( map { unpack 'C', $ } ( split '',$name ) ) );
    return $oid;
}

Может ли кто-нибудь помочь мне построить или понять логику Perl, чтобы преобразовать $PoolName в десятичный формат, который мне нужен для OID?


person BigD    schedule 25.10.2017    source источник
comment
Отсюда все выглядит нормально (за исключением того, что я не знаю, что делает unpack 'C',$. Вы имели в виду unpack 'C',$_? Кроме того, unpack 'C',$_ можно заменить на ord($_), а иногда просто на ord).   -  person mob    schedule 25.10.2017
comment
Этот нижний раздел был из сценария другого человека, который, как мне кажется, делает то, что я хочу сделать, но не понимаю его и не могу заставить его работать.   -  person BigD    schedule 25.10.2017
comment
sub to_oid($) должно быть просто sub to_oid. Это не вредит здесь, но это признак того, что вы смотрите на код, написанный кем-то, кто знает не лучше, чем вы! Вы уверены, что вам нужны точки . через каждый второй символ? Вполне может быть, что строка должна быть закодирована в UTF-16, а дисплей преобразовал нулевые байты в точки. У вас есть ссылка на соответствующую часть спецификации Nagios?   -  person Borodin    schedule 26.10.2017


Ответы (2)


Похоже, вы используете строку в качестве индекса для таблицы SNMP. Индекс таблицы можно рассматривать как номер строки или идентификатор строки для этой таблицы. Часто индекс таблицы представляет собой просто число, начинающееся с 1 и увеличивающееся с каждой строкой в ​​таблице. Такое число закодировано в OID как есть, т.е. если в таблице 3 столбца и две строки, то они будут иметь такие OID:

$base.1         # table
$base.1.1       # table entry
$base.1.1.1.1   # col1, row1
$base.1.1.1.2   # col1, row2
$base.1.1.2.1   # col2, row1
$base.1.1.2.2   # col2, row2
$base.1.1.3.1   # col3, row1
$base.1.1.3.2   # col3, row2
            ^---index

Иногда индекс представляет собой IP-адрес, комбинацию IP:порт или комбинацию двух IP-адресов, особенно для таблиц, связанных с IP. IP-адрес в качестве индекса будет выглядеть так:

$base.1                 # table
$base.1.1               # table entry
$base.1.1.1.1.0.0.127   # col1, row "127.0.0.1"
$base.1.1.1.0.0.0.0     # col1, row "0.0.0.0"
$base.1.1.2.1.0.0.127   # col2, row "127.0.0.1"
$base.1.1.2.0.0.0.0     # col2, row "0.0.0.0"
$base.1.1.3.1.0.0.127   # col3, row "127.0.0.1"
$base.1.1.3.0.0.0.0     # col3, row "0.0.0.0"
            ^^^^^^^---- index

Как видите, длина индекса зависит от его типа данных (существует специальный тип данных IPV4).

Иногда индекс представляет собой строку (как в вашем случае). Когда используется строка, она также должна быть каким-то образом закодирована, чтобы составить «номер строки» для таблицы. Строки в качестве индексов кодируются посимвольно и им предшествует их длина, т.е.:

$base.1                     # table
$base.1.1                   # table entry
$base.1.1.1.2.65.66         # col1, row "AB"
$base.1.1.1.3.120.121.122   # col1, row "xyz"
$base.1.1.2.2.65.66         # col2, row "AB"
$base.1.1.2.3.120.121.122   # col2, row "xyz"
$base.1.1.3.2.65.66         # col3, row "AB"
$base.1.1.3.3.120.121.122   # col3, row "xyz"
            ^^^^^^^^^^^^^---- index

Итак, «AB» становится «2.65.66», потому что length('AB')==2 и ord('A')==65, ord('B')==66. Точно так же «xyz» становится «3.120.121.122».

Ваша функция to_oid делает именно это, хотя я бы упростил ее следующим образом:

#!/usr/bin/env perl

use strict;
use warnings;

sub to_oid
{
    my $string = shift;
    return sprintf('%d.%s', length($string), join('.', unpack('C*', $string)));
}

my $rootOIDPoolStatus = '1.3.6.1.4.1.3375.2.2.5.5.2.1.2';
my $PoolName = '/Common/Atlassian';

my $poolname_oid = to_oid($PoolName);
my $complete_oid = "$rootOIDPoolStatus.$poolname_oid";

print $complete_oid, "\n";

Выход:

1.3.6.1.4.1.3375.2.2.5.5.2.1.2.17.47.67.111.109.109.111.110.47.65.116.108.97.115.115.105.97.110
|<------- rootOID ----------->|<------------ poolname_oid ----...--->|
person PerlDuck    schedule 26.10.2017
comment
Большое спасибо! Вы сделали все возможное с этим. Даже ловя мою ошибку о том, как работает длина. У меня было такое туннельное зрение, что я забыл упомянуть об этом. - person BigD; 26.10.2017
comment
Протестировал код, теперь он отлично работает в Nagios :) tyvm - person BigD; 26.10.2017

my $poolStatus = join '.', $rootOIDPoolStatus, map ord, split //, $poolName;

Не уверен, для чего в вашем коде предназначена длина(), вы не показываете ничего подобного в своем примере.

person ysth    schedule 25.10.2017
comment
Длина необходима, когда вы хотите закодировать строку в OID. - person PerlDuck; 26.10.2017
comment
Да, извините, я совершенно забыл упомянуть об этом в своем исходном посте. - person BigD; 26.10.2017
comment
@BigD означает ли это, что нужно удалить длину из $ rootOIDPoolStatus и добавить новую длину, которая учитывает как части статуса, так и части имени? - person ysth; 26.10.2017
comment
@ysth $rootOIDPoolStatus никогда не имел такой длины, поскольку она вычислялась при преобразовании $PoolName. Длина всегда будет меняться, а корень останется неизменным. PerlDuck отвечает на этот вопрос правильным решением, которое мне нужно. Спасибо за ваш вклад! - person BigD; 26.10.2017