status.jinja2 12.3 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
    <ul>
149
        <li>Current load: cores {{ '%.2f' % platform_load[0] }}, memory {{ '%.2f' % platform_load[1] }}</li>
150
        <li>Total containers: {{ stats.platform_stats.container_count }}</li>
151
        <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>
152
        <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>
153 154 155 156 157
    </ul>

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

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

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

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

295 296 297 298 299 300 301 302
    {% 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 %}

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