aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMorten Linderud <morten@linderud.pw>2019-01-21 23:11:51 +0100
committerMorten Linderud <morten@linderud.pw>2019-01-21 23:40:32 +0100
commitd4cd5cfac3c3c4028575114708eb551d25e1933e (patch)
treef9bcf4d5a1a6b63e46cfd6f62f6780962a8874b3
parent4f9cd6706692eb6b1a000efb37cfe76e202e6d07 (diff)
Added slight rewrite of template webserver
Moved to flask for more "free" things. Possibly easier to extend in the future. Added argparser so we are able to define settings from the command line.
-rw-r--r--build/test/gondul-templating-test.Dockerfile6
-rw-r--r--templating/requirements.txt4
-rwxr-xr-xtemplating/templating.py180
3 files changed, 85 insertions, 105 deletions
diff --git a/build/test/gondul-templating-test.Dockerfile b/build/test/gondul-templating-test.Dockerfile
index 80c09c0..6dabc9c 100644
--- a/build/test/gondul-templating-test.Dockerfile
+++ b/build/test/gondul-templating-test.Dockerfile
@@ -1,7 +1,9 @@
FROM debian:jessie
RUN apt-get update
-RUN apt-get -y install \
- python3-jinja2 \
+RUN apt-get -y install \
+ python3-jinja2 \
+ python3-netaddr \
+ python3-flask \
python3-requests
RUN mkdir -p /opt/gondul
diff --git a/templating/requirements.txt b/templating/requirements.txt
new file mode 100644
index 0000000..20e96a0
--- /dev/null
+++ b/templating/requirements.txt
@@ -0,0 +1,4 @@
+jinja2
+requests
+flask
+netaddr
diff --git a/templating/templating.py b/templating/templating.py
index fff5d42..9584fe3 100755
--- a/templating/templating.py
+++ b/templating/templating.py
@@ -1,115 +1,89 @@
-#!/usr/bin/env python3
+#!/usr/bin/python3
+
+import argparse
+import traceback
+import sys
-import requests,traceback
-from jinja2 import Template,Environment,FileSystemLoader,TemplateNotFound
-import json
import netaddr
-import http.server
-from enum import Enum
+import requests
+
+from flask import Flask, request
+from jinja2 import Environment, FileSystemLoader, TemplateNotFound
endpoints = "read/networks read/oplog read/snmp read/switches-management public/distro-tree public/config public/dhcp public/dhcp-summary public/ping public/switches public/switch-state".split()
-objects = dict()
+
+objects = {}
+
def getEndpoint(endpoint):
- r = requests.get("http://localhost:80/api/%s" % endpoint)
- if (r.status_code != 200):
- raise Exception("Bad status code for endpoint %s: %s" % (endpoint, r.status_code))
+ r = requests.get(f"http://localhost:80/api/{endpoint}")
+ if r.status_code != 200:
+ raise Exception(f"Bad status code for endpoint {endpoint}: {r.status_code}")
return r.json()
+
def updateData():
for a in endpoints:
objects[a] = getEndpoint(a)
-def netmask(ip):
- return netaddr.IPNetwork(ip).netmask
-def cidr(ip):
- return netaddr.IPNetwork(ip).prefixlen
-def networkId(ip):
- return netaddr.IPNetwork(ip).ip
-def getFirstDhcpIp(ip):
- return netaddr.IPNetwork(ip)[3]
-def getLastDhcpIp(ip):
- return netaddr.IPNetwork(ip)[-1]
-def getDistro(src):
- return src.split(":")[0]
-def getPort(src):
- return src.split(":")[1]
-def getFirstFapIp(ip):
- return netaddr.IPNetwork(ip)[netaddr.IPNetwork(ip).size/2]
-
-env = Environment(loader=FileSystemLoader(['templates/','/opt/gondul/data/templates', '/opt/gondul/web/templates']), trim_blocks=True)
-
-env.filters["netmask"] = netmask
-env.filters["cidr"] = cidr
-env.filters["networkId"] = networkId
-env.filters["getFirstDhcpIp"] = getFirstDhcpIp
-env.filters["getLastDhcpIp"] = getLastDhcpIp
-env.filters["agentDistro"] = getDistro
-env.filters["agentPort"] = getPort
-env.filters["getFirstFapIP"] = getFirstFapIp
-
-class Mode(Enum):
- Get = 1
- Post = 2
-
-class MyHandler(http.server.BaseHTTPRequestHandler):
-
- options = dict()
-
- def parse_options(self):
- self.url = self.path[1:]
- self.options = dict()
- if self.url.find("?") != -1:
- (self.url, tmpoptions) = self.url.split("?")
- tmptuples = tmpoptions.split("&")
- for a in tmptuples:
- (x,y) = a.split("=")
- self.options[x] = y
-
- def generic(self, mode):
- updateData()
- self.parse_options()
- body = ""
- try:
- if mode == Mode.Get:
- template = env.get_template(self.url)
- elif mode == Mode.Post:
- length = self.headers.get('content-length')
- if not length:
- length = 0
- content = self.rfile.read(int(length)).decode('UTF-8')
- template = env.from_string(content)
- else:
- raise Exception("Invalid mode")
-
- body = template.render(objects=objects, options=self.options)
- self.send_response(200)
- except TemplateNotFound as err:
- body = "Template \"%s\" not found\n" % self.url
- self.send_response(404)
- except Exception as err:
- body = ("Templating of \"%s\" failed to render. Most likely due to an error in the template. Error transcript:\n\n%s\n----\n\n%s\n" % (self.url, err, traceback.format_exc()))
- if mode == Mode.Get:
- self.send_response(400)
- else:
- self.send_response(500)
- finally:
- self.send_header('Cache-Control','max-age=5, s-maxage=1')
- body = body.encode('UTF-8')
- self.send_header('Content-Length', int(len(body)))
- self.end_headers()
- self.wfile.write(body)
- self.wfile.flush()
-
- def do_GET(self):
- self.generic(Mode.Get)
-
- def do_POST(self):
- self.generic(Mode.Post)
-
-def run(server_class=http.server.HTTPServer, handler_class=http.server.BaseHTTPRequestHandler):
- server_address = ('localhost', 8081)
- httpd = server_class(server_address, handler_class)
- httpd.serve_forever()
-
-run(handler_class=MyHandler)
+
+env = Environment(loader=FileSystemLoader([]), trim_blocks=True)
+
+env.filters["netmask"] = lambda ip: netaddr.IPNetwork(ip).netmask
+env.filters["cidr"] = lambda ip: netaddr.IPNetwork(ip).prefixlen
+env.filters["networkId"] = lambda ip: netaddr.IPNetwork(ip).ip
+env.filters["getFirstDhcpIp"] = lambda ip: netaddr.IPNetwork(ip)[3]
+env.filters["getLastDhcpIp"] = lambda ip: netaddr.IPNetwork(ip)[-1]
+env.filters["agentDistro"] = lambda src: src.split(":")[0]
+env.filters["agentPort"] = lambda src: src.split(":")[1]
+env.filters["getFirstFapIP"] = lambda ip: netaddr.IPNetwork(ip)[netaddr.IPNetwork(ip).size / 2]
+
+app = Flask(__name__)
+
+
+@app.after_request
+def add_header(response):
+ if response.status_code == 200:
+ response.cache_control.max_age = 5
+ response.cache_control.s_maxage = 1
+ return response
+
+
+@app.route("/<path>", methods=["GET"])
+def root_get(path):
+ updateData()
+ try:
+ template = env.get_template(path)
+ body = template.render(objects=objects, options=request.args)
+ except TemplateNotFound:
+ return f'Template "{path}" not found\n', 404
+ except Exception as err:
+ return f'Templating of "{path}" failed to render. Most likely due to an error in the template. Error transcript:\n\n{err}\n----\n\n{traceback.format_exe()}\n', 400
+ return body, 200
+
+
+@app.route("/<path>", methods=["POST", "PUT"])
+def root_post(path):
+ updateData()
+ try:
+ content = request.stream.read(int(request.headers["Content-Length"]))
+ template = env.from_string(content.decode("utf-8"))
+ body = template.render(objects=objects, options=request.args)
+ except Exception as err:
+ return f'Templating of "{path}" failed to render. Most likely due to an error in the template. Error transcript:\n\n{err}\n----\n\n{traceback.format_exe()}\n', 400
+ return body, 200
+
+
+parser = argparse.ArgumentParser(description="Process templates for gondul.", add_help=False)
+parser.add_argument("-t", "--templates", type=str, nargs="+", help="location of templates")
+parser.add_argument("-h", "--host", type=str, default="127.0.0.1", help="host address")
+parser.add_argument("-p", "--port", type=int, default=8080, help="host port")
+parser.add_argument("-d", "--debug", action="store_true", help="enable debug mode")
+
+args = parser.parse_args()
+env.loader.searchpath = args.templates
+
+if not sys.argv[1:]:
+ parser.print_help()
+
+app.run(host=args.host, port=args.port, debug=args.debug)