Completed
Push — master ( 233ebc...7fc0f8 )
by Nicolas
01:24 queued 50s
created

GlancesExport.__build_export()   F

Complexity

Conditions 12

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
c 0
b 0
f 0
dl 0
loc 37
rs 2.7855

How to fix   Complexity   

Complexity

Complex classes like GlancesExport.__build_export() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2017 Nicolargo <[email protected]>
6
#
7
# Glances is free software; you can redistribute it and/or modify
8
# it under the terms of the GNU Lesser General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# Glances is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU Lesser General Public License for more details.
16
#
17
# You should have received a copy of the GNU Lesser General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20
"""
21
I am your father...
22
23
...for all Glances exports IF.
24
"""
25
26
import json
27
28
from glances.compat import NoOptionError, NoSectionError, iteritems, iterkeys
29
from glances.logger import logger
30
31
32
class GlancesExport(object):
33
34
    """Main class for Glances export IF."""
35
36
    def __init__(self, config=None, args=None):
37
        """Init the export class."""
38
        # Export name (= module name without glances_)
39
        self.export_name = self.__class__.__module__[len('glances_'):]
40
        logger.debug("Init export module %s" % self.export_name)
41
42
        # Init the config & args
43
        self.config = config
44
        self.args = args
45
46
        # By default export is disable
47
        # Had to be set to True in the __init__ class of child
48
        self.export_enable = False
49
50
        # Mandatory for (most of) the export module
51
        self.host = None
52
        self.port = None
53
54
    def exit(self):
55
        """Close the export module."""
56
        logger.debug("Finalise export interface %s" % self.export_name)
57
58
    def plugins_to_export(self):
59
        """Return the list of plugins to export."""
60
        return ['cpu',
61
                'percpu',
62
                'load',
63
                'mem',
64
                'memswap',
65
                'network',
66
                'diskio',
67
                'fs',
68
                'processcount',
69
                'ip',
70
                'system',
71
                'uptime',
72
                'sensors',
73
                'docker',
74
                'uptime']
75
76
    def load_conf(self, section, mandatories=['host', 'port'], options=None):
77
        """Load the export <section> configuration in the Glances configuration file.
78
79
        :param section: name of the export section to load
80
        :param mandatories: a list of mandatories parameters to load
81
        :param options: a list of optionnals parameters to load
82
83
        :returns: Boolean -- True if section is found
84
        """
85
        options = options or []
86
87
        if self.config is None:
88
            return False
89
90
        # By default read the mandatory host:port items
91
        try:
92
            for opt in mandatories:
93
                setattr(self, opt, self.config.get_value(section, opt))
94
        except NoSectionError:
95
            logger.critical("No {} configuration found".format(section))
96
            return False
97
        except NoOptionError as e:
98
            logger.critical("Error in the {} configuration ({})".format(section, e))
99
            return False
100
101
        # Load options
102
        for opt in options:
103
            try:
104
                setattr(self, opt, self.config.get_value(section, opt))
105
            except NoOptionError:
106
                pass
107
108
        logger.debug("Load {} from the Glances configuration file".format(section))
109
        logger.debug("{} parameters: {}".format(section, {opt: getattr(self, opt) for opt in mandatories + options}))
110
111
        return True
112
113
    def get_item_key(self, item):
114
        """Return the value of the item 'key'."""
115
        try:
116
            ret = item[item['key']]
117
        except KeyError:
118
            logger.error("No 'key' available in {}".format(item))
119
        if isinstance(ret, list):
120
            return ret[0]
121
        else:
122
            return ret
123
124
    def parse_tags(self, tags):
125
        """Parse tags into a dict.
126
127
        input tags: a comma separated list of 'key:value' pairs.
128
            Example: foo:bar,spam:eggs
129
        output dtags: a dict of tags.
130
            Example: {'foo': 'bar', 'spam': 'eggs'}
131
        """
132
        dtags = {}
133
        if tags:
134
            try:
135
                dtags = dict([x.split(':') for x in tags.split(',')])
136
            except ValueError:
137
                # one of the 'key:value' pairs was missing
138
                logger.info('Invalid tags passed: %s', tags)
139
                dtags = {}
140
141
        return dtags
142
143
    def update(self, stats):
144
        """Update stats to a server.
145
146
        The method builds two lists: names and values
147
        and calls the export method to export the stats.
148
149
        Be aware that CSV export overwrite this class and use a specific one.
150
        """
151
        if not self.export_enable:
152
            return False
153
154
        # Get all the stats & limits
155
        all_stats = stats.getAllExportsAsDict(plugin_list=self.plugins_to_export())
156
        all_limits = stats.getAllLimitsAsDict(plugin_list=self.plugins_to_export())
157
158
        # Loop over plugins to export
159
        for plugin in self.plugins_to_export():
160
            if isinstance(all_stats[plugin], dict):
161
                all_stats[plugin].update(all_limits[plugin])
162
            elif isinstance(all_stats[plugin], list):
163
                # TypeError: string indices must be integers (Network plugin) #1054
164
                for i in all_stats[plugin]:
165
                    i.update(all_limits[plugin])
166
            else:
167
                continue
168
            export_names, export_values = self.__build_export(all_stats[plugin])
169
            self.export(plugin, export_names, export_values)
170
171
        return True
172
173
    def __build_export(self, stats):
174
        """Build the export lists."""
175
        export_names = []
176
        export_values = []
177
178
        if isinstance(stats, dict):
179
            # Stats is a dict
180
            # Is there a key ?
181
            if 'key' in iterkeys(stats) and stats['key'] in iterkeys(stats):
182
                pre_key = '{}.'.format(stats[stats['key']])
183
            else:
184
                pre_key = ''
185
            # Walk through the dict
186
            for key, value in iteritems(stats):
187
                if isinstance(value, bool):
188
                    value = json.dumps(value)
189
                if isinstance(value, list):
190
                    try:
191
                        value = value[0]
192
                    except IndexError:
193
                        value = ''
194
                if isinstance(value, dict):
195
                    item_names, item_values = self.__build_export(value)
196
                    item_names = [pre_key + key.lower() + str(i) for i in item_names]
197
                    export_names += item_names
198
                    export_values += item_values
199
                else:
200
                    export_names.append(pre_key + key.lower())
201
                    export_values.append(value)
202
        elif isinstance(stats, list):
203
            # Stats is a list (of dict)
204
            # Recursive loop through the list
205
            for item in stats:
206
                item_names, item_values = self.__build_export(item)
207
                export_names += item_names
208
                export_values += item_values
209
        return export_names, export_values
210