Skip to main content

Do patterns need to be standardized or will blockMatches match when lines are missing?

 

pattern=```
line one {main:string}
    sub-line1 may or may not be consistently present
    sub-line2 may or may not be consistently present
    sub-line3 {value1:string} is target and sub-line3 will always be there
    sub-line4 may or may not be consistently present
    sub-line5 may or may not be consistently present
    sub-line6 may or may not be consistently present
    sub-line7 may or may not be consistently present
    sub-line8 {value2:string} is target and sub-line8 will always be there
         sub-sub-line9 {value3:string} is target and sub-sub-line9 will always be there    

    sub-line10 may or may not be consistently present
    sub-line11 may or may not be consistently present
    sub-line12 {value4:string} is target and may or may not be present

         sub-sub-line13 {value5:string} is target and sub-sub-line13 will be there if sub-line12 is present

    sub-line14 may or may not be consistently present
```
foreach device in network.devices
foreach command in device.outputs.commands
where command.commandText == "show my lines"
let parsed_respone = parseConfigBlocks(OS.Other, command.response)
let  my_data = blockMatches(parsed_resonse, pattern)

foreach r in my_data
select {
  main: r.data.main,
  value1: r.data.value1,
  value2: r.data.value2,
  value3: r.data.value3,
  value4: r.data.value4

  value5: r.data.value5
}

Hi,

please check my posts how to start with Parsers:

 

it explains how to take the texts blob and make it parsable. 

Regarding parser structure, there is your exact example described in part 2 

I hope it helps.


In your case, you actually have two pattern.

The first one is when subline 12 not present: 

stats_pattern1 =
```
line one {main:string}
sub-line3 {value1:string} is target and sub-line3 will always be there
sub-line8 {value2:string} is target and sub-line8 will always be there
sub-sub-line9 {value3:string} is target and sub-sub-line9 will always be there
```;

The second one of subline 12 is present:

stats_pattern2 =
```
line one {main:string}
sub-line3 {value1:string} is target and sub-line3 will always be there
sub-line8 {value2:string} is target and sub-line8 will always be there
sub-sub-line9 {value3:string} is target and sub-sub-line9 will always be there
sub-line12 {value4:string} is target and may or may not be present
sub-sub-line13 {value5:string} is target and sub-sub-line13 will be there if sub-line12 is present
```;

 

The reason you need two pattern is that in your select statement you are asking for the output of value 4 and value 5 that do not exist in stats_pattern1:

select {
main: r.data.main,
value1: r.data.value1,
value2: r.data.value2,
value3: r.data.value3,
value4: r.data.value4,
value5: r.data.value5
}

additionally you have to replace:

let  my_data = blockMatches(parsed_resonse, pattern)

with 

foreach r in blockMatches(parsed_respone, stats_pattern)

to allow NQE to iterate over each line of block code.

 

Here is your NQE with both patterns that matches subline 12 pattern:

stats_pattern1 =
```
line one {main:string}
sub-line3 {value1:string} is target and sub-line3 will always be there
sub-line8 {value2:string} is target and sub-line8 will always be there
sub-sub-line9 {value3:string} is target and sub-sub-line9 will always be there
```;
stats_pattern2 =
```
line one {main:string}
sub-line3 {value1:string} is target and sub-line3 will always be there
sub-line8 {value2:string} is target and sub-line8 will always be there
sub-sub-line9 {value3:string} is target and sub-sub-line9 will always be there
sub-line12 {value4:string} is target and may or may not be present
sub-sub-line13 {value5:string} is target and sub-sub-line13 will be there if sub-line12 is present
```;

foreach device in network.devices
foreach command in device.outputs.commands
where command.commandText == "show my lines"
let parsed_respone = parseConfigBlocks(OS.UNKNOWN, command.response)
foreach r in blockMatches(parsed_respone, stats_pattern2)

select {
main: r.data.main,
value1: r.data.value1,
value2: r.data.value2,
value3: r.data.value3,
value4: r.data.value4,
value5: r.data.value5
}

 


Thank you. I’ll study this today and follow-up with “Best answer”


I apologize for the delayed response; I haven’t have time to get this to work with both patterns.  Pattern2 runs fine when there is a match but if not if value 4 and value 5 are missing, i.e. matches pattern1.  I hope to have some time this week to research the solution for myself. Thank you.


Hi @dakotaglory ,

 

try this one. It addresses the missing value 4 and 5

stats_pattern =
```
line one {main:string}
sub-line3 {value1:string} is target and sub-line3 will always be there
sub-line8 {value2:string} is target and sub-line8 will always be there
sub-sub-line9 {value3:string} is target and sub-sub-line9 will always be there
```;

stats_pattern2 =
```
line one {main:string}
sub-line3 {value1:string} is target and sub-line3 will always be there
sub-line8 {value2:string} is target and sub-line8 will always be there
sub-sub-line9 {value3:string} is target and sub-sub-line9 will always be there
sub-line12 {value4:string} is target and may or may not be present
sub-sub-line13 {value5:string} is target and sub-sub-line13 will be there if sub-line12 is present
```;

foreach device in network.devices
foreach command in device.outputs.commands
where command.commandText == "show my lines"
let parsed_respone = parseConfigBlocks(OS.UNKNOWN, command.response)
foreach r in blockMatches(parsed_respone, stats_pattern)
let rPlus = max(foreach match in blockMatches(parsed_respone, stats_pattern2)
where match.data.main == r.data.main
select match)
select {
main: r.data.main,
value1: r.data.value1,
value2: r.data.value2,
value3: r.data.value3,
value4: rPlus?.data?.value4,
value5: rPlus?.data?.value5
}

credits for this enhancement is to @Tyson Henrie 

Thank you Tyson


can you post the entirety of the NQE with the enhancement in 1 code block?


Hi @CarlB 

Can you use the code block above?


having to modify to match my environment and hitting the usual challenges.  Is that final block 100% with all replacements/modifications?  


@CarlB That example is fairly generic.  If you are having trouble adapting that to your use case.  Can you share a sanitized example of the data file you are trying to parse and the query you are currently using? That might be good as a new post.


I think I have it working.

 

NHRPnoFWpattern =

  ```

{IPandPrefix:string} via {VPNpeer: ipv4Address}

  {tunnelnum: string} created

  NBMA address: {TunPublic: ipv4Address}

```;

 

NHRPwithNATpattern =

  ```

{IPandPrefix:string} via {VPNpeer: ipv4Address}

  {tunnelnum: string} created

  NBMA address: {TunPublic: ipv4Address}

   {string} NBMA address: {NoNATtunPublic: string}

```;

 

cleanParen(s) = cleanLParen(cleanRParen(s));

 

cleanLParen(s) = replaceMatches(s, "(", "");

 

cleanRParen(s) = replaceMatches(s, ")", "");


 

foreach device in network.devices

foreach command in device.outputs.commands

  where command.commandType == CommandType.NHRP_STATE

 

foreach x in <1]

//let ParsedResponse = parseConfigBlocks(OS.UNKNOWN, command.response)

let ParsedResponse = parseConfigBlocks(OS.UNKNOWN, cleanParen(command.response))

foreach r in blockMatches(ParsedResponse, NHRPnoFWpattern)

let rPlus = max(foreach match in blockMatches(ParsedResponse, NHRPwithNATpattern)

            where match.data.IPandPrefix == r.data.IPandPrefix

            select match)

 

select {

  Prefix: r.data.IPandPrefix,

  IP: r.data.VPNpeer,

  ARIN: r.data.TunPublic,

  LAN: rPlus?.data?.NoNATtunPublic

}

 


@CarlB going to use the code embedding so its easier for others to read. Thanks for posting!!

 

NHRPnoFWpattern =

```

{IPandPrefix:string} via {VPNpeer: ipv4Address}

{tunnelnum: string} created

NBMA address: {TunPublic: ipv4Address}

```;



NHRPwithNATpattern =

```

{IPandPrefix:string} via {VPNpeer: ipv4Address}

{tunnelnum: string} created

NBMA address: {TunPublic: ipv4Address}

{string} NBMA address: {NoNATtunPublic: string}

```;



cleanParen(s) = cleanLParen(cleanRParen(s));



cleanLParen(s) = replaceMatches(s, "(", "");



cleanRParen(s) = replaceMatches(s, ")", "");




foreach device in network.devices

foreach command in device.outputs.commands

where command.commandType == CommandType.NHRP_STATE



foreach x in 1]

//let ParsedResponse = parseConfigBlocks(OS.UNKNOWN, command.response)

let ParsedResponse = parseConfigBlocks(OS.UNKNOWN, cleanParen(command.response))

foreach r in blockMatches(ParsedResponse, NHRPnoFWpattern)

let rPlus = max(foreach match in blockMatches(ParsedResponse, NHRPwithNATpattern)

where match.data.IPandPrefix == r.data.IPandPrefix

select match)



select {

Prefix: r.data.IPandPrefix,

IP: r.data.VPNpeer,

ARIN: r.data.TunPublic,

LAN: rPlus?.data?.NoNATtunPublic

}

 


Reply