Automation in JunOS: writing scripts

    In the life of each system administrator, there come moments when there is a need to automate the execution of certain operations or, for example, you have to delegate part of your authority to subordinates. Moreover, it is advisable to do this safely, and the ability to nakosyachit to minimize. Well, if we are talking about a server running * NIX-systems - there is a great number of tools designed for this. But it’s not always so lucky ...

    It would seem that a rather trivial task is to enable junior technical personnel to hang and remove the blackhole community on routers running JunOS in the simplest way possible. Everything would be fine, but bash + ssh + expect did not suit me very much, perl + Net :: OpenSSH / Net :: SSH / etc, too. In the process of thinking over the task, I recalled Tcl in IOS, and it turned out that JunOS also had similar proprietary automation tools, elegant and really powerful, and, as for me, more convenient than Tcl. And the most surprising - Google in RuNet mentions of them for some reason did not find.

    Well, let me try to fill this gap, at least for general education, in a volume that allows us to appreciate the "beauty of the game." So, in JunOS there is a built-in ability to write your own scripts and then use them like regular commands, for example like this:

    / * Create a new entry that installs blackhole community * /
    user @ junosbox> op blackhole set

    Agree, it’s much more convenient than entering the configuration mode, manually creating routes, hanging community on them and committing changes. To make mistakes in the case of performing these actions using the script is much less likely. In addition, in the script you can perform all the necessary checks so that the operator does not perform anything superfluous.

    This feature is provided by the JunOS Automation Tool Kit, which allows you to use the built-in XML features of JunOS, which is a standard component of JunOS and, accordingly, is present on any device running JunOS. The main tool for this is the XSLT scripting language. And this, it seems to me, is bad news - writing on it, of course, is more convenient than on Brainfuck, but it’s still somewhat peculiar. But there is good news: to simplify the life of administrators, the guys from Juniper Networks also implemented SLAX support. In JunOS prior to version 11, SLAX 1.0 is supported, in newer versions 1.1. The documentation mentions that its syntax is somewhat reminiscent of perl. This statement seems somewhat controversial to me, but there are definitely some distant similarities,

    JunOS has several classes of scripts:

    • commit - are used to automate the process of commit - for example, to verify that changes in the configuration match some rules and display messages and interrupt the commit in case of any problems; when calling commit, all active commit scripts are executed in turn;
    • op - scripts in the usual understanding of the system administrator - are used to perform a standard sequence of actions, change the format of the output of commands, etc.
    • event - scripts that are called when some events occur;
    • SNMP - scripts that are called when accessing the SNMP agent of the system

    Obviously, the most popular are op-scripts, although others can also be used.

    To install the script on the system, you must copy it to the appropriate subdirectory of the / var / db / scripts directory , and then run the edit system scripts type file filename command to activate it . After activating the script, it can be called like any other command allowed to the user in operation mode: op filename arguments . It's nice that the valid parameters of the activated CLI script by pressing "?" shows exactly the same as for the built-in system commands. Help is shown in the same way, if envisaged:

    user @ junosbox> op blackhole?
    Possible completions:
      <[Enter]> Execute this command
                     Argument name
      detail Display detailed output
      set Set blackhole community for IP address
      | Pipe through a command

    Of course, setting up a user and granting him the rights necessary to execute a script is the administrator's task. But she, just right, is well-documented and everyone has come across it at least once.

    So up to this point, everything seems to be quite simple. The nuances begin with writing a script: examples from the documentation are somewhat useless, because they implement things that are no less conveniently performed by built-in commands. Therefore, I allow myself to draw your attention to some points that the authors of the documentation paid insufficient attention to, but in real life they matter:

    1. Remember, JunOS is XML. The most necessary command when writing scripts is show configuration ... | display xml . This is the only way to understand which templates and parameters should be used to build a new configuration or make changes to an existing one;
    2. The documentation is not always true. So, for example, in SLAX 1.0 named. JunOS declare a function by usingit really didn’t work out, because the interpreter swore at all references to “var”, “param”, etc. inside it. At the same time, a similar result was achieved by using custom templates, about which nothing was written in the Juniper Networks documentation (see example);
    3. In functions, the order of the arguments matters; it does not matter in the templates - their name is important here (again, see an example);
    4. In XSLT and SLAX, it is very bad with variable reuse - the value of a variable, once assigned, cannot change in the general case. Theoretically, this issue is addressed by using mvar (mutable var) instead of var to declare variables, but in some situations their behavior becomes strange (assigned values ​​are lost). Therefore, since the documentation says that there are many variables, this is normal and it’s just worth taking note of this syntax nuance, probably it’s worth doing that.

    Well, finally:

    Example - op / blackhole.slax
    version 1.0;
    ns junos = "*/junos";
    ns xnm = "";
    ns jcs = "";
    ns ext = "";
    import "../import/junos.xsl";
    var $ arguments = {
         "Set blackhole community for IP address";
    param $ set;
    match / {
        var $ instance = "INSTANCE";
        var $ community = "65535: 666";
        if ($ set) {
          var $ addr = jcs: parse-ip ($ set);
          var $ ip = $ addr [1] _ "/ 32";
          var $ connection = jcs: open ();
          call set_community ($ connection, $ ip, $ instance, $ community);
          var $ close-results = jcs: close ($ connection);
          if ($ close-results) {expr jcs: output ($ close-results); }
        else {
          call show_community ($ community);
    template set_community ($ connection, $ ip, $ instance, $ community) {
      var $ configuration =  {
             $ instance;
                   $ ip;
                   { $ community; }
      var $ commit-options: = {  { "setting blackhole community for" _ $ ip; }}
      var $ results: = {call jcs: load-configuration ($ connection, $ configuration, $ commit-options); }
      copy-of $ results;
    template show_community ($ community) {
      var $ command = { "show route community" _ $ community; }
      var $ results = jcs: invoke ($ command);
      copy-of $ results;


    Also popular now: