mirror of https://github.com/nicolargo/glances.git
WebUI is OK, had to manage the error when Glances stop, see Github issue #2252 for detail
This commit is contained in:
parent
9d76bfeb3e
commit
5ed876423f
|
|
@ -144,6 +144,11 @@ body {
|
|||
#processlist-plugin .table-cell {
|
||||
padding: 0px 5px 0px 5px;
|
||||
white-space: nowrap;
|
||||
|
||||
#vms-plugin .table-cell {
|
||||
padding: 0px 10px 0px 10px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
#containers-plugin .table-cell {
|
||||
padding: 0px 10px 0px 10px;
|
||||
|
|
|
|||
|
|
@ -79,6 +79,10 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="col-sm-18">
|
||||
<glances-plugin-vms
|
||||
v-if="!args.disable_vms"
|
||||
:data="data"
|
||||
></glances-plugin-vms>
|
||||
<glances-plugin-containers
|
||||
v-if="!args.disable_containers"
|
||||
:data="data"
|
||||
|
|
@ -126,6 +130,7 @@ import GlancesPluginSmart from './components/plugin-smart.vue';
|
|||
import GlancesPluginSensors from './components/plugin-sensors.vue';
|
||||
import GlancesPluginSystem from './components/plugin-system.vue';
|
||||
import GlancesPluginUptime from './components/plugin-uptime.vue';
|
||||
import GlancesPluginVms from './components/plugin-vms.vue';
|
||||
import GlancesPluginWifi from './components/plugin-wifi.vue';
|
||||
|
||||
import uiconfig from './uiconfig.json';
|
||||
|
|
@ -159,6 +164,7 @@ export default {
|
|||
GlancesPluginSmart,
|
||||
GlancesPluginSystem,
|
||||
GlancesPluginUptime,
|
||||
GlancesPluginVms,
|
||||
GlancesPluginWifi
|
||||
},
|
||||
data() {
|
||||
|
|
@ -374,6 +380,11 @@ export default {
|
|||
this.store.args.disable_ports = !this.store.args.disable_ports;
|
||||
});
|
||||
|
||||
// V => Enable/disable VMs stats
|
||||
hotkeys('shift+V', () => {
|
||||
this.store.args.disable_vms = !this.store.args.disable_vms;
|
||||
});
|
||||
|
||||
// 'W' > Enable/Disable Wifi plugin
|
||||
hotkeys('shift+W', () => {
|
||||
this.store.args.disable_wifi = !this.store.args.disable_wifi;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@
|
|||
<div class="divTableCell">
|
||||
{{ help.sort_io_rate }}
|
||||
</div>
|
||||
<div class="divTableCell">
|
||||
{{ help.show_hide_vms }}
|
||||
</div>
|
||||
<div class="divTableCell">
|
||||
{{ help.show_hide_containers }}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,158 @@
|
|||
<template>
|
||||
<section id="vms-plugin" class="plugin" v-if="vms.length">
|
||||
<span class="title">VMs</span>
|
||||
{{ vms.length }} sorted by {{ sorter.getColumnLabel(sorter.column) }}
|
||||
<div class="table">
|
||||
<div class="table-row">
|
||||
<div class="table-cell text-left" v-show="showEngine">Engine</div>
|
||||
<div
|
||||
class="table-cell text-left"
|
||||
:class="['sortable', sorter.column === 'name' && 'sort']"
|
||||
@click="args.sort_processes_key = 'name'"
|
||||
>
|
||||
Name
|
||||
</div>
|
||||
<div class="table-cell">Status</div>
|
||||
<div class="table-cell">Core</div>
|
||||
<div
|
||||
class="table-cell"
|
||||
:class="['sortable', sorter.column === 'memory_usage' && 'sort']"
|
||||
@click="args.sort_processes_key = 'memory_usage'"
|
||||
>
|
||||
MEM
|
||||
</div>
|
||||
<div class="table-cell text-left">/MAX</div>
|
||||
<div
|
||||
class="table-cell"
|
||||
:class="['sortable', sorter.column === 'load_1min' && 'sort']"
|
||||
@click="args.sort_processes_key = 'load_1min'"
|
||||
>
|
||||
LOAD 1/5/15min
|
||||
</div>
|
||||
<div class="table-cell text-right">Release</div>
|
||||
</div>
|
||||
<div
|
||||
class="table-row"
|
||||
v-for="(vm, vmId) in vms"
|
||||
:key="vmId"
|
||||
>
|
||||
<div class="table-cell text-left" v-show="showEngine">{{ vm.engine }}</div>
|
||||
<div class="table-cell text-left">{{ vm.name }}</div>
|
||||
<div class="table-cell" :class="vm.status == 'stopped' ? 'careful' : 'ok'">
|
||||
{{ vm.status }}
|
||||
</div>
|
||||
<div class="table-cell">
|
||||
{{ $filters.number(vm.cpu_count, 1) }}
|
||||
</div>
|
||||
<div class="table-cell">
|
||||
{{ $filters.bytes(vm.memory_usage) }}
|
||||
</div>
|
||||
<div class="table-cell text-left">
|
||||
/{{ $filters.bytes(vm.memory_total) }}
|
||||
</div>
|
||||
<div class="table-cell">
|
||||
{{ $filters.number(vm.load_1min) }}/{{ $filters.number(vm.load_5min) }}/{{ $filters.number(vm.load_15min) }}
|
||||
</div>
|
||||
<div class="table-cell text-right">
|
||||
{{ vm.release }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { orderBy } from 'lodash';
|
||||
import { store } from '../store.js';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
data: {
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
store,
|
||||
sorter: undefined
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
args() {
|
||||
return this.store.args || {};
|
||||
},
|
||||
sortProcessesKey() {
|
||||
return this.args.sort_processes_key;
|
||||
},
|
||||
stats() {
|
||||
return this.data.stats['vms'];
|
||||
},
|
||||
views() {
|
||||
return this.data.views['vms'];
|
||||
},
|
||||
vms() {
|
||||
const { sorter } = this;
|
||||
const vms = (this.stats || []).map(
|
||||
(vmData) => {
|
||||
return {
|
||||
'id': vmData.id,
|
||||
'name': vmData.name,
|
||||
'status': vmData.status != undefined ? vmData.status : '?',
|
||||
'cpu_count': vmData.cpu_count != undefined ? vmData.cpu_count : '?',
|
||||
'memory_usage': vmData.memory_usage != undefined ? vmData.memory_usage : '?',
|
||||
'memory_total': vmData.memory_total != undefined ? vmData.memory_total : '?',
|
||||
'load_1min': vmData.load_1min != undefined ? vmData.load_1min : '?',
|
||||
'load_5min': vmData.load_5min != undefined ? vmData.load_5min : '?',
|
||||
'load_15min': vmData.load_15min != undefined ? vmData.load_15min : '?',
|
||||
'release': vmData.release,
|
||||
'image': vmData.image,
|
||||
'engine': vmData.engine,
|
||||
'engine_version': vmData.engine_version,
|
||||
};
|
||||
}
|
||||
);
|
||||
return orderBy(
|
||||
vms,
|
||||
[sorter.column].reduce((retval, col) => {
|
||||
if (col === 'memory_usage') {
|
||||
col = ['memory_usage'];
|
||||
}
|
||||
return retval.concat(col);
|
||||
}, []),
|
||||
[sorter.isReverseColumn(sorter.column) ? 'desc' : 'asc']
|
||||
);
|
||||
},
|
||||
showEngine() {
|
||||
return this.views.show_engine_name;
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
sortProcessesKey: {
|
||||
immediate: true,
|
||||
handler(sortProcessesKey) {
|
||||
const sortable = ['load_1min', 'memory_usage', 'name'];
|
||||
function isReverseColumn(column) {
|
||||
return !['name'].includes(column);
|
||||
}
|
||||
function getColumnLabel(value) {
|
||||
const labels = {
|
||||
load_1min: 'load',
|
||||
memory_usage: 'memory consumption',
|
||||
name: 'VM name',
|
||||
None: 'None'
|
||||
};
|
||||
return labels[value] || value;
|
||||
}
|
||||
if (!sortProcessesKey || sortable.includes(sortProcessesKey)) {
|
||||
this.sorter = {
|
||||
column: this.args.sort_processes_key || 'load_1min',
|
||||
auto: !this.args.sort_processes_key,
|
||||
isReverseColumn,
|
||||
getColumnLabel
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -227,7 +227,7 @@ class PluginModel(GlancesPluginModel):
|
|||
for engine, watcher in iteritems(self.watchers):
|
||||
version, containers = watcher.update(all_tag=self._all_tag())
|
||||
for container in containers:
|
||||
container["engine"] = 'docker'
|
||||
container["engine"] = engine
|
||||
stats.extend(containers)
|
||||
|
||||
# Sort and update the stats
|
||||
|
|
@ -307,6 +307,9 @@ class PluginModel(GlancesPluginModel):
|
|||
ret.append(self.curse_add_line(msg))
|
||||
msg = f' sorted by {sort_for_human[self.sort_key]}'
|
||||
ret.append(self.curse_add_line(msg))
|
||||
if not self.views['show_engine_name']:
|
||||
msg = f' (served by {self.stats[0].get("engine", "")})'
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_new_line())
|
||||
# Header
|
||||
ret.append(self.curse_new_line())
|
||||
|
|
@ -430,25 +433,29 @@ class PluginModel(GlancesPluginModel):
|
|||
|
||||
@staticmethod
|
||||
def container_alert(status: str) -> str:
|
||||
"""Analyse the container status."""
|
||||
"""Analyse the container status.
|
||||
One of created, restarting, running, removing, paused, exited, or dead
|
||||
"""
|
||||
if status == 'running':
|
||||
return 'OK'
|
||||
if status == 'exited':
|
||||
return 'WARNING'
|
||||
if status == 'dead':
|
||||
return 'CRITICAL'
|
||||
return 'CAREFUL'
|
||||
return 'ERROR'
|
||||
if status in ['created', 'restarting', 'exited']:
|
||||
return 'WARNING'
|
||||
return 'INFO'
|
||||
|
||||
|
||||
def sort_docker_stats(stats: List[Dict[str, Any]]) -> Tuple[str, List[Dict[str, Any]]]:
|
||||
# Sort Docker stats using the same function than processes
|
||||
sort_by = glances_processes.sort_key
|
||||
sort_by_secondary = 'memory_usage'
|
||||
if sort_by == 'memory_percent':
|
||||
# Make VM sort related to process sort
|
||||
if glances_processes.sort_key == 'memory_percent':
|
||||
sort_by = 'memory_usage'
|
||||
sort_by_secondary = 'cpu_percent'
|
||||
elif sort_by in ['username', 'io_counters', 'cpu_times']:
|
||||
elif glances_processes.sort_key == 'name':
|
||||
sort_by = 'name'
|
||||
sort_by_secondary = 'cpu_percent'
|
||||
else:
|
||||
sort_by = 'cpu_percent'
|
||||
sort_by_secondary = 'memory_usage'
|
||||
|
||||
# Sort docker stats
|
||||
sort_stats_processes(
|
||||
|
|
|
|||
|
|
@ -61,6 +61,12 @@ fields_description = {
|
|||
'ipv4': {
|
||||
'description': 'Vm IP v4 address',
|
||||
},
|
||||
'engine': {
|
||||
'description': 'VM engine name (only Mutlipass is currently supported)',
|
||||
},
|
||||
'engine_version': {
|
||||
'description': 'VM engine version',
|
||||
},
|
||||
}
|
||||
|
||||
# Define the items history list (list of items to add to history)
|
||||
|
|
@ -73,7 +79,8 @@ export_exclude_list = []
|
|||
sort_for_human = {
|
||||
'cpu_count': 'CPU count',
|
||||
'memory_usage': 'memory consumption',
|
||||
'name': 'vm name',
|
||||
'load_1min': 'load',
|
||||
'name': 'VM name',
|
||||
None: 'None',
|
||||
}
|
||||
|
||||
|
|
@ -155,9 +162,9 @@ class PluginModel(GlancesPluginModel):
|
|||
stats = []
|
||||
for engine, watcher in iteritems(self.watchers):
|
||||
version, vms = watcher.update(all_tag=self._all_tag())
|
||||
# print(engine, version, vms)
|
||||
for vm in vms:
|
||||
vm["engine"] = 'vm'
|
||||
vm["engine"] = engine
|
||||
vm["engine_version"] = version
|
||||
stats.extend(vms)
|
||||
|
||||
# Sort and update the stats
|
||||
|
|
@ -173,36 +180,6 @@ class PluginModel(GlancesPluginModel):
|
|||
if not self.stats:
|
||||
return False
|
||||
|
||||
# Add specifics information
|
||||
# Alert
|
||||
# TODO
|
||||
# for i in self.stats:
|
||||
# # Init the views for the current vm (key = vm name)
|
||||
# self.views[i[self.get_key()]] = {'cpu': {}, 'mem': {}}
|
||||
# # CPU alert
|
||||
# if 'cpu' in i and 'total' in i['cpu']:
|
||||
# # Looking for specific CPU vm threshold in the conf file
|
||||
# alert = self.get_alert(i['cpu']['total'], header=i['name'] + '_cpu', action_key=i['name'])
|
||||
# if alert == 'DEFAULT':
|
||||
# # Not found ? Get back to default CPU threshold value
|
||||
# alert = self.get_alert(i['cpu']['total'], header='cpu')
|
||||
# self.views[i[self.get_key()]]['cpu']['decoration'] = alert
|
||||
# # MEM alert
|
||||
# if 'memory' in i and 'usage' in i['memory']:
|
||||
# # Looking for specific MEM vm threshold in the conf file
|
||||
# alert = self.get_alert(
|
||||
# self.memory_usage_no_cache(i['memory']),
|
||||
# maximum=i['memory']['limit'],
|
||||
# header=i['name'] + '_mem',
|
||||
# action_key=i['name'],
|
||||
# )
|
||||
# if alert == 'DEFAULT':
|
||||
# # Not found ? Get back to default MEM threshold value
|
||||
# alert = self.get_alert(
|
||||
# self.memory_usage_no_cache(i['memory']), maximum=i['memory']['limit'], header='mem'
|
||||
# )
|
||||
# self.views[i[self.get_key()]]['mem']['decoration'] = alert
|
||||
|
||||
# Display Engine ?
|
||||
show_engine_name = False
|
||||
if len({ct["engine"] for ct in self.stats}) > 1:
|
||||
|
|
@ -228,6 +205,9 @@ class PluginModel(GlancesPluginModel):
|
|||
ret.append(self.curse_add_line(msg))
|
||||
msg = f' sorted by {sort_for_human[self.sort_key]}'
|
||||
ret.append(self.curse_add_line(msg))
|
||||
if not self.views['show_engine_name']:
|
||||
msg = f' (served by {self.stats[0].get("engine", "")})'
|
||||
ret.append(self.curse_add_line(msg))
|
||||
ret.append(self.curse_new_line())
|
||||
# Header
|
||||
ret.append(self.curse_new_line())
|
||||
|
|
@ -239,13 +219,13 @@ class PluginModel(GlancesPluginModel):
|
|||
)
|
||||
|
||||
if self.views['show_engine_name']:
|
||||
msg = ' {:{width}}'.format('Engine', width=6)
|
||||
msg = ' {:{width}}'.format('Engine', width=8)
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = ' {:{width}}'.format('Name', width=name_max_width)
|
||||
ret.append(self.curse_add_line(msg, 'SORT' if self.sort_key == 'name' else 'DEFAULT'))
|
||||
msg = '{:>10}'.format('Status')
|
||||
ret.append(self.curse_add_line(msg))
|
||||
msg = '{:>6}'.format('CPU')
|
||||
msg = '{:>6}'.format('Core')
|
||||
ret.append(self.curse_add_line(msg, 'SORT' if self.sort_key == 'cpu_count' else 'DEFAULT'))
|
||||
msg = '{:>7}'.format('MEM')
|
||||
ret.append(self.curse_add_line(msg, 'SORT' if self.sort_key == 'memory_usage' else 'DEFAULT'))
|
||||
|
|
@ -260,7 +240,7 @@ class PluginModel(GlancesPluginModel):
|
|||
for vm in self.stats:
|
||||
ret.append(self.curse_new_line())
|
||||
if self.views['show_engine_name']:
|
||||
ret.append(self.curse_add_line(' {:{width}}'.format(vm["engine"], width=6)))
|
||||
ret.append(self.curse_add_line(' {:{width}}'.format(vm["engine"], width=8)))
|
||||
# Name
|
||||
ret.append(self.curse_add_line(' {:{width}}'.format(vm['name'][:name_max_width], width=name_max_width)))
|
||||
# Status
|
||||
|
|
@ -269,7 +249,7 @@ class PluginModel(GlancesPluginModel):
|
|||
ret.append(self.curse_add_line(msg, status))
|
||||
# CPU (count)
|
||||
try:
|
||||
msg = '{:>6.1f}'.format(vm['cpu_count'])
|
||||
msg = '{:>6}'.format(vm['cpu_count'])
|
||||
except (KeyError, TypeError):
|
||||
msg = '{:>6}'.format('-')
|
||||
ret.append(self.curse_add_line(msg, self.get_views(item=vm['name'], key='cpu_count', option='decoration')))
|
||||
|
|
@ -309,23 +289,20 @@ class PluginModel(GlancesPluginModel):
|
|||
if status == 'running':
|
||||
return 'OK'
|
||||
if status in ['starting', 'restarting', 'delayed shutdown']:
|
||||
return 'INFO'
|
||||
if status in ['stopped', 'deleted', 'suspending', 'suspended']:
|
||||
return 'CRITICAL'
|
||||
return 'CAREFUL'
|
||||
return 'WARNING'
|
||||
return 'INFO'
|
||||
|
||||
|
||||
def sort_vm_stats(stats: List[Dict[str, Any]]) -> Tuple[str, List[Dict[str, Any]]]:
|
||||
# Sort Vm stats using the same function than processes
|
||||
sort_by = glances_processes.sort_key
|
||||
if sort_by == 'cpu_percent':
|
||||
sort_by = 'cpu_count'
|
||||
sort_by_secondary = 'memory_usage'
|
||||
elif sort_by == 'memory_percent':
|
||||
# Make VM sort related to process sort
|
||||
if glances_processes.sort_key == 'memory_percent':
|
||||
sort_by = 'memory_usage'
|
||||
sort_by_secondary = 'cpu_count'
|
||||
elif sort_by in ['username', 'io_counters', 'cpu_times']:
|
||||
sort_by = 'cpu_count'
|
||||
sort_by_secondary = 'load_1min'
|
||||
elif glances_processes.sort_key == 'name':
|
||||
sort_by = 'name'
|
||||
sort_by_secondary = 'load_1min'
|
||||
else:
|
||||
sort_by = 'load_1min'
|
||||
sort_by_secondary = 'memory_usage'
|
||||
|
||||
# Sort vm stats
|
||||
|
|
|
|||
|
|
@ -41,7 +41,8 @@ class VmExtension:
|
|||
# "multipass": "1.13.1",
|
||||
# "multipassd": "1.13.1"
|
||||
# }
|
||||
return orjson.loads(secure_popen(f'{MULTIPASS_PATH} {MULTIPASS_VERSION_OPTIONS}'))
|
||||
ret = orjson.loads(secure_popen(f'{MULTIPASS_PATH} {MULTIPASS_VERSION_OPTIONS}'))
|
||||
return ret.get('multipass', None)
|
||||
|
||||
def update_info(self):
|
||||
# > multipass info --format json
|
||||
|
|
|
|||
Loading…
Reference in New Issue