Test Failed
Push — develop ( 6fa969...8e4b9d )
by Nicolas
02:22
created

VmExtension._want_display()   A

Complexity

Conditions 1

Size

Total Lines 2
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nop 4
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
#
2
# This file is part of Glances.
3
#
4
# SPDX-FileCopyrightText: 2024 Nicolas Hennion <[email protected]>
5
#
6
# SPDX-License-Identifier: LGPL-3.0-only
7
#
8
9
"""Multipass Extension unit for Glances' Vms plugin."""
10
11
import os
12
from typing import Any, Dict, List, Tuple
13
14
import orjson
15
16
from glances.globals import nativestr
17
from glances.secure import secure_popen
18
19
# Check if multipass binary exist
20
# TODO: make this path configurable from the Glances configuration file
21
MULTIPASS_PATH = '/snap/bin/multipass'
22
MULTIPASS_VERSION_OPTIONS = 'version --format json'
23
MULTIPASS_INFO_OPTIONS = 'info --format json'
24
import_multipass_error_tag = not os.path.exists(MULTIPASS_PATH)
25
26
27
class VmExtension:
28
    """Glances' Vms Plugin's Vm Extension unit"""
29
30
    CONTAINER_ACTIVE_STATUS = ['running']
31
32
    def __init__(self):
33
        self.ext_name = "Multipass (Vm)"
34
35
    def update_version(self):
36
        # > multipass version --format json
37
        # {
38
        #     "multipass": "1.13.1",
39
        #     "multipassd": "1.13.1"
40
        # }
41
        ret_cmd = secure_popen(f'{MULTIPASS_PATH} {MULTIPASS_VERSION_OPTIONS}')
42
        try:
43
            ret = orjson.loads(ret_cmd)
44
        except orjson.JSONDecodeError:
45
            return {}
46
        else:
47
            return ret.get('multipass', None)
48
49
    def update_info(self):
50
        # > multipass info  --format json
51
        # {
52
        #     "errors": [
53
        #     ],
54
        #     "info": {
55
        #         "adapted-budgerigar": {
56
        #             "cpu_count": "1",
57
        #             "disks": {
58
        #                 "sda1": {
59
        #                     "total": "5116440064",
60
        #                     "used": "2287162880"
61
        #                 }
62
        #             },
63
        #             "image_hash": "182dc760bfca26c45fb4e4668049ecd4d0ecdd6171b3bae81d0135e8f1e9d93e",
64
        #             "image_release": "24.04 LTS",
65
        #             "ipv4": [
66
        #                 "10.160.166.174"
67
        #             ],
68
        #             "load": [
69
        #                 0,
70
        #                 0.03,
71
        #                 0
72
        #             ],
73
        #             "memory": {
74
        #                 "total": 1002500096,
75
        #                 "used": 432058368
76
        #             },
77
        #             "mounts": {
78
        #             },
79
        #             "release": "Ubuntu 24.04 LTS",
80
        #             "snapshot_count": "0",
81
        #             "state": "Running"
82
        #         }
83
        #     }
84
        # }
85
        ret_cmd = secure_popen(f'{MULTIPASS_PATH} {MULTIPASS_INFO_OPTIONS}')
86
        try:
87
            ret = orjson.loads(ret_cmd)
88
        except orjson.JSONDecodeError:
89
            return {}
90
        else:
91
            return ret.get('info', {})
92
93
    def update(self, all_tag) -> Tuple[Dict, List[Dict]]:
94
        """Update Vm stats using the input method."""
95
        # Can not run multipass on this system then...
96
        if import_multipass_error_tag:
97
            return {}, []
98
99
        # Get the stats from the system
100
        version_stats = self.update_version()
101
        info_stats = self.update_info()
102
        returned_stats = []
103
        for k, v in info_stats.items():
104
            # Only display when VM in on 'running' states
105
            # See states list here: https://multipass.run/docs/instance-states
106
            if self._want_display(v, 'state', ['Running', 'Starting', 'Restarting']):
107
                returned_stats.append(self.generate_stats(k, v))
108
109
        return version_stats, returned_stats
110
111
    @property
112
    def key(self) -> str:
113
        """Return the key of the list."""
114
        return 'name'
115
116
    def _want_display(self, vm_stats, key, values):
117
        return vm_stats.get(key).lower() in [v.lower() for v in values]
118
119
    def generate_stats(self, vm_name, vm_stats) -> Dict[str, Any]:
120
        # Init the stats for the current vm
121
        return {
122
            'key': self.key,
123
            'name': nativestr(vm_name),
124
            'id': vm_stats.get('image_hash'),
125
            'status': vm_stats.get('state').lower() if vm_stats.get('state') else None,
126
            'release': vm_stats.get('release') if len(vm_stats.get('release')) > 0 else vm_stats.get('image_release'),
127
            'cpu_count': int(vm_stats.get('cpu_count', 1)) if len(vm_stats.get('cpu_count', 1)) > 0 else None,
128
            'memory_usage': vm_stats.get('memory').get('used') if vm_stats.get('memory') else None,
129
            'memory_total': vm_stats.get('memory').get('total') if vm_stats.get('memory') else None,
130
            'load_1min': vm_stats.get('load')[0] if vm_stats.get('load') else None,
131
            'load_5min': vm_stats.get('load')[1] if vm_stats.get('load') else None,
132
            'load_15min': vm_stats.get('load')[2] if vm_stats.get('load') else None,
133
            'ipv4': vm_stats.get('ipv4')[0] if len(vm_stats.get('ipv4')) > 0 else None,
134
            # TODO: disk
135
        }
136