Chapter 3. Understanding the Salt CLI Syntax

It is very important to understand how Salt works when running commands from the CLI. The same methodologies can be used when instructing the system to execute commands periodically via Salt’s scheduler or when listening to events and via the reactor, only the syntax is different.

The Salt CLI syntax has the following pattern:

$ sudo salt [<options>] <target> <function> [<arguments>]

One of the simplest uses is shown in Example 3-1, which executes the test.ping function on the device identified using the minion ID device1, without any options or arguments.

Example 3-1. Basic CLI execution invoking the test.ping execution function
$ sudo salt device1 test.ping
# output omitted

As we move forward, we’ll analyze each of the components shown here.

Functions and Arguments

Salt is structured as a very simple and pluggable core with many features able to interact between them. A very important functionlity is represented by the execution modules. They are the main entry point into the Salt world. The execution modules are Python modules, and are very easy to read (and eventually write) by anyone with basic Python programming knowledge. Everything is linear, which makes them flexible and easy to understand; in general, they consist only of simple functions.

In Example 3-1 we executed test.ping: test is the name of the execution module, while ping is the execution function inside this module.

Note

There are many module types in Salt and some even have overlapping names, so it is important to always qualify the type of the module. For example, the file state module and the file execution module are different modules and used in different contexts.

This function only returns the logical value True when the minion is up. test.ping is an excellent way to test that the minion has been configured correctly and its key is accepted by the master. It doesn’t mean, however, that the connection to the network device succeeded. For this particular usage we can execute the net.connected module. Repeating the exercise: the Python function connected is defined under the Salt execution module net. While the test execution module corresponds to a Python module called test.py, net corresponds to napalm_network.py. This is because some modules have a virtual name associated and they are loaded under a cross-platform consistent name.

Tip

There are many thousands of functions available. For the complete module reference, consult the Salt Module Index.

An execution function must return JSON-serializable data structures. Thanks to this approach the output can be manipulated, ported, and reused in different modules, displayed in the shape we require or transform it and load in a certain service. A good example is on the CLI: the output is transformed into a more human-readable and colorful format. There are many possibilities to adjust the output and this can be pluggable: you even have the option of customizing the way the output is processed and presented.

In Example 3-2, after test.ping was executed Salt provides the response from device1 as True.

Example 3-2. Sample CLI output
$ sudo salt device1 test.ping
device1:
    True

Another useful function is grains.items, which provides the complete list of grains, and grains.get, which returns the value of a given grain identified by name, as shown in Example 3-3.

Example 3-3. Retrieve the serial grain value
$ sudo salt device1 grains.get serial
device1:
    VM58737E84CF

In a similar way, pillar.items provides the pillar data available on the minion, while pillar.get returns a specific value (see Example 3-4).

Example 3-4. Retrieve the ntp.servers grain value
$ sudo salt device1 pillar.get ntp.servers
device1:
    - 172.17.17.1
    - 172.17.17.2

Here, the pillar key ntp.servers has the value of a list of NTP servers. This also introduces the arguments to Example 3-4. ntp.servers is an argument passed to the get execution function from the pillar execution module.

To check what modules are loaded, identified by their virtual name, we can run sys.list_modules. Similarly, to display the complete list of available functions we can run sys.list_functions.

For network automation needs there are many execution functions natively embedded in Salt. For example, net.arp retrieves the ARP tables (see Example 3-5).

Example 3-5. Sample CLI output: net.arp
$ sudo salt device1 net.arp
device1:
    ----------
    out:
        |_
          ----------
          age:
              129.0
          interface:
              ae2.100
          ip:
              10.0.0.1
          mac:
              00:0f:53:36:e4:50
        |_
          ----------
          age:
              1101.0
          interface:
              xe-0/0/3.0
          ip:
              10.0.0.2
          mac:
              00:1d:70:83:40:c0

In Example 3-5 we executed the net.arp function, which retrieves the ARP table from device1. One can easily notice that the output is not a Python object, though. The reasoning is that although the arp execution function returned JSON-serializable data, Salt transformed it in a more human-readable and colorful format when displaying on the CLI. This format comes from an outputter module called nested. The user can choose to display the data formatted by a different outputter if they prefer.

The output is a list of ARP entries, each having the following details: age, interface, ip, and mac. It is vendor-agnostic, thanks to NAPALM capabilities, so executing net.arp against a device running a different supported platform will return exactly the same structure!

Several other samples are provided in Examples 3-6 through 3-8.

Example 3-6. net.arp using arguments
$ sudo salt device3 net.arp interface=TenGigE0/0/0/0
# output omitted

Note that although net.arp does not require an argument in Example 3-5, it can be passed. However, in Example 3-6, we retrieve the ARP table from device3 but only on the interface TenGigE0/0/0/0.

Example 3-7. The ntp.stats execution function
$ sudo salt device2 ntp.stats 172.17.17.1
# output omitted

Example 3-7 returns the NTP synchronization statistics with the server 172.17.17.1 from device2. The ntp.stats execution function can be equally executed without an explicit argument, in that case it returns the synchronization details with all the NTP peers.

Example 3-8. The net.ping execution function
$ sudo salt device1 net.ping 8.8.8.8 vrf=CUSTOMER1
# output omitted

In Example 3-8 we execute a ping to 8.8.8.8 from the CUSTOMER1 VRF.

You can learn more about these functions in the documentation, but sometimes it’s easier to check it directly from the CLI by executing sys.doc followed by the function or module name (e.g., salt device1 sys.doc net.arp). To check which arguments are mandatory and which ones are the default values, you can run sys.argspec in a similar way (e.g., salt device1 sys.argspec net.arp).

Targeting Devices

Targeting is used on the CLI but also in scheduled actions or when reacting to events. It is used to select a group of minions that need to execute a function. Targeting is a task sent by the master in a payload to all minions and the minions decide independently if the target matched their characteristics. This is yet another optimization that makes Salt extremely scalable. In the next sections, we will be executing the test.ping function.

Targeting Using the Minion ID

This is the first targeting method we are exposed to. It’s very easy to understand because it executes the function on a single minion, identified by its ID.

As we have already seen, the command shown in Example 3-9 executes test.ping only on device1.

Example 3-9. Global targeting command
$ sudo salt device1 test.ping
# output omitted

Targeting Using a List of Minion IDs

As shown in Example 3-10, using the -L option we can tell the salt executable to call the function on a list of minions, their IDs being specified as comma-separated values. (It is best to avoid spaces in-between each ID since that format isn’t universally supported throughout Salt.)

Example 3-10. List targeting
$ sudo salt -L device1,device2 grains.get vendor
device2:
    Juniper
device1:
    Arista

Example 3-10 is going to execute the grains.get function on device1 and device2 using the vendor argument. The reply provides the value of the vendor grain for each device.

Important

The reply order from each device is not necessarily the order we have requested. Salt works asynchronously and the output is displayed as soon as it is received from the minion.

Targeting Using Shell-Like Globbing

The minions can be selected via their minion ID using shell-style globbing:

Pattern Explanation

*

Matches everything

?

Matches any single character

[seq]

Matches any character in the sequence

[!seq]

Matches any character that is not in the sequence

The device* expression from Example 3-11 matches device1, device2, and device3, as these are the Minions authenticated to this Salt master whose ID starts with “device”. If you have thousands of minions with the ID beginning with device, they all would be matched so you don’t need to write a static list.

Example 3-11. Shell-style globbing to target minions whose ID starts with device
$ sudo salt 'device*' grains.get model
device1:
    VMX
device2:
    vEOS
device3:
    ASR9001

Targeting Using Regular Expressions

Using Perl-compatible regular expressions (PCRE), we can use an even more flexible way to select groups of minions using their ID (see Example 3-12).

Example 3-12. Targeting using regular expressions
$ sudo salt -E '(device|edge)d' test.ping
# output omitted

In this example, the command would be executed on minions starting with either device or edge, followed by a digit. Note the usage of the -E option.

Targeting Using Grains

Grains can be also used to target minions using their characteristics, as shown in Examples 3-13 through 3-15 (if you need a refresher on the topic, refer back to “Grains”).

Example 3-13. Target devices running Junos
$ sudo salt -G 'os:junos' test.ping
# output omitted
Example 3-14. Target devices running Junos 15.1F7.3
$ sudo salt -C 'G@os:junos and G@version:15.1F7.3' test.ping
# output omitted
Example 3-15. Target Cisco ASR routers having TenGigE0/0/0/30 in the list of interfaces
$ sudo salt -C 'G@vendor:cisco
and G@model:ASR*
and G@interfaces:TenGigE0/0/0/30' test.ping
# output omitted
Note

Example 3-15 shows that grain matching also accepts globbing (model:ASR* matches any ASR model). To match grains using regular expressions use the -P option instead.

Targeting Using Pillar Data

In a very similar way it is also possible to target using nested pillar values. For example, we could match the minions that have the hostname ending with as1234.net (Example 3-16).

Example 3-16. Target using the host field under the proxy key in pillar
$ sudo salt -I 'proxy:host:*as1234.net' test.ping
# output omitted

The nesting levels are separated using the : character. However, this can also be changed and select a different delimiter, using the --delimiter option: salt --delimiter='/' -I 'proxy/host/*as1234.net' test.ping.

Note

This option also allows globbing. To match using regular expressions, use the -J option.

Compound Target Matching

Everything we just covered can be combined and form a very complex target expression. The command option in that case becomes -C and the previous options must be specified in the body of the match string using the @ sign (see Examples 3-17 and 3-18).

Example 3-17. Target minions whose ID starts with device that are running IOS-XR 6.x
$ sudo salt -C 'device* and G@os:iosxr and G@version:6.*' test.ping
# output omitted
Example 3-18. Target MX960 and MX480 routers having the hostname respecting a regular expression
$ sudo salt -C '
P@model:(MX960|MX480)
and J@proxy:host:^(.*bbone.asd+.net)$ ' test.ping
# output omitted

Defining and Targeting Using Nodegroups

For very complex examples such as the one shown in Example 3-18, we can add their definition in the master configuration file along with a name and then use it directly rather than typing the same matching expression each time. These are called nodegroups, and they serve mostly as shortcuts (see Example 3-19).

Example 3-19. Nodegroups definition in the master config file
nodegroups:
  bbone-mxs: |
    P@model:(MX960|MX480)
    and J@proxy:host:^(.*bbone.asd+.net)$
  iosxr6: |
    device*
    and G@os:iosxr and G@version:6.*

Which can be used through the -N CLI option (Example 3-20):

Example 3-20. Nodegroups usage
$ salt -N bbone-mxs test.ping
# output omitted
$ salt -N iosxr6 test.ping
# output omitted

Targeting Inside the Top File

The matching techniques presented can also be used in the top file, where the default match is the compound matcher. We can exploit this flexibility to create smart mappings between the device characteristics and the data entities to be provided.

For example, consider the pillar top file shown in Example 3-21.

Example 3-21. Pillar top file mappings using advanced targeting
base:
  'device* and G@os:iosxr and G@version:6.*':
    - pillar_for_iosxr6
  'N@bbone-mxs':
    - mx_routers_bbone

This top file includes the pillar_for_iosxr6.sls pillar on minions managing Cisco IOS-XR 6.x devices, and equally the mx_routers_bbone.sls pillar for minions matching the bbone-mxs nodegroup defined earlier in Example 3-19.

Options

The salt command has a very long list of options, which you can retrieve by executing salt --help. In “Targeting Devices” we have listing some of the most usual, the target options. We highly encourage you to explore the full list of options, as they prove very handy in many situations. Due to size limitations in this book, we will present only a few of the most common.

Outputters

As we discussed earlier, the output from Salt functions is JSON serializable. This output can be transformed in different shapes depending on the application or personal preferences. One can choose using the --out option between: json, yaml, nested (default), table, raw (displays the exact Python object), or pprint (displays the Python object in a more human-readable form).

Example 3-22. net.arp using the JSON outputter
$ sudo salt --out=json device1 net.arp
[
  {
    "interface": "ae2.100",
    "ip": "10.0.0.1",
    "mac": "00:0f:53:36:e4:50",
    "age": 129.0
  },
  {
    "interface": "xe-0/0/3.0",
    "ip": "10.0.0.2",
    "mac": "00:1d:70:83:40:c0",
    "age": 1101.0
  }
]
Important

The outputter only displays the Python object on the CLI in a more readable shape. It does not change its structure!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.142.136.226