bgpwtf/cccampix: draw the rest of the fucking owl

Change-Id: I49fd5906e69512e8f2d414f406edc0179522f225
diff --git a/bgpwtf/cccampix/frontend/frontend.py b/bgpwtf/cccampix/frontend/frontend.py
new file mode 100644
index 0000000..2a6f240
--- /dev/null
+++ b/bgpwtf/cccampix/frontend/frontend.py
@@ -0,0 +1,64 @@
+import logging
+
+import arrow
+import grpc
+from flask import Flask, render_template
+from flask.logging import default_handler
+
+from bgpwtf.cccampix.proto import ix_pb2 as ipb
+from bgpwtf.cccampix.proto import ix_pb2_grpc as ipb_grpc
+
+from bgpwtf.cccampix.frontend.channel import Channel
+
+
+logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(message)s')
+logger = logging.getLogger(__name__)
+
+
+check_info = {
+    'irr': ('IRR', 'Required IRR entires are present for this AS'),
+}
+
+
+def create_app(config=None):
+    app = Flask(__name__)
+    app.config.update(config or {})
+    app.logger.removeHandler(default_handler)
+    verifier = Channel(app, config['verifier'])
+    
+    
+    @app.route('/')
+    def view_index():
+        req = ipb.ProcessorStatusRequest()
+        processors = verifier.stub(ipb_grpc.VerifierStub).ProcessorStatus.future(req)
+        req = ipb.PeerSummaryRequest()
+        peers = verifier.stub(ipb_grpc.VerifierStub).PeerSummary(req)
+
+        processors = sorted(processors.result().processors, key=lambda el: el.name)
+        peers = sorted(list(peers), key=lambda el: el.peeringdb_info.asn)
+
+        return render_template('index.html',
+                processors=processors, peers=peers)
+
+    @app.route('/asn/<int:asn>')
+    def view_asn(asn):
+        req = ipb.PeerDetailsRequest()
+        req.asn = asn
+
+        details = None
+        try:
+            details = verifier.stub(ipb_grpc.VerifierStub).PeerDetails(req)
+        except grpc.RpcError as e:
+            if e.code() == grpc.StatusCode.NOT_FOUND:
+                return 'No such ASN.'
+            else:
+                return 'Internal server error.'
+        
+        return render_template('asn.html', details=details, asn=asn, check_info=check_info)
+    
+    
+    @app.template_filter()
+    def from_nano(v):
+        return arrow.get(v/1e9)
+
+    return app