From e72e5946c8592d7f0dfe834512fc25737625bd10 Mon Sep 17 00:00:00 2001 From: Avsecz Date: Sun, 8 Oct 2017 16:17:01 +0200 Subject: [PATCH 1/6] added -proxy_sub_url --- .gitignore | 1 + sacredboard/app/webapi/proxy.py | 31 +++++++++++++++++++ sacredboard/bootstrap.py | 8 ++++- .../runs/metricsViewer/ProxiedMetric.js | 2 +- sacredboard/static/scripts/runs/runTable.js | 4 +-- 5 files changed, 42 insertions(+), 4 deletions(-) create mode 100644 sacredboard/app/webapi/proxy.py diff --git a/.gitignore b/.gitignore index a56ccf1..c4d4ba0 100644 --- a/.gitignore +++ b/.gitignore @@ -92,3 +92,4 @@ sacredboard/Scripts/ \.idea/ node_modules +*~ \ No newline at end of file diff --git a/sacredboard/app/webapi/proxy.py b/sacredboard/app/webapi/proxy.py new file mode 100644 index 0000000..217dfad --- /dev/null +++ b/sacredboard/app/webapi/proxy.py @@ -0,0 +1,31 @@ +# prody implementation + +# http://blog.macuyiko.com/post/2016/fixing-flask-url_for-when-behind-mod_proxy.html + + +class ReverseProxied(object): + """ + Allow to use a reverse proxy + http://blog.macuyiko.com/post/2016/fixing-flask-url_for-when-behind-mod_proxy.html + """ + + def __init__(self, app, script_name=None, scheme=None, server=None): + self.app = app + self.script_name = script_name + self.scheme = scheme + self.server = server + + def __call__(self, environ, start_response): + script_name = environ.get('HTTP_X_SCRIPT_NAME', '') or self.script_name + if script_name: + environ['SCRIPT_NAME'] = script_name + path_info = environ['PATH_INFO'] + if path_info.startswith(script_name): + environ['PATH_INFO'] = path_info[len(script_name):] + scheme = environ.get('HTTP_X_SCHEME', '') or self.scheme + if scheme: + environ['wsgi.url_scheme'] = scheme + server = environ.get('HTTP_X_FORWARDED_SERVER', '') or self.server + if server: + environ['HTTP_HOST'] = server + return self.app(environ, start_response) diff --git a/sacredboard/bootstrap.py b/sacredboard/bootstrap.py index bf6803e..92ee748 100755 --- a/sacredboard/bootstrap.py +++ b/sacredboard/bootstrap.py @@ -15,6 +15,7 @@ from sacredboard.app.data.filestorage import FileStorage from sacredboard.app.data.mongodb import PyMongoDataAccess from sacredboard.app.webapi import routes, metrics +from sacredboard.app.prody import ReverseProxied locale.setlocale(locale.LC_ALL, '') app = Flask(__name__) @@ -41,11 +42,14 @@ "File Storage observer. (experimental)") @click.option("--no-browser", is_flag=True, default=False, help="Do not open web browser automatically.") +@click.option("-proxy_sub_url", default="/", + help="Run in sub-url mode. Example '-proxy_sub_url /sacredboard/'" + "Use with proxy") @click.option("--debug", is_flag=True, default=False, help="Run the application in Flask debug mode " "(for development).") @click.version_option() -def run(debug, no_browser, m, mu, mc, f): +def run(debug, no_browser, m, mu, mc, f, sub_url): """ Sacredboard. @@ -93,6 +97,8 @@ def run(debug, no_browser, m, mu, mc, f): app.config['DEBUG'] = debug app.debug = debug + if sub_url is not "/": + app.wsgi_app = ReverseProxied(app.wsgi_app, script_name=sub_url) jinja_filters.setup_filters(app) routes.setup_routes(app) metrics.initialize(app) diff --git a/sacredboard/static/scripts/runs/metricsViewer/ProxiedMetric.js b/sacredboard/static/scripts/runs/metricsViewer/ProxiedMetric.js index 2e277b8..f8da953 100644 --- a/sacredboard/static/scripts/runs/metricsViewer/ProxiedMetric.js +++ b/sacredboard/static/scripts/runs/metricsViewer/ProxiedMetric.js @@ -62,7 +62,7 @@ define(["runs/Metric", "knockout", "jquery"], function (Metric, ko, $) { } var self = this; this._fetchingInProgress = true; - $.getJSON("/api/run/" + this._runId + "/metric/" + this._metricId, + $.getJSON("api/run/" + this._runId + "/metric/" + this._metricId, function (data) { self._values(data["values"]); self._steps(data["steps"]); diff --git a/sacredboard/static/scripts/runs/runTable.js b/sacredboard/static/scripts/runs/runTable.js index a811095..49bc3d6 100644 --- a/sacredboard/static/scripts/runs/runTable.js +++ b/sacredboard/static/scripts/runs/runTable.js @@ -71,7 +71,7 @@ define(["bootstrap", "datatable", "datatables-bootstrap", "runs/detailView", "jq * and additional URL parameters to be passed to the backend. */ ajax: { - url: "/api/run", + url: "api/run", data: function (request) { request.queryFilter = JSON.stringify(createRunTable.queryFilter); @@ -132,7 +132,7 @@ define(["bootstrap", "datatable", "datatables-bootstrap", "runs/detailView", "jq var id = row.data().id; var loadDetailData = function () { $.ajax({ - url: "/api/run/" + id + url: "api/run/" + id }).done(function (data) { if (data.data[0].id != row.data().id) { /* Before this ajax function was called, From cd26cd44c64d621ba3244eaa8846bc10e4dd06ea Mon Sep 17 00:00:00 2001 From: Avsecz Date: Sun, 8 Oct 2017 16:33:36 +0200 Subject: [PATCH 2/6] changed the api --- sacredboard/bootstrap.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sacredboard/bootstrap.py b/sacredboard/bootstrap.py index 92ee748..fb9cd6b 100755 --- a/sacredboard/bootstrap.py +++ b/sacredboard/bootstrap.py @@ -15,7 +15,7 @@ from sacredboard.app.data.filestorage import FileStorage from sacredboard.app.data.mongodb import PyMongoDataAccess from sacredboard.app.webapi import routes, metrics -from sacredboard.app.prody import ReverseProxied +from sacredboard.app.webapi.proxy import ReverseProxied locale.setlocale(locale.LC_ALL, '') app = Flask(__name__) @@ -42,9 +42,10 @@ "File Storage observer. (experimental)") @click.option("--no-browser", is_flag=True, default=False, help="Do not open web browser automatically.") -@click.option("-proxy_sub_url", default="/", - help="Run in sub-url mode. Example '-proxy_sub_url /sacredboard/'" - "Use with proxy") +@click.option("-sub_url", default="/", + help="Run the app on a sub-url. Example '-sub_url /sacredboard/' " + "maps localhost:5000/ -> localhost:5000/sacredboard/" + "Use with Apache proxy") @click.option("--debug", is_flag=True, default=False, help="Run the application in Flask debug mode " "(for development).") From c3c53e6e4b9eaba59a45863604a9afff049e9973 Mon Sep 17 00:00:00 2001 From: Avsecz Date: Sun, 8 Oct 2017 16:37:00 +0200 Subject: [PATCH 3/6] updated help message --- sacredboard/bootstrap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sacredboard/bootstrap.py b/sacredboard/bootstrap.py index fb9cd6b..b0b81dc 100755 --- a/sacredboard/bootstrap.py +++ b/sacredboard/bootstrap.py @@ -44,8 +44,8 @@ help="Do not open web browser automatically.") @click.option("-sub_url", default="/", help="Run the app on a sub-url. Example '-sub_url /sacredboard/' " - "maps localhost:5000/ -> localhost:5000/sacredboard/" - "Use with Apache proxy") + "maps localhost:5000/ -> localhost:5000/sacredboard/. " + "Useful with http proxy.") @click.option("--debug", is_flag=True, default=False, help="Run the application in Flask debug mode " "(for development).") From 2c34e2b21a37bc48c9d3eb2e425971bb024ea969 Mon Sep 17 00:00:00 2001 From: Martin Chovanec Date: Thu, 19 Oct 2017 21:13:49 +0200 Subject: [PATCH 4/6] Rename -sub_url option to --sub-url --- sacredboard/bootstrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sacredboard/bootstrap.py b/sacredboard/bootstrap.py index b0b81dc..38c5a02 100755 --- a/sacredboard/bootstrap.py +++ b/sacredboard/bootstrap.py @@ -42,7 +42,7 @@ "File Storage observer. (experimental)") @click.option("--no-browser", is_flag=True, default=False, help="Do not open web browser automatically.") -@click.option("-sub_url", default="/", +@click.option("--sub-url", default="/", help="Run the app on a sub-url. Example '-sub_url /sacredboard/' " "maps localhost:5000/ -> localhost:5000/sacredboard/. " "Useful with http proxy.") From 46842e8ffd4f6992d28e0a018875a28a86d2a282 Mon Sep 17 00:00:00 2001 From: Martin Chovanec Date: Thu, 19 Oct 2017 21:15:23 +0200 Subject: [PATCH 5/6] Relax python code line length to 120 characters and move flake8 configuration to .flake8 --- .flake8 | 4 ++++ tox.ini | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..6c8cf32 --- /dev/null +++ b/.flake8 @@ -0,0 +1,4 @@ +[flake8] +max-line-length = 120 +exclude = tests +max-complexity = 10 diff --git a/tox.ini b/tox.ini index b686bda..c79ccf3 100644 --- a/tox.ini +++ b/tox.ini @@ -13,7 +13,7 @@ commands = {envpython} setup.py test --addopts -v deps = flake8 commands = - flake8 sacredboard --max-complexity 10 --exclude tests + flake8 sacredboard [testenv:pydocstyle] deps = From a1687f14303ef6fa0632b9b0f0a4d2b481be6a2f Mon Sep 17 00:00:00 2001 From: Martin Chovanec Date: Thu, 19 Oct 2017 21:23:49 +0200 Subject: [PATCH 6/6] Fix comments for reverse proxy --- sacredboard/app/webapi/proxy.py | 11 ++++++++--- sacredboard/static/scripts/runs/filters.js | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/sacredboard/app/webapi/proxy.py b/sacredboard/app/webapi/proxy.py index 217dfad..44a91a9 100644 --- a/sacredboard/app/webapi/proxy.py +++ b/sacredboard/app/webapi/proxy.py @@ -1,21 +1,26 @@ -# prody implementation +""" +Reverse proxy support for Sacredboard. -# http://blog.macuyiko.com/post/2016/fixing-flask-url_for-when-behind-mod_proxy.html +http://blog.macuyiko.com/post/2016/fixing-flask-url_for-when-behind-mod_proxy.html +""" class ReverseProxied(object): """ - Allow to use a reverse proxy + Allow to use a reverse proxy. + http://blog.macuyiko.com/post/2016/fixing-flask-url_for-when-behind-mod_proxy.html """ def __init__(self, app, script_name=None, scheme=None, server=None): + """Create a new wrapper for Flask.""" self.app = app self.script_name = script_name self.scheme = scheme self.server = server def __call__(self, environ, start_response): + """Set environment for Flask.""" script_name = environ.get('HTTP_X_SCRIPT_NAME', '') or self.script_name if script_name: environ['SCRIPT_NAME'] = script_name diff --git a/sacredboard/static/scripts/runs/filters.js b/sacredboard/static/scripts/runs/filters.js index 6086bd6..295ec45 100644 --- a/sacredboard/static/scripts/runs/filters.js +++ b/sacredboard/static/scripts/runs/filters.js @@ -24,7 +24,7 @@ define(["knockout", "jquery", "text!runs/filters.html", "runs/filters/queryFilte Example: - @method + @function */ "initialize": function () { ko.components.register("query-filter", {