New device
New device
This is an example how to make a config for a new vendor. See full documentation here.
Here we are playing with qfx in docker:
docker run -it -p 2222:22 --privileged aninchat/vr-vqfx:19.4R1.10
Let's start with an empty config:
# gnetcli_conf.yaml
devices:
- name: myvendor
prompt_expression: '$.^' # just stub that will never match
error_expression: '$.^'
Run any command to get debug output with read data:
cli -dev-conf gnetcli_conf.yaml -devtype 'myvendor' -command 'show system uptime' -port 2222 -hostname 127.0.0.1 -login vrnetlab -password VR-netlab9 -debug
Output:
read {"data": "Last login: Mon Dec 4 22:22:25 2023 from 10.0.0.2\r\r\n--- JUNOS 19.4R1.10 built 2019-12-19 03:54:05 UTC\r\n"}
read {"data": "{master:0}\r\n"}
read {"data": "vrnetlab@vr-vqfx> "}
In the output we see prompt vrnetlab@vr-vqfx>
for which we must write regular expression.
Keep in mind that expressions must be as specific as possible. https://regex101.com/ is very instrumental for testing. Expression
\r\n(?P<user>[\w]{1,10})@(?P<hostname>[\w-]{1,10})> $
will go well. Also, we can add test data in test
section.
# gnetcli_conf.yaml
devices:
- name: myvendor
prompt_expression: `\r\n(?P<user>[\w]{1,10})@(?P<hostname>[\w-]{1,10})> $`
error_expression: '$.^'
tests:
prompt_expression_variants:
- "\r\nvrnetlab@vr-vqfx> "
Next run:
cli -dev-conf gnetcli_conf.yaml -devtype 'myvendor' -command 'show system uptime' -port 2222 -hostname 127.0.0.1 -login vrnetlab -password VR-netlab9 -debug
Output:
read {"data": "Last login: Mon Dec 4 23:17:37 2023 from 10.0.0.2\r\r\n--- JUNOS 19.4R1.10 built 2019-12-19 03:54:05 UTC\r\n"}
read {"data": "{master:0}\r\n"}
read {"data": "vrnetlab@vr-vqfx> "}
write {"text": "show system uptime", "written": 18}
write {"text": "\n", "written": 1}
read to {"expr": "show system uptime(\\r\\n|\\n),\\n(?P<user>[\\w]{1,10})@(?P<hostname>[\\w-]{1,10})> $"}
read {"data": "show system uptime "}
read {"data": "\r\n"}
read {"data": "fpc0:\r\n"}
read {"data": "--------------------------------------------------------------------------\r\n"}
read {"data": "Current time: 2023-12-04 23:18:12 UTC\r\n"}
read {"data": "Time Source: LOCAL CLOCK \r\n"}
read {"data": "System booted: 2023-12-04 20:49:37 UTC (02:28:35 ago)\r\n"}
read {"data": "Protocols started: 2023-12-04 20:52:13 UTC (02:25:59 ago)\r\n"}
read {"data": "Last configured: 2023-12-04 20:54:17 UTC (02:23:55 ago) by root\r\n"}
read {"data": "11:18PM up 2:29, 2 users, load averages: 0.28, 0.18, 0.11\r\n"}
read {"data": "\r\n{master:0}\r\n"}
read {"data": "vrnetlab@vr-vqfx> "}
Here we see a quirk - CLI added white space in echo. This behaviour brakes Gnetcli's echo reading algorith.
Luckily there is feature called spaces_after_echo
, which modifies expression for echo.
devices:
- name: myvendor
prompt_expression: '\n(?P<user>[\w]{1,10})@(?P<hostname>[\w-]{1,10})> $'
error_expression: '$.^'
features: [ spaces_after_echo ]
With current config is it possible to run commands, but without error detection. Let's add them.
Error prompt
Run:
cli -dev-conf gnetcli_conf.yaml -devtype 'myvendor' -command 'show123' -port 2222 -hostname 127.0.0.1 -login vrnetlab -password VR-netlab9 -debug
Output:
read {"data": "Last login: Mon Dec 4 23:43:47 2023 from 10.0.0.2\r\r\n--- JUNOS 19.4R1.10 built 2019-12-19 03:54:05 UTC\r\n"}
read {"data": "{master:0}\r\n"}
read {"data": "vrnetlab@vr-vqfx> "}
write {"text": "show123", "written": 7}
write {"text": "\n", "written": 1}
read to {"expr": "show123 *\\r\\n,\\n(?P<user>[\\w]{1,10})@(?P<hostname>[\\w-]{1,10})> $"}
read {"data": "show123\r\n"}
read to {"expr": "\\n(?P<user>[\\w]{1,10})@(?P<hostname>[\\w-]{1,10})> $"}
read {"data": " ^\r\nunknown command.\r\n\r\n"}
read {"data": "{master:0}\r\nvrnetlab@vr-vqfx> "}
Update config with error_expression
and test data for it.
devices:
- name: myvendor
prompt_expression: '\n(?P<user>[\w]{1,10})@(?P<hostname>[\w-]{1,10})> $'
error_expression: ' *\^\r\nunknown command.\r\n'
features:
- spaces_after_echo
tests:
prompt_expression_variants:
- "\r\nvrnetlab@vr-vqfx> "
error_expression_variants:
- " ^\r\nunknown command\.\r\n"
Pager
What if a device use pagination for long output?
write {"text": "show interfaces", "written": 15}
write {"text": "\n", "written": 1}
read to {"expr": "show interfaces *\\r\\n,\\n(?P<user>[\\w]{1,10})@(?P<hostname>[\\w-]{1,10})> $"}
read {"data": "show interfaces \r\n"}
read to {"expr": "\\n(?P<user>[\\w]{1,10})@(?P<hostname>[\\w-]{1,10})> $"}
read {"data": "Physical interface: gr-0/0/0, Enabled, Physical link is Up\r\n"}
read {"data": " Interface index: 646, SNMP ifIndex: 504\r\n"}
read {"data": " Type: GRE, Link-level type: GRE, MTU: Unlimited, Speed: 800mbps\r\n"}
read {"data": " Device flags : Present Running\r\n"}
read {"data": " Interface flags: Point-To-Point SNMP-Traps\r\n"}
read {"data": " Input rate : 0 bps (0 pps)\r\n"}
read {"data": " Output rate : 0 bps (0 pps)\r\n"}
read {"data": "\r\n"}
read {"data": "Physical interface: pfe-0/0/0, Enabled, Physical link is Up\r\n Interface index: 649, SNMP ifIndex: 511\r\n Speed: 800mbps\r\n Device flags : Present Running\r\n Link flags : None\r\n Last flapped : Never\r\n Input packets : 0\r\n Output packets: 0\r\n"}
read {"data": "\r\n"}
read {"data": " Logical interface pfe-0/0/0.16383 (Index 552) (SNMP ifIndex 512)\r\n Flags: Up SNMP-Traps Encapsulation: ENET2\r\n Bandwidth: 0\r\n Input packets : 0\r\n Output packets: 0\r\n"}
read {"data": " Protocol inet, MTU: Unlimited\r\n"}
read {"data": "---(more)---"}
error {"error": "read timeout error...
---(more 76%)---
.
Let's add pager expression and test cases.
devices:
- name: myvendor
prompt_expression: '\n(?P<user>[\w]{1,10})@(?P<hostname>[\w-]{1,10})> $'
error_expression: ' *\^\r\nunknown command.\r\n'
pager_expression: '---\(more( \d{1,2}%)?\)---'
features:
- spaces_after_echo
tests:
prompt_expression_variants:
- "\r\nvrnetlab@vr-vqfx> "
error_expression_variants:
- " ^\r\nunknown command\.\r\n"
pager_expression_variants:
- "---(more)---"
- "---(more 76%)---"
Questions
cli -dev-conf myvendor.yaml -devtype 'myvendor' -command 'request system reboot' -port 2222 -hostname 127.0.0.1 -login vrnetlab -password VR-netlab9 -debug 2>&1
Output:
write {"text": "request system reboot", "written": 21}
write {"text": "\n", "written": 1}
read to {"expr": "request system reboot *\\r\\n,\\n(?P<user>[\\w]{1,10})@(?P<hostname>[\\w-]{1,10})> $,---\\(more( \\d{1,2}%)?\\)---"}
read {"data": "request system reboot "}
read {"data": "\r\n"}
read to {"expr": "\\n(?P<user>[\\w]{1,10})@(?P<hostname>[\\w-]{1,10})> $,---\\(more( \\d{1,2}%)?\\)---"}
read {"data": "Reboot the system ? [yes,no] (no) "}
error {"error": "read timeout error...
The command didn't return prompt, that is why it timed out.
First of all, we can add expression question_expression
for the question.
With this the expression we will see more descriptive error: no answer for question
.
devices:
- name: myvendor
prompt_expression: '\n(?P<user>[\w]{1,10})@(?P<hostname>[\w-]{1,10})> $'
error_expression: ' *\^\r\nunknown command.\r\n'
pager_expression: '---\(more( \d{1,2}%)?\)---'
question_expression: '\n.+\? \[yes,no\] \(no\) $'
Even without question_expression
we can specify question and answer using -question
arg:
cli -dev-conf myvendor.yaml -devtype 'myvendor' -command 'request system reboot' -port 2222 -hostname 127.0.0.1 -login vrnetlab -password VR-netlab9 -debug -question 'Reboot the system ? [yes,no] (no) :::yes'
Auto commands
Sometimes it is needed to run some commands to set up CLI, like disable paging, set terminal width, etc.
autocmd
feature solves it:
devices:
- name: myvendor
features:
- spaces_after_echo
- autocmd:
- set cli complete-on-space off
- set cli screen-length 0
Final config
devices:
- name: myvendor
prompt_expression: '\n(?P<user>[\w]{1,10})@(?P<hostname>[\w-]{1,10})> $'
error_expression: ' *\^\r\nunknown command\.\r\n'
pager_expression: '---\(more( \d{1,2}%)?\)---'
question_expression: '\n.+\? \[yes,no\] \(no\) $'
features: [spaces_after_echo, {autocmd: [test, test]}]
tests:
prompt_expression_variants:
- "\r\nvrnetlab@vr-vqfx> "
error_expression_variants:
- " ^\r\nunknown command.\r\n"