Kubernetes Web View to list and view all Kubernetes resources https://kube-web-view.readthedocs.io/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

232 lines
11 KiB

{% extends "base.html" %}
{% block title %}{{ plural }} in {{ cluster }}{% endblock %}
{% block content %}
<nav class="breadcrumb" aria-label="breadcrumbs">
<ul>
{% if is_all_clusters: %}
<li><a href="/clusters">all</a></li>
{% else: %}
<li><a href="/clusters/{{ cluster }}">{{ cluster }}</a></li>
{% endif %}
{% if is_all_namespaces: %}
<li><a href="/clusters/{{ cluster }}/namespaces">all</a></li>
{% elif namespace: %}
<li><a href="/clusters/{{ cluster }}/namespaces/{{ namespace }}">{{ namespace }}</a></li>
{% endif %}
<li class="is-active"><a href="#">{{ plural }}</a></li>
</ul>
</nav>
{% for table in tables: %}
<h1 class="title">{{ table.api_obj_class.kind|pluralize }}
<span class="links">
<a
{% if namespace: %}
href="/clusters/{{ table.obj.clusters|map(attribute='name')|join(',') }}/namespaces/{{ namespace }}/{{ table.api_obj_class.endpoint }}?{{ rel_url.update_query(download='tsv').query_string }}"
{% else: %}
href="/clusters/{{ table.obj.clusters|map(attribute='name')|join(',') }}/{{ table.api_obj_class.endpoint }}?{{ rel_url.update_query(download='tsv').query_string }}"
{% endif %}
title="Download resource list as Tab-Separated-Values (TSV)"
class="button is-{{ theme.button_class }}">
<span class="icon"><i class="fas fa-file-download"></i></span>
</a>
<a
href="#"
class="button is-{{ theme.button_class }} toggle-tools" data-target="tools-table-{{ loop.index }}">
<span class="icon"><i class="fas fa-caret-square-down"></i></span>
</a>
<a
href="/search?cluster={{ table.obj.clusters|map(attribute='name')|join(',') }}&namespace={{ namespace or '' }}&type={{ table.api_obj_class.endpoint }}"
class="button is-{{ theme.button_class }}">
<span class="icon"><i class="fas fa-search"></i></span>
</a>
</span>
</h1>
<form action="#" method="get" id="tools-table-{{ loop.index }}" class="tools-form {% if rel_url.query.labelcols or rel_url.query.selector or rel_url.query.filter: %}is-active{% endif%}">
{% if rel_url.query.join: %}
<input type="hidden" name="join" value="{{ rel_url.query.join }}">
{% endif %}
{% if rel_url.query.sort: %}
<input type="hidden" name="sort" value="{{ rel_url.query.sort }}">
{% endif %}
{% if rel_url.query.customcols: %}
<input type="hidden" name="customcols" value="{{ rel_url.query.customcols }}">
{% endif %}
{% if rel_url.query.hidecols: %}
<input type="hidden" name="hidecols" value="{{ rel_url.query.hidecols }}">
{% endif %}
<div class="field is-horizontal">
<div class="field-label is-normal">
<label class="label">Label Columns</label>
</div>
<div class="field-body">
<div class="field has-addons">
<p class="control is-expanded has-icons-left">
<input class="input" type="text" placeholder="Labels to show as columns (comma separated) or '*' to show all labels" name="labelcols" value="{{ rel_url.query.labelcols }}">
<span class="icon is-small is-left">
<i class="fas fa-table"></i>
</span>
</p>
</div>
</div>
</div>
<div class="field is-horizontal">
<div class="field-label is-normal">
<label class="label">Label Selector</label>
</div>
<div class="field-body">
<div class="field">
<p class="control is-expanded has-icons-left">
<input class="input" type="text" placeholder="Label selector (label=value)" name="selector" value="{{ rel_url.query.selector }}">
<span class="icon is-small is-left">
<i class="fas fa-tags"></i>
</span>
</p>
</div>
</div>
</div>
<div class="field is-horizontal">
<div class="field-label is-normal">
<label class="label">Filter</label>
</div>
<div class="field-body">
<div class="field">
<p class="control is-expanded has-icons-left">
<input class="input" type="text" placeholder="Filter by any column (Column=value) or text" name="filter" value="{{ rel_url.query.filter }}">
<span class="icon is-small is-left">
<i class="fas fa-filter"></i>
</span>
</p>
</div>
</div>
</div>
<div class="field is-horizontal">
<div class="field-label is-normal">
</div>
<div class="field-body">
<div class="control">
<button class="button is-primary" type="submit">Submit</button>
</div>
</div>
</div>
</form>
{% if table.api_obj_class.endpoint in ('pods', 'nodes') and not rel_url.query.join: %}
<div class="section">
<a href="{{ rel_url.update_query(join='metrics') }}">Show CPU/Memory Usage</a>
</div>
{% endif %}
<table class="table is-striped">
<thead>
<tr>
{% if table.obj.clusters|length > 1: %}
<th>Cluster</th>
{% endif %}
{% if is_all_namespaces: %}
<th>Namespace</th>
{% endif %}
{% for column in table.columns: %}
<th title="{{ column.description }}" class="{{ column.class }}"><a href="{{ rel_url.update_query(sort=(column.name + ':desc' if rel_url.query.sort == column.name else column.name)) }}">{{ column.name }}
{% if rel_url.query.sort == column.name: %}
<span class="icon"><i class="fas fa-sort-down"></i></span>
{% elif rel_url.query.sort == column.name + ':desc': %}
<span class="icon"><i class="fas fa-sort-up"></i></span>
{% endif %}
</a></th>
{% endfor %}
<th><a href="{{ rel_url.update_query(sort=('Created:desc' if rel_url.query.sort == 'Created' else 'Created')) }}">Created
{% if rel_url.query.sort == 'Created': %}
<span class="icon"><i class="fas fa-sort-down"></i></span>
{% elif rel_url.query.sort == 'Created:desc': %}
<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>
</thead>
<tbody>
{% for row in table.rows: %}
<tr>
{% if table.obj.clusters|length > 1: %}
<td><a href="/clusters/{{ row.cluster.name }}">{{ row.cluster.name }}</a></td>
{% endif %}
{% if is_all_namespaces: %}
<td><a href="/clusters/{{ row.cluster.name }}/namespaces/{{ row.object.metadata.namespace }}">{{ row.object.metadata.namespace }}</a></td>
{% endif %}
{% for cell in row.cells: %}
{% if table.columns[loop.index0].name == 'Name': %}
{% if row.object.metadata.namespace: %}
<td><a href="/clusters/{{ row.cluster.name }}/namespaces/{{ row.object.metadata.namespace }}/{{ table.api_obj_class.endpoint }}/{{ row.object.metadata.name }}">{{ cell }}</a></td>
{% else: %}
<td><a href="/clusters/{{ row.cluster.name }}/{{ table.api_obj_class.endpoint }}/{{ row.object.metadata.name }}">{{ cell }}</a></td>
{% endif %}
{% else: %}
<td class="{{ get_cell_class(table, loop.index0, cell) }} {{ table.columns[loop.index0].class }}"
{% if table.columns[loop.index0].name in ('Age', 'First Seen'): %}
style="color:{{ age_color(row.object.metadata.creationTimestamp, days=1) }}"
{% endif %}
>
{% if table.columns[loop.index0].label and table.columns[loop.index0].label != '*': %}
<a href="{{ rel_url.update_query(selector=table.columns[loop.index0].label+'='+cell) }}">{{ cell if cell is not none}}</a>
{% elif table.columns[loop.index0].name == 'Node': %}
<a href="/clusters/{{ row.cluster.name }}/nodes/{{ cell }}">{{ cell if cell is not none}}</a>
{% elif table.columns[loop.index0].name == 'CPU Usage': %}
{{ cell|cpu if cell is not none }}
{% elif table.columns[loop.index0].name == 'Memory Usage': %}
{{ cell|memory('MiB') if cell is not none }} MiB
{% else: %}
{{ cell if cell is not none}}
{% endif %}
</td>
{% endif %}
{% endfor %}
<td style="color:{{ age_color(row.object.metadata.creationTimestamp, 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>
<td colspan="{{ table.columns|length + 1 }}">No {{ table.api_obj_class.kind }} objects {% if namespace and not is_all_namespaces:%} in namespace "{{ namespace }}"{% endif %} found.</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endfor %}
<div class="content">
{% if namespace and plural != 'namespaces' and not is_all_namespaces: %}
<p><a href="/clusters/{{ cluster }}/namespaces/_all/{{ plural }}?{{ rel_url.query_string }}">Show {{ plural }} across all namespaces</a></p>
{% endif %}
<p class="has-text-grey">Found {{ list_total_rows }} row{{ 's' if list_total_rows != 1 }} for {{ list_resource_types|length }} resource type{{ 's' if list_resource_types|length != 1}} in {{ list_clusters|length }} cluster{{ 's' if list_clusters|length != 1 }} in {{ '%.3f'|format(list_duration) }} seconds.</p>
</div>
{% for cluster_name, errors in list_errors.items(): %}
<article class="message is-danger">
<div class="message-header">
<p>Error{{ 's' if errors|length > 1 }} for cluster {{ cluster_name }}</p>
</div>
<div class="message-body">
{% for error in errors: %}
<p>Failed to search {{ error.resource_type }}: {{ error.exception }}</p>
{% endfor %}
</div>
</article>
{% endfor %}
{% endblock %}