| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <title>Nodes and Networks report</title> |
| {% include 'common_styles.j2' %} |
| {% include 'common_scripts.j2' %} |
| <style> |
| table.cluster_nodes { |
| width: 90%; |
| margin-left: 5%; |
| margin-right: 5%; |
| } |
| |
| /* Node rows*/ |
| .node { |
| font-family: "LaoSangamMN", Monaco, monospace; |
| font-size: 0.8em; |
| display: inline-block; |
| background-color: white; |
| } |
| .collapsable { |
| font-family: "LaoSangamMN", Monaco, monospace; |
| font-size: 0.8em; |
| display: none; |
| background-color: white; |
| visibility: hidden; |
| } |
| .collapsable.in { |
| visibility: visible; |
| display: inline-block; |
| } |
| |
| div.services > .collapsable.in { |
| display: table-row; |
| } |
| |
| tr.node > td, tr.collapsable > td { |
| display: block; |
| float: left; |
| padding: 1px; |
| margin: 2px; |
| } |
| td > .disk_group { |
| display: grid; |
| grid-template-columns: auto auto auto auto auto; |
| padding-left: 0px; |
| padding-right: 0px; |
| margin: 1px; |
| } |
| td > .ram_group { |
| display: grid; |
| grid-template-columns: auto auto auto auto; |
| padding-left: 0px; |
| padding-right: 0px; |
| margin: 1px; |
| } |
| td > .vcpu_group { |
| display: grid; |
| grid-template-columns: auto; |
| padding-left: 0px; |
| padding-right: 0px; |
| margin: 1px; |
| } |
| |
| .item { |
| display: inline-grid; |
| border-width: 1px; |
| border-style: solid; |
| margin: 1px 1px 1px 1px; |
| padding: 0px 1px 0px 1px; |
| } |
| |
| .status_none { border-radius: 10px; width: 8px; } |
| .status_up { border-radius: 10px; width: 8px; background-color: #393; color: #393; } |
| .status_down { border-radius: 10px; width: 8px; background-color: #933; color: #933; } |
| |
| .head { height: 18px; } |
| .col_name { width: 250px; } |
| .col_role { width: 150px; } |
| .col_vendor { width: 100px; } |
| .col_release { width: 100px; } |
| .col_kernel { min-width: 100px; } |
| .col_vcpu { min-width: 40px; } |
| .col_ram { min-width: 150px; } |
| .col_disk { min-width: 200px; } |
| |
| .col_notes { width: 618px; } |
| .meters { |
| display: inline-block; |
| margin: 1px; |
| } |
| .meters > .meter { |
| display: block; |
| float: left; |
| border-width: 1px; |
| border-style: solid; |
| margin: 0px 1px 0px 1px; |
| padding: 0px 1px 0px 1px; |
| |
| } |
| .meters > .ok, .disk_group > .ok, .ram_group > .ok{ |
| border-color: #80a080; |
| background-color: #efe; |
| } |
| .meters > .warn, .disk_group > .warn, .ram_group > .warn { |
| border-color: #d3a200; |
| background-color: rgb(255, 216, 133); |
| } |
| .meters > .fail, .disk_group > .fail, .ram_group > .fail { |
| border-color: #bb0000; |
| background-color: rgb(250, 135, 135); |
| } |
| .cpu { border-color: #a0c0a0; background-color: rgb(252, 248, 248); } |
| .ram { border-color: #c0c0a0; background-color: rgb(255, 255, 251); } |
| .disk { border-color: #cedfdf; background-color: rgb(237, 241, 243); } |
| |
| .map_grid { |
| display: grid; |
| grid-template-columns: auto auto auto auto auto auto auto auto auto auto; |
| grid-column-gap: 20px; |
| padding-left: 0px; |
| padding-right: 0px; |
| margin: 1px; |
| margin-left: 20px; |
| |
| } |
| .map_item { |
| display: inline-grid; |
| border-width: 0px; |
| border-style: solid; |
| margin: 1px 1px 1px 1px; |
| padding: 0px 1px 0px 1px; |
| } |
| |
| .map_grid > .ok { |
| color: #80a080; |
| } |
| .map_grid > .warn { |
| color: #d3a200; |
| } |
| .map_grid > .fail { |
| color: #bb0000; |
| } |
| |
| .services { |
| font-family: "LaoSangamMN", Monaco, monospace; |
| font-size: 1.1em; |
| background-color: white; |
| } |
| .service_node { |
| background-color: #ddd; |
| margin-bottom: 2px; |
| } |
| .service_grid { |
| display: grid; |
| grid-template-columns: repeat(8, auto); |
| grid-template-rows: repeat(10, auto); |
| grid-auto-flow: column; |
| grid-column-gap: 20px; |
| padding-left: 0px; |
| padding-right: 0px; |
| margin: 1px; |
| margin-left: 20px; |
| } |
| .service { |
| display: inline-grid; |
| text-align: center; |
| border-width: 0px; |
| border-style: solid; |
| margin: 1px 1px 1px 1px; |
| padding: 0px 1px 0px 1px; |
| min-width: 150px; |
| border-radius: 10px; |
| } |
| |
| .service_grid > .on { |
| background-color: #8c8; |
| } |
| .service_grid > .off { |
| background-color: #9aa; |
| } |
| .service_grid > .fail { |
| background-color: rgb(250, 135, 135); |
| } |
| |
| </style> |
| </head> |
| <body onload="init()"> |
| |
| <div class="header"> |
| <div class="label">OpenStack release:</div> |
| <div class="text">{{ openstack_release }}</div> |
| <div class="label">MCP Version:</div> |
| <div class="text">{{ mcp_release }}</div> |
| <div class="label">RAM % Warning/Critical:</div> |
| <div class="text">{{ const['ram_warn'] }}/{{ const['ram_critical'] }}</div> |
| <div class="label">Disk % Warning/Critical:</div> |
| <div class="text">{{ const['disk_warn'] }}/{{ const['disk_critical'] }}</div> |
| <div class="label date">generated on: {{ gen_date }}</div> |
| </div> |
| |
| <div class="bar"> |
| <button class="bar-item" onclick="openBar(event, 'nodes')">Nodes</button> |
| <button class="bar-item" onclick="openBar(event, 'networks')">Networks</button> |
| <button class="bar-item" onclick="openBar(event, 'services')">Other</button> |
| </div> |
| |
| {% macro nodes_page(nodes, id_label) %} |
| <div id="{{ id_label }}" class="barcontent"> |
| <h5>{{ caller() }}</h5> |
| <hr> |
| <table class="cluster_nodes"> |
| <tr class="node"> |
| <td class="status_none"></td> |
| <td class="head col_name">Name</td> |
| <td class="head col_role">Role</td> |
| <td class="head col_vendor">Virtual</td> |
| <td class="head col_release">Linux</td> |
| <td class="head col_kernel">Kernel</td> |
| |
| <td class="head col_vcpu"> |
| <div class="meters vcpu"> |
| <div class="meter cpu">vCPU</div> |
| </div> |
| </td> |
| <td class="head col_ram"> |
| <div class="meters"> |
| <div class="meter ram">Total</div> |
| <div class="meter ram">Used</div> |
| <div class="meter ram">Free</div> |
| <div class="meter ram">Available</div> |
| </div> |
| </td> |
| <td class="head col_disk"> |
| <div class="meters"> |
| <div class="meter disk">device</div> |
| <div class="meter disk">total</div> |
| <div class="meter disk">used</div> |
| <div class="meter disk">free</div> |
| <div class="meter disk">percent</div> |
| </div> |
| </td> |
| </tr> |
| {% for node in nodes.keys() | sort %} |
| {% set _ndat = nodes[node] %} |
| <tr class="node" onclick="toggleClassByID('info_{{ node }}')" id='info_{{ node }}_button'> |
| <td class="status_{{ _ndat['status'] | node_status_class }}">.</td> |
| <td class="head col_name">{{ node }}</td> |
| <td class="head col_role">{{ _ndat['role'] }}</td> |
| <td class="head col_vendor">{{ _ndat['virt_vendor'] }}/{{ _ndat['virt_mode'] }}/{{ _ndat['virt_type'] }}</td> |
| <td class="head col_release">{{ _ndat['linux_arch'] }}/{{ _ndat['linux_codename'] }}</td> |
| <td class="head col_kernel">{{ _ndat['kernel'] }}</td> |
| <td class="head col_vcpu"> |
| <div class="meters vcpu"> |
| <div class="meter cpu">{{ _ndat['cpus'] }}</div> |
| </div> |
| </td> |
| <td class="head col_ram"> |
| <div class="ram_group"> |
| <div class="item ram">{{ _ndat['ram_total'] }}</div> |
| <div class="item ram">{{ _ndat['ram_used'] }}</div> |
| <div class="item ram">{{ _ndat['ram_free'] }}</div> |
| <div class="item ram {{ _ndat['ram_status'] }}">{{ _ndat['ram_available'] }}</div> |
| </div> |
| </td> |
| <td class="head col_disk"> |
| <div class="disk_group"> |
| <div class="item disk">{{ _ndat['disk_max_dev'] }}</div> |
| {% for val in _ndat['disk'][_ndat['disk_max_dev']]['v'] %} |
| <div class="item disk {{ _ndat['disk'][_ndat['disk_max_dev']]['f'] }}">{{ val }}</div> |
| {% endfor %} |
| </div> |
| </td> |
| </tr> |
| <tr class="collapsable" id="info_{{ node }}"> |
| <td class="status_none"></td> |
| <td class="col_notes" colspan="4">.</td> |
| <td class="col_kernel"></td> |
| <td class="col_vcpu"></td> |
| <td class="col_ram"></td> |
| <td class="col_disk"> |
| <div class="disk_group"> |
| {% for dev in _ndat['disk'].keys() | sort %} |
| <div class="item disk">{{ dev }}</div> |
| {% for val in _ndat['disk'][dev]['v'] %} |
| <div class="item disk {{ _ndat['disk'][dev]['f'] }}">{{ val }}</div> |
| {% endfor %} |
| {% endfor %} |
| </div> |
| </td> |
| </tr> |
| {% endfor %} |
| </table> |
| <hr> |
| </div> |
| {% endmacro %} |
| |
| {% macro networks_page(networks, id_label) %} |
| <div id="{{ id_label }}" class="barcontent"> |
| <h5>{{ caller() }}</h5> |
| <hr> |
| <table class="networks"> |
| {% for net in map.keys() %} |
| <tr class="subnet" onclick="toggleClassByID('net_{{ net }}')" id="{{ net }}_net_button"> |
| <td>{{ net }}</td> |
| </tr> |
| <tr class="collapsable" id="net_{{ net }}"><td> |
| <div class="map_grid"> |
| {% for node in map[net].keys() | sort %} |
| {% for d in map[net][node] %} |
| <div class="map_item name">{{ node }}</div> |
| <div class="map_item interface {{ d['interface_error'] }}">{{ d['interface'] }}</div> |
| <div class="map_item note">{{ d['interface_note'] }}</div> |
| <div class="map_item ipaddr">{{ d['ip_address'] }}</div> |
| <div class="map_item ipaddr_type">{{ d['address_type'] }}</div> |
| <div class="map_item mtu {{ d['mtu_error'] }}">{{ d['rt_mtu'] }}</div> |
| <div class="map_item status {{ d['status_error'] }}">{{ d['status'] }}</div> |
| <div class="map_item gate {{ d['subnet_gateway_error'] }}">{{ d['subnet_gateway'] }}</div> |
| <div class="map_item gate">{{ d['default_gateway'] }}</div> |
| <div class="map_item error_note">{{ d['error_note'] }}</div> |
| {% endfor %} |
| {% endfor %} |
| </div> |
| </td></tr> |
| {% endfor %} |
| </table> |
| <hr> |
| </div> |
| {% endmacro %} |
| |
| {% macro services_page(services, id_label) %} |
| <div id="{{ id_label }}" class="barcontent"> |
| <h5>{{ caller() }}</h5> |
| <hr> |
| <div class="services"> |
| {% for node in nodes.keys() | sort %} |
| <div class="service_node" onclick="toggleClassByID('svc_{{ node }}')" id="svc_{{ node }}_button">{{ node }}</div> |
| <div class="collapsable" id="svc_{{ node }}"> |
| <div class="service_grid"> |
| {% for service in nodes[node]['services'].keys() | sort -%} |
| {% if nodes[node]['services'][service] %} |
| <div class="service name on">{{ service }}</div> |
| {% else %} |
| <div class="service name off">{{ service }}</div> |
| {% endif %} |
| {% endfor %} |
| </div> |
| </div> |
| {% endfor %} |
| </div> |
| <hr> |
| </div> |
| {% endmacro %} |
| |
| <!-- Cluster nodes page --> |
| {% call nodes_page(nodes, "nodes") %} |
| Cluster nodes status and simple meterings |
| {% endcall %} |
| |
| <!-- Cluster nodes page --> |
| {% call networks_page(networks, "networks") %} |
| Networks in the cluster |
| {% endcall %} |
| |
| <!-- Cluster nodes page --> |
| {% call services_page(services, "services") %} |
| Services status in the cluster |
| {% endcall %} |
| |
| </body> |
| </html> |