Browse Source

#12 new option --object-links to link to external tools

tags/0.16^2
Henning Jacobs 4 months ago
parent
commit
01c4ad74b8
9 changed files with 61 additions and 4 deletions
  1. +1
    -1
      .flake8
  2. +1
    -1
      Makefile
  3. +4
    -0
      kube_web/main.py
  4. +12
    -0
      kube_web/templates/resource-list.html
  5. +5
    -0
      kube_web/templates/resource-view.html
  6. +9
    -0
      kube_web/web.py
  7. +1
    -0
      tests/e2e/deployment.yaml
  8. +10
    -2
      tests/e2e/test_list.py
  9. +18
    -0
      tests/e2e/test_view.py

+ 1
- 1
.flake8 View File

@@ -1,3 +1,3 @@
[flake8]
max-line-length=120
max-line-length=200
ignore=E722,W503

+ 1
- 1
Makefile View File

@@ -67,7 +67,7 @@ docs:

.PHONY: run
run:
poetry run python3 -m kube_web --show-container-logs --debug
poetry run python3 -m kube_web --show-container-logs --debug "--object-links=ingresses=javascript:alert('{name}')"

.PHONY: run.kind
run.kind:

+ 4
- 0
kube_web/main.py View File

@@ -72,6 +72,10 @@ def main(argv=None):
"--static-assets-path",
help="Path to custom JS/CSS assets (will be mounted as /assets HTTP path)",
)
parser.add_argument(
"--object-links",
help="Comma-separated list of URL templates per resource type to link to external tools, e.g. 'pods=https://mymonitoringtool/{cluster}/{namespace}/{name}'",
)

args = parser.parse_args(argv)


+ 12
- 0
kube_web/templates/resource-list.html View File

@@ -135,6 +135,9 @@
<span class="icon"><i class="fas fa-sort-up"></i></span>
{% endif %}
</a></th>
{% if object_links[table.api_obj_class.endpoint]: %}
<th></th>
{% endif %}
</tr>
{% for row in table.rows: %}
<tr>
@@ -170,6 +173,15 @@
{% endif %}
{% endfor %}
<td style="color:{{ row.object.metadata.creationTimestamp|age_color(days=1) }}">{{ row.object.metadata.creationTimestamp.replace('T', ' ').replace('Z', '') }}</td>
{% if object_links[table.api_obj_class.endpoint]: %}
<td>
{% for link in object_links[table.api_obj_class.endpoint]: %}
<a href="{{ link.href.format(cluster=row.cluster.name, namespace=row.object.metadata.namespace, name=row.object.metadata.name) }}" class="button is-primary">
<span class="icon"><i class="fas fa-{{ link.icon }}"></i></span>
</a>
{% endfor %}
</td>
{% endif %}
</tr>
{% else: %}
<tr>

+ 5
- 0
kube_web/templates/resource-view.html View File

@@ -26,6 +26,11 @@
class="button is-light">
<span class="icon"><i class="fas fa-file-download"></i></span>
</a>
{% for link in object_links[resource.endpoint]: %}
<a href="{{ link.href.format(cluster=cluster, namespace=namespace, name=resource.name) }}" class="button is-primary">
<span class="icon"><i class="fas fa-{{ link.icon }}"></i></span>
</a>
{% endfor %}
</span>
</h1>
<div class="tabs is-small">

+ 9
- 0
kube_web/web.py View File

@@ -1023,6 +1023,14 @@ def get_app(cluster_manager, config):
# overwrite assets path
static_assets_path = Path(config.static_assets_path)

object_links = collections.defaultdict(list)
if config.object_links:
for link_def in config.object_links.split(","):
resource_type, sep, url_template = link_def.partition("=")
object_links[resource_type].append(
{"href": url_template, "icon": "external-link-alt"}
)

app = web.Application()
aiohttp_jinja2.setup(
app,
@@ -1040,6 +1048,7 @@ def get_app(cluster_manager, config):
memory=jinja2_filters.memory,
)
env.globals["version"] = __version__
env.globals["object_links"] = object_links

app.add_routes(routes)
app.router.add_static("/assets", static_assets_path)

+ 1
- 0
tests/e2e/deployment.yaml View File

@@ -70,4 +70,5 @@ spec:
imagePullPolicy: IfNotPresent # For our E2E tests.
args:
- --show-container-logs
- --object-links=pods=#cluster={cluster};namespace={namespace};name={name}
env: []

+ 10
- 2
tests/e2e/test_list.py View File

@@ -79,8 +79,9 @@ def test_list_pods_with_metrics(session):
response.raise_for_status()
check_links(response, session)
ths = response.html.find("main table th")
assert ths[-3].text == "CPU Usage"
assert ths[-2].text == "Memory Usage"
# note: pods have an extra "Links" column (--object-links)
assert ths[-4].text == "CPU Usage"
assert ths[-3].text == "Memory Usage"


def test_list_namespaced_resource_type_not_found(session):
@@ -214,3 +215,10 @@ def test_download_sort_link(session):
"/clusters/local/namespaces/default/pods?sort=Status&download=tsv"
== link.attrs["href"]
)


def test_object_links(session):
response = session.get("/clusters/local/namespaces/default/pods")
response.raise_for_status()
link = response.html.find("main table a.button", first=True)
assert link.attrs["href"].startswith("#cluster=local;namespace=default;name=")

+ 18
- 0
tests/e2e/test_view.py View File

@@ -112,3 +112,21 @@ def test_owner_links(session):
assert found_link.attrs["href"].startswith(
"/clusters/local/namespaces/default/replicasets/kube-web-view-"
)


def test_object_links(session):
response = session.get(
"/clusters/local/namespaces/default/pods?selector=application=kube-web-view"
)
response.raise_for_status()
pod_link = response.html.find("main table td a", first=True)
url = pod_link.attrs["href"]
assert url.startswith("/clusters/local/namespaces/default/pods/kube-web-view-")
response = session.get(url)
response.raise_for_status()
check_links(response, session)

link = response.html.find("main h1 a.is-primary", first=True)
assert link.attrs["href"].startswith(
"#cluster=local;namespace=default;name=kube-web-view-"
)

Loading…
Cancel
Save