Add ROUTE_PREFIX parameter for working with reverse proxies. (#256)

* Add ROUTE_PREFIX parameter for working with reverse proxies.

* [flake8/E304] remove blank line after function decoder

* Add APPLICATION_ROOT and use route_prefix in requests.

* [black/code-styling] use double quotes instead of single.

* handle right events url depending route path

* properly handle redirects

* [flake8] remove unused module, fix styling issues

Co-authored-by: Henning Jacobs <henning@jacobs1.de>
This commit is contained in:
Khachatur Ashotyan
2020-08-23 17:27:34 +04:00
committed by GitHub
parent 3c6056dac3
commit 89c143d3aa
5 changed files with 25 additions and 10 deletions

View File

@@ -163,7 +163,8 @@ The following environment variables are supported:
Template to make Nodes clickable, e.g. can point to `kube-web-view <https://codeberg.org/hjacobs/kube-web-view/>`_. ``{cluster}`` (cluster ID) and ``{name}`` (Node name) will be replaced in the URL template. Template to make Nodes clickable, e.g. can point to `kube-web-view <https://codeberg.org/hjacobs/kube-web-view/>`_. ``{cluster}`` (cluster ID) and ``{name}`` (Node name) will be replaced in the URL template.
``POD_LINK_URL_TEMPLATE`` ``POD_LINK_URL_TEMPLATE``
Template to make Pods clickable, e.g. can point to `kube-web-view <https://codeberg.org/hjacobs/kube-web-view/>`_. ``{cluster}`` (cluster ID), ``{namespace}`` (Pod's namespace), and ``{name}`` (Pod name) will be replaced in the URL template. Template to make Pods clickable, e.g. can point to `kube-web-view <https://codeberg.org/hjacobs/kube-web-view/>`_. ``{cluster}`` (cluster ID), ``{namespace}`` (Pod's namespace), and ``{name}`` (Pod name) will be replaced in the URL template.
``ROUTE_PREFIX``
The URL prefix under which kube-ops-view is externally reachable (for example, if kube-ops-view is served via a reverse proxy). Used for generating relative and absolute links back to kube-ops-view itself. If the URL has a path portion, it will be used to prefix all HTTP endpoints served by kube-ops-view. If omitted, relevant URL components will be derived automatically.
Supported Browsers Supported Browsers
================== ==================

View File

@@ -20,6 +20,7 @@ export default class App {
this.config = Config.fromParams(params) this.config = Config.fromParams(params)
this.config.nodeLinkUrlTemplate = config['node_link_url_template'] this.config.nodeLinkUrlTemplate = config['node_link_url_template']
this.config.podLinkUrlTemplate = config['pod_link_url_template'] this.config.podLinkUrlTemplate = config['pod_link_url_template']
this.config.route_prefix = config['route_prefix']
this.filterString = (params.get('q') && decodeURIComponent(params.get('q'))) || '' this.filterString = (params.get('q') && decodeURIComponent(params.get('q'))) || ''
this.selectedClusters = new Set((params.get('clusters') || '').split(',').filter(x => x)) this.selectedClusters = new Set((params.get('clusters') || '').split(',').filter(x => x))
@@ -658,7 +659,7 @@ export default class App {
this.disconnect() this.disconnect()
const that = this const that = this
// NOTE: path must be relative to work with kubectl proxy out of the box // NOTE: path must be relative to work with kubectl proxy out of the box
let url = 'events' let url = this.config.route_prefix + (this.config.route_prefix === '/' ? 'events' : '/events')
const clusterIds = Array.from(this.selectedClusters).join(',') const clusterIds = Array.from(this.selectedClusters).join(',')
if (clusterIds) { if (clusterIds) {
url += '?cluster_ids=' + clusterIds url += '?cluster_ids=' + clusterIds

View File

@@ -19,7 +19,6 @@ from pathlib import Path
from flask import Flask, redirect, url_for from flask import Flask, redirect, url_for
from .oauth import OAuth2ConsumerBlueprintWithClientRefresh from .oauth import OAuth2ConsumerBlueprintWithClientRefresh
from urllib.parse import urljoin
from .mock import query_mock_cluster from .mock import query_mock_cluster
from .kubernetes import query_kubernetes_cluster from .kubernetes import query_kubernetes_cluster
@@ -39,7 +38,6 @@ logger = logging.getLogger(__name__)
SERVER_STATUS = {"shutdown": False} SERVER_STATUS = {"shutdown": False}
AUTHORIZE_URL = os.getenv("AUTHORIZE_URL") AUTHORIZE_URL = os.getenv("AUTHORIZE_URL")
ACCESS_TOKEN_URL = os.getenv("ACCESS_TOKEN_URL") ACCESS_TOKEN_URL = os.getenv("ACCESS_TOKEN_URL")
APP_URL = os.getenv("APP_URL") or ""
SCOPE = os.getenv("SCOPE") SCOPE = os.getenv("SCOPE")
app = Flask(__name__) app = Flask(__name__)
@@ -97,6 +95,7 @@ def index():
"index.html", "index.html",
app_js=app_js, app_js=app_js,
version=kube_ops_view.__version__, version=kube_ops_view.__version__,
route_prefix=app.app_config["route_prefix"],
app_config_json=json.dumps(app.app_config), app_config_json=json.dumps(app.app_config),
) )
@@ -168,13 +167,13 @@ def redeem_screen_token(token: str):
except Exception: except Exception:
flask.abort(401) flask.abort(401)
flask.session["auth_token"] = (token, "") flask.session["auth_token"] = (token, "")
return redirect(urljoin(APP_URL, "/")) return redirect(app.config["APPLICATION_ROOT"])
@app.route("/logout") @app.route("/logout")
def logout(): def logout():
flask.session.pop("auth_token", None) flask.session.pop("auth_token", None)
return redirect(urljoin(APP_URL, "/")) return redirect(app.config["APPLICATION_ROOT"])
def shutdown(): def shutdown():
@@ -228,6 +227,17 @@ class CommaSeparatedValues(click.ParamType):
envvar="SERVER_PORT", envvar="SERVER_PORT",
default=8080, default=8080,
) )
@click.option(
"--route-prefix",
help="""The URL prefix under which kube-ops-view is externally reachable
(for example, if kube-ops-view is served via a reverse proxy). Used for
generating relative and absolute links back to kube-ops-view itself. If the
URL has a path portion, it will be used to prefix all HTTP endpoints served
by kube-ops-view. If omitted, relevant URL components will be derived
automatically.""",
envvar="ROUTE_PREFIX",
default="/",
)
@click.option( @click.option(
"-d", "--debug", is_flag=True, help="Run in debugging mode", envvar="DEBUG" "-d", "--debug", is_flag=True, help="Run in debugging mode", envvar="DEBUG"
) )
@@ -300,6 +310,7 @@ def main(
query_interval, query_interval,
node_link_url_template: str, node_link_url_template: str,
pod_link_url_template: str, pod_link_url_template: str,
route_prefix: str,
): ):
logging.basicConfig(level=logging.DEBUG if debug else logging.INFO) logging.basicConfig(level=logging.DEBUG if debug else logging.INFO)
@@ -308,9 +319,11 @@ def main(
app.debug = debug app.debug = debug
app.secret_key = secret_key app.secret_key = secret_key
app.store = store app.store = store
app.config["APPLICATION_ROOT"] = route_prefix
app.app_config = { app.app_config = {
"node_link_url_template": node_link_url_template, "node_link_url_template": node_link_url_template,
"pod_link_url_template": pod_link_url_template, "pod_link_url_template": pod_link_url_template,
"route_prefix": route_prefix,
} }
discoverer: Union[ discoverer: Union[

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Kubernetes Operational View {{ version }}</title> <title>Kubernetes Operational View {{ version }}</title>
<link rel="shortcut icon" href="static/favicon.ico"> <link rel="shortcut icon" href="{{ route_prefix }}static/favicon.ico">
<style>* {padding: 0; margin: 0} body { color: #aaaaff; background: #000; }</style> <style>* {padding: 0; margin: 0} body { color: #aaaaff; background: #000; }</style>
<style> <style>
/* latin */ /* latin */
@@ -14,7 +14,7 @@
font-weight: 400; font-weight: 400;
/* ShareTechMono-Regular.ttf: Copyright (c) 2012, Carrois Type Design, Ralph du Carrois (www.carrois.com post@carrois.com), with Reserved Font Name 'Share' /* ShareTechMono-Regular.ttf: Copyright (c) 2012, Carrois Type Design, Ralph du Carrois (www.carrois.com post@carrois.com), with Reserved Font Name 'Share'
License: SIL Open Font License, 1.1 */ License: SIL Open Font License, 1.1 */
src: local('Share Tech Mono'), local('ShareTechMono-Regular'), url(static/sharetechmono.woff2) format('woff2'); src: local('Share Tech Mono'), local('ShareTechMono-Regular'), url({{ route_prefix }}static/sharetechmono.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000; unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215, U+E0FF, U+EFFD, U+F000;
} }
</style> </style>
@@ -22,7 +22,7 @@
<body> <body>
<!-- make sure the font is loaded --> <!-- make sure the font is loaded -->
<div id="loading" style="font-family: ShareTechMono">Loading..</div> <div id="loading" style="font-family: ShareTechMono">Loading..</div>
<script src="static/build/{{ app_js }}"></script> <script src="{{ route_prefix }}static/build/{{ app_js }}"></script>
<script>document.getElementById('loading').style.display = 'none'; const app = new App({{ app_config_json|safe }}); app.run()</script> <script>document.getElementById('loading').style.display = 'none'; const app = new App({{ app_config_json|safe }}); app.run()</script>
</body> </body>
</html> </html>

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>Screen Tokens</title> <title>Screen Tokens</title>
<link rel="shortcut icon" href="static/favicon.ico"> <link rel="shortcut icon" href="{{ route_prefix }}static/favicon.ico">
</head> </head>
<body> <body>
<h1>Screen Tokens</h1> <h1>Screen Tokens</h1>