From 3215bf5c635bcc6698019a659f3884b73bce77bb Mon Sep 17 00:00:00 2001 From: nicolargo Date: Fri, 15 Dec 2023 19:06:33 +0100 Subject: Optimize basic HTTP authentication --- docs/api.rst | 479 ++++++++++++++++--------------- docs/man/glances.1 | 2 +- glances/globals.py | 20 ++ glances/outputs/glances_restful_api.py | 45 ++- glances/outputs/glances_stdout_apidoc.py | 22 +- glances/outputs/static/js/services.js | 10 +- glances/outputs/static/public/glances.js | 2 +- glances/password.py | 8 +- glances/plugins/processlist/__init__.py | 65 ++--- glances/processes.py | 21 +- glances/stats.py | 6 +- unitest-restful.py | 3 +- 12 files changed, 367 insertions(+), 316 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index faf7104c..45ed3b31 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -12,12 +12,16 @@ The Glances Restfull/API server could be ran using the following command line: API URL ------- -The default root API URL is ``http://localhost:61208/api/3``. +The default root API URL is ``http://localhost:61208/api/4``. + +Warning: if you use Glances 3.x then the API URL is ``http://localhost:61208/api/3``. The bind address and port could be changed using the ``--bind`` and ``--port`` command line options. It is also possible to define an URL prefix using the ``url_prefix`` option from the [outputs] section -of the Glances configuration file. The url_prefix should always end with a slash (``/``). +of the Glances configuration file. + +Note: The url_prefix should always end with a slash (``/``). For example: @@ -25,19 +29,25 @@ For example: [outputs] url_prefix = /glances/ -will change the root API URL to ``http://localhost:61208/glances/api/3`` and the Web UI URL to +will change the root API URL to ``http://localhost:61208/glances/api/4`` and the Web UI URL to ``http://localhost:61208/glances/`` +Web UI refresh +-------------- + +It is possible to change the Web UI refresh rate (default is 2 seconds) using the following option in the URL: +``http://localhost:61208/glances/?refresh=5`` + GET API status -------------- This entry point should be used to check the API status. -It will return nothing but a 200 return code if everything is OK. +It will the Glances version and a 200 return code if everything is OK. Get the Rest API status:: - # curl -I http://localhost:61208/api/3/status + # curl -I http://localhost:61208/api/4/status "HTTP/1.0 200 OK" GET plugins list @@ -45,7 +55,7 @@ GET plugins list Get the plugins list:: - # curl http://localhost:61208/api/3/pluginslist + # curl http://localhost:61208/api/4/pluginslist ["alert", "amps", "cloud", @@ -83,15 +93,15 @@ GET alert Get plugin stats:: - # curl http://localhost:61208/api/3/alert - [[1702235550.0, + # curl http://localhost:61208/api/4/alert + [[1702657018.0, -1, "WARNING", "MEM", - 77.46614626280395, - 77.46614626280395, - 77.46614626280395, - 77.46614626280395, + 71.53233807403451, + 71.53233807403451, + 71.53233807403451, + 71.53233807403451, 1, [], "", @@ -102,7 +112,7 @@ GET amps Get plugin stats:: - # curl http://localhost:61208/api/3/amps + # curl http://localhost:61208/api/4/amps [{"count": 0, "countmax": None, "countmin": 1.0, @@ -111,7 +121,7 @@ Get plugin stats:: "refresh": 3.0, "regex": True, "result": None, - "timer": 0.326155424118042}, + "timer": 0.40151143074035645}, {"count": 0, "countmax": 20.0, "countmin": None, @@ -120,16 +130,16 @@ Get plugin stats:: "refresh": 3.0, "regex": True, "result": None, - "timer": 0.32600831985473633}] + "timer": 0.4013493061065674}] Get a specific field:: - # curl http://localhost:61208/api/3/amps/name + # curl http://localhost:61208/api/4/amps/name {"name": ["Dropbox", "Python", "Conntrack", "Nginx", "Systemd", "SystemV"]} Get a specific item when field matches the given value:: - # curl http://localhost:61208/api/3/amps/name/Dropbox + # curl http://localhost:61208/api/4/amps/name/Dropbox {"Dropbox": [{"count": 0, "countmax": None, "countmin": 1.0, @@ -138,19 +148,19 @@ Get a specific item when field matches the given value:: "refresh": 3.0, "regex": True, "result": None, - "timer": 0.326155424118042}]} + "timer": 0.40151143074035645}]} GET connections --------------- Get plugin stats:: - # curl http://localhost:61208/api/3/connections + # curl http://localhost:61208/api/4/connections {"net_connections_enabled": True, "nf_conntrack_enabled": True} Get a specific field:: - # curl http://localhost:61208/api/3/connections/net_connections_enabled + # curl http://localhost:61208/api/4/connections/net_connections_enabled {"net_connections_enabled": True} GET containers @@ -158,22 +168,45 @@ GET containers Get plugin stats:: - # curl http://localhost:61208/api/3/containers - {"containers": [{"Command": ["top"], + # curl http://localhost:61208/api/4/containers + {"containers": [{"Command": ["/portainer"], + "Created": "2022-10-29T14:59:10.266701439Z", + "Id": "3abd51c615968482d9ccff5afc629f267f6dda113ed68b75b432615fae3b49fb", + "Image": ["portainer/portainer-ce:2.9.3"], + "Status": "running", + "Uptime": "2 weeks", + "cpu": {"total": 0.0}, + "cpu_percent": 0.0, + "engine": "docker", + "io": {"cumulative_ior": 1339392, "cumulative_iow": 2080768}, + "io_r": None, + "io_w": None, + "key": "name", + "memory": {"cache": None, + "limit": 7823585280, + "max_usage": None, + "rss": None, + "usage": 16338944}, + "memory_usage": 16338944, + "name": "portainer", + "network": {"cumulative_rx": 5881801, "cumulative_tx": 0}, + "network_rx": None, + "network_tx": None}, + {"Command": ["top"], "Created": "2023-12-09T10:45:34.339489876+01:00", "Id": "481d6ffb7eef284d062628cf350bdd9ce0a803db8a2a505d75565ed24322b714", "Image": "["docker.io/library/ubuntu:latest"]", "Status": "running", - "Uptime": "yesterday", - "cpu": {"total": 2.780420133159415e-07}, - "cpu_percent": 2.780420133159415e-07, + "Uptime": "6 days", + "cpu": {"total": 4.471361474716739e-07}, + "cpu_percent": 4.471361474716739e-07, "engine": "podman", "io": {"ior": 0.0, "iow": 0.0, "time_since_update": 1}, "io_r": 0.0, "io_w": 0.0, "key": "name", - "memory": {"limit": 7823585280.0, "usage": 1974272.0}, - "memory_usage": 1974272.0, + "memory": {"limit": 7823585280.0, "usage": 1499136.0}, + "memory_usage": 1499136.0, "name": "sad_darwin", "network": {"rx": 0.0, "time_since_update": 1, "tx": 0.0}, "network_rx": 0.0, @@ -185,41 +218,22 @@ Get plugin stats:: "Id": "9491515251edcd5bb5dc17205d7ee573c0be96fe0b08b0a12a7e2cea874565ea", "Image": "["k8s.gcr.io/pause:3.5"]", "Status": "running", - "Uptime": "yesterday", - "cpu": {"total": 3.1294141365715215e-10}, - "cpu_percent": 3.1294141365715215e-10, + "Uptime": "6 days", + "cpu": {"total": 3.2049907519180374e-10}, + "cpu_percent": 3.2049907519180374e-10, "engine": "podman", "io": {"ior": 0.0, "iow": 0.0, "time_since_update": 1}, "io_r": 0.0, "io_w": 0.0, "key": "name", - "memory": {"limit": 7823585280.0, "usage": 692224.0}, - "memory_usage": 692224.0, + "memory": {"limit": 7823585280.0, "usage": 409600.0}, + "memory_usage": 409600.0, "name": "8d0f1c783def-infra", "network": {"rx": 0.0, "time_since_update": 1, "tx": 0.0}, "network_rx": 0.0, "network_tx": 0.0, "pod_id": "8d0f1c783def", - "pod_name": "8d0f1c783def-infra"}, - {"Command": ["/portainer"], - "Created": "2022-10-29T14:59:10.266701439Z", - "Id": "3abd51c615968482d9ccff5afc629f267f6dda113ed68b75b432615fae3b49fb", - "Image": ["portainer/portainer-ce:2.9.3"], - "Status": "running", - "Uptime": "2 weeks", - "cpu": {"total": 0.0}, - "cpu_percent": 0.0, - "engine": "docker", - "io": {}, - "io_r": None, - "io_w": None, - "key": "name", - "memory": {}, - "memory_usage": None, - "name": "portainer", - "network": {}, - "network_rx": None, - "network_tx": None}], + "pod_name": "8d0f1c783def-infra"}], "version": {}, "version_podman": {}} @@ -228,7 +242,7 @@ GET core Get plugin stats:: - # curl http://localhost:61208/api/3/core + # curl http://localhost:61208/api/4/core {"log": 4, "phys": 2} Fields descriptions: @@ -238,7 +252,7 @@ Fields descriptions: Get a specific field:: - # curl http://localhost:61208/api/3/core/phys + # curl http://localhost:61208/api/4/core/phys {"phys": 2} GET cpu @@ -246,24 +260,24 @@ GET cpu Get plugin stats:: - # curl http://localhost:61208/api/3/cpu + # curl http://localhost:61208/api/4/cpu {"cpucore": 4, "ctx_switches": 0, "guest": 0.0, "guest_nice": 0.0, - "idle": 71.9, + "idle": 71.8, "interrupts": 0, - "iowait": 0.5, + "iowait": 0.2, "irq": 0.0, "nice": 0.0, "soft_interrupts": 0, "softirq": 0.0, "steal": 0.0, "syscalls": 0, - "system": 3.5, + "system": 3.2, "time_since_update": 1, - "total": 27.6, - "user": 24.1} + "total": 28.0, + "user": 24.8} Fields descriptions: @@ -285,15 +299,15 @@ Fields descriptions: Get a specific field:: - # curl http://localhost:61208/api/3/cpu/total - {"total": 27.6} + # curl http://localhost:61208/api/4/cpu/total + {"total": 28.0} GET diskio ---------- Get plugin stats:: - # curl http://localhost:61208/api/3/diskio + # curl http://localhost:61208/api/4/diskio [{"disk_name": "sda", "key": "disk_name", "read_bytes": 0, @@ -311,12 +325,12 @@ Get plugin stats:: Get a specific field:: - # curl http://localhost:61208/api/3/diskio/disk_name + # curl http://localhost:61208/api/4/diskio/disk_name {"disk_name": ["sda", "sda1", "sda2", "sda5", "dm-0", "dm-1"]} Get a specific item when field matches the given value:: - # curl http://localhost:61208/api/3/diskio/disk_name/sda + # curl http://localhost:61208/api/4/diskio/disk_name/sda {"sda": [{"disk_name": "sda", "key": "disk_name", "read_bytes": 0, @@ -330,66 +344,66 @@ GET fs Get plugin stats:: - # curl http://localhost:61208/api/3/fs + # curl http://localhost:61208/api/4/fs [{"device_name": "/dev/mapper/ubuntu--gnome--vg-root", - "free": 24790568960, + "free": 24446767104, "fs_type": "ext4", "key": "mnt_point", "mnt_point": "/", - "percent": 89.3, + "percent": 89.4, "size": 243334156288, - "used": 206156132352}, + "used": 206499934208}, {"device_name": "zsfpool", - "free": 41811968, + "free": 31195136, "fs_type": "zfs", "key": "mnt_point", "mnt_point": "/zsfpool", - "percent": 0.3, - "size": 41943040, - "used": 131072}] + "percent": 25.4, + "size": 41811968, + "used": 10616832}] Get a specific field:: - # curl http://localhost:61208/api/3/fs/mnt_point + # curl http://localhost:61208/api/4/fs/mnt_point {"mnt_point": ["/", "/zsfpool", "/var/snap/firefox/common/host-hunspell"]} Get a specific item when field matches the given value:: - # curl http://localhost:61208/api/3/fs/mnt_point// + # curl http://localhost:61208/api/4/fs/mnt_point// {"/": [{"device_name": "/dev/mapper/ubuntu--gnome--vg-root", - "free": 24790568960, + "free": 24446767104, "fs_type": "ext4", "key": "mnt_point", "mnt_point": "/", - "percent": 89.3, + "percent": 89.4, "size": 243334156288, - "used": 206156132352}]} + "used": 206499934208}]} GET ip ------ Get plugin stats:: - # curl http://localhost:61208/api/3/ip - {"address": "192.168.0.32", - "gateway": "192.168.0.254", + # curl http://localhost:61208/api/4/ip + {"address": "192.168.1.14", + "gateway": "192.168.1.1", "mask": "255.255.255.0", "mask_cidr": 24, - "public_address": "91.166.228.228", + "public_address": "92.151.148.66", "public_info_human": ""} Get a specific field:: - # curl http://localhost:61208/api/3/ip/gateway - {"gateway": "192.168.0.254"} + # curl http://localhost:61208/api/4/ip/gateway + {"gateway": "192.168.1.1"} GET load -------- Get plugin stats:: - # curl http://localhost:61208/api/3/load - {"cpucore": 4, "min1": 0.67626953125, "min15": 1.359375, "min5": 1.27734375} + # curl http://localhost:61208/api/4/load + {"cpucore": 4, "min1": 1.9189453125, "min15": 0.9111328125, "min5": 1.537109375} Fields descriptions: @@ -400,25 +414,25 @@ Fields descriptions: Get a specific field:: - # curl http://localhost:61208/api/3/load/min1 - {"min1": 0.67626953125} + # curl http://localhost:61208/api/4/load/min1 + {"min1": 1.9189453125} GET mem ------- Get plugin stats:: - # curl http://localhost:61208/api/3/mem - {"active": 2575863808, - "available": 1762955264, - "buffers": 91045888, - "cached": 1823641600, - "free": 1762955264, - "inactive": 3581095936, - "percent": 77.5, - "shared": 453021696, + # curl http://localhost:61208/api/4/mem + {"active": 2916397056, + "available": 2227191808, + "buffers": 126803968, + "cached": 2636341248, + "free": 2227191808, + "inactive": 3422937088, + "percent": 71.5, + "shared": 556515328, "total": 7823585280, - "used": 6060630016} + "used": 5596393472} Fields descriptions: @@ -436,7 +450,7 @@ Fields descriptions: Get a specific field:: - # curl http://localhost:61208/api/3/mem/total + # curl http://localhost:61208/api/4/mem/total {"total": 7823585280} GET memswap @@ -444,14 +458,14 @@ GET memswap Get plugin stats:: - # curl http://localhost:61208/api/3/memswap - {"free": 5212143616, - "percent": 35.5, - "sin": 2563657728, - "sout": 5443428352, + # curl http://localhost:61208/api/4/memswap + {"free": 4683223040, + "percent": 42.1, + "sin": 4915187712, + "sout": 8894914560, "time_since_update": 1, "total": 8082419712, - "used": 2870276096} + "used": 3399196672} Fields descriptions: @@ -465,7 +479,7 @@ Fields descriptions: Get a specific field:: - # curl http://localhost:61208/api/3/memswap/total + # curl http://localhost:61208/api/4/memswap/total {"total": 8082419712} GET network @@ -473,11 +487,11 @@ GET network Get plugin stats:: - # curl http://localhost:61208/api/3/network + # curl http://localhost:61208/api/4/network [{"alias": None, - "cumulative_cx": 357426016, - "cumulative_rx": 178713008, - "cumulative_tx": 178713008, + "cumulative_cx": 1314073012, + "cumulative_rx": 657036506, + "cumulative_tx": 657036506, "cx": 0, "interface_name": "lo", "is_up": True, @@ -487,14 +501,14 @@ Get plugin stats:: "time_since_update": 1, "tx": 0}, {"alias": None, - "cumulative_cx": 4300161137, - "cumulative_rx": 4046835795, - "cumulative_tx": 253325342, - "cx": 126, + "cumulative_cx": 5651740693, + "cumulative_rx": 5354455235, + "cumulative_tx": 297285458, + "cx": 224, "interface_name": "wlp2s0", "is_up": True, "key": "interface_name", - "rx": 0, + "rx": 98, "speed": 0, "time_since_update": 1, "tx": 126}] @@ -515,7 +529,7 @@ Fields descriptions: Get a specific field:: - # curl http://localhost:61208/api/3/network/interface_name + # curl http://localhost:61208/api/4/network/interface_name {"interface_name": ["lo", "wlp2s0", "br-40875d2e2716", @@ -526,11 +540,11 @@ Get a specific field:: Get a specific item when field matches the given value:: - # curl http://localhost:61208/api/3/network/interface_name/lo + # curl http://localhost:61208/api/4/network/interface_name/lo {"lo": [{"alias": None, - "cumulative_cx": 357426016, - "cumulative_rx": 178713008, - "cumulative_tx": 178713008, + "cumulative_cx": 1314073012, + "cumulative_rx": 657036506, + "cumulative_tx": 657036506, "cx": 0, "interface_name": "lo", "is_up": True, @@ -545,45 +559,45 @@ GET now Get plugin stats:: - # curl http://localhost:61208/api/3/now - "2023-12-10 20:12:30 CET" + # curl http://localhost:61208/api/4/now + "2023-12-15 17:16:58 CET" GET percpu ---------- Get plugin stats:: - # curl http://localhost:61208/api/3/percpu + # curl http://localhost:61208/api/4/percpu [{"cpu_number": 0, "guest": 0.0, "guest_nice": 0.0, - "idle": 47.0, + "idle": 75.0, "iowait": 0.0, "irq": 0.0, "key": "cpu_number", "nice": 0.0, "softirq": 0.0, "steal": 0.0, - "system": 1.0, - "total": 53.0, - "user": 1.0}, + "system": 4.1, + "total": 25.0, + "user": 20.9}, {"cpu_number": 1, "guest": 0.0, "guest_nice": 0.0, - "idle": 45.0, - "iowait": 1.0, + "idle": 89.4, + "iowait": 0.7, "irq": 0.0, "key": "cpu_number", "nice": 0.0, "softirq": 0.0, "steal": 0.0, - "system": 0.0, - "total": 55.0, - "user": 4.0}] + "system": 2.6, + "total": 10.6, + "user": 7.3}] Get a specific field:: - # curl http://localhost:61208/api/3/percpu/cpu_number + # curl http://localhost:61208/api/4/percpu/cpu_number {"cpu_number": [0, 1, 2, 3]} GET ports @@ -591,52 +605,52 @@ GET ports Get plugin stats:: - # curl http://localhost:61208/api/3/ports + # curl http://localhost:61208/api/4/ports [{"description": "DefaultGateway", - "host": "192.168.0.254", + "host": "192.168.1.1", "indice": "port_0", "port": 0, "refresh": 30, "rtt_warning": None, - "status": 0.084546, + "status": 0.006155, "timeout": 3}] Get a specific field:: - # curl http://localhost:61208/api/3/ports/host - {"host": ["192.168.0.254"]} + # curl http://localhost:61208/api/4/ports/host + {"host": ["192.168.1.1"]} Get a specific item when field matches the given value:: - # curl http://localhost:61208/api/3/ports/host/192.168.0.254 - {"192.168.0.254": [{"description": "DefaultGateway", - "host": "192.168.0.254", - "indice": "port_0", - "port": 0, - "refresh": 30, - "rtt_warning": None, - "status": 0.084546, - "timeout": 3}]} + # curl http://localhost:61208/api/4/ports/host/192.168.1.1 + {"192.168.1.1": [{"description": "DefaultGateway", + "host": "192.168.1.1", + "indice": "port_0", + "port": 0, + "refresh": 30, + "rtt_warning": None, + "status": 0.006155, + "timeout": 3}]} GET processcount ---------------- Get plugin stats:: - # curl http://localhost:61208/api/3/processcount - {"pid_max": 0, "running": 1, "sleeping": 319, "thread": 1713, "total": 385} + # curl http://localhost:61208/api/4/processcount + {"pid_max": 0, "running": 1, "sleeping": 323, "thread": 1634, "total": 388} Get a specific field:: - # curl http://localhost:61208/api/3/processcount/total - {"total": 385} + # curl http://localhost:61208/api/4/processcount/total + {"total": 388} GET psutilversion ----------------- Get plugin stats:: - # curl http://localhost:61208/api/3/psutilversion + # curl http://localhost:61208/api/4/psutilversion [5, 9, 6] GET quicklook @@ -644,77 +658,77 @@ GET quicklook Get plugin stats:: - # curl http://localhost:61208/api/3/quicklook - {"cpu": 27.6, + # curl http://localhost:61208/api/4/quicklook + {"cpu": 28.0, "cpu_hz": 2025000000.0, - "cpu_hz_current": 1771800000.0, + "cpu_hz_current": 2048950249.9999998, "cpu_name": "Intel(R) Core(TM) i7-4500U CPU @ 1.80GHz", - "mem": 77.5, + "mem": 71.5, "percpu": [{"cpu_number": 0, "guest": 0.0, "guest_nice": 0.0, - "idle": 47.0, + "idle": 75.0, "iowait": 0.0, "irq": 0.0, "key": "cpu_number", "nice": 0.0, "softirq": 0.0, "steal": 0.0, - "system": 1.0, - "total": 53.0, - "user": 1.0}, + "system": 4.1, + "total": 25.0, + "user": 20.9}, {"cpu_number": 1, "guest": 0.0, "guest_nice": 0.0, - "idle": 45.0, - "iowait": 1.0, + "idle": 89.4, + "iowait": 0.7, "irq": 0.0, "key": "cpu_number", "nice": 0.0, "softirq": 0.0, "steal": 0.0, - "system": 0.0, - "total": 55.0, - "user": 4.0}, + "system": 2.6, + "total": 10.6, + "user": 7.3}, {"cpu_number": 2, "guest": 0.0, "guest_nice": 0.0, - "idle": 27.0, + "idle": 95.2, "iowait": 0.0, "irq": 0.0, "key": "cpu_number", "nice": 0.0, "softirq": 0.0, "steal": 0.0, - "system": 1.0, - "total": 73.0, - "user": 20.0}, + "system": 2.0, + "total": 4.8, + "user": 2.7}, {"cpu_number": 3, "guest": 0.0, "guest_nice": 0.0, - "idle": 24.0, + "idle": 28.0, "iowait": 0.0, "irq": 0.0, "key": "cpu_number", "nice": 0.0, "softirq": 0.0, "steal": 0.0, - "system": 3.0, - "total": 76.0, - "user": 23.0}], - "swap": 35.5} + "system": 4.7, + "total": 72.0, + "user": 67.3}], + "swap": 42.1} Get a specific field:: - # curl http://localhost:61208/api/3/quicklook/cpu - {"cpu": 27.6} + # curl http://localhost:61208/api/4/quicklook/cpu + {"cpu": 28.0} GET sensors ----------- Get plugin stats:: - # curl http://localhost:61208/api/3/sensors + # curl http://localhost:61208/api/4/sensors [{"critical": 105, "key": "label", "label": "acpitz 0", @@ -732,7 +746,7 @@ Get plugin stats:: Get a specific field:: - # curl http://localhost:61208/api/3/sensors/label + # curl http://localhost:61208/api/4/sensors/label {"label": ["acpitz 0", "acpitz 1", "Package id 0", @@ -745,7 +759,7 @@ Get a specific field:: Get a specific item when field matches the given value:: - # curl http://localhost:61208/api/3/sensors/label/acpitz 0 + # curl http://localhost:61208/api/4/sensors/label/acpitz 0 {"acpitz 0": [{"critical": 105, "key": "label", "label": "acpitz 0", @@ -759,7 +773,7 @@ GET system Get plugin stats:: - # curl http://localhost:61208/api/3/system + # curl http://localhost:61208/api/4/system {"hostname": "XPS13-9333", "hr_name": "Ubuntu 22.04 64bit", "linux_distro": "Ubuntu 22.04", @@ -769,7 +783,7 @@ Get plugin stats:: Get a specific field:: - # curl http://localhost:61208/api/3/system/os_name + # curl http://localhost:61208/api/4/system/os_name {"os_name": "Linux"} GET uptime @@ -777,15 +791,15 @@ GET uptime Get plugin stats:: - # curl http://localhost:61208/api/3/uptime - "15 days, 11:14:41" + # curl http://localhost:61208/api/4/uptime + "20 days, 8:19:07" GET all stats ------------- Get all Glances stats:: - # curl http://localhost:61208/api/3/all + # curl http://localhost:61208/api/4/all Return a very big dictionary (avoid using this request, performances will be poor)... GET top n items of a specific plugin @@ -793,7 +807,7 @@ GET top n items of a specific plugin Get top 2 processes of the processlist plugin:: - # curl http://localhost:61208/api/3/processlist/top/2 + # curl http://localhost:61208/api/4/processlist/top/2 [{"cmdline": ["/snap/firefox/3206/usr/lib/firefox/firefox", "-contentproc", "-childID", @@ -821,19 +835,19 @@ Get top 2 processes of the processlist plugin:: "cpu_times": {"children_system": 0.0, "children_user": 0.0, "iowait": 0.0, - "system": 226.21, - "user": 2650.94}, + "system": 261.09, + "user": 3002.21}, "gids": {"effective": 1000, "real": 1000, "saved": 1000}, - "io_counters": [230234112, 0, 0, 0, 0], + "io_counters": [372081664, 0, 0, 0, 0], "key": "pid", - "memory_info": {"data": 1036189696, + "memory_info": {"data": 1145556992, "dirty": 0, "lib": 0, - "rss": 505749504, - "shared": 67194880, + "rss": 533700608, + "shared": 66142208, "text": 643072, - "vms": 3629031424}, - "memory_percent": 6.464421181589011, + "vms": 3753902080}, + "memory_percent": 6.8216883807010795, "name": "WebExtensions", "nice": 0, "num_threads": 20, @@ -841,28 +855,33 @@ Get top 2 processes of the processlist plugin:: "status": "S", "time_since_update": 1, "username": "nicolargo"}, - {"cmdline": ["/snap/firefox/3206/usr/lib/firefox/firefox"], + {"cmdline": ["/usr/share/code/code", + "--ms-enable-electron-run-as-node", + "/home/nicolargo/.vscode/extensions/ms-python.vscode-pylance-2023.11.10/dist/server.bundle.js", + "--cancellationReceive=file:909dfdaf9d60a0ebbc9aa560a7438878b4f45eec8b", + "--node-ipc", + "--clientProcessId=10692"], "cpu_percent": 0.0, - "cpu_times": {"children_system": 709.9, - "children_user": 4938.6, + "cpu_times": {"children_system": 0.61, + "children_user": 4.25, "iowait": 0.0, - "system": 1739.59, - "user": 5867.67}, + "system": 336.31, + "user": 5395.51}, "gids": {"effective": 1000, "real": 1000, "saved": 1000}, - "io_counters": [3403158528, 6581563392, 0, 0, 0], + "io_counters": [550125568, 2199552, 0, 0, 0], "key": "pid", - "memory_info": {"data": 1767538688, + "memory_info": {"data": 862629888, "dirty": 0, "lib": 0, - "rss": 399204352, - "shared": 108036096, - "text": 643072, - "vms": 14074568704}, - "memory_percent": 5.102575580284338, - "name": "firefox", + "rss": 469827584, + "shared": 24416256, + "text": 120561664, + "vms": 1207768686592}, + "memory_percent": 6.005272099494517, + "name": "code", "nice": 0, - "num_threads": 177, - "pid": 7195, + "num_threads": 13, + "pid": 11004, "status": "S", "time_since_update": 1, "username": "nicolargo"}] @@ -874,42 +893,42 @@ GET stats history History of a plugin:: - # curl http://localhost:61208/api/3/cpu/history - {"system": [["2023-12-10T20:12:33.056772", 3.4], - ["2023-12-10T20:12:34.107797", 3.4], - ["2023-12-10T20:12:35.377582", 1.9]], - "user": [["2023-12-10T20:12:33.056764", 20.8], - ["2023-12-10T20:12:34.107773", 20.8], - ["2023-12-10T20:12:35.377571", 9.1]]} + # curl http://localhost:61208/api/4/cpu/history + {"system": [["2023-12-15T17:17:00.234889", 3.2], + ["2023-12-15T17:17:01.256351", 2.0], + ["2023-12-15T17:17:02.459609", 2.0]], + "user": [["2023-12-15T17:17:00.234874", 24.8], + ["2023-12-15T17:17:01.256343", 11.3], + ["2023-12-15T17:17:02.459594", 11.3]]} Limit history to last 2 values:: - # curl http://localhost:61208/api/3/cpu/history/2 - {"system": [["2023-12-10T20:12:34.107797", 3.4], - ["2023-12-10T20:12:35.377582", 1.9]], - "user": [["2023-12-10T20:12:34.107773", 20.8], - ["2023-12-10T20:12:35.377571", 9.1]]} + # curl http://localhost:61208/api/4/cpu/history/2 + {"system": [["2023-12-15T17:17:01.256351", 2.0], + ["2023-12-15T17:17:02.459609", 2.0]], + "user": [["2023-12-15T17:17:01.256343", 11.3], + ["2023-12-15T17:17:02.459594", 11.3]]} History for a specific field:: - # curl http://localhost:61208/api/3/cpu/system/history - {"system": [["2023-12-10T20:12:30.854088", 3.5], - ["2023-12-10T20:12:33.056772", 3.4], - ["2023-12-10T20:12:34.107797", 3.4], - ["2023-12-10T20:12:35.377582", 1.9]]} + # curl http://localhost:61208/api/4/cpu/system/history + {"system": [["2023-12-15T17:16:58.322839", 3.2], + ["2023-12-15T17:17:00.234889", 3.2], + ["2023-12-15T17:17:01.256351", 2.0], + ["2023-12-15T17:17:02.459609", 2.0]]} Limit history for a specific field to last 2 values:: - # curl http://localhost:61208/api/3/cpu/system/history - {"system": [["2023-12-10T20:12:34.107797", 3.4], - ["2023-12-10T20:12:35.377582", 1.9]]} + # curl http://localhost:61208/api/4/cpu/system/history + {"system": [["2023-12-15T17:17:01.256351", 2.0], + ["2023-12-15T17:17:02.459609", 2.0]]} GET limits (used for thresholds) -------------------------------- All limits/thresholds:: - # curl http://localhost:61208/api/3/all/limits + # curl http://localhost:61208/api/4/all/limits {"alert": {"alert_disable": ["False"], "history_size": 1200.0}, "amps": {"amps_disable": ["False"], "history_size": 1200.0}, "containers": {"containers_all": ["False"], @@ -1092,7 +1111,7 @@ All limits/thresholds:: Limits/thresholds for the cpu plugin:: - # curl http://localhost:61208/api/3/cpu/limits + # curl http://localhost:61208/api/4/cpu/limits {"cpu_ctx_switches_careful": 160000.0, "cpu_ctx_switches_critical": 200000.0, "cpu_ctx_switches_warning": 180000.0, diff --git a/docs/man/glances.1 b/docs/man/glances.1 index 04a2f4ed..cc1c571e 100644 --- a/docs/man/glances.1 +++ b/docs/man/glances.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "GLANCES" "1" "Dec 10, 2023" "4.0.0_beta01" "Glances" +.TH "GLANCES" "1" "Dec 15, 2023" "4.0.0_beta01" "Glances" .SH NAME glances \- An eye on your system .SH SYNOPSIS diff --git a/glances/globals.py b/glances/globals.py index ccf3f5be..46f47f7b 100644 --- a/glances/globals.py +++ b/glances/globals.py @@ -25,6 +25,8 @@ import subprocess from datetime import datetime import re import base64 +import functools +import weakref import queue from configparser import ConfigParser, NoOptionError, NoSectionError @@ -406,3 +408,21 @@ def folder_size(path, errno=0): except OSError as e: ret_err = e.errno return ret_size, ret_err + + +def weak_lru_cache(maxsize=128, typed=False): + """LRU Cache decorator that keeps a weak reference to self + Source: https://stackoverflow.com/a/55990799""" + def wrapper(func): + + @functools.lru_cache(maxsize, typed) + def _func(_self, *args, **kwargs): + return func(_self(), *args, **kwargs) + + @functools.wraps(func) + def inner(self, *args, **kwargs): + return _func(weakref.ref(self), *args, **kwargs) + + return inner + + return wrapper diff --git a/glances/outputs/glances_restful_api.py b/glances/outputs/glances_restful_api.py index c8e7094a..02a86cf8 100644 --- a/glances/outputs/glances_restful_api.py +++ b/glances/outputs/glances_restful_api.py @@ -20,6 +20,8 @@ from urllib.parse import urljoin # from typing import Annotated from typing_extensions import Annotated +from glances import __version__ +from glances.password import GlancesPassword from glances.timer import Timer from glances.logger import logger @@ -48,7 +50,7 @@ security = HTTPBasic() class GlancesRestfulApi(object): """This class manages the Restful API server.""" - API_VERSION = '3' + API_VERSION = '4' def __init__(self, config=None, args=None): # Init config @@ -77,8 +79,12 @@ class GlancesRestfulApi(object): # FastAPI Init if self.args.password: self._app = FastAPI(dependencies=[Depends(self.authentication)]) + self._password = GlancesPassword(username=args.username, + config=config) + else: self._app = FastAPI() + self._password = None # Change the default root path if self.url_prefix != '/': @@ -104,8 +110,6 @@ class GlancesRestfulApi(object): # FastAPI Enable GZIP compression # https://fastapi.tiangolo.com/advanced/middleware/ - # TODO: do not work for the moment - # curl return a binary stream, not the JSON self._app.add_middleware(GZipMiddleware, minimum_size=1000) @@ -131,26 +135,20 @@ class GlancesRestfulApi(object): def app(self): return self._app() - # TODO: the password comparaison is not working for the moment. - # if the password is wrong, authentication is working... - # Perhaps because the password is hashed in the GlancesPassword class - # and the one given by creds.password is not hashed ? def authentication(self, creds: Annotated[HTTPBasicCredentials, Depends(security)]): """Check if a username/password combination is valid.""" - # print(creds.username, creds.password) - # print(self.args.username, self.args.password) if creds.username == self.args.username: - from glances.password import GlancesPassword - - pwd = GlancesPassword(username=creds.username, config=self.config) - # print(self.args.password, pwd.get_hash(creds.username)) - return pwd.check_password(self.args.password, pwd.get_hash(creds.username)) - else: - raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Incorrect username or password", - headers={"WWW-Authenticate": "Basic"}, - ) + # check_password and get_hash are (lru) cached to optimize the requests + if self._password.check_password(self.args.password, + self._password.get_hash(creds.password)): + return creds.username + + # If the username/password combination is invalid, return an HTTP 401 + raise HTTPException( + status_code=status.HTTP_401_UNAUTHORIZED, + detail="Incorrect username or password", + headers={"WWW-Authenticate": "Basic"}, + ) def _router(self): """Define a custom router for Glances path.""" @@ -282,10 +280,12 @@ class GlancesRestfulApi(object): def _index(self, request: Request): """Return main index.html (/) file. + Parameters are available through the request object. Example: http://localhost:61208/?refresh=5 - """ + Note: This function is only called the first time the page is loaded. + """ refresh_time = request.query_params.get('refresh', default=max(1, int(self.args.time))) @@ -308,8 +308,7 @@ class GlancesRestfulApi(object): See related issue: Web server health check endpoint #1988 """ - # TODO: return a more useful status - return "Active" + return ORJSONResponse({'version': __version__}) def _api_help(self): """Glances API RESTful implementation. diff --git a/glances/outputs/glances_stdout_apidoc.py b/glances/outputs/glances_stdout_apidoc.py index ed9c2da1..c02af535 100644 --- a/glances/outputs/glances_stdout_apidoc.py +++ b/glances/outputs/glances_stdout_apidoc.py @@ -13,10 +13,12 @@ from pprint import pformat import json import time +from glances.outputs.glances_restful_api import GlancesRestfulApi from glances.logger import logger from glances.globals import iteritems -API_URL = "http://localhost:61208/api/3" + +API_URL = "http://localhost:61208/api/{api_version}".format(api_version=GlancesRestfulApi.API_VERSION) APIDOC_HEADER = """\ .. _api: @@ -33,12 +35,14 @@ The Glances Restfull/API server could be ran using the following command line: API URL ------- -The default root API URL is ``http://localhost:61208/api/3``. +The default root API URL is ``http://localhost:61208/api/{api_version}``. The bind address and port could be changed using the ``--bind`` and ``--port`` command line options. It is also possible to define an URL prefix using the ``url_prefix`` option from the [outputs] section -of the Glances configuration file. The url_prefix should always end with a slash (``/``). +of the Glances configuration file. + +Note: The url_prefix should always end with a slash (``/``). For example: @@ -46,10 +50,16 @@ For example: [outputs] url_prefix = /glances/ -will change the root API URL to ``http://localhost:61208/glances/api/3`` and the Web UI URL to +will change the root API URL to ``http://localhost:61208/glances/api/{api_version}`` and the Web UI URL to ``http://localhost:61208/glances/`` -""" +Web UI refresh +-------------- + +It is possible to change the Web UI refresh rate (default is 2 seconds) using the following option in the URL: +``http://localhost:61208/glances/?refresh=5`` + +""".format(api_version=GlancesRestfulApi.API_VERSION) def indent_stat(stat, indent=' '): @@ -67,7 +77,7 @@ def print_api_status(): print('-' * len(sub_title)) print('') print('This entry point should be used to check the API status.') - print('It will return nothing but a 200 return code if everything is OK.') + print('It will the Glances version and a 200 return code if everything is OK.') print('') print('Get the Rest API status::') print('') diff --git a/glances/outputs/static/js/services.js b/glances/outputs/static/js/services.js index ac6c782f..a79ccd30 100644 --- a/glances/outputs/static/js/services.js +++ b/glances/outputs/static/js/services.js @@ -2,15 +2,15 @@ import { store } from './store.js'; import Favico from 'favico.js'; // prettier-ignore -const fetchAll = () => fetch('api/3/all', { method: 'GET' }).then((response) => response.json()); +const fetchAll = () => fetch('api/4/all', { method: 'GET' }).then((response) => response.json()); // prettier-ignore -const fetchAllViews = () => fetch('api/3/all/views', { method: 'GET' }).then((response) => response.json()); +const fetchAllViews = () => fetch('api/4/all/views', { method: 'GET' }).then((response) => response.json()); // prettier-ignore -const fetchAllLimits = () => fetch('api/3/all/limits', { method: 'GET' }).then((response) => response.json()); +const fetchAllLimits = () => fetch('api/4/all/limits', { method: 'GET' }).then((response) => response.json()); // prettier-ignore -const fetchArgs = () => fetch('api/3/args', { method: 'GET' }).then((response) => response.json()); +const fetchArgs = () => fetch('api/4/args', { method: 'GET' }).then((response) => response.json()); // prettier-ignore -const fetchConfig = () => fetch('api/3/config', { method: 'GET' }).then((response) => response.json()); +const fetchConfig = () => fetch('api/4/config', { method: 'GET' }).then((response) => response.json()); class GlancesHelperService { limits = {}; diff --git a/glances/outputs/static/public/glances.js b/glances/outputs/static/public/glances.js index 412665af..477aed1b 100644 --- a/glances/outputs/static/public/glances.js +++ b/glances/outputs/static/public/glances.js @@ -28,4 +28,4 @@ function n(e){return"[object Object]"===Object.prototype.toString.call(e)}Object * https://jaywcjlove.github.io/hotkeys-js * Licensed under the MIT license */ -var ho="undefined"!=typeof navigator&&navigator.userAgent.toLowerCase().indexOf("firefox")>0;function go(e,t,n,r){e.addEventListener?e.addEventListener(t,n,r):e.attachEvent&&e.attachEvent("on".concat(t),(function(){n(window.event)}))}function mo(e,t){for(var n=t.slice(0,t.length-1),r=0;r=0;)t[n-1]+=",",t.splice(n,1),n=t.lastIndexOf("");return t}for(var vo={backspace:8,"⌫":8,tab:9,clear:12,enter:13,"↩":13,return:13,esc:27,escape:27,space:32,left:37,up:38,right:39,down:40,del:46,delete:46,ins:45,insert:45,home:36,end:35,pageup:33,pagedown:34,capslock:20,num_0:96,num_1:97,num_2:98,num_3:99,num_4:100,num_5:101,num_6:102,num_7:103,num_8:104,num_9:105,num_multiply:106,num_add:107,num_enter:108,num_subtract:109,num_decimal:110,num_divide:111,"⇪":20,",":188,".":190,"/":191,"`":192,"-":ho?173:189,"=":ho?61:187,";":ho?59:186,"'":222,"[":219,"]":221,"\\":220},yo={"⇧":16,shift:16,"⌥":18,alt:18,option:18,"⌃":17,ctrl:17,control:17,"⌘":91,cmd:91,command:91},wo={16:"shiftKey",18:"altKey",17:"ctrlKey",91:"metaKey",shiftKey:16,ctrlKey:17,altKey:18,metaKey:91},xo={16:!1,18:!1,17:!1,91:!1},_o={},ko=1;ko<20;ko++)vo["f".concat(ko)]=111+ko;var So=[],Co=!1,To="all",Ao=[],Eo=function(e){return vo[e.toLowerCase()]||yo[e.toLowerCase()]||e.toUpperCase().charCodeAt(0)};function Oo(e){To=e||"all"}function Io(){return To||"all"}var Po=function(e){var t=e.key,n=e.scope,r=e.method,i=e.splitKey,s=void 0===i?"+":i;bo(t).forEach((function(e){var t=e.split(s),i=t.length,o=t[i-1],a="*"===o?"*":Eo(o);if(_o[a]){n||(n=Io());var l=i>1?mo(yo,t):[];_o[a]=_o[a].filter((function(e){return!((!r||e.method===r)&&e.scope===n&&function(e,t){for(var n=e.length>=t.length?e:t,r=e.length>=t.length?t:e,i=!0,s=0;s0,xo)Object.prototype.hasOwnProperty.call(xo,s)&&(!xo[s]&&t.mods.indexOf(+s)>-1||xo[s]&&-1===t.mods.indexOf(+s))&&(i=!1);(0!==t.mods.length||xo[16]||xo[18]||xo[17]||xo[91])&&!i&&"*"!==t.shortcut||(t.keys=[],t.keys=t.keys.concat(So),!1===t.method(e,t)&&(e.preventDefault?e.preventDefault():e.returnValue=!1,e.stopPropagation&&e.stopPropagation(),e.cancelBubble&&(e.cancelBubble=!0)))}}function Lo(e,t){var n=_o["*"],r=e.keyCode||e.which||e.charCode;if(Do.filter.call(this,e)){if(93!==r&&224!==r||(r=91),-1===So.indexOf(r)&&229!==r&&So.push(r),["ctrlKey","altKey","shiftKey","metaKey"].forEach((function(t){var n=wo[t];e[t]&&-1===So.indexOf(n)?So.push(n):!e[t]&&So.indexOf(n)>-1?So.splice(So.indexOf(n),1):"metaKey"===t&&e[t]&&3===So.length&&(e.ctrlKey||e.shiftKey||e.altKey||(So=So.slice(So.indexOf(n))))})),r in xo){for(var i in xo[r]=!0,yo)yo[i]===r&&(Do[i]=!0);if(!n)return}for(var s in xo)Object.prototype.hasOwnProperty.call(xo,s)&&(xo[s]=e[wo[s]]);e.getModifierState&&(!e.altKey||e.ctrlKey)&&e.getModifierState("AltGraph")&&(-1===So.indexOf(17)&&So.push(17),-1===So.indexOf(18)&&So.push(18),xo[17]=!0,xo[18]=!0);var o=Io();if(n)for(var a=0;a1&&(i=mo(yo,e)),(e="*"===(e=e[e.length-1])?"*":Eo(e))in _o||(_o[e]=[]),_o[e].push({keyup:l,keydown:c,scope:s,mods:i,shortcut:r[a],method:n,key:r[a],splitKey:u,element:o});void 0!==o&&!function(e){return Ao.indexOf(e)>-1}(o)&&window&&(Ao.push(o),go(o,"keydown",(function(e){Lo(e,o)}),d),Co||(Co=!0,go(window,"focus",(function(){So=[]}),d)),go(o,"keyup",(function(e){Lo(e,o),function(e){var t=e.keyCode||e.which||e.charCode,n=So.indexOf(t);if(n>=0&&So.splice(n,1),e.key&&"meta"===e.key.toLowerCase()&&So.splice(0,So.length),93!==t&&224!==t||(t=91),t in xo)for(var r in xo[t]=!1,yo)yo[r]===t&&(Do[r]=!1)}(e)}),d))}var Mo={getPressedKeyString:function(){return So.map((function(e){return t=e,Object.keys(vo).find((function(e){return vo[e]===t}))||function(e){return Object.keys(yo).find((function(t){return yo[t]===e}))}(e)||String.fromCharCode(e);var t}))},setScope:Oo,getScope:Io,deleteScope:function(e,t){var n,r;for(var i in e||(e=Io()),_o)if(Object.prototype.hasOwnProperty.call(_o,i))for(n=_o[i],r=0;r1&&void 0!==arguments[1]?arguments[1]:"all";Object.keys(_o).forEach((function(n){_o[n].filter((function(n){return n.scope===t&&n.shortcut===e})).forEach((function(e){e&&e.method&&e.method()}))}))},unbind:function(e){if(void 0===e)Object.keys(_o).forEach((function(e){return delete _o[e]}));else if(Array.isArray(e))e.forEach((function(e){e.key&&Po(e)}));else if("object"==typeof e)e.key&&Po(e);else if("string"==typeof e){for(var t=arguments.length,n=new Array(t>1?t-1:0),r=1;r=this.limits[e][l]){var c=l.lastIndexOf("_");return l.substring(c+1)+s}}return"ok"+s}getAlertLog(e,t,n,r){return this.getAlert(e,t,n,r,!0)}};const zo=new class{data=void 0;init(e=60){let t;const n=()=>(qo.status="PENDING",Promise.all([fetch("api/3/all",{method:"GET"}).then((e=>e.json())),fetch("api/3/all/views",{method:"GET"}).then((e=>e.json()))]).then((e=>{const t={stats:e[0],views:e[1],isBsd:"FreeBSD"===e[0].system.os_name,isLinux:"Linux"===e[0].system.os_name,isSunOS:"SunOS"===e[0].system.os_name,isMac:"Darwin"===e[0].system.os_name,isWindows:"Windows"===e[0].system.os_name};this.data=t,qo.data=t,qo.status="SUCCESS"})).catch((e=>{console.log(e),qo.status="FAILURE"})).then((()=>{t&&clearTimeout(t),t=setTimeout(n,1e3*e)})));n(),fetch("api/3/all/limits",{method:"GET"}).then((e=>e.json())).then((e=>{Fo.setLimits(e)})),fetch("api/3/args",{method:"GET"}).then((e=>e.json())).then(((e={})=>{qo.args={...qo.args,...e}})),fetch("api/3/config",{method:"GET"}).then((e=>e.json())).then(((e={})=>{qo.config={...qo.config,...e}}))}getData(){return this.data}};const $o=new class{constructor(){this.favico=new(Uo())({animation:"none"})}badge(e){this.favico.badge(e)}reset(){this.favico.reset()}},Ho={key:0},Vo={class:"container-fluid"},Go={class:"row"},Wo={class:"col-sm-12 col-lg-24"},Zo=wi("div",{class:"row"}," ",-1),Ko={class:"row"},Qo={class:"col-sm-12 col-lg-24"},Xo=wi("div",{class:"row"}," ",-1),Jo={class:"divTable",style:{width:"100%"}},Yo={class:"divTableBody"},ea={class:"divTableRow"},ta={class:"divTableHead"},na={class:"divTableHead"},ra={class:"divTableHead"},ia={class:"divTableHead"},sa={class:"divTableRow"},oa={class:"divTableCell"},aa={class:"divTableCell"},la={class:"divTableCell"},ca={class:"divTableCell"},ua={class:"divTableRow"},da={class:"divTableCell"},fa={class:"divTableCell"},pa={class:"divTableCell"},ha={class:"divTableCell"},ga={class:"divTableRow"},ma={class:"divTableCell"},ba={class:"divTableCell"},va={class:"divTableCell"},ya={class:"divTableCell"},wa={class:"divTableRow"},xa={class:"divTableCell"},_a={class:"divTableCell"},ka={class:"divTableCell"},Sa={class:"divTableCell"},Ca={class:"divTableRow"},Ta={class:"divTableCell"},Aa={class:"divTableCell"},Ea={class:"divTableCell"},Oa={class:"divTableCell"},Ia={class:"divTableRow"},Pa={class:"divTableCell"},Na={class:"divTableCell"},La={class:"divTableCell"},Da={class:"divTableCell"},Ma={class:"divTableRow"},ja={class:"divTableCell"},Ra={class:"divTableCell"},qa={class:"divTableCell"},Ba={class:"divTableCell"},Ua={class:"divTableRow"},Fa=wi("div",{class:"divTableCell"}," ",-1),za={class:"divTableCell"},$a={class:"divTableCell"},Ha={class:"divTableCell"},Va={class:"divTableRow"},Ga=wi("div",{class:"divTableCell"}," ",-1),Wa={class:"divTableCell"},Za={class:"divTableCell"},Ka={class:"divTableCell"},Qa={class:"divTableRow"},Xa=wi("div",{class:"divTableCell"}," ",-1),Ja={class:"divTableCell"},Ya={class:"divTableCell"},el={class:"divTableCell"},tl={class:"divTableRow"},nl=wi("div",{class:"divTableCell"}," ",-1),rl={class:"divTableCell"},il=wi("div",{class:"divTableCell"}," ",-1),sl={class:"divTableCell"},ol={class:"divTableRow"},al=wi("div",{class:"divTableCell"}," ",-1),ll={class:"divTableCell"},cl=wi("div",{class:"divTableCell"}," ",-1),ul=wi("div",{class:"divTableCell"}," ",-1),dl={class:"divTableRow"},fl=wi("div",{class:"divTableCell"}," ",-1),pl={class:"divTableCell"},hl=wi("div",{class:"divTableCell"}," ",-1),gl=wi("div",{class:"divTableCell"}," ",-1),ml={class:"divTableRow"},bl=wi("div",{class:"divTableCell"}," ",-1),vl={class:"divTableCell"},yl=wi("div",{class:"divTableCell"}," ",-1),wl=wi("div",{class:"divTableCell"}," ",-1),xl={class:"divTableRow"},_l=wi("div",{class:"divTableCell"}," ",-1),kl={class:"divTableCell"},Sl=wi("div",{class:"divTableCell"}," ",-1),Cl=wi("div",{class:"divTableCell"}," ",-1),Tl={class:"divTableRow"},Al=wi("div",{class:"divTableCell"}," ",-1),El={class:"divTableCell"},Ol=wi("div",{class:"divTableCell"}," ",-1),Il=wi("div",{class:"divTableCell"}," ",-1),Pl={class:"divTableRow"},Nl=wi("div",{class:"divTableCell"}," ",-1),Ll={class:"divTableCell"},Dl=wi("div",{class:"divTableCell"}," ",-1),Ml=wi("div",{class:"divTableCell"}," ",-1),jl={class:"divTableRow"},Rl=wi("div",{class:"divTableCell"}," ",-1),ql={class:"divTableCell"},Bl=wi("div",{class:"divTableCell"}," ",-1),Ul=wi("div",{class:"divTableCell"}," ",-1),Fl={class:"divTableRow"},zl=wi("div",{class:"divTableCell"}," ",-1),$l={class:"divTableCell"},Hl=wi("div",{class:"divTableCell"}," ",-1),Vl=wi("div",{class:"divTableCell"}," ",-1),Gl={class:"divTableRow"},Wl=wi("div",{class:"divTableCell"}," ",-1),Zl={class:"divTableCell"},Kl=wi("div",{class:"divTableCell"}," ",-1),Ql=wi("div",{class:"divTableCell"}," ",-1),Xl=wi("div",null,[wi("p",null,[Si(" For an exhaustive list of key bindings, "),wi("a",{href:"https://glances.readthedocs.io/en/latest/cmds.html#interactive-commands"},"click here"),Si(". ")])],-1),Jl=wi("div",null,[wi("p",null,[Si("Press "),wi("b",null,"h"),Si(" to came back to Glances.")])],-1);const Yl={data:()=>({help:void 0}),mounted(){fetch("api/3/help",{method:"GET"}).then((e=>e.json())).then((e=>this.help=e))}};var ec=n(3744);const tc=(0,ec.Z)(Yl,[["render",function(e,t,n,r,i,s){return i.help?(li(),pi("div",Ho,[wi("div",Vo,[wi("div",Go,[wi("div",Wo,pe(i.help.version)+" "+pe(i.help.psutil_version),1)]),Zo,wi("div",Ko,[wi("div",Qo,pe(i.help.configuration_file),1)]),Xo]),wi("div",Jo,[wi("div",Yo,[wi("div",ea,[wi("div",ta,pe(i.help.header_sort.replace(":","")),1),wi("div",na,pe(i.help.header_show_hide.replace(":","")),1),wi("div",ra,pe(i.help.header_toggle.replace(":","")),1),wi("div",ia,pe(i.help.header_miscellaneous.replace(":","")),1)]),wi("div",sa,[wi("div",oa,pe(i.help.sort_auto),1),wi("div",aa,pe(i.help.show_hide_application_monitoring),1),wi("div",la,pe(i.help.toggle_bits_bytes),1),wi("div",ca,pe(i.help.misc_erase_process_filter),1)]),wi("div",ua,[wi("div",da,pe(i.help.sort_cpu),1),wi("div",fa,pe(i.help.show_hide_diskio),1),wi("div",pa,pe(i.help.toggle_count_rate),1),wi("div",ha,pe(i.help.misc_generate_history_graphs),1)]),wi("div",ga,[wi("div",ma,pe(i.help.sort_io_rate),1),wi("div",ba,pe(i.help.show_hide_containers),1),wi("div",va,pe(i.help.toggle_used_free),1),wi("div",ya,pe(i.help.misc_help),1)]),wi("div",wa,[wi("div",xa,pe(i.help.sort_mem),1),wi("div",_a,pe(i.help.show_hide_top_extended_stats),1),wi("div",ka,pe(i.help.toggle_bar_sparkline),1),wi("div",Sa,pe(i.help.misc_accumulate_processes_by_program),1)]),wi("div",Ca,[wi("div",Ta,pe(i.help.sort_process_name),1),wi("div",Aa,pe(i.help.show_hide_filesystem),1),wi("div",Ea,pe(i.help.toggle_separate_combined),1),wi("div",Oa,pe(i.help.misc_kill_process)+" - N/A in WebUI ",1)]),wi("div",Ia,[wi("div",Pa,pe(i.help.sort_cpu_times),1),wi("div",Na,pe(i.help.show_hide_gpu),1),wi("div",La,pe(i.help.toggle_live_cumulative),1),wi("div",Da,pe(i.help.misc_reset_processes_summary_min_max),1)]),wi("div",Ma,[wi("div",ja,pe(i.help.sort_user),1),wi("div",Ra,pe(i.help.show_hide_ip),1),wi("div",qa,pe(i.help.toggle_linux_percentage),1),wi("div",Ba,pe(i.help.misc_quit),1)]),wi("div",Ua,[Fa,wi("div",za,pe(i.help.show_hide_tcp_connection),1),wi("div",$a,pe(i.help.toggle_cpu_individual_combined),1),wi("div",Ha,pe(i.help.misc_reset_history),1)]),wi("div",Va,[Ga,wi("div",Wa,pe(i.help.show_hide_alert),1),wi("div",Za,pe(i.help.toggle_gpu_individual_combined),1),wi("div",Ka,pe(i.help.misc_delete_warning_alerts),1)]),wi("div",Qa,[Xa,wi("div",Ja,pe(i.help.show_hide_network),1),wi("div",Ya,pe(i.help.toggle_short_full),1),wi("div",el,pe(i.help.misc_delete_warning_and_critical_alerts),1)]),wi("div",tl,[nl,wi("div",rl,pe(i.help.sort_cpu_times),1),il,wi("div",sl,pe(i.help.misc_edit_process_filter_pattern)+" - N/A in WebUI ",1)]),wi("div",ol,[al,wi("div",ll,pe(i.help.show_hide_irq),1),cl,ul]),wi("div",dl,[fl,wi("div",pl,pe(i.help.show_hide_raid_plugin),1),hl,gl]),wi("div",ml,[bl,wi("div",vl,pe(i.help.show_hide_sensors),1),yl,wl]),wi("div",xl,[_l,wi("div",kl,pe(i.help.show_hide_wifi_module),1),Sl,Cl]),wi("div",Tl,[Al,wi("div",El,pe(i.help.show_hide_processes),1),Ol,Il]),wi("div",Pl,[Nl,wi("div",Ll,pe(i.help.show_hide_left_sidebar),1),Dl,Ml]),wi("div",jl,[Rl,wi("div",ql,pe(i.help.show_hide_quick_look),1),Bl,Ul]),wi("div",Fl,[zl,wi("div",$l,pe(i.help.show_hide_cpu_mem_swap),1),Hl,Vl]),wi("div",Gl,[Wl,wi("div",Zl,pe(i.help.show_hide_all),1),Kl,Ql])])]),Xl,Jl])):Ti("v-if",!0)}]]),nc={class:"plugin"},rc={id:"alerts"},ic={key:0,class:"title"},sc={key:1,class:"title"},oc={id:"alert"},ac={class:"table"},lc={class:"table-cell text-left"};var cc=n(6486);const uc={props:{data:{type:Object}},computed:{stats(){return this.data.stats.alert},alerts(){return(this.stats||[]).map((e=>{const t={};var n=(new Date).getTimezoneOffset();if(t.name=e[3],t.level=e[2],t.begin=1e3*e[0]-60*n*1e3,t.end=1e3*e[1]-60*n*1e3,t.ongoing=-1==e[1],t.min=e[6],t.mean=e[5],t.max=e[4],!t.ongoing){const e=t.end-t.begin,n=parseInt(e/1e3%60),r=parseInt(e/6e4%60),i=parseInt(e/36e5%24);t.duration=(0,cc.padStart)(i,2,"0")+":"+(0,cc.padStart)(r,2,"0")+":"+(0,cc.padStart)(n,2,"0")}return t}))},hasAlerts(){return this.countAlerts>0},countAlerts(){return this.alerts.length},hasOngoingAlerts(){return this.countOngoingAlerts>0},countOngoingAlerts(){return this.alerts.filter((({ongoing:e})=>e)).length}},watch:{countOngoingAlerts(){this.countOngoingAlerts?$o.badge(this.countOngoingAlerts):$o.reset()}},methods:{formatDate:e=>new Date(e).toISOString().slice(0,19).replace(/[^\d-:]/," ")}},dc=(0,ec.Z)(uc,[["render",function(e,t,n,r,i,s){return li(),pi("div",nc,[wi("section",rc,[s.hasAlerts?(li(),pi("span",ic," Warning or critical alerts (last "+pe(s.countAlerts)+" entries) ",1)):(li(),pi("span",sc,"No warning or critical alert detected"))]),wi("section",oc,[wi("div",ac,[(li(!0),pi(ni,null,pr(s.alerts,((t,n)=>(li(),pi("div",{class:"table-row",key:n},[wi("div",lc,[Si(pe(s.formatDate(t.begin))+" "+pe(t.tz)+" ("+pe(t.ongoing?"ongoing":t.duration)+") - ",1),On(wi("span",null,pe(t.level)+" on ",513),[[Ds,!t.ongoing]]),wi("span",{class:ce(t.level.toLowerCase())},pe(t.name),3),Si(" ("+pe(e.$filters.number(t.max,1))+") ",1)])])))),128))])])])}]]),fc={key:0,id:"cloud",class:"plugin"},pc={class:"title"};const hc={props:{data:{type:Object}},computed:{stats(){return this.data.stats.cloud},provider(){return void 0!==this.stats.id?`${stats.platform}`:null},instance(){const{stats:e}=this;return void 0!==this.stats.id?`${e.type} instance ${e.name} (${e.region})`:null}}},gc=(0,ec.Z)(hc,[["render",function(e,t,n,r,i,s){return s.instance||s.provider?(li(),pi("section",fc,[wi("span",pc,pe(s.provider),1),Si(" "+pe(s.instance),1)])):Ti("v-if",!0)}]]),mc={class:"plugin",id:"connections"},bc=wi("div",{class:"table-row"},[wi("div",{class:"table-cell text-left title"},"TCP CONNECTIONS"),wi("div",{class:"table-cell"})],-1),vc={class:"table-row"},yc=wi("div",{class:"table-cell text-left"},"Listen",-1),wc=wi("div",{class:"table-cell"},null,-1),xc={class:"table-cell"},_c={class:"table-row"},kc=wi("div",{class:"table-cell text-left"},"Initiated",-1),Sc=wi("div",{class:"table-cell"},null,-1),Cc={class:"table-cell"},Tc={class:"table-row"},Ac=wi("div",{class:"table-cell text-left"},"Established",-1),Ec=wi("div",{class:"table-cell"},null,-1),Oc={class:"table-cell"},Ic={class:"table-row"},Pc=wi("div",{class:"table-cell text-left"},"Terminated",-1),Nc=wi("div",{class:"table-cell"},null,-1),Lc={class:"table-cell"},Dc={class:"table-row"},Mc=wi("div",{class:"table-cell text-left"},"Tracked",-1),jc=wi("div",{class:"table-cell"},null,-1);const Rc={props:{data:{type:Object}},computed:{stats(){return this.data.stats.connections},view(){return this.data.views.connections},listen(){return this.stats.LISTEN},initiated(){return this.stats.initiated},established(){return this.stats.ESTABLISHED},terminated(){return this.stats.terminated},tracked(){return{count:this.stats.nf_conntrack_count,max:this.stats.nf_conntrack_max}}},methods:{getDecoration(e){if(void 0!==this.view[e])return this.view[e].decoration.toLowerCase()}}},qc=(0,ec.Z)(Rc,[["render",function(e,t,n,r,i,s){return li(),pi("section",mc,[bc,wi("div",vc,[yc,wc,wi("div",xc,pe(s.listen),1)]),wi("div",_c,[kc,Sc,wi("div",Cc,pe(s.initiated),1)]),wi("div",Tc,[Ac,Ec,wi("div",Oc,pe(s.established),1)]),wi("div",Ic,[Pc,Nc,wi("div",Lc,pe(s.terminated),1)]),wi("div",Dc,[Mc,jc,wi("div",{class:ce(["table-cell",s.getDecoration("nf_conntrack_percent")])},pe(s.tracked.count)+"/"+pe(s.tracked.max),3)])])}]]),Bc={id:"cpu",class:"plugin"},Uc={class:"row"},Fc={class:"col-sm-24 col-md-12 col-lg-8"},zc={class:"table"},$c={class:"table-row"},Hc=wi("div",{class:"table-cell text-left title"},"CPU",-1),Vc={class:"table-row"},Gc=wi("div",{class:"table-cell text-left"},"user:",-1),Wc={class:"table-row"},Zc=wi("div",{class:"table-cell text-left"},"system:",-1),Kc={class:"table-row"},Qc=wi("div",{class:"table-cell text-left"},"iowait:",-1),Xc={class:"table-row"},Jc=wi("div",{class:"table-cell text-left"},"dpc:",-1),Yc={class:"hidden-xs hidden-sm col-md-12 col-lg-8"},eu={class:"table"},tu={class:"table-row"},nu=wi("div",{class:"table-cell text-left"},"idle:",-1),ru={class:"table-cell"},iu={class:"table-row"},su=wi("div",{class:"table-cell text-left"},"irq:",-1),ou={class:"table-cell"},au={class:"table-row"},lu=wi("div",{class:"table-cell text-left"},"inter:",-1),cu={class:"table-cell"},uu={class:"table-row"},du=wi("div",{class:"table-cell text-left"},"nice:",-1),fu={class:"table-cell"},pu={key:0,class:"table-row"},hu=wi("div",{class:"table-cell text-left"},"ctx_sw:",-1),gu={class:"table-row"},mu=wi("div",{class:"table-cell text-left"},"steal:",-1),bu={key:1,class:"table-row"},vu=wi("div",{class:"table-cell text-left"},"syscal:",-1),yu={class:"table-cell"},wu={class:"hidden-xs hidden-sm hidden-md col-lg-8"},xu={class:"table"},_u={key:0,class:"table-row"},ku=wi("div",{class:"table-cell text-left"},"ctx_sw:",-1),Su={key:1,class:"table-row"},Cu=wi("div",{class:"table-cell text-left"},"inter:",-1),Tu={class:"table-cell"},Au={key:2,class:"table-row"},Eu=wi("div",{class:"table-cell text-left"},"sw_int:",-1),Ou={class:"table-cell"};const Iu={props:{data:{type:Object}},computed:{stats(){return this.data.stats.cpu},view(){return this.data.views.cpu},isLinux(){return this.data.isLinux},isSunOS(){return this.data.isSunOS},isWindows(){return this.data.isWindows},total(){return this.stats.total},user(){return this.stats.user},system(){return this.stats.system},idle(){return this.stats.idle},nice(){return this.stats.nice},irq(){return this.stats.irq},iowait(){return this.stats.iowait},dpc(){return this.stats.dpc},steal(){return this.stats.steal},ctx_switches(){const{stats:e}=this;return e.ctx_switches?Math.floor(e.ctx_switches/e.time_since_update):n