From 3ca7852eb2e2ec53e09e09db0e593bd0e7c82121 Mon Sep 17 00:00:00 2001 From: Mauricio Massa Date: Fri, 3 Jan 2025 16:50:55 -0500 Subject: [PATCH] add support for ltm rules --- ast/ast.go | 17 +++++++++++++++++ parser/parser.go | 34 +++++++++++++++++++++++++++++----- test-data/ltm.irule | 9 +++++++++ token/token.go | 4 ++++ 4 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 test-data/ltm.irule diff --git a/ast/ast.go b/ast/ast.go index a6cbdaf..6a6d468 100644 --- a/ast/ast.go +++ b/ast/ast.go @@ -752,3 +752,20 @@ func (ns *NodeStatement) TokenLiteral() string { return ns.Token.Literal } func (ns *NodeStatement) String() string { return fmt.Sprintf("node %s %s", ns.IPAddress, ns.Port) } + +type LtmRule struct { + Token token.Token + Name *Identifier + Body *BlockStatement +} + +func (lr *LtmRule) statementNode() {} +func (lr *LtmRule) TokenLiteral() string { return lr.Token.Literal } +func (lr *LtmRule) String() string { + var out bytes.Buffer + out.WriteString("ltm rule ") + out.WriteString(lr.Name.String()) + out.WriteString(" ") + out.WriteString(lr.Body.String()) + return out.String() +} diff --git a/parser/parser.go b/parser/parser.go index ad0c3fa..383a3e6 100644 --- a/parser/parser.go +++ b/parser/parser.go @@ -286,6 +286,8 @@ func (p *Parser) parseStatement() ast.Statement { stmt = p.parseBlockStatement() case token.SWITCH: stmt = p.parseSwitchStatement() + case token.LTM: + stmt = p.parseLtmRule() default: stmt = p.parseExpressionStatement() } @@ -2188,15 +2190,37 @@ func (p *Parser) parseNodeStatement() ast.Expression { } nodeStmt.IPAddress = p.curToken.Literal - // Expect the next token to be a port number - if !p.expectPeek(token.NUMBER) { - return nil + // Expect the next token to be a port number, but don't require it + if p.peekTokenIs(token.NUMBER) { + p.nextToken() + nodeStmt.Port = p.curToken.Literal } - nodeStmt.Port = p.curToken.Literal if config.DebugMode { - fmt.Printf("DEBUG: parseNodeStatement End\n") + fmt.Printf("DEBUG: parseNodeStatement End - IP: %s, Port: %s\n", nodeStmt.IPAddress, nodeStmt.Port) } return nodeStmt } + +func (p *Parser) parseLtmRule() ast.Statement { + stmt := &ast.LtmRule{Token: p.curToken} + + if !p.expectPeek(token.RULE) { + return nil + } + + if !p.expectPeek(token.IDENT) { + return nil + } + + stmt.Name = &ast.Identifier{Token: p.curToken, Value: p.curToken.Literal} + + if !p.expectPeek(token.LBRACE) { + return nil + } + + stmt.Body = p.parseBlockStatement() + + return stmt +} diff --git a/test-data/ltm.irule b/test-data/ltm.irule new file mode 100644 index 0000000..f1a04a4 --- /dev/null +++ b/test-data/ltm.irule @@ -0,0 +1,9 @@ +ltm rule redirect_rule { + when HTTP_REQUEST { + if {[string tolower [HTTP::host]] eq "test.com" } { + node 192.168.191.5 + } + elseif {[string tolower [HTTP::host]] eq "test2.com"}{ + node 192.168.191.6 + }} +} diff --git a/token/token.go b/token/token.go index 5467856..0647aa7 100644 --- a/token/token.go +++ b/token/token.go @@ -169,6 +169,8 @@ const ( MATCH = "match" MATCHES = "matches" CLASS = "class" + LTM = "ltm" + RULE = "rule" // Additional control structures SWITCH = "switch" @@ -209,6 +211,8 @@ var keywords = map[string]TokenType{ "class": CLASS, "foreach": FOREACH, "in": IN, + "ltm": LTM, + "rule": RULE, // F5 Event Contexts "HTTP_REQUEST": HTTP_REQUEST,