Завершение сеансов спавна в ожидании

Я пытаюсь решить проблему со сценарием Expect, который регистрируется на очень большом количестве устройств (тысячи). Сценарий состоит примерно из 1500 строк и довольно запутан; его работа заключается в проверке управляемого оборудования в сети со многими тысячами узлов. В результате он входит в устройства через telnet, выполняет команды для проверки работоспособности оборудования, записывает эту информацию в файл, а затем выходит из системы, чтобы перейти к следующему устройству.

Здесь я сталкиваюсь со своей проблемой; каждый expect в моем скрипте включает тайм-аут и eof следующим образом:

timeout {
    lappend logmsg "$rtrname timed out while <description of expect statement>"
    logmessage
    close
    wait
    set session 0
    continue
}
eof {
    lappend logmsg "$rtrname disconnected while <description of expect statement>"
    logmessage
    set session 0
    continue
}

Мой последний expect закрывает каждую сессию появления вручную:

-re "OK.*#" {
    close
    send_user "Closing session... "
    wait
    set session 0
    send_user "closed.\n\n"
    continue
}

Продолжения возвращают скрипт обратно в цикл while, который инициирует следующий сеанс порождения, предполагая, что сеанс = 0.

Установленный сеанс 0 отслеживает, когда сеанс порождения закрывается либо вручную по тайм-ауту, либо через EOF до открытия нового сеанса порождения, и все, кажется, указывает на то, что сеансы порождения закрываются, но после тысячи или около того порожденных сеансов я получаю следующая ошибка:

spawn telnet <IP removed>
too many programs spawned?  could not create pipe: too many open files

Я сетевой инженер, а не администратор UNIX или профессиональный программист, так что может ли кто-нибудь помочь мне исправить мою ошибку? Я закрываю сеансы запуска telnet, но неправильно закрываю канал? Я написал второй, тестовый скрипт, который буквально просто подключается к устройствам по одному и отключается сразу после установления соединения. Он не входит в систему и не запускает никаких команд, как это делает мой основной скрипт, и безупречно работает при тысячах подключений. Этот скрипт ниже:

#!/usr/bin/expect -f

#SPAWN TELNET LIMIT TEST

set ifile [open iad.list]
set rtrname ""
set sessions 0

while {[gets $ifile rtrname] != -1} {
set timeout 2
spawn telnet $rtrname
incr sessions
send_user "Session# $sessions\n"
expect  {
    "Connected" {
                close
                wait
                continue
                }
    timeout     {
                close
                wait
                continue
                }
    eof         {
                continue
                }
}

В моем основном скрипте я регистрирую каждое отдельное соединение и причины, по которым они могут быть EOF или тайм-аут (через процесс logmessage, который записывает конкретную причину в файл), и даже когда я не вижу ничего, кроме успешных созданных соединений и закрытых соединений, я получаю такая же проблема с моим основным скриптом, но не с тестовым скриптом.

Я кое-что читал об уничтожении идентификаторов процессов, но, насколько я понимаю, close должен убивать идентификатор процесса текущего сеанса создания, а wait должен останавливаться. сценарий, пока процесс не будет мертв. Я также пытался использовать простую команду «выход» с устройств, чтобы закрыть соединение telnet, но это не дает лучших результатов.

Мне может просто понадобиться предложение о том, как лучше отслеживать открытие и закрытие моих сеансов и гарантировать, что между устройствами ни один из сеансов порождения не останется открытым. Любая помощь, которая может быть предложена, будет высоко оценена.

Спасибо!


person Eleck    schedule 04.11.2013    source источник
comment
Эта статья сообщение об ошибке "Слишком много открытых файлов" может помочь.   -  person glenn jackman    schedule 04.11.2013
comment
Похоже, что PID меняется всякий раз, когда открывается новый сеанс. Я пытаюсь exec убить $pid до моего близкого ожидания. Сейчас я просматриваю несколько тысяч устройств, чтобы посмотреть, поможет ли это; по-видимому, некоторые старые версии команды telnet не всегда корректно закрывают свои процессы.   -  person Eleck    schedule 05.11.2013
comment
Я не уверен, что размещение continue внутри предложения eof — хорошая идея, но мои знания Expect все еще немного неоднородны…   -  person Donal Fellows    schedule 06.11.2013
comment
У меня все еще есть проблема. Уничтожение PID по-прежнему не решает проблему. Мой тестовый скрипт использует continue внутри eof без проблем.   -  person Eleck    schedule 25.11.2013
comment
@Eleck: вы пытались отправить escape-символы (например, Ctrl + ']'), чтобы закрыть сеанс telnet вместо close и wait ?   -  person Dinesh    schedule 29.12.2016
comment
@joshua-briefman дал хороший ответ. Я бы предложил рассмотреть возможность использования ssh вместо telnet. Это повысит безопасность. Вы получаете дополнительное преимущество, заключающееся в том, что ssh закрывает больше, чем вы ожидаете, вместо двухэтапного процесса, который использует telnet.   -  person Hod    schedule 05.01.2017
comment
@Hod Не мой выбор; устройства принимают только соединения telnet. Надеюсь, когда-нибудь это изменится, но до тех пор я застрял с telnet.   -  person Eleck    schedule 27.04.2017


Ответы (1)


Ошибка?

spawn telnet породило слишком много программ? не удалось создать канал: слишком много открытых файлов

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

Я подозреваю, что причиной этого являются заброшенные сеансы telnet, которые остаются открытыми.

Теперь давайте поговорим о том, почему они могут все еще торчать.


Даже не близко?

Close может фактически не закрывать telnet-соединение, особенно если telnet не распознает, что сеанс был закрыт, а только ожидает сеанс с telnet (см.: Команда закрытия). В этом случае Telnet, скорее всего, будет поддерживать активность в ожидании дополнительных данных со стороны сети и поддержки активности TCP.

Не все приложения распознают close, который представляется принимающему приложению как EOF. Из-за этого они могут оставаться открытыми, даже когда их вход закрыт.

Скажите "Telnet", все кончено.

В этом случае вам нужно будет прервать telnet. Если вы намерены завершить какую-то работу и выйти. Тогда это именно то, что нам нужно сделать.

Для «telnet» вы можете выйти, выполнив «отправить «35 \ r»» (что было бы «ctrl +]» на клавиатуре, если бы вам пришлось набирать его самостоятельно), за которым следует «выход», а затем возврат каретки. Это укажет telnet корректно завершить работу.

Сценарий ожидания: запустить telnet, выполнить команды , закрыть телнет Выдержка:

#!/usr/bin/expect
set timeout 1
set ip [lindex $argv 0]
set port [lindex $argv 1]
set username [lindex $argv 2]
set password [lindex $argv 3]
spawn telnet $ip $port
expect “‘^]’.”
send – – “\r”
expect “username:” {
    send – – “$username\r”
    expect “password:”
    send – – “$password\r”
}
expect “$”
send – – “ls\r”
expect “$”
sleep 2
# Send special ^] to telnet so we can tell telnet to quit.
send “35\r”
expect “telnet>”
# Tell Telnet to quit.
send – – “quit\r”
expect eof
# You should also, either call "wait" (block) for process to exit or "wait -nowait" (don't block waiting) for process exit.
wait

Подождите, для Финиша.

Ожидание — команда ожидания

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

В противном случае мы не можем закрыть ни один из этих процессов до тех пор, пока не будет завершено ожидание выхода. Это может привести к тому, что у нас закончатся дескрипторы файлов, если ни один из них не закроется для долго выполняющегося сценария ожидания (или того, который подключается к большому количеству серверов). Как только у нас закончатся дескрипторы файлов, ожидайте, и все, что было начато, просто умрет, и вы больше не увидите, что эти дескрипторы файлов исчерпаны.

Тайм-аут?, Уловить все?, Почему?

Вы также можете рассмотреть возможность использования «тайм-аута» на случай, если сервер не отвечает, когда ожидается, чтобы мы могли выйти раньше. Это идеально подходит для сильно отстающих серверов, которые вместо этого должны привлекать внимание администратора.

Catch all может помочь вашему сценарию справляться с любыми неожиданными ответами, которые не обязательно мешают нам продолжать. Мы можем просто продолжить обработку или выйти раньше.

Ожидаемые примеры Выдержка:

expect {           
    "password:" {
        send "password\r"
    } "yes/no)?" {
        send "yes\r"
        set timeout -1
    } timeout {
        exit
    # Below is our catch all
    } -re . {
        exp_continue
    #
    } eof {
        exit
    }
}
person Joshua Briefman    schedule 30.12.2016
comment
Спасибо за это! За годы я нашел способы обойти эту проблему (а именно, поместив все это в обертку), но я попробую это! Я не уверен, почему мой тест ограничения telnet работает нормально, а более крупный сценарий - нет; как вы говорите, вполне вероятно, что некоторые из моих сеансов в моем более сложном сценарии на самом деле не закрываются должным образом (хотя Expect, похоже, так думает). - person Eleck; 27.04.2017