Add python script, cli and guit
This commit is contained in:
parent
051f4b3002
commit
1bef81de3e
6 changed files with 255 additions and 85 deletions
41
cli.py
Normal file
41
cli.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
##########
|
||||||
|
# IMPORT #
|
||||||
|
##########
|
||||||
|
import argparse
|
||||||
|
from os.path import exists, isfile
|
||||||
|
from parser import ParserJuniper
|
||||||
|
|
||||||
|
__author__ = "rick@gnous.eu"
|
||||||
|
__licence__ = "GPL3"
|
||||||
|
|
||||||
|
parserJuniper = ParserJuniper()
|
||||||
|
parserArg = argparse.ArgumentParser(
|
||||||
|
description="Parse a Juniper conf file and print the series of set commands for."
|
||||||
|
)
|
||||||
|
parserArg.add_argument("-f", "--file", nargs=1, required=True, type=str, help="The conf file.")
|
||||||
|
parserArg.add_argument("-o", "--output", nargs=1, type=str, help="The output file.")
|
||||||
|
|
||||||
|
arg = parserArg.parse_args()
|
||||||
|
|
||||||
|
inputFile = str(arg.file[0])
|
||||||
|
outputFile = None
|
||||||
|
if arg.output:
|
||||||
|
outputFile = str(arg.output[0])
|
||||||
|
if exists(outputFile) and isfile(outputFile):
|
||||||
|
writeOverFile = input("The file already exists, write over it ? o/O")
|
||||||
|
if writeOverFile.lower() != 'o':
|
||||||
|
print("STOP EVERYTHING!!!!!!!!!!!!!")
|
||||||
|
exit(0)
|
||||||
|
elif exists(outputFile):
|
||||||
|
print("The output musts be a file.")
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
if exists(inputFile) and isfile(inputFile):
|
||||||
|
parseResul = parserJuniper.parseFile(inputFile)
|
||||||
|
if outputFile:
|
||||||
|
with open(outputFile, 'w') as file:
|
||||||
|
file.write(parseResul)
|
||||||
|
else:
|
||||||
|
print(parseResul)
|
||||||
|
else:
|
||||||
|
print("Pass an existing file.")
|
36
controllers/controller.py
Normal file
36
controllers/controller.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
##########
|
||||||
|
# IMPORT #
|
||||||
|
##########
|
||||||
|
from PyQt5.QtWidgets import QTextEdit, QTextBrowser
|
||||||
|
from parser import ParserJuniper
|
||||||
|
|
||||||
|
__author__ = "rick@gnous.eu"
|
||||||
|
__licence__ = "GPL3"
|
||||||
|
|
||||||
|
class Controller:
|
||||||
|
def __init__(self, inputText, outputText):
|
||||||
|
"""
|
||||||
|
Init the controller
|
||||||
|
|
||||||
|
:param inputText QTextEdit: the area where Juniper conf in write
|
||||||
|
:param outputText QTextBrowser: area where a series of set
|
||||||
|
command is showed
|
||||||
|
"""
|
||||||
|
self.inputText = inputText
|
||||||
|
self.outputText = outputText
|
||||||
|
self.parser = ParserJuniper()
|
||||||
|
|
||||||
|
def click(self):
|
||||||
|
"""
|
||||||
|
Called when the user press the Parse button.
|
||||||
|
Gets the text of inputText and parse it. Shows the result on
|
||||||
|
outputText.
|
||||||
|
"""
|
||||||
|
self.parser.resetTree()
|
||||||
|
textToParse = self.inputText.toPlainText()
|
||||||
|
parsedText = ""
|
||||||
|
for line in textToParse.splitlines():
|
||||||
|
textConf = self.parser.parse(line)
|
||||||
|
if textConf:
|
||||||
|
parsedText += textConf + "\n"
|
||||||
|
self.outputText.setText(parsedText)
|
36
gui.py
Normal file
36
gui.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
##########
|
||||||
|
# IMPORT #
|
||||||
|
##########
|
||||||
|
from sys import argv
|
||||||
|
from PyQt5 import uic
|
||||||
|
from PyQt5.QtWidgets import QMainWindow, QApplication, QPushButton, QTextEdit,\
|
||||||
|
QTextBrowser
|
||||||
|
from controllers.controller import Controller
|
||||||
|
|
||||||
|
__author__ = "rick@gnous.eu"
|
||||||
|
__licence__ = "GPL3"
|
||||||
|
|
||||||
|
class Interface(QMainWindow):
|
||||||
|
def __init__(self):
|
||||||
|
super(Interface, self).__init__()
|
||||||
|
|
||||||
|
self.setWindowTitle("Parser Juniper")
|
||||||
|
self.ui = uic.loadUi("views/principal.ui")
|
||||||
|
self.setCentralWidget(self.ui)
|
||||||
|
|
||||||
|
inputText = self.ui.findChildren(QTextEdit, "inputText")[0]
|
||||||
|
outputText = self.ui.findChildren(QTextBrowser, "outputText")[0]
|
||||||
|
parseButton = self.ui.findChildren(QPushButton, "parse")[0]
|
||||||
|
quitButton = self.ui.findChildren(QPushButton, "quit")[0]
|
||||||
|
|
||||||
|
self.controller = Controller(inputText, outputText)
|
||||||
|
|
||||||
|
parseButton.clicked.connect(self.controller.click)
|
||||||
|
quitButton.clicked.connect(quit)
|
||||||
|
|
||||||
|
self.show()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = QApplication(argv)
|
||||||
|
window = Interface()
|
||||||
|
exit(app.exec_())
|
|
@ -1,85 +0,0 @@
|
||||||
#!/usr/bin/php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
/******************************************************************************************************
|
|
||||||
*
|
|
||||||
* Written by Tim Price 24/11/2016
|
|
||||||
*
|
|
||||||
* The purpose of this script is to take a juniper config and convert it to set commands.
|
|
||||||
* There was a business need to audit thbe correctness of Juniper configs and the process of logging
|
|
||||||
* into each Juniper device and dumping the configs in set format was too burdensome on both the Juniper
|
|
||||||
* devices in question but also extended the execution time of the audit scripts by some minutes.
|
|
||||||
*
|
|
||||||
* Usage example: `cat juniper-config.txt | juniper-config-to-set.php`
|
|
||||||
*
|
|
||||||
******************************************************************************************************/
|
|
||||||
|
|
||||||
function endswith($string, $test) {
|
|
||||||
$strlen = strlen($string);
|
|
||||||
$testlen = strlen($test);
|
|
||||||
if ($testlen > $strlen) return false;
|
|
||||||
return substr_compare($string, $test, $strlen - $testlen, $testlen) === 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
function addtotree($tree,$word) {
|
|
||||||
array_push($tree,$word);
|
|
||||||
return $tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
function removewordfromtree($tree) {
|
|
||||||
array_pop($tree);
|
|
||||||
return $tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
function printtree($tree) {
|
|
||||||
return implode(" ",$tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
$tree=array();
|
|
||||||
|
|
||||||
while($line = fgets(STDIN)){
|
|
||||||
|
|
||||||
// Skip any commented lines
|
|
||||||
if(strpos($line,'#')===0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trim white space from the line
|
|
||||||
$line=trim($line);
|
|
||||||
|
|
||||||
// Trim inline comments from the line
|
|
||||||
if(preg_match('/; ##/',$line)==1) {
|
|
||||||
list($line,$comment)=preg_split('/; ##/',$line);
|
|
||||||
$line .= ";";
|
|
||||||
}
|
|
||||||
|
|
||||||
// What remains is a series of tests to see what the line ends with.
|
|
||||||
|
|
||||||
// This test matches a ';' character which means its a leaf and we can output the whole line to STDOUT
|
|
||||||
if(endswith($line,';')) {
|
|
||||||
|
|
||||||
// Trim the semi-colon from the end of the line, we don't need that.
|
|
||||||
$line = rtrim($line,';');
|
|
||||||
|
|
||||||
//Test to see if the tree is empty, if it is then we'll just print the leaf and not the tree
|
|
||||||
//to avoid excess white spaces
|
|
||||||
if(count($tree)==0) {
|
|
||||||
echo "set $line\n";
|
|
||||||
} else {
|
|
||||||
echo "set " . printtree($tree) . " $line\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// This test matches a '{' character on the end of the line and means we need to add a branch to the tree
|
|
||||||
if(endswith($line,'{')) {
|
|
||||||
$line = rtrim($line,' {');
|
|
||||||
$tree=addtotree($tree,$line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This test matches a '}' character on the end of the line and means we need to remove the last branch that we added to the tree
|
|
||||||
if(endswith($line,'}')) {
|
|
||||||
$tree=removewordfromtree($tree);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
64
parser.py
Normal file
64
parser.py
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
# Tom Price writes the program in PHP here : https://github.com/pgnuta/juniper-config-to-set
|
||||||
|
# I adapt it in Python and add some enhancements
|
||||||
|
__author__ = "Tim Price | rick@gnous.eu"
|
||||||
|
__licence__ = "GPL3"
|
||||||
|
|
||||||
|
class ParserJuniper:
|
||||||
|
def __init__(self):
|
||||||
|
self.tree = []
|
||||||
|
|
||||||
|
def resetTree(self):
|
||||||
|
self.tree = []
|
||||||
|
|
||||||
|
def printTree(self, tree):
|
||||||
|
return ''.join(map(str, tree))
|
||||||
|
|
||||||
|
def parse(self, line):
|
||||||
|
"""
|
||||||
|
Parse a line of conf
|
||||||
|
|
||||||
|
:param line str: line will be parse
|
||||||
|
:ret str: a parse string, empty if its a comment
|
||||||
|
"""
|
||||||
|
ret = ""
|
||||||
|
line = line.strip()
|
||||||
|
if not line.startswith('#'):
|
||||||
|
if '#' in line:
|
||||||
|
line, comment = line.split('#', 1)
|
||||||
|
line = line.strip()
|
||||||
|
|
||||||
|
if line.endswith(';'):
|
||||||
|
line = line[:-1]
|
||||||
|
|
||||||
|
if not self.tree:
|
||||||
|
ret = "set " + line
|
||||||
|
else:
|
||||||
|
ret = "set " + self.printTree(self.tree) + line
|
||||||
|
|
||||||
|
if line.endswith('{'):
|
||||||
|
line = line[:-1]
|
||||||
|
self.tree.append(line)
|
||||||
|
|
||||||
|
if line.endswith('}'):
|
||||||
|
self.tree.pop()
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def parseFile(self, path):
|
||||||
|
"""
|
||||||
|
parse a file and return the commands
|
||||||
|
|
||||||
|
:param path str: the path to file
|
||||||
|
:ret str: the series of set commands
|
||||||
|
"""
|
||||||
|
ret = ""
|
||||||
|
with open(path, 'r') as file:
|
||||||
|
self.resetTree()
|
||||||
|
for line in file:
|
||||||
|
lineConf = self.parse(line)
|
||||||
|
if lineConf:
|
||||||
|
ret += lineConf + "\n"
|
||||||
|
return ret
|
||||||
|
|
||||||
|
#parser = ParserJuniper()
|
||||||
|
#parser.parseFile("test")
|
78
views/principal.ui
Normal file
78
views/principal.ui
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>MainWindow</class>
|
||||||
|
<widget class="QMainWindow" name="MainWindow">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>550</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>MainWindow</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<widget class="QTextEdit" name="inputText">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>20</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>361</width>
|
||||||
|
<height>391</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="parse">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>420</x>
|
||||||
|
<y>430</y>
|
||||||
|
<width>131</width>
|
||||||
|
<height>41</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Parse !</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QTextBrowser" name="outputText">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>420</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>351</width>
|
||||||
|
<height>391</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QPushButton" name="quit">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>250</x>
|
||||||
|
<y>430</y>
|
||||||
|
<width>131</width>
|
||||||
|
<height>41</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Quit</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>20</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
Loading…
Reference in a new issue