The OpenNET Project / Index page

[ новости/++ | форум | wiki | теги ]

Junoscript на удаленном устройстве c JunOS
Развертывание и поддержка крупной вычислительной сети требует значительных
усилий инженеров различных специальностей. Во многом помогают средства
автоматизации. Cisco IOS в этом смысле предоставляет возможность создания
автоматических средств с помощью TCL. Juniper Networks JunOS предоставляет
множество средств, основанных на XML. Linux/BSD-платформы в отношении
автоматизации значительно гибче.

Однако, если говорить об IOS и Linux/BSD, то это уже прижившиеся в сетях
операционные системы, о которых достаточно информации в интернете, и
большинство сетевых администраторов чувствуют себя уверенно при работе с ними.

Особняком стоит Junos, появившийся относительно недавно и не накопивший
достаточного объема документации в рунете.

Большая часть информации о JunOS сконцентрирована на официальном сайте.
Информации много, и она очень подробная. Если у вас есть специалист, который
вас может направить на путь к правильному решению, - это очень хорошо. Но если
такого специалиста нет, вы начинаете просматривать мегабайты документации в
поисках нужной информации, собирая по деталям всю мозаику, в рисунке которой
чудесным образом появляется решение проблемы. На это уходит много времени, эта
статья призвана сократить ваш путь от постановки задачи на автоматизацию до
начала непосредственно реализации (примеры на PHP).

Для понимания статьи достаточны базовые навыки работы с командным интерфейсом и
конфигурацией JunOS.


Как JunOS работает с конфигурацией и как взаимодействует с CLI

В целом управление устройством на базе JunOS производится с помощью процесса
mgd (management daemon), который готов принимать запросы из CLI, изменения
конфигурации и удаленные вызовы. Этот процесс тесно взаимодействует с другими
процессами операционной системы и позволяет организовывать интерактивный режим
работы с пользователем. В данном контексте под пользователем подразумевается
или скрипт, выполняемый локально, или удаленное подключение через (например)
SSL-сокет, или инженер, находящийся на устройстве посредством ssh или telnet.

Для обеспечения взаимодействия между mgd и другими процессами был выбран
механизм RPC, основанный на использовании XML. На запросы и ответы в формате
XML можно взглянуть, направив вывод основной команды пайпом в команды 'display
xml rpc' и 'display xml' соответственно.

Например:

   > show interfaces xe-1/0/0 terse | display xml rpc

   <rpc-reply xmlns:junos="http://xml.juniper.net/junos/10.3R2/junos">
    <rpc>
       <get-interface-information>
               <terse/>
               <interface-name>xe-1/0/0</interface-name>
       </get-interface-information>
    </rpc>
    <cli>
       <banner></banner>
    </cli>
   </rpc-reply>

   > show interfaces xe-1/0/0 terse | display xml

   <rpc-reply xmlns:junos="http://xml.juniper.net/junos/10.3R2/junos">
    <interface-information
       xmlns="http://xml.juniper.net/junos/10.3R2/junos-interface"
       junos:style="terse">
       <physical-interface>
           <name>xe-1/0/0</name>
           <admin-status>up</admin-status>
           <oper-status>up</oper-status>
           <description>TEST PORT</description>
           <logical-interface>
               <name>xe-1/0/0.10</name>
               ...
           </logical-interface>
       </physical-interface>
    </interface-information>
    <cli>
       <banner></banner>
    </cli>
   </rpc-reply>

Это значит, что при вводе команды CLI формирует XML-документ и отправляет его
mgd, который в свою очередь интерпретирует запрос, подготавливает результат в
формате XML и отправляет его CLI. Получив ответ командная оболочка форматирует
XML-документ в читаемый вид и выводит его на терминал.

Конфигурация тоже представлена в формате XML.

   > show configuration | display xml'
   <rpc-reply xmlns:junos="http://xml.juniper.net/junos/10.3R2/junos">
      <configuration junos:commit-seconds="1296472234"
                  junos:commit-localtime="2011-01-31 17:10:34 NOVT"
                  junos:commit-user="root">
           <version>10.3R2.11</version>
               ...
      </configuration>
   </rpc-reply>

После того, как вы входите в режим конфигурирования устройства, изменяете
конфигурацию (она приобретает статус candidate) и вводите 'commit', CLI
форматирует в виде XML конфигурацию-кандидата, которая в последствии сливается
с активной конфигурацией средствами XSLT-менеджера.

В общем случае любое взаимодействие с JunOS происходит посредством
взаимодействия с mgd. С этим менеджером мы можем "общаться" из CLI, из
op-скрипта, из event-скрипта, из commit-скрипта или удаленно через RPC-сессию
(установить сессию в открытом виде или шифрованную с помощью SSL, работать с
Junoscript RPC внутри SSH-соединения или с помощью специфичной технологии
Outbound SSH).

Описание каждого способа взаимодействия - это тема нескольких статей. 
Вкратце, op-скрипты позволяют автоматизировать работу оператора устройства,
event-скрипты готовы к выполнению при наступлении какого-либо события (или
каскада взаимозависимых событий), commit-скрипт выполняется каждый раз, когда
производится выполнение команды 'commit' из конфигурационного режима.

Ниже мы поговорим о работе с JunOS удаленно.

Теория удаленной работы с JunOS

Первым этапом взаимодействия с устройством JunOS является поднятие транспорта и
открытие RPC-сессии (последнее требуется только для соединения через SSH).
Технические детали зависят от того, какой транспорт вы предпочтете. Для работы
различных транспортных средств может потребоваться дополнительная конфигурация
или генерирование сертификата. Об этом подробнее рассказано в документации.

Я же буду использовать SSH-соединение, так как его поддержка настроена
практически на всех моих устройствах под управлением JunOS.

Следующим шагом является отправка XML PI (processing instructions) с указанием
используемой кодировки "us-ascii" и версии XML. За PI следует отправить
открывающий тег <junoscript> с атрибутом version="1.0". (Это единственный
обязательный атрибут, остальные являются опциональными. Ими вы можете
сопоставить текущую версию JunOS и версию своего скрипта, или указать hostname,
от которого выполняется скрипт.)

Все готово для того, чтобы отправлять запросы внутри пары тегов <rpc></rpc>.

Информацию о формате запроса можно получить из командной строки, отправив в '|
display xml rpc' вывод практически любой команды, о чем было сказано выше.

Проверить работоспособность любого RPC-запроса можно из CLI с помощью скрытой
команды 'junoscript interactive'. (Не забудьте отправить PI и junoscript-тег.)

Ответ вы получите внутри пары тегов <rpc-reply></rpc-reply> сразу после ввода и
отправки закрывающего тега </rpc>. Обратил внимание, что JunOS никак не
форматирует ответ (нет отступов, каждый новый тег в новой строке).

Получив от JunOS все, что нам нужно, мы можем закрыть сессию. Можно оборвать
транспорт, но этот путь не является кошерным, ибо RPC-сессия так и останется
висеть незавершенной. Лучшим и правильным решением является запрос
<request-end-session/>, получение от JunOS закрывающего тега </junoscript> и
отправка этого же тега на устройство. Отключение транспорта будет инициировано
самой операционной системой JunOS.


От слов к делу

Для работы с SSH я использовал библиотеку libssh2-php. Итак, установка
транспорта и открытие RPC-сессии требует от нас следующих шагов:

1. Подключение к устройству.
2. Аутентификация посредством ключа или пароля.
3. Получение файлового дескриптора потока SSH-сессии.
4. Выполнение команды junoscript на устройстве для открытия сессии.


   /* Открытие сессии */
   public function sshconnect($host, $port=22)
   {
      $this->ssh = ssh2_connect($host, $port);
      if (!$this->ssh) return false;
      return true;
   }

   /* Аутентификация по паролю */
   public function authpass($username, $password)
   {
      if (!$this->ssh) return false;
      $this->auth = ssh2_auth_password($this->ssh, $username, $password);
      return $this->auth;
   }

   /* Аутентификация по ключу */
   public function authkey($username, $pubkeyfile, $privkeyfile, $passphrase=null)
   {
      if (!$this->ssh) return false;
      $this->auth = ssh2_auth_pubkey_file($this->ssh,
           $username, $pubkeyfile, $privkeyfile, $passphrase);
      return $this->auth;
   }

   /* Открытие сессии, отправка PI и junoscript-тега */
   public function startshell($hostname=null, $encoding="us-ascii", $version="1.0")
   {
      if (!$this->auth) return false;
      $this->stream = ssh2_shell($this->ssh,
           'vt102', null, 0, 0, SSH2_TERM_UNIT_CHARS);
      if (!$this->stream) return false;

      /* Старт Junoscript сессии */
      fwrite($this->stream, "junoscript\n");

      $s = '';
      while (strstr($s, 'start') === FALSE)
      {
          $s = fgets($this->stream);
          $this->rawXml .= $s;
      }

      /* Отправка PI и  тега */
      fwrite($this->stream, '<?xml version="1.0" encoding="'.$encoding.'"?>');
      fwrite($this->stream, "<junoscript version=\"$version\" "
       . ($hostname ? " hostname=\"$hostname\"" : "") . '>');

      return true;
   }


Как вы могли заметить, в функции startshell я сразу отправил PI и
junoscript-тег. Теперь самое интересное: отправка RPC и получение ответа.

   public function exec($rpcstring)
   {
      $answer = '';

      if (!$this->stream) return false;
      fwrite($this->stream, '<rpc>'.$rpcstring.'</rpc>');
   
      $s = '';
      while (strstr($s, '/rpc-reply') === FALSE)
      {
          $s = fgets($this->stream);
          $this->rawXml .= $s;
          $answer .= $s;
      }

      return $answer;
   }


Описывать подробно работу функции смысла нет, она достаточно простая, чтобы
быть понятной для программиста любой квалификации. Осталось только закрыть
сессию и закончить работу с устройством.

   public function close()
   {
      if (!$this->stream) return false;
      $close = '<rpc><request-end-session/></rpc>';
      fwrite($this->stream, $close);

      $s = '';
      while (strstr($s, '/junoscript') === FALSE)
      {
          $s = fgets($this->stream);
          $this->rawXml .= $s;
      }
      fwrite($this->stream, '</junoscript>');

      /* server resets connection now */
      $this->auth = null;
      $this->stream = null;
      $this->ssh = null;

      return true;
   }


А вот пример работы с классом:

   $j = new JunosRPC();
   $result = $j->connect_key("juniper", "username", "id_rsa.pub", "id_rsa");
   echo 'Connect: ', ($result ? 'true' : 'false'), "\n";

   $answer = $j->exec('<get-bgp-summary-information/>');

   $result = $j->close();
   echo 'Close: ', ($result ? 'true' : 'false'), "\n";

   $xml = simplexml_load_string($answer);
   print_r($xml);


Полный исходный код класса JunosRPC вы можете изучить 
здесь или здесь. Подробнее изучить про то, как работает Junos XML
Management Protocol, можно используя официальную документацию.


Заключение

Кто-то может спросить: "И в чем преимущество такого хитрого метода работы с
устройством по сравнению, скажем, с простым использованием expect'а ?"
Преимущество основано на том, что JunOS использует именно XML для работы с
конфигурацией. Учитывая богатый выбор инструментов для работы с XML можно
предположить, что некий провайдер захочет создать систему управления
устройствами в сети на основе информации из своего биллинга (похоже это делает
JunOS Space). В некоторых случаях требуется мониторинг специфичных параметров
устройства, которых нет в OID-дереве SNMP.

Многие вопросы не были затронуты в статье, как то использование NETCONF,
создание op-, event- и commit-скриптов. Однозначно, автоматизация - это очень
широкое поле для исследований.

На Youtube есть пользователь JuniperNetworks, подкасты которого помогут
ориентироваться во всем многообразии продуктов Juniper.
 
01.03.2011 , Автор: nocn
Ключи: Junoscript, junos, script, network, juniper, router, php / Лицензия: CC-BY
Раздел:    Корень / Маршрутизаторы Cisco, VoIP / Ограничение и учет трафика на Cisco

Обсуждение [ RSS ]
 
  • 1, freeseacher, 15:49, 02/03/2011 [ответить] [смотреть все]
  • +/
    Спасибо за отличную статью!
     

    Ваш комментарий
    Имя:         
    E-Mail:      
    Заголовок:
    Текст:



      Закладки на сайте
      Проследить за страницей
    Created 1996-2017 by Maxim Chirkov  
    ДобавитьРекламаВебмастеруГИД  
    Hosting by Ihor