status.jinja2 12.2 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
    <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>
24 25 26
        {% if eurecom %}
        <li><a href="#logs">Zoe process logs</a></li>
        {% endif %}
27 28 29 30
    </ul>
    </div>

    <h3 class="section"><a name="scheduler">Scheduler</a></h3>
31 32 33 34

    <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>
35
        <li>Clean-up queue length: <span id="termination_threads_count">{{ stats.termination_queue_length }}</span></li>
36 37 38 39 40 41 42 43 44 45 46
    </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 }}">
47 48 49 50 51
            {% 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 %}
52 53
            {% for service in executions_in_queue[id].services %}
                {% if service.essential %}
54
                <div class="service essential {{ 'running' if not service.is_dead() }}">
55
                    {{ service['name'] }}<br/>
56 57
                    M: <script>format_bytes({{ service['resource_reservation']['memory']['min'] }});</script><br/>
                    C: {{ service['resource_reservation']['cores']['min'] }}
58 59 60 61 62
                </div>
                {% endif %}
            {% endfor %}
            {% for service in executions_in_queue[id].services %}
                {% if not service.essential %}
63
                <div class="service {{ 'running' if not service.is_dead() }}">
64
                    {{ service['name'] }}<br/>
65 66
                    M: <script>format_bytes({{ service['resource_reservation']['memory']['min'] }});</script><br/>
                    C: {{ service['resource_reservation']['cores']['min'] }}
67 68 69 70 71 72 73 74 75 76 77 78 79 80
                </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'] %}
81 82 83 84 85 86
            <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 %}
87 88 89 90
            {% 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/>
91 92
                    M: <script>format_bytes({{ service['resource_reservation']['memory']['min'] }});</script><br/>
                    C: {{ service['resource_reservation']['cores']['min'] }}
93 94 95 96 97
                </div>
                {% endif %}
            {% endfor %}
            {% for service in executions_in_queue[id].services %}
                {% if not service.essential %}
98 99 100 101 102 103 104 105 106 107
                <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 %}
108
    <p>The queue is empty.</p>
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
    {% 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 %}
133 134
                <div class="service {{ 'running' if service.status == service.ACTIVE_STATUS }}">
                    {{ service['name'] }}<br/>
135 136
                    M: <script>format_bytes({{ service['resource_reservation']['memory']['min'] }});</script><br/>
                    C: {{ service['resource_reservation']['cores']['min'] }}
137 138 139 140 141
                </div>
                {% endif %}
            {% endfor %}
        </div>
    {% endfor %}
142 143
    {% if stats['termination_queue']|length == 0 %}
    <p>The queue is empty.</p>
144 145 146
    {% endif %}
    </div>

147
    <h3 class="section"><a name="platform">Platform</a></h3>
148 149
    <ul>
        <li>Total containers: {{ stats.platform_stats.container_count }}</li>
150
        <li>Memory: <script>format_bytes({{ stats.platform_stats.memory_total }}, 2)</script> total, <script>format_bytes({{ stats.platform_stats.memory_reserved }}, 2)</script> reserved, <script>format_bytes({{ stats.platform_stats.memory_in_use }}, 2)</script> in use</li>
151
        <li>Cores: {{ '%.2f' % stats.platform_stats.cores_total }} total, {{ '%.2f' % stats.platform_stats.cores_reserved }} reserved, {{ '%.2f' % stats.platform_stats.cores_in_use }} in use</li>
152 153 154 155 156
    </ul>

    <div class="platform_node_detail">
    {% for node in stats.platform_stats.nodes %}
        <div class="node_detail">
157 158 159 160 161 162
        <div class="node_name">
            {{ node['name'] }}
            {% if node['status'] == 'offline' %}
                (node is offline/unreachable)
            {% endif %}
        </div>
163
        <div class="container_count">{{ node['container_count'] }} containers</div>
164 165 166 167 168 169 170 171 172
        {% 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 %}
173 174 175 176

        <div class="plot-container">
            <p>Memory</p>
            <div class="pie-plots">
177
                <canvas class="node_status_canvas" id="{{ node.name }}-mem"></canvas>
178
            </div>
179
        </div>
180 181 182
        <script>
        data = {
            datasets: [{
183
                label: 'Memory',
184 185
                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)']
186
            }],
187
            'labels': ['Reserved', 'Allocated', 'In use']
188
        };
189
        ctx = document.getElementById("{{ node.name }}-mem").getContext('2d');
190
        new Chart(ctx,{
191
            type: 'bar',
192 193 194
            data: data,
            options: {
                animation: {
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
                    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);
                        }
                    }
217 218 219 220 221 222 223 224
                }
            }
        });
        </script>

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

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

294 295 296 297 298 299 300 301
    {% if eurecom %}
    <h3 class="section"><a name="logs">Zoe process</a></h3>
    <ul>
        <li><a href="http://192.168.46.31:9001">Zoe API</a></li>
        <li><a href="http://192.168.46.31:9002">Zoe master</a></li>
    </ul>
    {% endif %}

302 303 304 305 306 307
    <script>
    function refresh_page() {
        document.location.reload();
    }
    setInterval(refresh_page, 15000);
    </script>
308
{% endblock %}