Child pages
  • Обновление полей name, snmp_ro, object_profiles в МО с использованием snmp ( bash, snmp ) (добавлен код для микросвервисов)
Skip to end of metadata
Go to start of metadata

Типичная ситуация которая возникает при запуске в эксплуатацию NOC - первичная настройка ПРАВИЛЬНЫХ профилей оборудования, snmp_ro, name полей объектов МО, а так же её актуализация в процессе эксплуатации сети.

Я не умею программировать, поэтому задачу решал "в лоб" с использованием подручных инструментов:

  1. nmap
  2. snmp-get (есть во всех дистрибутивах unix)
  3. psql (для прямой работы с БД )

Алгоритм действий такой:

  1. получаем из БД для всех IP параметры для объектов:
    1. name
    2. profile_name
    3. address
    4. snmp_ro
  2. передаём из скрипту snmp.sh который производит опрос оборудования (при необходимости производится попытка подбора snmp_ro комьюнити из файла) и формирует .sql файл для обновления БД
  3. если оборудование не ответило на snmp запрос - передаём управление rescan.sh, который пытается включить его на оборудовании с помощью setupsnmp.sh
  4. применяем в БД полученные .sql файлы с результатами работы скриптов.

После работы скриптов у нас получатся файлы  out.snmpscan.sql    и   out.snmpscanrescan.sql  с подобным содержимым:

sql result

UPDATE sa_managedobject SET name='pe-dfff20150225-286863540' where address = '192.168.101.5' and name not like 'wiping-%';

UPDATE sa_managedobject SET profile_name='Juniper.JUNOS',snmp_ro=(E'public') where address = '192.168.101.5' and name not like 'wiping-%';

ВНИМАНИЕ!

Поле name  имеет признак УНИКАЛЬНОСТИ а поле address нет. Поэтому чтобы застраховаться от ситуации когда hostname не уникален, а настройки snmp и профиля обновлялись.

 

 

  1. в переменной BASEDIR - путь где выполняется скрипт

 

Файлы:

  1. cron.sh
  2. snmp.sh - файл в котором происходит опрос по snmp объекта МО и формируется .sql файл для обновления БД
  3. rescan.sh - файл с повторным опросом оборудования после работы setupsnmp.sh
  4. setupsnmp.sh - файл с инструкциями для expat для "принудительной" настройки оборудования на включение snmp
  5. community.txt - текстовый файл с возможными snmp_ro комьюнити для подбора

 

cron.sh

#!/bin/bash

export LANG="ru_RU.UTF-8"

export LOCALE="ru_RU"

 

BASEDIR=/opt/scripts/snmp.update

 

rm $BASEDIR/out.*.txt $BASEDIR/out.*.sql $BASEDIR/out.*.log

 

# получить из БД hostname ip profile_name snmp_ro для которых стоит признак что управляется вывести в файл

    SQLQUERY="SELECT name,profile_name,address,snmp_ro from sa_managedobject where is_managed = TRUE and name not like 'wiping-%' and name not like 'SAE' order by address; "

    SQLRESULT=`echo $SQLQUERY | psql -U noc --dbname noc -X -A -t -q -F"     " --single-transaction --no-align -o $BASEDIR/out.hostsscan.txt`.

 

# прочитать построчно и получить актуальный список настроек.

while read -r line

do

    name=`echo $line | awk '{print $1}'`

    profile_name=`echo $line | awk '{print $2}'`

    address=`echo $line | awk '{print $3}'`

    snmp_ro=`echo $line | awk '{print $4}'`

    snmp_rw=`echo $line | awk '{print $5}'`

    

# полученные данные передаём в скрипт который уже опрашивает железку по snmp и выводит в файл результат с обновлённых name profile_name

    $BASEDIR/snmp.sh $name $profile_name $address $snmp_ro  &

done < $BASEDIR/out.hostsscan.txt

 

# обновляем БД полученным файлом out.snmpscan.sql где snmp отработал нормально

    sleep 120

    psql -U noc --dbname noc -X -A -t -e -a --no-align -f $BASEDIR/out.snmpscan.sql -o $BASEDIR/out.snmpupdatedb.txt  -L $BASEDIR/out.snmpupdatedb.log

 

# построчно читаем файл badsnmphost.txt со списком хостов для которых snmp было недоступно и для которых работал setupsnmp.sh

# файл out.snmpscan.txt очищаем для повторного использования

 

rm $BASEDIR/out.snmpscan.txt

#  $BASEDIR/out.snmpscan.sql

 

while read -r line

do

    name=`echo $line | awk '{print $1}'`

    profile_name=`echo $line | awk '{print $2}'`

    address=`echo $line | awk '{print $3}'`

    snmp_ro=`echo $line | awk '{print $4}'`

    snmp_rw=`echo $line | awk '{print $5}'`

    

    # запускает в отдельном потоке процесс попытки настроить snmp и повторного рескана    

    $BASEDIR/rescan.sh $name $profile_name $address $snmp_ro &

    sleep 1    

done < $BASEDIR/out.badsnmphost.txt

 

# обновляем БД полученным файлом out.snmpscan.sql где snmp был опрошен ПОВТОРНО

    sleep 120

    psql -U noc --dbname noc -X -A -t -e -a --no-align -f $BASEDIR/out.snmpscanrescan.sql -o $BASEDIR/out.snmpupdatebad.txt -L $BASEDIR/out.snmpupdatebad.log

 

# echo -e $SQLRESULT "\n"

 

 

rescan.sh

#!/bin/bash

 

export LANG="ru_RU.UTF-8"

export LOCALE="ru_RU"

 

BASEDIR=/opt/scripts/snmp.update

 

name=$1

profile_name=$2

address=$3

snmp_ro=$4

snmp_rw=$5

rescan=$6

 

# полученные данные передаём в скрипт который пытается настроить там snmp

$BASEDIR/setupsnmp.sh $address

 

# повторно сканируем хост на доступность. при этом формируется новый файл.

$BASEDIR/snmp.sh $name $profile_name $address $snmp_ro rescan

Ubuntu snmp

Для корректной работы в ubuntu определения hostname необходимо добавлять параметр   -m SNMPv2-MIB  к строке запроса. В противном случае будет возвращаться хостнем в кавычка: "hostnmane" а не hostname

snmp.sh

#!/bin/bash

 

# скрипт принимает в качестве параметров ip snmp_ro и проверяет хост на данные.

# возвращает hostname ip profile_name

 

 

export LANG="ru_RU.UTF-8"

export LOCALE="ru_RU"

 

BASEDIR=/opt/scripts/snmp.update

 

name=$1

profile_name=$2

address=$3

snmp_ro=$4

rescan=$5

 

# проверяем тип найденного оборудования. делаем это с использованием snmp

# /usr/bin/snmpget -v 2c -Oqv -c rhjkbr 10.64.69.240 .1.3.6.1.2.1.1.1.0

# platformtype .1.3.6.1.2.1.1.1.0

# hostname     .1.3.6.1.2.1.1.5.0

snmpcheck="/usr/bin/snmpget -m SNMPv2-MIB -t 1 -v 2c -Oqv -c $snmp_ro $address .1.3.6.1.2.1.1.5.0"

snmpcheckresult=`$snmpcheck`

RETVAL=$?

 

            hostname=`echo $snmpcheckresult | head -n 1 `

            echo "hostname :" $hostname

 

            if [ $RETVAL -eq 0 -a -z "$hostname" ]

        then

         hostname="random-snmp-"`/bin/date +\%Y\%m\%d-\%N`

         echo $hostname

        fi

 

# проверяем наличие в имени пробелов. если есть - формируем список таких

pattern=" "

if [[ $hostname =~ $pattern ]];then

    echo $address ":" $hostname >> out.hostname.space.txt  

fi

 

echo "проверка хостнейма" $RETVAL

 

    # выводим RAW данные для последующего анализа формрования условий.

    echo $snmpcheckresult >> $BASEDIR/out.snmp-resultscan.txt

    # подготавливаем данные для анализа условий.    

 

# проверяем чем закончилось. если результат нулевой - значит snmp_ro неверное и\или какая то другая фигня. поэтому пытаемся

# подобрать snmp_ro через набор стандартных комьюнити.    

if [ $RETVAL -ne 0 ]

then

  # кусок который пробует долбиться с разными snmp_ro если не прокатило то что есть в БД

  # public jwtyysqvt[ и другие стандартные для алкателей и тд

  while read -r line

  do

#    echo $line

    snmp_ro_file=$line

    echo $snmp_ro_file

    snmpcheck="/usr/bin/snmpget -m SNMPv2-MIB  -t 1 -v 2c -Oqv -c $snmp_ro_file $address .1.3.6.1.2.1.1.5.0"

    snmpcheckresult=`$snmpcheck`

    RETVAL=$?

    echo $snmpcheckresult >> $BASEDIR/out.snmp-resultscan.txt

    

    echo "brute force snmp_ro:" $snmp_ro_file $RETVAL

    if [ $RETVAL -eq 0 ]

        then

            # мы нашли комьюнити на который железка отзывается и можно дальше не перебирать

            # присваиваем его переменной и продолжаем сканить

 

            hostname=`echo $snmpcheckresult | head -n 1`

            echo "hostname :" $hostname

 

            if [ -z "$hostname" ]

        then

         hostname="random-"`/bin/date +\%Y\%m\%d-\%N`

         echo $hostname

        fi

 

        snmp_ro=$snmp_ro_file

        # проверяем наличие в имени пробелов. если есть - формируем список таких

        pattern=" "

        if [[ $hostname =~ $pattern ]]; then

        echo $address ":" $hostname >> out.hostname.space.txt  

        fi

 

         break

    fi

  done < $BASEDIR/community.txt

fi

 

# Если хост доступен по snmp значит продолжаем проверять на нём данные

# Получаем по snmp hosttype

 

echo "проверка платформы" $RETVAL

if [ $RETVAL -eq 0 ]

    then

        # check sysLocation

    snmpcheck="/usr/bin/snmpget -t 2 -v 2c -Oqv -c $snmp_ro $address .1.3.6.1.2.1.1.6.0"

    snmpcheckresult=`$snmpcheck`

    echo $snmpcheckresult >> $BASEDIR/out.snmp-resultscan.syslocation.txt

                

        

        #echo -e "check hosttype"

    snmpcheck="/usr/bin/snmpget -t 2 -v 2c -Oqv -c $snmp_ro $address .1.3.6.1.2.1.1.1.0"

    snmpcheckresult=`$snmpcheck | head -n 1`

    # | awk '{print $1}'`

    echo $snmpcheckresult >> $BASEDIR/out.snmp-resultscan.hosttype.txt

    ### вывод в файл пары snmp  + IP

        echo -e $address "\t" $snmpcheckresult  >> $BASEDIR/out.ip-snmp.txt

    echo $snmpcheckresult

 

    # определяем тип оборудования.

    # Cisco

    foo=`echo -e $snmpcheckresult | grep Cisco`

    if [ -n "$foo" ]

        then

#        echo $foo

#        echo -e "found Juniper host"

        profile_name="Cisco.IOS"

        #object_profile="juniper.OS"

    fi

    # Juniper

    foo=`echo -e $snmpcheckresult | grep Juniper`

    if [ -n "$foo" ]

        then

#        echo $foo

#        echo -e "found Juniper host"

        profile_name="Juniper.JUNOS"

        #object_profile="juniper.OS"

    fi

    # huawei

    foo=`echo -e $snmpcheckresult | grep -E ^S[09]{4}`

    if [ -n "$foo" ]

        then

#        echo -e "found Huawei host"

        profile_name="Huawei.VRP"

        #object_profile="huawei.fttb"

    fi

    # qtech

    foo=`echo -e $snmpcheckresult | grep "QSW-"`

    if [ -n "$foo"  ]

        then

#        echo -e "found Qtech host"

        profile_name="Qtech.QSW2800"

        #object_profile="qtech.fttb"

    fi

    # edgecore

    foo=`echo -e $snmpcheckresult | grep Edge-Core`

    if [ -n "$foo" ]

        then

#        echo -e "found edgecore host"

        profile_name="EdgeCore.ES"

        #object_profile="edgecore.fttb"

    fi

    # dlink

    foo=`echo -e $snmpcheckresult | grep -E "^D-Link|^DES-`

    if [ -n "$foo" ]

        then

#        echo -e "found DLink.DxS host"

        profile_name="DLink.DxS"

        #object_profile="sar.corp.all"

    fi

    # eltex

    foo=`echo -e $snmpcheckresult | grep eltex`

    if [ -n "$foo"  ]

        then

#        echo -e "found eltex host"

        profile_name="eltex.OS"

        #profile_name="Generic.Host"

    fi

    foo=`echo -e $snmpcheckresult | grep ASAM`

    if [ -n "$foo" ]

        then

    #    echo -e "found Alcatel DSLAM host"

        profile_name="Alcatel.7302"

    #    name=$address

    fi

    foo=`echo -e $snmpcheckresult | grep 7324`

    if [ -n "$foo" ]

        then

    #    echo -e "found Alcatel DSLAM host"

        profile_name="Alcatel.7324RU"

    #    name=$address

    fi

    

 

    foo=`echo -e $snmpcheckresult | grep -E "ES-2310C|16-Port|8-Port|^8"`

    if [ -n "$foo" ]

        then

#        echo -e "found Rubytech host"

        profile_name="Rubytech.l2ms"

        #="rubytech"

    fi

 

    foo=`echo -e $snmpcheckresult | grep "ROS"`

    if [ -n "$foo" ]

        then

#        echo -e "found raisecom host"

        profile_name="Raisecom.ROS"

        #="rubytech"

    fi

    # ZyXEL

    #ZyXEL IES-1000 AAM1008-61 version V2.05(DN.2)C0 (May 24 2005)

    #Copyright (c) 2005 ZyXEL Communications Corp.

    foo=`echo -e $snmpcheckresult | grep "ZyXEL"`

    if [ -n "$foo" ]

        then

#        echo -e "found Zyxel host"

        profile_name="Zyxel.ZyNOS"

    fi

 

    foo=`echo -e $snmpcheckresult | grep "Sprinter"`

    if [ -n "$foo" ]

        then

#        echo -e "found Sprinter host"

        profile_name="Generic.Host"

    fi

    # Nateks Networks Co.Ltd Internetwork Operating System Software

    foo=`echo -e $snmpcheckresult | grep "Nateks"`

    if [ -n "$foo" ]

        then

#        echo -e "found Nateks host"

        profile_name="Nateks.flexgain"

    fi

    # iPlex OS 5.6 Tue Jan 31 12:02:31 2012

    foo=`echo -e $snmpcheckresult | grep "iPlex"`

    if [ -n "$foo" ]

        then

#        echo -e "found iPlex host"

        profile_name="Generic.Host"

        

    fi

    foo=`echo -e $snmpcheckresult | grep -E "SunOS|Linux"`

    if [ -n "$foo" ]

        then

#        echo -e "found Solaris-Linux host"

        profile_name="OS.Linux"

        

    fi

    foo=`echo -e $snmpcheckresult | grep "MM-104M1-4ES-4E1-T-UPR"`

    if [ -n "$foo" ]

        then

#        echo -e "found Zelax host"

        profile_name="Generic.Host"

        

    fi

    foo=`echo -e $snmpcheckresult | grep "Xerox"`

    if [ -n "$foo" ]

        then

#        echo -e "found Xerox printer host"

        profile_name="Generic.Host"

        

    fi

    # включённый по дефолту natex

    foo=`echo -e $snmpcheckresult | grep "10000000"`

    if [ -n "$foo" ]

        then

#        echo -e "found NATEX printer host"

        profile_name="Nateks.flexgain"

        

    fi

    foo=`echo -e $snmpcheckresult | grep "Appear"`

    if [ -n "$foo" ]

        then

#        echo -e "found Appear TV  host"

        profile_name="Generic.Host"

    fi

# dslam huawei 5300 ?

    foo=`echo -e $snmpcheckresult | grep "MA5300"`

    if [ -n "$foo" ]

        then

#        echo -e "fou"

        profile_name="Huawei.MA5300"

    fi

    foo=`echo -e $snmpcheckresult | grep "MA5600"`

    if [ -n "$foo" ]

        then

#        echo -e "fou"

        profile_name="Huawei.MA5600"

    fi

 

### вывод в файл пары snmp  + IP

snmpcheckresult=`$snmpcheck | head -n 1 | awk '{print $1}'`

echo -e $address "\t" $snmpcheckresult  >> $BASEDIR/out.ip-snmp.txt


# Если имя PE-xxxx и IP 10.64.xx.xx то имя необходимо изменить на рандомное чтобы была уникальность в бд. Добавлять надо. потому что

# snmp trap\syslog может идти откуда угодно.

#  -a в условии работать как AND   

#  ${hostname:0:3}  - отрезает с начала переменной с 0 позиции три знака

 

    if  [ "${hostname:0:3}" = "pe-" -a  "${address:0:6}" == "10.64." ]

        then

        echo ${hostname:0:3}  ${address:0:6}

        hostname="$hostname-"`/bin/date +\%Y\%m\%d-\%N`

        echo $hostname

        else

        # проверяем на BGW

        if [ "${hostname:0:3}" = "bgw" -a  "${address:0:6}" == "10.64." ]

            then

            echo ${hostname:0:3}  ${address:0:6}

            hostname="$hostname-"`/bin/date +\%Y\%m\%d-\%N`

            echo $hostname

        fi

    fi

 

 

# возвращаем результат

    if [ "$rescan" = "rescan" ]

        then

         echo -e $hostname "\t" $profile_name "\t" $address "\t" $snmp_ro "\t" $snmp_rw  >> $BASEDIR/out.snmpscanrescan.txt

             echo -e "UPDATE sa_managedobject SET name='$hostname'  where address = '$address' and name not like 'wiping-%';" >> $BASEDIR/out.snmpscanrescan.sql

             echo -e "UPDATE sa_managedobject SET profile_name='$profile_name',snmp_ro=(E'$snmp_ro') where address = '$address' and name not like 'wiping-%';" >> $BASEDIR/out.snmpscanrescan.sql

    

        else

         echo -e $hostname "\t" $profile_name "\t" $address "\t" $snmp_ro "\t" $snmp_rw  >> $BASEDIR/out.snmpscan.txt

             echo -e "UPDATE sa_managedobject SET name='$hostname' where address = '$address' and name not like 'wiping-%';" >> $BASEDIR/out.snmpscan.sql

             echo -e "UPDATE sa_managedobject SET profile_name='$profile_name',snmp_ro=(E'$snmp_ro') where address = '$address' and name not like 'wiping-%';" >> $BASEDIR/out.snmpscan.sql

        fi

 

 

    else

    # snmp недоступно, выводим список неработающих хостов а файл

    #echo -e $rescan "\n dfsdfsdfs"

        if [ "$rescan" = "rescan" ]

        then

        echo -e $name "\t" $profile_name "\t" $address "\t" $snmp_ro "\t" $snmp_rw  >> $BASEDIR/out.badsnmphostrescan.txt

        

        else

        echo -e $name "\t" $profile_name "\t" $address "\t" $snmp_ro "\t" $snmp_rw  >> $BASEDIR/out.badsnmphost.txt

        fi

    exit

fi

echo "-----------------------------------"

 

Скрипт который пытается через телнет сконфигурировать snmp на оборудовании через telnet

setupsnmp.sh

#!/usr/bin/expect -f

# ftp-rfc <ip-addr>

# makes a telnet connection to ip-addr

exp_version -exit 5.0

if {$argc!=1} {

        send_user "usage: qtech_file.exp \[ip-addr]\n"

                exit

                }

                

                set prompt "(#|:|>$)"               ;# default prompt

                #set timeout 60

                set timeout 2

                

                spawn telnet $argv

                expect -re "login:$"

                send "admin\r"

                expect -re "Password:$"

                send "admin\r"

                expect -re ".*#$"

 

# huawei

sleep 2

send "sys\r"

sleep 2

send "snmp-agent community read cipher public"

sleep 2

send "snmp-agent sys-info version v2c\r"

#sleep 2

#send "exit\r"

sleep 2

# qtech

send "conf\r"

sleep 2

send "logging 192.168.0.1\r"

sleep 2

send "snmp-server enable\r"

sleep 2

send "snmp-server securityip disable\r"

sleep 2

send "snmp-server community rw 0 \r"

sleep 2

send "snmp-server enable traps\r"

sleep 2

send "exit\r"

# EC

send "configure\r"

sleep 2

send "logging host 192.168.0.1\r"

sleep 1

send "logging on\r"

sleep 1

send "snmp-server enable traps\r"

sleep 1

send "snmp-server community qvt\[ rw\r"

sleep 1

send "end\r"

# rubytech

send "snmp"

sleep 2

send "enable snmp"

sleep 2

send "exit"

sleep 2

send "save start"

# nateks

#create snmp comm community public

#create snmp host ip 192.168.0.1 community public

#commit

 

                send "exit\r"

 

                expect -re "Connection closed by foreign host\."

                #expect eof

                close

1 Comment

  1. Unknown User (e_zombie)

    m-name.py

    # -*- coding: utf-8 -*-
    ##----------------------------------------------------------------------
    ## discovery commands
    ##----------------------------------------------------------------------
    ## Copyright (C) 2007-2016 The NOC Project
    ## See LICENSE for details
    ##----------------------------------------------------------------------
    '''
    Скрипт проверяет доступность по snmp и получает значение имени через snmp.
    Если имя не удалось сохранить в базе то ему добавляется адрес после имени
    это обеспечивает уникальность имени в бд.
    '''
    ## Обновление имени оборудования черезе SNMP
    import re
    import commands
    from django.db.models import Q
    from noc.inv.models import *
    from noc.sa.models import *
    from noc.sa.models.managedobjectprofile import *
    from noc.sa.models.managedobject import ManagedObject
    from noc.sa.models.managedobject import AdministrativeDomain
    from noc.sa.models.managedobjectprofile import ManagedObjectProfile

    # exlude "staticip" group with clients
    staticob = ManagedObjectProfile.objects.get(name='staticip')


    ob = ManagedObjectProfile.objects.get(name='ec.fttb')
    #adm = AdministrativeDomain.objects.get(name='saratov')
    host = 'test.host.local'
    #mo = ManagedObject.objects.filter(name=host)
    #mo = ManagedObject.objects.filter(object_profile=ob)
    #mo = ManagedObject.objects.filter(administrative_domain=adm,object_profile=ob)
    #mo = ManagedObject.objects.filter(administrative_domain=adm)
    mo = ManagedObject.objects.filter().exclude(Q(object_profile=staticob) | Q(object_profile=ob))
    for m in mo:
        print m.name, m.address, m.profile_name, m.snmp_ro
        if m.snmp_ro == "rhjkbrb'njytnjkmrjwtyysqvt[":
            m.snmp_ro = "rhjkbrb\\'njytnjkmrjwtyysqvt\["
        
    #    snmpro = m.snmp_ro
        if m.snmp_ro is not None and m.profile_name != 'staticip':
            cmd = "/usr/bin/snmpget -t 2 -r 1 -v 2c -Oqv -c "+ m.snmp_ro + " "+ m.address + " .1.3.6.1.2.1.1.5.0 "
            snmpname = commands.getoutput(cmd)
    #        print cmd
            print snmpname
    #        print snmpname[-4:-1]
            # некоторое оборудование возвращает пустой хостнейм для этого прописываем ему IP в имя
            if snmpname == '':
                snmpname = m.address
            # отрезаем ".san.ru" если оно приехало в ответе SNMPv2-MIB::sysName.0
            if snmpname[-7:] == ".san.ru":
                snmpname = snmpname[:-7]
            
                 
            if  not ( snmpname[:7]=='Timeout' or snmpname[:14]=='No Such Object') and snmpname != m.name  :
                print "SNMP name: " , snmpname , "BD name: ", m.name
                # если железка -AR1 -BPE1 -CR1 и тд. бывшие PE
                if (snmpname[-4:-1]=='-AR' or snmpname[-4:-1]=='-CR' or snmpname[-5:-1]=='-BPE') and m.address[:5]=='10.00':
                    snmpname = snmpname + "-" +  m.address
                m.name = snmpname
                try:
                    m.save()
                
            # если имя совпадает с уже имеющимся - добавляем ему к имени айпи и пишем в базу
                except:
                    m.name = m.name + "-" + m.address
                    print "Dublicate: ", ManagedObject.objects.get(name=snmpname)
                    
                    # тут всё может сломаться на сохранении изза дубляжа ID
                    try:
                        m.save()
                    except:
                        print "Error save"