Skip to content

Commit

Permalink
12.11 work
Browse files Browse the repository at this point in the history
  • Loading branch information
DumpySquare committed Dec 11, 2024
1 parent f5376e2 commit db1aa29
Show file tree
Hide file tree
Showing 12 changed files with 417 additions and 175 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how

### Fixed

[BUG] clean up quotes from strings with spaces #47


---

## [1.11.0] - (10-24-2024)
## [1.11.1] - (12-11-2024)

### Fixed

Expand All @@ -29,6 +31,8 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
- Most of the time they are applied at the "service group"
- [RFE] Processing vservers using IPv6 addresses #43
- [RFE] ns json output to main work flow #45
- [BUG] options parsing breaks with spaces/quotes/special-chars #46
- [BUG] not capturing DISABLED state of serviceGroup/service members #49

---

Expand Down
Binary file modified f5_flipper_test.tgz
Binary file not shown.
309 changes: 182 additions & 127 deletions src/digLbVserver.ts

Large diffs are not rendered by default.

12 changes: 9 additions & 3 deletions src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,8 @@ export type Stats = {
export type AdcRegExTree = {
adcVersion: RegExp;
adcBuild: RegExp;
cfgOptions: RegExp;
cfgOptionsQuotes: RegExp;
// cfgOptions: RegExp;
// cfgOptionsQuotes: RegExp;
verbs: RegExp;
trimQuotes: RegExp;
parents: {
Expand All @@ -238,8 +238,10 @@ export type AdcRegExTree = {
'add gslb vserver': RegExp;
'add gslb service': RegExp;
'add gslb site': RegExp;
'add rewrite action': RegExp;
'add rewrite policy': RegExp;
'add rewrite action': RegExp;
'add responder policy': RegExp;
'add responder action': RegExp;
'add appflow policy': RegExp;
'add appflow action': RegExp;
'add appflow collector': RegExp;
Expand Down Expand Up @@ -287,8 +289,12 @@ export type AdcConfObj = {
service?: string[];
}
rewrite?: {
policy?: string[];
action?: string[];
};
responder?: {
policy?: string[];
action?: string[];
};
cache?: string;
dns?: {
Expand Down
65 changes: 46 additions & 19 deletions src/parseAdcUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,38 +17,65 @@ import { AdcRegExTree } from "./models";
* @param rx regex tree for specific ns adc version
* @returns options as an object
*/
export function parseNsOptions(str: string, rx: AdcRegExTree): { [k: string]: string } {
export function parseNsOptions(str: string = "", rx: AdcRegExTree): { [k: string]: string } {
const obj = {}

// grep out all the options with quotes/spaces
str.match(rx.cfgOptionsQuotes)?.forEach(el => {
// if(str === undefined) return obj;

// 12.11.2024: this is a hack to get the regex working for now.
// The current rx doesn't pick up the last "-key value" since it uses forward lookups.
str = str.concat(" -devno 12345")

// grep out all the options with quotes/spaces/normal
// tested with https://regex101.com/r/WCU928/1
const matches = str.match(/(?<key>-\S+) (?<value>.*?) (?=-\S+)/g);

matches?.forEach(el => {
// split the name off by the first space
const [k, v] = el.split(/ (.*)/)
obj[k] = v;
str = str.replace(el, '')
})
const k = el.substring(0, el.indexOf(' '));
// everything after the first space and trim any trailing white space
const v = el.substring(el.indexOf(' ') + 1).trimEnd().replaceAll(/^\"|\"$/g, "");

// capture everything else without spaces
str.match(rx.cfgOptions)?.forEach(el => {
const [k, v] = el.split(' ')
if (k === '-devno') {
// no nothing, devno is not needed
if(k === '-devno') {

// skip adding it to the return object
} else {
// add to object
obj[k] = v;
str = str.replace(el, '')

obj[k] = trimQuotes(v);
}
str = str.replace(el, '')
})

// // turn certain object values to arrays
// if () {

// }
// only thing left in the string should be '-devno 123456'
// todo: add some logic to check if other things are left outside -devno and log those details for visibility

return obj;
}


/**
* detects and trims quotes at the beginning and end of string
* @param s string
* @returns
*/
export function trimQuotes(s: string): string {

// what is the index of the first "
const first = s.indexOf('"');
// what is the index of the last "
const last = s.lastIndexOf('"');
// get the total length of string
const stringL = s.length;

// Do we have a quote at the beginning and end?
if(first === 0 && last === s.length-1) {
// return the string between the first and last char (")
s = s.substring(1, s.length-1)
}
return s;
}


/**
* sort ns adc config by verbs
* add -> set -> bind -> link -> enable -> disable
Expand Down
14 changes: 8 additions & 6 deletions src/regex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ export class RegExTree {
* example; "set ns config -IPAddress 192.168.86.140 -netmask 255.255.255.0"
* captures ['-IPAddress 192.168.86.140', '-netmask 255.255.255.0']
*/
public cfgOptions = /-\w+ \S+/g;
public cfgOptionsQuotes = /-\w+ "[\S ]+"/g;
// public cfgOptions = /-\w+ \S+/g;
// public cfgOptionsQuotes = /-\w+ "[\S ]+"/g;

private ipAddr = /(?:[0-9]{1,3}\.){3}[0-9]{1,3}/;

Expand All @@ -54,8 +54,8 @@ export class RegExTree {
private regexTree: AdcRegExTree = {
adcVersion: this.adcVersionBaseReg,
adcBuild: this.adcVersionBuildReg,
cfgOptions: this.cfgOptions,
cfgOptionsQuotes: this.cfgOptionsQuotes,
// cfgOptions: this.cfgOptions,
// cfgOptionsQuotes: this.cfgOptionsQuotes,
verbs: /^(add|set|bind|link|enable|disable) /,
trimQuotes: /^"(.*)"$/,
parents: {
Expand All @@ -76,8 +76,10 @@ export class RegExTree {
'add gslb vserver': /(?<name>("[\S ]+"|[\S]+)) (?<protocol>\S+) (?<opts>[\S ]+)/,
'add gslb service': /(?<name>("[\S ]+"|[\S]+)) (?<server>\S+) (?<protocol>\S+) (?<port>(\d+|\*)) (?<opts>[\S ]+)/,
'add gslb site': /(?<name>("[\S ]+"|[\S]+)) (?<server>\S+) (?<opts>[\S ]+)/,
'add rewrite action': /(?<name>\S+) (?<opts>[\S ]+)/,
'add rewrite policy': /(?<name>\S+) (?<opts>[\S ]+)/,
'add rewrite action': /(?<name>\S+) (?<opts>[\S ]+)/,
'add responder policy': /(?<name>\S+) (?<opts>[\S ]+)/,
'add responder action': /(?<name>\S+) (?<opts>[\S ]+)/,
'add appflow policy': /(?<name>\S+) (?<rule>[\S]+) (?<action>[\S]+)/,
'add appflow action': /(?<name>\S+) (?<opts>[\S ]+)/,
'add appflow collector': /(?<name>\S+) (?<opts>[\S ]+)/,
Expand All @@ -88,7 +90,7 @@ export class RegExTree {
'set ns hostName': /(?<hostName>[\S ]+)/,
'set gslb vserver': /(?<name>\S+) (?<opts>[\S ]+)/,
'bind service': /(?<name>("[\S ]+"|[\S]+)) ((?<serv>\S+ (\d+|\*))|(?<monitor>-monitorName \S+)|(?<opts>[\S ]+))/,
'bind serviceGroup': /(?<name>("[\S ]+"|[\S]+)) ((?<serv>\S+ (\d+|\*))|(?<monitor>-monitorName \S+)|(?<opts>[\S ]+))/,
'bind serviceGroup': /(?<name>("[\S ]+"|[\S]+)) ((?<serv>\S+) (?<port>\d+|\*))?(?<opts>[\S ]+)?/,
'bind lb vserver': /(?<name>("[\S ]+"|[\S]+)) ((?<opts>-[\S ]+)|(?<service>("[\S ]+"|[\S]+)))/,
'bind cs vserver': /(?<name>("[\S ]+"|[\S]+)) (?<opts>[\S ]+)/,
'bind ssl service': /(?<name>("[\S ]+"|[\S]+)) (?<opts>[\S ]+)/,
Expand Down
108 changes: 108 additions & 0 deletions tests/007_parseNsOpts.unit.tests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/*
* Copyright 2020. F5 Networks, Inc. See End User License Agreement ("EULA") for
* license terms. Notwithstanding anything to the contrary in the EULA, Licensee
* may copy and modify this software product for its internal business purposes.
* Further, Licensee may upload, publish and distribute the modified version of
* the software product on devcentral.f5.com.
*/

'use strict';

import assert from 'assert';
import { RegExTree } from '../src/regex';
import { parseNsOptions } from '../src/parseAdcUtils';

const events = [];
const parsedFileEvents: any[] = []
const parsedObjEvents: any[] = []
const rx = new RegExTree().get('13.1');

describe('parse NS options function tests', function () {




before(async function () {
// log test file name - makes it easer for troubleshooting
console.log(' file:', __filename)

// clear the events arrays
parsedFileEvents.length = 0
parsedObjEvents.length = 0

});

afterEach(function () {
events.length = 0;
})



// it(`regular options single`, async () => {

// const items = [
// 'add server sprout135A_groot 192.168.160.120 -devno 108847',
// 'add server sprout135c_groot 192.168.160.69 -devno 108848',
// 'add server dorsal-nedc 10.8.101.46 -comment "automated deployment"',
// 'add server dorsal-swdc 10.12.101.46 -comment "automated deployment"',
// 'add server stpvec1 stpvec1.f5flipper.com -comment "automated deployment"',
// 'add server stpvec2 stpvec2.f5flipper.com -comment "automated deployment"',
// ];

// // strip off all the leading parent object details 'add server '
// const slim = items.map(x => x.replace('add server ', ''))

// const rxMatches = slim.map(x => x.match(rx.parents['add server']))

// const misses = rxMatches.filter(x => x === undefined)

// assert.ok(misses.length === 0, 'should not have any rx misses');
// })

it(`lb monitor options complicated`, async () => {

// this test should accomodate all options on all NS configs.
// just happened to be monitors when this needed to get worked out.
// so add any other config lines with options and add additional tests as needed

const items = [
'add lb monitor test01_http_ecv_mon HTTP-ECV -customHeaders "Host:flippy.doda.com\\r\\n" -send "GET /HealthCheck" -recv "\\\"Version\\\"" -LRTM DISABLED -secure YES -devno 12357',
'add lb monitor http-custom-8202_mon HTTP -respCode 306-307 -httpRequest "HEAD /" -LRTM DISABLED -interval 10 -resptimeout 5 -destPort 8202 -secure YES -devno 12355',
'add lb monitor test02_http_80_mon HTTP -respCode 200 -httpRequest "HEAD /to/know/all" -LRTM DISABLED -devno 12345',
'add lb monitor basic_tcp_monitor TCP -LRTM DISABLED -interval 10 -resptimeout 5 -secure YES -devno 12356',
'add lb monitor "test with spaces http mon" HTTP-ECV -send "GET /some/complicated/name" -recv OK -LRTM DISABLED -destPort 8081 -devno 12365',
'add lb monitor redirect_http-mon HTTP -respCode 301 -httpRequest "HEAD /artifactory" -LRTM DISABLED -secure YES -devno 12366',
'add lb monitor http200_mon HTTP -respCode 200 -httpRequest "GET /api/v1/system/health" -LRTM DISABLED -destPort 8082 -devno 12367',
'add lb monitor kaizen_http1.1_mon HTTP-ECV -customHeaders "Host:modern.samurai.chi\\r\\n" -send "GET /focusReady" -recv "\"zen\"" -LRTM DISABLED -secure YES -devno 12363',
];

// cut down array of monitors
// these shorter versions better represent what the function will actually see during processing
const slim: string[] = []

// strip off all the leading parent object details 'add lb monitor ... ... '
for await(const x of items) {
//find the index of the first opt "-\S+"
const firstOptIdx = x.match(/ -\S+ /)?.index || 0;
// return the rest of the string from the first match index
const restOfString = x.substring(firstOptIdx);
slim.push(restOfString);
}

// loop through the array and parse all the ns options
const optsObx = slim.map(i => parseNsOptions(i, rx));

assert.deepStrictEqual("Host:flippy.doda.com\\r\\n", optsObx[0]['-customHeaders']);
assert.deepStrictEqual('306-307', optsObx[1]['-respCode']);
assert.deepStrictEqual('HEAD /to/know/all', optsObx[2]['-httpRequest']);
assert.deepStrictEqual('YES', optsObx[3]['-secure']);
assert.deepStrictEqual('8081', optsObx[4]['-destPort']);
assert.deepStrictEqual('DISABLED', optsObx[5]['-LRTM']);
assert.deepStrictEqual("GET /api/v1/system/health", optsObx[6]['-httpRequest']);
assert.deepStrictEqual("Host:modern.samurai.chi\\r\\n", optsObx[7]['-customHeaders']);
assert.deepStrictEqual("GET /focusReady", optsObx[7]['-send']);
})


});
34 changes: 17 additions & 17 deletions tests/024_service.unit.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ describe('service abstraction tests', function () {

assert.deepStrictEqual(app!.bindings!.service!.length, 3, "should have three service bindings")
assert.deepStrictEqual(app!.lines!.length, 16, "should have 16 total lines of ns config")

})

it(`basic service reference non ssl with monitor`, async () => {
Expand All @@ -81,7 +81,7 @@ describe('service abstraction tests', function () {

assert.deepStrictEqual(app!.bindings!.service!.length, 1, "should have three service bindings")
assert.deepStrictEqual(app!.lines!.length, 6, "should have 16 total lines of ns config")

})

it(`basic service reference ssl`, async () => {
Expand All @@ -93,7 +93,7 @@ describe('service abstraction tests', function () {

assert.deepStrictEqual(app!.bindings!.service!.length, 1, "should have one service bindings")
assert.deepStrictEqual(app!.lines!.length, 9, "should have 16 total lines of ns config")

})


Expand All @@ -115,27 +115,27 @@ describe('service abstraction tests', function () {
port: "82",
server: "SERVERCORE1",
opts: {
"-gslb": "NONE",
"-maxClient": "0",
"-maxReq": "0",
"-cip": "ENABLED",
"-ip": "-usip",
"-useproxyport": "YES",
"-sp": "OFF",
"-cltTimeout": "180",
"-svrTimeout": "360",
"-CKA": "NO",
"-TCPB": "NO",
"-CMP": "YES",
"-gslb": "NONE",
"-maxClient": "0",
"-maxReq": "0",
"-cip": "ENABLED client-ip",
"-usip": "NO",
"-useproxyport": "YES",
"-sp": "OFF",
"-cltTimeout": "180",
"-svrTimeout": "360",
"-CKA": "NO",
"-TCPB": "NO",
"-CMP": "YES",
},
hostname: "sevcore1.jonny.dev",
}, "should have three service bindings")
}, "should have three service bindings")

const addressService = appServices!.filter(x => x.address === "10.240.21.115")[0]

// this just confirms that we got back the service with the right "address" and "name"
assert.deepStrictEqual(addressService.name, "FUJI02_HTTPS_SVC")

})


Expand Down
2 changes: 1 addition & 1 deletion tests/031_sslCerts.unit.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ describe('ssl certificate tests', function () {
"-key": "www.star.groot_2022.pfx",
"-inform": "PFX",
"-passcrypt": "XXXX",
"-encrypted": "-encryptmethod",
"-encrypted": "-encryptmethod ENCMTHD_3",
profileName: "star.groot.cer",
})

Expand Down
Loading

0 comments on commit db1aa29

Please sign in to comment.