Skip to content
This repository has been archived by the owner on Oct 3, 2020. It is now read-only.

Commit

Permalink
allow custom links e.g. to monitoring tools (#67)
Browse files Browse the repository at this point in the history
* allow custom links e.g. to monitoring tools

* fix test

* mention custom links in README
  • Loading branch information
hjacobs authored Mar 2, 2019
1 parent e3d94c1 commit 6eecf69
Show file tree
Hide file tree
Showing 13 changed files with 330 additions and 140 deletions.
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.7-alpine3.8
FROM python:3.7-alpine3.9

WORKDIR /

Expand All @@ -9,7 +9,7 @@ RUN /pipenv-install.py && \
rm -fr /usr/local/lib/python3.7/site-packages/pip && \
rm -fr /usr/local/lib/python3.7/site-packages/setuptools

FROM python:3.7-alpine3.8
FROM python:3.7-alpine3.9

WORKDIR /

Expand Down
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ black = "*"
"boto3" = "*"
pytest-cov = "*"
coveralls = "*"
coverage = "*"

[requires]
python_version = "3.7"
Expand Down
302 changes: 168 additions & 134 deletions Pipfile.lock

Large diffs are not rendered by default.

33 changes: 33 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ What the script does:
* Collect all pods and use the ``application`` or ``app`` label as application ID
* Get additional information for each app from the application registry (``team_id`` and ``active`` field)
* Group and aggregate resource usage and slack costs per cluster, team and application
* Allow custom links to existing systems (e.g. link to a monitoring dashboard for each cluster)


-----
Usage
Expand Down Expand Up @@ -74,6 +76,7 @@ Running as Docker container
$ # run kube-resource-report and generate static HTML to ./output (this trick does not work with Docker for Mac!)
$ docker run -it --user=$(id -u) --net=host -v $(pwd)/output:/output hjacobs/kube-resource-report:0.6 /output
--------------------
Application Registry
--------------------
Expand All @@ -89,3 +92,33 @@ The optional application registry can provide information per application ID, it
}
See the ``application-registry.py`` script in the ``sample-report`` folder for an example implementation.


------------
Custom Links
------------

The generated report can be enhanced with custom links to existing systems, e.g. to link to monitoring dashboards or similar.
This currently works for clusters, teams, and applications. Custom links can be specified by providing the ``--links-file`` option which must point to a YAML file
with the links per entity. Example file:

.. code-block:: yaml
cluster:
- href: "https://mymonitoringsystem.example.org/dashboard?cluster={name}"
title: "Grafana dashboard for cluster {name}"
icon: chart-area
application:
- href: "https://mymonitoringsystem.example.org/dashboard?application={id}"
title: "Grafana dashboard for application {id}"
icon: chart-area
- href: "https://apps.mycorp.example.org/apps/{id}"
title: "Go to detail page of application {id}"
icon: search
team:
- href: "https://people.mycorp.example.org/search?q=team:{id}"
title: "Search team {id} on people.mycorp"
icon: search
For available icon names, see the `Font Awesome gallery with free icons <https://fontawesome.com/icons?d=gallery&m=free>`_.

7 changes: 7 additions & 0 deletions kube_resource_report/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ def convert(self, value, param, ctx):
type=click.Path(exists=True),
help="Path to alternate pricing file"
)
@click.option(
"--links-file",
type=click.Path(exists=True),
help="Path to YAML file defining custom links for resources"
)
@click.option(
"--node-label",
help="Value for the kubernetes.io/role label (e.g. 'worker' if nodes are labeled kubernetes.io/role=worker)",
Expand All @@ -101,6 +106,7 @@ def main(
additional_cost_per_cluster,
update_interval_minutes,
pricing_file,
links_file,
node_label,
):
"""Kubernetes Resource Report
Expand Down Expand Up @@ -131,6 +137,7 @@ def main(
exclude_clusters,
additional_cost_per_cluster,
pricing_file,
links_file,
node_label,
)
if update_interval_minutes > 0:
Expand Down
13 changes: 11 additions & 2 deletions kube_resource_report/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import re
import requests
import shutil
import yaml
from urllib.parse import urljoin
from pathlib import Path

Expand Down Expand Up @@ -509,6 +510,7 @@ def generate_report(
exclude_clusters,
additional_cost_per_cluster,
pricing_file,
links_file,
node_label,
):
notifications = []
Expand All @@ -518,6 +520,12 @@ def generate_report(
if pricing_file:
pricing.regenerate_cost_dict(pricing_file)

if links_file:
with open(links_file, 'rb') as fd:
links = yaml.safe_load(fd)
else:
links = {}

start = datetime.datetime.utcnow()

pickle_path = output_path / "dump.pickle"
Expand Down Expand Up @@ -635,12 +643,12 @@ def cluster_name(cluster_id):
fd,
)

write_report(output_path, start, notifications, cluster_summaries, namespace_usage, applications, teams, node_label)
write_report(output_path, start, notifications, cluster_summaries, namespace_usage, applications, teams, node_label, links)

return cluster_summaries


def write_report(output_path: Path, start, notifications, cluster_summaries, namespace_usage, applications, teams, node_label):
def write_report(output_path: Path, start, notifications, cluster_summaries, namespace_usage, applications, teams, node_label, links):
total_allocatable = collections.defaultdict(int)
total_requests = collections.defaultdict(int)
total_user_requests = collections.defaultdict(int)
Expand Down Expand Up @@ -781,6 +789,7 @@ def write_report(output_path: Path, start, notifications, cluster_summaries, nam
total_hourly_cost = total_cost / HOURS_PER_MONTH
now = datetime.datetime.utcnow()
context = {
"links": links,
"notifications": notifications,
"cluster_summaries": cluster_summaries,
"teams": teams,
Expand Down
16 changes: 16 additions & 0 deletions kube_resource_report/templates/applications.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
<th>Memory (MiB)</th>
<th class="has-text-right">Cost</th>
<th class="has-text-right">Slack Cost</th>
{% if links['application']: %}
<th></th>
{% endif %}
</tr>
</thead>
<tbody>
Expand Down Expand Up @@ -60,6 +63,19 @@
<td class="has-text-right">{{ app.cost|money }}</td>
<td class="has-text-right">{{ app.slack_cost|money }}</td>

{% if links['application']: %}
<td class="links">
<div class="buttons has-addons">
{% for link in links['application']: %}
<a href="{{ link.href.format(**app) }}"
title="{{ link.title.format(**app) }}"
class="button is-small">
<span class="icon"><i class="fas fa-{{ link.icon }}"></i></span>
</a>
{% endfor %}
</div>
</td>
{% endif %}
</tr>

{%endfor %}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
h1 .links {
margin-left: 1rem;
}

.resource-labels {
display: flex;
line-height: 1;
Expand Down
12 changes: 11 additions & 1 deletion kube_resource_report/templates/cluster.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
{% extends "base.html" %}
{% block title %}Cluster {{ summary.cluster.name }}{% endblock %}
{% block content %}
<h1 class="title">Cluster {{ summary.cluster.name }}</h1>
<h1 class="title">Cluster {{ summary.cluster.name }}
<span class="links">
{% for link in links['cluster']: %}
<a href="{{ link.href.format(id=summary.cluster.id, name=summary.cluster.name, api_server_url=summary.cluster.api_server_url) }}"
title="{{ link.title.format(id=summary.cluster.id, name=summary.cluster.name, api_server_url=summary.cluster.api_server_url) }}"
class="button is-light">
<span class="icon"><i class="fas fa-{{ link.icon }}"></i></span>
</a>
{% endfor %}
</span>
</h1>
<h2 class="subtitle">{{ summary.cluster.id if summary.cluster.id != summary.cluster.name else summary.cluster.api_server_url }}</h1>

<nav class="level">
Expand Down
16 changes: 16 additions & 0 deletions kube_resource_report/templates/clusters.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
<th>CPU</th>
<th>Memory (GiB)</th>
<th class="has-text-right">Cost</th>
{% if links['cluster']: %}
<th></th>
{% endif %}
</tr>
</thead>
<tbody>
Expand Down Expand Up @@ -53,6 +56,19 @@
</div>
</td>
<td class="has-text-right">{{ summary.cost|money }}</td>
{% if links['cluster']: %}
<td class="links">
<div class="buttons has-addons">
{% for link in links['cluster']: %}
<a href="{{ link.href.format(id=summary.cluster.id, name=summary.cluster.name, api_server_url=summary.cluster.api_server_url) }}"
title="{{ link.title.format(id=summary.cluster.id, name=summary.cluster.name, api_server_url=summary.cluster.api_server_url) }}"
class="button is-small">
<span class="icon"><i class="fas fa-{{ link.icon }}"></i></span>
</a>
{% endfor %}
</div>
</td>
{% endif %}

</tr>

Expand Down
44 changes: 43 additions & 1 deletion kube_resource_report/templates/team.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
{% extends "base.html" %}
{% block title %}Team {{ team_id|capitalize }}{% endblock %}
{% block content %}
<h1 class="title">Team {{ team_id|capitalize }}</h1>
<h1 class="title">Team {{ team_id|capitalize }}
<span class="links">
{% for link in links['team']: %}
<a href="{{ link.href.format(id=team_id) }}"
title="{{ link.title.format(id=team_id) }}"
class="button is-light">
<span class="icon"><i class="fas fa-{{ link.icon }}"></i></span>
</a>
{% endfor %}
</span>
</h1>

<nav class="level">
<div class="level-item has-text-centered">
Expand Down Expand Up @@ -53,6 +63,9 @@ <h2 class="title is-5">Clusters</h2>
<th>CPU</th>
<th>Memory (GiB)</th>
<th class="has-text-right">Cost</th>
{% if links['cluster']: %}
<th></th>
{% endif %}
</tr>
</thead>
<tbody>
Expand Down Expand Up @@ -87,6 +100,19 @@ <h2 class="title is-5">Clusters</h2>
</div>
</td>
<td class="has-text-right">{{ summary.cost|money }}</td>
{% if links['cluster']: %}
<td class="links">
<div class="buttons has-addons">
{% for link in links['cluster']: %}
<a href="{{ link.href.format(id=summary.cluster.id, name=summary.cluster.name, api_server_url=summary.cluster.api_server_url) }}"
title="{{ link.title.format(id=summary.cluster.id, name=summary.cluster.name, api_server_url=summary.cluster.api_server_url) }}"
class="button is-small">
<span class="icon"><i class="fas fa-{{ link.icon }}"></i></span>
</a>
{% endfor %}
</div>
</td>
{% endif %}

</tr>

Expand All @@ -109,6 +135,9 @@ <h2 class="title is-5">Applications</h2>
<th class="has-text-right">Cost</th>
<th class="has-text-right">Slack Cost</th>
<th class="has-text-right">Cost %</th>
{% if links['application']: %}
<th></th>
{% endif %}
</tr>
</thead>
<tbody>
Expand Down Expand Up @@ -169,6 +198,19 @@ <h2 class="title is-5">Applications</h2>
{% else %}
<td class="has-text-right">-</td>
{% endif %}
{% if links['application']: %}
<td class="links">
<div class="buttons has-addons">
{% for link in links['application']: %}
<a href="{{ link.href.format(**app) }}"
title="{{ link.title.format(**app) }}"
class="button is-small">
<span class="icon"><i class="fas fa-{{ link.icon }}"></i></span>
</a>
{% endfor %}
</div>
</td>
{% endif %}
</tr>
{% endif %}
{%endfor %}
Expand Down
17 changes: 17 additions & 0 deletions kube_resource_report/templates/teams.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
<th>Memory (MiB)</th>
<th class="has-text-right">Cost</th>
<th class="has-text-right">Slack Cost</th>
{% if links['team']: %}
<th></th>
{% endif %}
</tr>
</thead>
<tbody>
Expand Down Expand Up @@ -48,6 +51,20 @@
<td class="has-text-right">{{ team.cost|money }}</td>
<td class="has-text-right">{{ team.slack_cost|money }}</td>

{% if links['team']: %}
<td class="links">
<div class="buttons has-addons">
{% for link in links['team']: %}
<a href="{{ link.href.format(id=team_id) }}"
title="{{ link.title.format(id=team_id) }}"
class="button is-small">
<span class="icon"><i class="fas fa-{{ link.icon }}"></i></span>
</a>
{% endfor %}
</div>
</td>
{% endif %}

</tr>

{%endfor %}
Expand Down
1 change: 1 addition & 0 deletions tests/test_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ def wrapper(responses):
None,
100.0,
None,
None,
"worker"
)
assert len(cluster_summaries) == 1
Expand Down

0 comments on commit 6eecf69

Please sign in to comment.