Sooshell
The Sooshell shell leverages ZSH capabilities to provide new features to users. In Sooshell, you have access to both Soodar configuration commands and POSIX shell syntax structures simultaneously. Sooshell offers new capabilities to Soodar users and network administrators in both interactive usage and scripting, allowing you to increase your efficiency.
Interactive Usage
Sooshell presents unique features for interactive user to use, making working with the command-line interface easier, more efficient, and more enjoyable.
Prompt
The Sooshell prompt accurately indicates the status of the user session in terms of the configuration path it is in:
router1/c/interface/ge0#
For example, the above prompt shows that we have entered the path enable -> config -> interface : ge0
router1/c/i/g/link-params#
Or here we have entered enable -> config -> interface : ge0 -> link-params.
Auto-completion
Using the auto-completion feature, you can avoid writing full commands and save time. To complete a word, simply press the TAB key, and Sooshell will suggest possible words to complete the commands:
router1/config# p<TAB>
password pbr pbr-map pseudowire
You can select one of the options by pressing the arrow keys ⬆️➡️⬅️⬇️ or the TAB key. Also, if Sooshell finds only one possible way to complete the command, it will automatically complete it without the need to press another key.
router1/config# ps<TAB>
router1/config# pseudowire
History
Sooshell stores a list of commands you’ve previously entered. The command history doesn’t disappear when you close the session and will be available in the next Sooshell execution. By pressing the up and down arrow keys ⬆️⬇️, you can view the history and re-execute previously entered commands.
Highlighting
Sooshell indicates whether the entered command is correct or not by coloring the initial word of the commands:
Red color: The command does not exist.
Green color: The command exists.
Yellow color: The command is ambiguous as typed so far and needs more of it to be typed.
Blue color: The command exists but was in the previous configuration path, and executing it will cause us to exit the current path.
Auto-suggestion
Sooshell simultaneously suggests a command in faded text in front of the user’s input based on the history of commands the user has entered and the input typed so far. The user can select that suggestion by pressing the right arrow key ➡️ or continue typing and ignore it.
Scripting
Sooshell’s scripting capability allows us to automate many tedious manual tasks. The syntax of Sooshell scripts is the same as POSIX shells in Unix-like operating systems such as Bash and Zsh. The programmability of Sooshell gives network administrators the ability to write and execute scripts for configuration automation and any desired routine. Scripts can also be executed interactively. Just paste the script code you’ve written previously into the terminal to run it. However, a more efficient method of running scripts is through saving and calling them by their names, which we’ll discuss next.
Syntax
In this part, we will show with numerous examples how to make the most of Sooshell’s scripting capabilities.
Variable Definition
Defining variables allows us to run our commands for different values by simply changing the value of that variable, without needing to change the command itself.
router1/config# # set variable IFNAME to ge0
router1/config# IFNAME=ge0
router1/config# # following command evaluates to 'interface ge0' and
router1/config# interface $IFNAME
router1/c/interface/ge0#
Deleting a variable:
router1/config# unset IFNAME
Command Execution Syntax
The above commands can be written in one line:
router1/config# IFNAME=ge0; interface $IFNAME && { no shut; quit; }
Commands are separated by the ; character.
The && series also acts like ;, with the difference that the second command is only executed if the first command was executed successfully.
The {} characters place one or more commands in a block.
In the above example, if the value we put in the IFNAME variable is not the name of an existing interface, the interface $IFNAME command fails and the commands placed in the block are not executed.
Output Processing
Consider the following command:
router1# show interface brief
Interface Status VRF Addresses
--------- ------ --- ---------
lo up default
ge0 up default 192.168.1.1/24
ge1 up default 192.168.2.1/24
wg0 down default 10.10.49.1/16
We want to get only the information related to ge1. Sooshell allows us to use the output of one command as input for another command. The grep command can search for a pattern in its input. We just need to give the name of our desired interface along with the input of the previous command to grep:
router1# show interface brief | grep ge1
ge1 up default 192.168.2.1/24
Another command we can use is the awk command. This command provides the user with more advanced search capabilities. For example, we want to find the IP address of the ge1 interface:
router1# show interface brief | awk 'NR > 1 && $1 == "ge1" { print $4 }'
192.168.2.1/24
It’s also possible to store the output of a command in a variable to use later, which we do using the VAR=$(COMMAND) syntax:
router1# ipv4=$(show interface brief | awk '$1 == "ge1" { print $4 }')
Conditional Operations
Sometimes we need certain commands to be executed only under specific conditions. In Sooshell, each condition is actually a command where the successful execution of the command means the condition is met. Let’s say we want to show all interfaces if there are less than 5 interfaces:
router# # get all rows except the first 2 heading rows
router# interfaces=$(show interface brief | tail +3)
router# # count the number of rows
router# count=$(wc -l <<< $interfaces)
router# # check if we have less than 5 rows
router# if [[ $count -lt 5 ]]
if> then
then> # print all rows
then> echo $interfaces
then> fi
ge0 up default 192.168.30.251/24
ge1 up default 200.1.2.1/24
ge2 down default
ge3 up default 1.1.1.1/24
In the first line, we use the tail command to store only from the third line onwards.
We get the number of rows using the wc -l command.
In the next line, we use the if structure to check the mentioned condition
If the condition is met, we print all rows
Note
The command arg1 arg2 <<< $variable syntax gives the value of a variable as an argument to a command.
The general syntax of the conditional control structure is as follows:
if command1
then
command2
command3
fi
If the first command is successful, both subsequent commands are executed. In the example we mentioned, the first command is [[ $count -lt 5 ]]. The string [[` is actually a command that is called with the arguments $count, -lt, and 5. Its second argument, -lt, means less than, and the command is successful and the condition is met if the first argument is less than the third.
Now suppose we want to print only the interface names if the number of interfaces is between 5 and 10, and if it’s more, print only their number:
router1# # get all rows except the first 2 heading rows
router1# interfaces=$(show interface brief | tail +3)
router1# # count the number of rows
router1# count=$(wc -l <<< $interfaces);
router1# # check if we have less than 5 rows
router1# if [[ $count -lt 5 ]]
if> then
then> # print all rows
then> echo $interfaces
then> elif [[ $count -lt 10 ]]
elif> then
elif-then> # print first column of all rows
elif-then> echo $interfaces | awk '{print $1}'
elif-then> else
else> echo "number of interfaces: $count"
else> fi
number of interfaces: 16
The complete syntax of the conditional control structure is as follows:
if cond1
then
command1-1
command1-2
...
elif cond2
then
command2-1
command2-2
...
elif...
fi
Other conditional operators:
Is the length of string a greater than zero? [[ -n a ]]
Is the length of string a equal to zero? [[ -z a ]]
Are strings a and b equal? [[ a == b ]]
Are strings a and b not equal? [[ a != b ]]
Does string a match regex b? [[ a =~ b ]]
Is number a less than number b? [[ a -lt b ]]
Is number a greater than number b? [[ a -gt b ]]
Is number a less than or equal to number b? [[ a -le b ]]
Is number a greater than or equal to number b? [[ a -ge b ]]
Is number a equal to number b? [[ a -eq b ]]
Is number a not equal to number b? [[ a -ne b ]]
Helper Commands
When you are interacting with Sooshell or running a script, you are always in a configuration path.
router1/c/interface/ge0# node
interface
With this command, you can get the name of the node you are in. If that node has additional information, you can also obtain it:
router1/c/interface/ge0# node
interface
router1/c/interface/ge0# node -x
ge0
Also, we can use the following conditional command to check if we are in a specific node or not:
router1/c/interface/ge0# if [[ -in interface ]]; then echo "yes"; else echo "no"; fi
yes
For Loop
In Sooshell script, you can use a loop to perform repetitive tasks. The for loop in Sooshell has a simple syntax and can be used to perform a task for a range of numbers. For example, here we want to repeat the command for adding a static NAT for ports [1200,1400]:
router1/config# for port in {1200..1400}; do
for> ip nat inside source static tcp "1.1.1.10" $port "200.1.2.2" $port
for> done
In this loop, the variable port is the loop index that can be used in the commands within the loop. Sometimes we want to execute commands for each element in an array. In that case, we act like the following example:
router1/config# # Define variables for VLAN configuration
router1/config# vlan_ids=(10 20 30)
router1/config# vlan_ifname="ge0"
router1/config# # Loop through VLAN configuration
router1/config# for idx in $vlan_ids; do
for> vlan_name="$vlan_ifname.$idx"
for> echo "Configuring VLAN $vlan_name ..."
for> interface "$vlan_name"
for> encapsulation dot1q $idx
for> bridge-group 1 split-horizon group 1
for> no shutdown
for> exit
for> done
Configuring VLAN ge0.10 ...
Configuring VLAN ge0.20 ...
Configuring VLAN ge0.30 ...
n1/config# echo "VLAN configuration completed."
VLAN configuration completed.
n1/config#
In this example, the commands inside the loop are executed 3 times, where idx is equal to 10, 20, and 30.
While Loop
Another type of loop is while loops, which execute the commands inside them as long as their condition is met. In the following example, a script is written that reads the name of a protocol from the input and as long as the input is not empty, it denies that protocol and gets the next protocol from the input:
# read protocol names (one per line) and deny them in current ACL
[[ -in "ip-access-list" ]] || {
echo Error: Must be in ACL node 1>&2
return 1
}
while read PROTOCOL && [[ -n $PROTOCOL ]]
do
deny $PROTOCOL any any
echo denied protocol $PROTOCOL in ACL $(node -x)
done
permit any
The read command reads a line from the input and puts it in the variable whose name it received as an argument (here Protocol`). If it receives an EOF( Ctrl+D), the command fails and the loop condition is not met.
Functions
Sooshell provides the ability to define functions and call them for code reuse. Functions can receive arguments when called and even return a status code. The function’s status code acts like the status code of other commands, with code zero meaning success and other codes meaning failure. Functions can also act like output processing commands, meaning they can be called after the | character to take the output of the previous command as input. Here we define a simple function that fails if all its arguments are not equal:
check-equality()
{
if [[ $# -eq 0 ]]; then
return 2
fi
for arg in $@; do
if [[ $arg -neq $1 ]]; then
return 1
fi
done
return 0
}
To define a function, we must use the name(){ … } syntax. The function definition is placed between two curly braces. At the beginning of the function, we check if any arguments have been given to the function. The term $# represents the number of arguments. We want the function to fail and return value 2 if no argument is given. Then we put a loop that traverses all arguments using the $@ expression and compares them with the first argument, i.e., $1 (in general, $n means the nth argument.) and if they are not equal, it returns 1 meaning error. Now we want to call the function we’ve written. The function call is in the form check-equality arg1 arg2 arg3 …. In the example below, in the first line, we use the && operator to check if the execution was successful or not, because if it failed, the next command should not be executed. In the next line, we also ensure the function fails, because the || operator with the meaning “or” causes Sooshell to ignore executing the next command if the first command was successful.
check-equality a a a && echo '1st' case passed
check-equality a a b || echo '2nd' case failed
Execution output:
1st case passed
2nd case failed
Examples:
A function to get the names of all interfaces:
interfaces()
{
do sh int brief json | jq -r 'keys[]'
}
A function to bring up all VLAN interfaces:
vlanup()
{
if [[ ! -in config ]]; then
echo this command must be run in config node, not $(node) node 1>&2
return 1
fi
for ifname in $(interfaces); do
if [[ $ifname =~ .*\\..* ]]; then
interface $ifname
no shut
quit
fi
done
}
# usage
valnup
A function that receives interface/IP pairs and sets the IPs on the interfaces:
addips()
{
local retcode=0
if [[ ! -in config ]]; then
echo this command must be run in config node, not $(node) node 1>&2
return 1
fi
for pair in "$@"
do
ifname=($(cut -d '=' -f '1' <<< $pair))
ipaddr=($(cut -d '=' -f '2' <<< $pair))
if do sh int json | jq -e -r ".$ifname" &> /dev/null
then
echo "On $ifname set IP $ipaddr"
interface $ifname
ip address $ipaddr
no shut
quit
else
echo "interface $ifname does not exist" 1>&2
retcode=1
fi
done
return $retcode
}
# usage
addips wg0="192.168.1.1/24" wg1="192.168.2.1/24" wg2="192.168.3.1/24"
Manual pages
Sooshell provides a manual page for its functionality and other system binaries. To access the manual page of a wanted section, use the man command followed by the section name. As an example, the following manual pages are available:
man sooshell : Sooshell manual. It provides a more detailed overview of Sooshell and its features.
man awk : AWK is a powerful text processing tool. The manual of AWK provides an overview of the AWK command and its parameters.
man jq : jq is a lightweight and flexible command-line JSON processor. The manual of jq provides an overview of the jq command and its parameters.
Use man commands completion feature to see all available manual pages.
Script management
Script management is a feature that allows users to create, store, and execute custom scripts on the Soodar router. This functionality leverages the router’s file management engine.
Scripts are stored in a dedicated filesystem within the router, specifically the “script:” filesystem. This organization ensures that scripts are kept separate from other system files and can be easily managed, accessed, and executed as needed.
CLI
The Sooshell CLI provides a set of commands to manage scripts. The following commands are available:
- copy <system:startup-config|system:running-config> script: [force]
This command copies the startup configuration or the running configuration of the router to the script filesystem. It allows you to save the current configuration as a script, which can be useful for simple backup purposes or for creating templates for future configurations.
system:startup-config
: Specifies the source to be the saved startup configuration.system:running-config
: Specifies the source to be the currently active running configuration.script:
: Specifies that the source is copied to script filesystem. This URI accepts an optional name parameter to specify the name of the script.force
: Optional parameter to overwrite an existing file. If not provided, the command will fail if the file already exists.
Note
script: URI is: script:[name].
Note
If a filename is not specified, the script will be saved as startup for the startup config and running for the running config.
Examples:
Copy the startup configuration to the script filesystem with default name:
router1# copy system:startup-config script:
Copy the running configuration to the script filesystem, overwriting any existing file named running:
router1# copy system:running-config script:running force
- copy <sftp:|ftp:|http:|https:> script: [force]
This command copies a file from a remote server using various file transfer protocols (SFTP, FTP, HTTP, or HTTPS) to the router’s script filesystem. It allows you to download scripts or configuration files from external sources and store them in the router’s script directory.
sftp:
: Specifies the source to be an SFTP server. the sftp: URI could contain the username, password and address of the remote computer with the path in remote. If URI is provided, all fields are shown to the user for confirmation; Otherwise, the user is asked for the required informationftp:
: specifies the source to be an FTP server. the ftp: URI could contain the username, password and address of the remote computer with the path in remote. If URI is not provided with username and password, the operation will fail.http[s]:
: specifies the source to be an HTTP[S] server.script:
: Specifies that the source is copied to the script filesystem. This URI accepts an optional name parameter to specify the name of the script.force
: Optional parameter to overwrite an existing file. If not provided, the command will fail if the file already exists.
Note
script: URI is: script:[name].
Note
sftp URI is: sftp://[user]:[password]@[host]:[path].
Note
ftp URI is: ftp://[user[:password]@]host[:port]/[url-path].
Note
If a filename is not specified in the destination, the system will use the original filename from the source.
Examples:
Copy a file from an SFTP server:
router1# sftp://user:password@192.168.1.100/scripts/my_script script:
Download a script from an HTTP server
router1# copy http://example.com/router_scripts/config_template script:
Retrieve a file from an FTP server and force overwrite any existing file
router1# ftp://anonymous@ftp.example.com/public/network_script script: force
Download a file from an HTTPS server and save it with a specific name:
router1# copy https://example.com/scripts/script script:new_script
- copy script: <sftp:> [force]
This command copies a file from the router’s script filesystem to a remote server using the SFTP (Secure File Transfer Protocol) protocol. It allows you to upload scripts or configuration files from the router to an external SFTP server.
script:
: Specifies the source to be the script filesystem.sftp:
: Specifies the destination to be an SFTP server. the sftp: URI could contain the username, password and address of the remote computer with the path in remote. If URI is provided, all fields are shown to the user for confirmation; Otherwise, the user is asked for the required informationforce
: Optional parameter to overwrite an existing file. If not provided, the command will fail if the file already exists.
Note
script: URI is: script:name.
Note
sftp URI is: sftp://[user]:[password]@[host]:[path].
Note
If a filename is not specified in the destination, the system will use the original filename from the source.
Examples:
Copy a script file to an SFTP server:
router1# copy script:my_script sftp://user:password@192.168.1.100/backups/
Copy a script to a specific directory on the SFTP server with a new name:
router1# copy script:router_config sftp://user:password@10.0.0.5/configs/router1_backup
- copy script: script: [force]
This command copies a file from the router’s script filesystem to another file in the script filesystem. It allows you to create a copy of a script or configuration file within the router’s script directory.
script:
: Specifies the source to be the script filesystem.script:
: Specifies the destination to be the script filesystem.force
: Optional parameter to overwrite an existing file. If not provided, the command will fail if the file already exists.
Note
script: URI is: script:name.
Note
Both source and destination file names should be provided.
- delete script:
This command is used to delete files from the router’s script filesystem.
script:
: Specifies the file to be deleted from the script filesystem.
Note
script: URI is: script:name.
- dir script:
This command lists the files in the router’s script filesystem.
- import script:
This command is used to execute scripts or apply configuration files from the router’s script filesystem. It functions similarly to the source command in POSIX shells, reading and executing the contents of the specified file in the current context of the router’s CLI.
script:
: Specifies the script to be imported from the script filesystem.
Note
script: URI is: script:name.
Note
When importing a script, the router executes the commands in the script line by line, as if they were entered manually in the CLI.
Note
The execution context is the same as the current CLI session, meaning variables and environment settings are preserved and can be used or modified by the script.
Examples:
content of my_script:
Import the file:
router1# import script:my_script hello world! router1# echo $var1 hello world! router1#
- run script:
This command runs a script from the router’s script filesystem. It allows you to execute a script stored in the router’s script directory.
script:
: Specifies the script to be executed from the script filesystem.
Note
script: URI is: script:name.
Note
Unlike the ‘import’ command, which executes commands in the current CLI context, ‘run’ typically executes the script in a separate environment and the current shell context is not affected.
Examples:
content of my_script:
Run the file:
router1# run script:my_script hello world! router1# echo $var1 router1#
- check-syntax script:
This command checks the syntax of a script without executing it. It allows you to verify the correctness of a script before running it.
script:
: Specifies the script to be checked from the script filesystem.
Note
script: URI is: script:name.
Note
The script is checked for syntax errors, but it is not checked for errors in commands spelling or their presence.
- edit script:
This command opens a script in the router’s script filesystem for editing. It allows you to create or modify the contents of a script stored in the router’s script directory.
script:
: Specifies the script to be edited from the script filesystem.
Note
script: URI is: script:name.
Note
The script is opened in the nano text editor.
- more script:
This command displays the contents of a script stored in the router’s script filesystem. It allows you to view the contents of a script without executing it.
script:
: Specifies the script to be displayed from the script filesystem.
Note
script: URI is: script:name.
- rename script: script:
This command renames a file in the router’s script filesystem. It allows you to change the name of a script stored in the router’s script directory.
script:
: Specifies the source file to be renamed in the script filesystem.script:
: Specifies the destination file name in the script filesystem.
Note
script: URI is: script:name.
Note
Both source and destination file names should be provided.