Yet another one of these!
What i'm running:
Ubuntu 18.04.3 LTS
Python 3.6.9
Bottle 0.12.18
Grafana v6.5.1
SimpleJson 1.4.0
Chrome 78.0.3904.108
I'm trying to get Grafana to talk to my Python Bottle server with the end goal of pulling data from a MongoDB for that nice visualization.
My attempt is based on this example. It's not very explicit in it's descriptions but it's the best i found and after som tweaking i got it running without any immediate errors. I also modified the CORS enable part according to this answer by user "ron rothman". It currently looks like this:
#!/usr/bin/env python3
import math
from datetime import datetime
from calendar import timegm
from bottle import Bottle, HTTPResponse, run, request, response, json_dumps as dumps
class EnableCors(object):
name = 'enable_cors'
api = 2
def apply(self, fn, context):
def _enable_cors(*args, **kwargs):
# set CORS headers
for element in response:
print(element)
response.headers['Access-Control-Allow-Origin'] = "*"
response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS'
response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'
if request.method != 'OPTIONS':
# actual request; reply with the actual response
return fn(*args, **kwargs)
return _enable_cors
FUNCTIONS = {'series A': math.sin, 'series B': math.cos}
app = Bottle()
def convert_to_time_ms(timestamp):
return 1000 * timegm(
datetime.strptime(
timestamp, '%Y-%m-%dT%H:%M:%S.%fZ').timetuple())
def create_data_points(function, start, end, length=1020):
lower = convert_to_time_ms(start)
upper = convert_to_time_ms(end)
return [[function(i), int(i)] for i in [
lower + x*(upper-lower)/length for x in range(length)]]
@app.route("/", method='GET')
@app.route("/", method='OPTIONS')
def index():
return "OK"
@app.post('/search', method='OPTIONS')
@app.post('/search', method='POST')
@app.post('/search', method='GET')
def search():
return HTTPResponse(body=dumps(['series A', 'series B']),
headers={'Content-Type': 'application/json'})
@app.post('/query', method='OPTIONS')
@app.post('/query', method='POST')
@app.post('/query', method='GET')
def query():
print(request.json)
if request.json['targets'][0]['type'] == 'table':
series = request.json['targets'][0]['target']
bodies = {'series A': [{
"columns": [
{"text": "Time", "type": "time"},
{"text": "Country", " type": "string"},
{"text": "Number", "type": "number"}
],
"rows": [
[1234567, "SE", 123],
[1234567, "DE", 231],
[1234567, "US", 321]
],
"type": "table"
}],
'series B': [{"columns": [
{"text": "Time", "type": "time"},
{"text": "Country", "type": "string"},
{"text": "Number", "type": "number"}
],
"rows": [
[1234567, "BE", 123],
[1234567, "GE", 231],
[1234567, "PS", 321]
],
"type": "table"
}]}
series = request.json['targets'][0]['target']
body = dumps(bodies[series])
else:
body = []
body = dumps(body)
return HTTPResponse(body=body,
headers={'Content-Type': 'application/json'})
app.install(EnableCors())
app.run(port = 8081)
In the settings Grafana accepts the server, "Data source is working". How ever as soon as i try do add a dashboard panel i get three errors.
new?panelId=2&edit&fullscreen&orgId=1:1 Access to XMLHttpRequest at 'http://localhost:8081/search' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
,
Possibly unhandled rejection: {"err":{"data":null,"status":-1,"config":{"method":"POST","transformRequest":[null],"transformResponse":[null],"jsonpCallbackParam":"callback","url":"http://localhost:8081/search","data":{"target":""},"headers":{"Content-Type":"application/json","Accept":"application/json, text/plain, */*"},"retry":0},"statusText":"","xhrStatus":"error"},"cancelled":true}
and
new?panelId=2&edit&fullscreen&orgId=1:1 Access to XMLHttpRequest at 'http://localhost:8081/query' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
bottle responds with
Bottle v0.12.18 server starting up (using WSGIRefServer())...
Listening on http://127.0.0.1:8081/
Hit Ctrl-C to quit.
127.0.0.1 - - [05/Dec/2019 15:41:35] "OPTIONS /search HTTP/1.1" 200 0
127.0.0.1 - - [05/Dec/2019 15:41:35] "POST /search HTTP/1.1" 200 24
127.0.0.1 - - [05/Dec/2019 15:41:35] "OPTIONS /query HTTP/1.1" 200 0
{'requestId': 'Q100', 'timezone': '', 'panelId': 2, 'dashboardId': None, 'range': {'from': '2019-12-05T08:41:35.236Z', 'to': '2019-12-05T14:41:35.237Z', 'raw': {'from': 'now-6h', 'to': 'now'}}, 'interval': '1m', 'intervalMs': 60000, 'targets': [{'refId': 'A', 'type': 'timeserie'}], 'maxDataPoints': 335, 'scopedVars': {'__interval': {'text': '1m', 'value': '1m'}, '__interval_ms': {'text': '60000', 'value': 60000}}, 'startTime': 1575556895466, 'rangeRaw': {'from': 'now-6h', 'to': 'now'}, 'adhocFilters': []}
127.0.0.1 - - [05/Dec/2019 15:41:35] "POST /query HTTP/1.1" 200 2
I think i've verified that the response.headers['Access-Control-Allow-Origin'] = "*"
actually does something by setting it to 'foo'
and then getting
The 'Access-Control-Allow-Origin' header contains the invalid value 'foo'.
instead.
Soon i've spent an entire workday on this and would really appreciate some help from you, thanks!