status.jinja2 11.6 KB
Newer Older
Daniele Venzano's avatar
Daniele Venzano committed
1
{% extends "base_user.jinja2" %}
2 3
{% block title %}Zoe system status{% endblock %}

4
{% block custom_head %}
5
    <script src="{{ static_url("Chart.min.js") }}" type="application/javascript"></script>
6 7 8 9 10 11 12
    <script>
    Chart.scaleService.updateScaleDefaults('linear', {
        ticks: {
            min: 0
        }
    });
    </script>
13 14
{% endblock %}

15 16 17
{% block content %}
<h2>Zoe system status</h2>

18 19 20 21 22 23 24 25 26 27
    <div>
    <h3 class="section">Index</h3>
    <ul>
        <li><a href="#scheduler">Scheduler</a></li>
        <li><a href="#platform">Platform</a></li>
        <li><a href="#service-distrib">Service distribution</a></li>
    </ul>
    </div>

    <h3 class="section"><a name="scheduler">Scheduler</a></h3>
28 29 30 31

    <ul>
        <li>Queue length: <span id="sched_queue_len">{{ stats.queue_length }}</span></li>
        <li>Running queue length: <span id="sched_running_queue_len">{{ stats.running_length }}</span></li>
32
        <li>Clean-up queue length: <span id="termination_threads_count">{{ stats.termination_queue_length }}</span></li>
33 34 35 36 37 38 39 40 41 42 43
    </ul>

    <h4>Queue</h4>
    <p>Service border legend:</p>
    <ul>
        <li>Green/red: service is active/inactive. Active services have been scheduled and placed.</li>
        <li>Solid/dashed: service is essential/elastic</li>
    </ul>
    <div class="scheduler_queue">
    {% for id in stats['queue'] %}
        <div class="queue_item" id="{{ id }}">
44 45 46 47 48
            {% if user.role.can_operate_others %}
            <a href="{{ reverse_url('execution_inspect', id) }}">{{ id }}</a> ({{ executions_in_queue[id].owner.username }})
            {% else %}
            {{ id }} ({{ executions_in_queue[id].owner.username }})
            {% endif %}
49 50
            {% for service in executions_in_queue[id].services %}
                {% if service.essential %}
51
                <div class="service essential {{ 'running' if not service.is_dead() }}">
52
                    {{ service['name'] }}<br/>
53 54
                    M: <script>format_bytes({{ service['resource_reservation']['memory']['min'] }});</script><br/>
                    C: {{ service['resource_reservation']['cores']['min'] }}
55 56 57 58 59
                </div>
                {% endif %}
            {% endfor %}
            {% for service in executions_in_queue[id].services %}
                {% if not service.essential %}
60
                <div class="service {{ 'running' if not service.is_dead() }}">
61
                    {{ service['name'] }}<br/>
62 63
                    M: <script>format_bytes({{ service['resource_reservation']['memory']['min'] }});</script><br/>
                    C: {{ service['resource_reservation']['cores']['min'] }}
64 65 66 67 68 69 70 71 72 73 74 75 76 77
                </div>
                {% endif %}
            {% endfor %}
        </div>
    {% endfor %}
    {% if stats['queue']|length == 0 %}
    <p>The queue is empty.</p>
    {% endif %}
    </div>

    <h4>Running queue</h4>
    <p>This queue is unsorted, all services here should be green.</p>
    <div class="scheduler_queue">
    {% for id in stats['running_queue'] %}
78 79 80 81 82 83
            <div class="queue_item" id="{{ id }}">
            {% if user.role.can_operate_others %}
            <a href="{{ reverse_url('execution_inspect', id) }}">{{ id }}</a> ({{ executions_in_queue[id].owner.username }})
            {% else %}
            {{ id }} ({{ executions_in_queue[id].owner.username }})
            {% endif %}
84 85 86 87
            {% for service in executions_in_queue[id].services %}
                {% if service.essential %}
                <div class="service essential {{ 'running' if service.status == service.ACTIVE_STATUS }}">
                    {{ service['name'] }}<br/>
88 89
                    M: <script>format_bytes({{ service['resource_reservation']['memory']['min'] }});</script><br/>
                    C: {{ service['resource_reservation']['cores']['min'] }}
90 91 92 93 94
                </div>
                {% endif %}
            {% endfor %}
            {% for service in executions_in_queue[id].services %}
                {% if not service.essential %}
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
                <div class="service {{ 'running' if service.status == service.ACTIVE_STATUS }}">
                    {{ service['name'] }}<br/>
                    M: <script>format_bytes({{ service['resource_reservation']['memory']['min'] }});</script><br/>
                    C: {{ service['resource_reservation']['cores']['min'] }}
                </div>
                {% endif %}
            {% endfor %}
        </div>
    {% endfor %}
    {% if stats['running_queue']|length == 0 %}
    <p>The running queue is empty.</p>
    {% endif %}
    </div>

    <h4>Clean-up queue</h4>
    <p>This queue contains executions that are waiting to be cleaned-up.</p>
    <div class="scheduler_queue">
    {% for id in stats['termination_queue'] %}
            <div class="queue_item" id="{{ id }}">
            {% if user.role.can_operate_others %}
            <a href="{{ reverse_url('execution_inspect', id) }}">{{ id }}</a> ({{ executions_in_queue[id].owner.username }})
            {% else %}
            {{ id }} ({{ executions_in_queue[id].owner.username }})
            {% endif %}
            {% for service in executions_in_queue[id].services %}
                {% if service.essential %}
                <div class="service essential {{ 'running' if service.status == service.ACTIVE_STATUS }}">
                    {{ service['name'] }}<br/>
                    M: <script>format_bytes({{ service['resource_reservation']['memory']['min'] }});</script><br/>
                    C: {{ service['resource_reservation']['cores']['min'] }}
                </div>
                {% endif %}
            {% endfor %}
            {% for service in executions_in_queue[id].services %}
                {% if not service.essential %}
130 131
                <div class="service {{ 'running' if service.status == service.ACTIVE_STATUS }}">
                    {{ service['name'] }}<br/>
132 133
                    M: <script>format_bytes({{ service['resource_reservation']['memory']['min'] }});</script><br/>
                    C: {{ service['resource_reservation']['cores']['min'] }}
134 135 136 137 138 139 140 141 142 143
                </div>
                {% endif %}
            {% endfor %}
        </div>
    {% endfor %}
    {% if stats['running_queue']|length == 0 %}
    <p>The running queue is empty.</p>
    {% endif %}
    </div>

144
    <h3 class="section"><a name="platform">Platform</a></h3>
145 146 147 148 149 150 151 152 153
    <ul>
        <li>Total containers: {{ stats.platform_stats.container_count }}</li>
        <li>Total memory: <script>format_bytes({{ stats.platform_stats.memory_total }}, 2) </script></li>
        <li>Total cores: {{ stats.platform_stats.cores_total }}</li>
    </ul>

    <div class="platform_node_detail">
    {% for node in stats.platform_stats.nodes %}
        <div class="node_detail">
154 155 156 157 158 159
        <div class="node_name">
            {{ node['name'] }}
            {% if node['status'] == 'offline' %}
                (node is offline/unreachable)
            {% endif %}
        </div>
160
        <div class="container_count">{{ node['container_count'] }} containers</div>
161 162 163 164 165 166 167 168 169
        {% if node['labels']|length > 0 %}
        <div class="container_count">Labels:
            {% for label in node['labels'] %}
            {{ label }}&nbsp;
            {% endfor %}
        </div>
        {% else %}
        <div class="container_count">No labels</div>
        {% endif %}
170 171 172 173

        <div class="plot-container">
            <p>Memory</p>
            <div class="pie-plots">
174
                <canvas class="node_status_canvas" id="{{ node.name }}-mem"></canvas>
175
            </div>
176
        </div>
177 178 179
        <script>
        data = {
            datasets: [{
180
                label: 'Memory',
181 182
                data: [{{ node['memory_reserved'] }}, {{ node['memory_allocated'] }}, {{ node['memory_in_use'] }}],
                backgroundColor: ['rgba(0, 169, 225, 1.0)', 'rgba(53, 51, 144, 1.0)', 'rgba(145, 192, 46, 1.0)']
183
            }],
184
            'labels': ['Reserved', 'Allocated', 'In use']
185
        };
186
        ctx = document.getElementById("{{ node.name }}-mem").getContext('2d');
187
        new Chart(ctx,{
188
            type: 'bar',
189 190 191
            data: data,
            options: {
                animation: {
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
                    duration: 0
                },
                responsiveAnimationDuration: 0,
                scales: {
                    yAxes: [{
                        ticks: {
                            callback: function(value, index, values) {
                                return format_bytes_ret(value);
                            },
                            max: {{ node['memory_total'] }}
                        }
                    }]
                },
                legend: {
                    display: false
                },
                tooltips: {
                    callbacks: {
                        label: function(tooltipItem, data) {
                            return format_bytes_ret(tooltipItem.yLabel);
                        }
                    }
214 215 216 217 218 219 220 221
                }
            }
        });
        </script>

        <div class="plot-container">
            <p>Cores</p>
            <div class="pie-plots">
222
                <canvas class="node_status_canvas" id="{{ node.name }}-cpu"></canvas>
223
            </div>
224
        </div>
225 226 227
        <script>
        data = {
            datasets: [{
228
                label: 'Cores',
Daniele Venzano's avatar
Daniele Venzano committed
229
                data: [{{ '%0.2f'|format(node['cores_reserved']|float) }}, {{ '%0.2f'|format(node['cores_allocated']|float) }}, {{ '%0.2f'|format(node['cores_in_use']|float) }}],
230
                backgroundColor: ['rgba(0, 169, 225, 1.0)', 'rgba(53, 51, 144, 1.0)', 'rgba(145, 192, 46, 1.0)']
231
            }],
232
            'labels': ['Reserved', 'Allocated', 'In use']
233
        };
234
        ctx = document.getElementById("{{ node.name }}-cpu").getContext('2d');
235
        new Chart(ctx,{
236
            type: 'bar',
237 238 239
            data: data,
            options: {
                animation: {
240 241 242 243 244 245 246 247 248 249 250 251 252
                    duration: 0
                },
                responsiveAnimationDuration: 0,
                scales: {
                    yAxes: [{
                        ticks: {
                            max: {{ node['cores_total'] }},
                            stepSize: 8
                        }
                    }]
                },
                legend: {
                    display: false
253 254 255 256
                }
            }
        });
        </script>
257 258 259 260
        </div>
    {% endfor %}
    </div>

261
    <h3 class="section"><a name="service-distrib">Service distribution</a></h3>
262
    <p>Services marked with a green border are essential, elastic ones have no border.</p>
263 264 265 266
    <table class="service-distrib">
    <thead>
    <tr>
        <th class="cell-host">Host</th>
267
        <th colspan="{{ max_service_count }}">Services and allocated resources</th>
268 269 270 271 272 273
    </tr>
    </thead>
    <tbody>
    {% for node in stats.platform_stats.nodes %}
    <tr>
        <td class="cell-host">{{ node.name }}</td>
274
        {% for service in services_per_node[node.name] %}
Daniele Venzano's avatar
Daniele Venzano committed
275
            {% if service.backend_status == "started" %}
276 277
            <td class="{{ 'running' if service.essential }}">
                {% if user.role.can_operate_others %}
278
                    <a href="{{ reverse_url('execution_inspect', service['execution_id']) }}">{{ service['execution_id'] }}:{{ service['name'] }}</a>
279 280 281 282 283
                {% else %}
                    {{ service['name'] }}
                {% endif %}
                (M: <script>format_bytes({{ node.service_stats[service['id']]['mem_limit'] }});</script> C: {{ '%0.2f'|format(node.service_stats[service['id']]['core_limit']|float) }})
            </td>
Daniele Venzano's avatar
Daniele Venzano committed
284
            {% endif %}
285 286 287 288 289 290 291 292 293 294 295 296
        {% endfor %}
    </tr>
    {% endfor %}
    </tbody>
    </table>

    <script>
    function refresh_page() {
        document.location.reload();
    }
    setInterval(refresh_page, 15000);
    </script>
297
{% endblock %}