blockDiff
blockDiff(config: List<ConfigLine>, pattern: PatternBlocks<T>) : {data: T, blocks: MatchBlocks, diffCount: Integer}
Compares the block pattern pattern with the config lines in config and their children, and returns the closest
match: the match with the fewest differences. Unlike blockMatches,
blockDiff always returns exactly one record, even when the pattern does not fully match.
The record has the following fields:
data: TThe data extracted by the pattern lines that matched, merged into one record.blocks: MatchBlocksThe differences between the pattern and the configuration. Empty if the pattern fully matches.diffCount: IntegerThe number of differences.0if the pattern fully matches.
If several matches have the same number of differences, blockDiff returns one of them.
See Block Patterns for the block pattern syntax, and Details on Patterns for the syntax of each pattern line.
Matching rules
blockDiff matches pattern lines to config lines with the same rules as blockMatches. See
blockMatches matching rules.
Differences
The blocks field contains each difference, along with the config lines of its parent blocks. Lines that fully match
are omitted. Each difference counts toward diffCount and is one of the following:
| Difference | How blocks shows it | Contribution to diffCount |
|---|---|---|
| A pattern line that matches no config line | The pattern line, followed by **Missing** | 1 for the line and 1 for each pattern line nested under it |
| A config line that matches no pattern line, when unmatched config lines are forbidden | The config line, followed by **Extraneous** | 1 for the line and 1 for each config line nested under it |
A config line that matches a negated ({%-%}) pattern line | The config line, followed by **Present** | 1 |
Data
The type of data depends on the pattern:
- If the pattern has named components,
datais a record, and every field of the record is nullable. A field isnullif the pattern line that contains it is missing. For example, a pattern of typePatternBlocks<{name: String}>producesdataof type{name?: String}. - If the pattern does not produce a record, for example because it has a single unnamed component such as
{string},dataitself is nullable and isnullif the pattern line that contains the component is missing.
Null inputs
If config, any item in config, or pattern is null, the query fails with the error
First argument to “blockDiff” was null; consider adding an isPresent() condition. (or Second argument for
pattern). The config field of a device's files is nullable. Use
isPresent to exclude null values before calling blockDiff.
Examples
Each example compares a pattern with the following configuration, which is the same configuration used in the blockMatches examples:
hostname r1
interface GigabitEthernet1
description uplink
ip address 10.0.0.1 255.255.255.0
ip address 10.0.1.1 255.255.255.0 secondary
interface GigabitEthernet2
ip address 10.0.2.1 255.255.255.0
shutdown
interface GigabitEthernet3
shutdown
router bgp 65000
neighbor 10.0.0.2 remote-as 65001
You can try out each of these examples in NQE by inserting the pattern into the pattern variable in the following
template:
text =
"""
hostname r1
interface GigabitEthernet1
description uplink
ip address 10.0.0.1 255.255.255.0
ip address 10.0.1.1 255.255.255.0 secondary
interface GigabitEthernet2
ip address 10.0.2.1 255.255.255.0
shutdown
interface GigabitEthernet3
shutdown
router bgp 65000
neighbor 10.0.0.2 remote-as 65001
""";
pattern = ```
<your pattern here>
```;
match = blockDiff(parseConfigBlocks(OS.IOS, text), pattern);
[{ data: match.data, blocks: match.blocks, diffCount: match.diffCount }]
Full match
With pattern
interface {name:string}
ip address {ip:ipv4Address}
shutdown
We get results
data |
blocks |
diffCount |
|---|---|---|
{name: "GigabitEthernet2", ip: 10.0.2.1} |
Empty | 0 |
GigabitEthernet2 contains every line of the pattern, so there are no differences.
Missing child line
With pattern
interface GigabitEthernet3
shutdown
description uplink
We get results
data |
blocks |
diffCount |
|---|---|---|
{} |
|
1 |
GigabitEthernet3 has no description uplink line. The blocks field shows the missing line under the config line of
its parent block. The shutdown line fully matches, so blocks omits it.
Closest of several blocks
With pattern
interface {name:string}
description uplink
ip address 10.0.0.1 255.255.255.0
shutdown
We get results
data |
blocks |
diffCount |
|---|---|---|
{name: "GigabitEthernet1"} |
|
1 |
Every interface block matches the first pattern line, so blockDiff compares the pattern with each of them.
GigabitEthernet1 is missing one line, while GigabitEthernet2 and GigabitEthernet3 are each missing two, so
blockDiff returns the comparison with GigabitEthernet1.
Missing block
With pattern
router ospf 1
router-id 1.1.1.1
We get results
data |
blocks |
diffCount |
|---|---|---|
{} |
|
2 |
No config line matches router ospf 1, so that line and its child pattern line are both missing. Each missing line
counts toward diffCount.
Missing line with a named component
With pattern
hostname {host:string}
interface GigabitEthernet3
router ospf {id:number}
We get results
data |
blocks |
diffCount |
|---|---|---|
{host: "r1", id: null} |
|
1 |
The hostname and interface GigabitEthernet3 lines fully match, so blocks omits them. The router ospf line is
missing, so the id field of data is null.
Negated pattern line
With pattern
interface GigabitEthernet2
{%-%} shutdown
We get results
data |
blocks |
diffCount |
|---|---|---|
{} |
|
1 |
The pattern requires that GigabitEthernet2 has no shutdown line. The configuration has one, so blocks shows it as
present.
Forbidding unmatched config lines
With pattern
interface GigabitEthernet2
shutdown
{%unmatched-config:forbid%}
We get results
data |
blocks |
diffCount |
|---|---|---|
{} |
|
1 |
{%unmatched-config:forbid%} makes every child of the matched interface line that no pattern line matches a
difference. The ip address line is extraneous.
Example query
The following query checks each device for the required NTP and logging configuration, and lists the devices that differ from it, along with the differences.
pattern = ```
ntp server 10.0.0.1
logging host 10.0.0.2
```;
foreach device in network.devices
where isPresent(device.files.config)
let diff = blockDiff(device.files.config, pattern)
where diff.diffCount > 0
select {device: device.name, diffCount: diff.diffCount, differences: diff.blocks}
blockDiff returns a single record, so the query uses a let qualifier rather than a foreach qualifier. The
where diff.diffCount > 0 condition keeps only the devices that differ from the pattern.
blockDiff also accepts a Bag<ConfigLine> as its first argument. A Bag has no defined order, so this overload
produces a warning. Use orderBy() or order() to convert the argument to a List<ConfigLine>. In a future release,
the warning will become a type-checking error.
See also
Guides
Types
Functions
- blockMatches: Gets every complete match of a block pattern against a list of config lines.
- hasBlockMatch: Checks whether
blockMatchesreturns at least one match. - blockPattern: Creates a block pattern from a string.
- withOption: Changes how a block pattern handles unmatched config lines and partial line matches.