Test Failed
Push — develop ( 66c9ff...e21229 )
by Nicolas
05:06
created

glances/exports/glances_cassandra.py (4 issues)

1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of Glances.
4
#
5
# Copyright (C) 2019 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
"""Cassandra/Scylla interface class."""
21
22
import sys
23
from datetime import datetime
24
from numbers import Number
25
26
from glances.logger import logger
27
from glances.exports.glances_export import GlancesExport
28
from glances.compat import iteritems
29
30
from cassandra.auth import PlainTextAuthProvider
0 ignored issues
show
import missing from __future__ import absolute_import
Loading history...
Unable to import 'cassandra.auth'
Loading history...
31
from cassandra.cluster import Cluster
32
from cassandra.util import uuid_from_time
33
from cassandra import InvalidRequest
34
35
36
class Export(GlancesExport):
37
38
    """This class manages the Cassandra/Scylla export module."""
39
40
    def __init__(self, config=None, args=None):
41
        """Init the Cassandra export IF."""
42
        super(Export, self).__init__(config=config, args=args)
43
44
        # Mandatories configuration keys (additional to host and port)
45
        self.keyspace = None
46
47
        # Optionals configuration keys
48
        self.protocol_version = 3
49
        self.replication_factor = 2
50
        self.table = None
51
        self.username = None
52
        self.password = None
53
54
        # Load the Cassandra configuration file section
55
        self.export_enable = self.load_conf('cassandra',
56
                                            mandatories=['host', 'port', 'keyspace'],
57
                                            options=['protocol_version',
58
                                                     'replication_factor',
59
                                                     'table',
60
                                                     'username',
61
                                                     'password'])
62
        if not self.export_enable:
63
            sys.exit(2)
64
65
        # Init the Cassandra client
66
        self.cluster, self.session = self.init()
67
68
    def init(self):
69
        """Init the connection to the Cassandra server."""
70
        if not self.export_enable:
71
            return None
72
73
        # if username and/or password are not set the connection will try to connect with no auth
0 ignored issues
show
This line is too long as per the coding-style (97/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
74
        auth_provider = PlainTextAuthProvider(
75
            username=self.username, password=self.password)
76
77
        # Cluster
78
        try:
79
            cluster = Cluster([self.host],
80
                              port=int(self.port),
81
                              protocol_version=int(self.protocol_version),
82
                              auth_provider=auth_provider)
83
            session = cluster.connect()
84
        except Exception as e:
85
            logger.critical("Cannot connect to Cassandra cluster '%s:%s' (%s)" % (self.host, self.port, e))
86
            sys.exit(2)
87
88
        # Keyspace
89
        try:
90
            session.set_keyspace(self.keyspace)
91
        except InvalidRequest as e:
92
            logger.info("Create keyspace {} on the Cassandra cluster".format(self.keyspace))
93
            c = "CREATE KEYSPACE %s WITH replication = { 'class': 'SimpleStrategy', 'replication_factor': '%s' }" % (self.keyspace, self.replication_factor)
94
            session.execute(c)
95
            session.set_keyspace(self.keyspace)
96
97
        logger.info(
98
            "Stats will be exported to Cassandra cluster {} ({}) in keyspace {}".format(
99
                cluster.metadata.cluster_name, cluster.metadata.all_hosts(), self.keyspace))
100
101
        # Table
102
        try:
103
            session.execute("CREATE TABLE %s (plugin text, time timeuuid, stat map<text,float>, PRIMARY KEY (plugin, time)) WITH CLUSTERING ORDER BY (time DESC)" % self.table)
104
        except Exception:
105
            logger.debug("Cassandra table %s already exist" % self.table)
106
107
        return cluster, session
108
109
    def export(self, name, columns, points):
110
        """Write the points to the Cassandra cluster."""
111
        logger.debug("Export {} stats to Cassandra".format(name))
112
113
        # Remove non number stats and convert all to float (for Boolean)
114
        data = {k: float(v) for (k, v) in dict(zip(columns, points)).iteritems() if isinstance(v, Number)}
115
116
        # Write input to the Cassandra table
117
        try:
118
119
            stmt = "INSERT INTO {} (plugin, time, stat) VALUES (?, ?, ?)".format(self.table)
0 ignored issues
show
This line is too long as per the coding-style (92/80).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
120
            query = self.session.prepare(stmt)
121
            self.session.execute(
122
                query,
123
                (name, uuid_from_time(datetime.now()), data)
124
            )
125
        except Exception as e:
126
            logger.error("Cannot export {} stats to Cassandra ({})".format(name, e))
127
128
    def exit(self):
129
        """Close the Cassandra export module."""
130
        # To ensure all connections are properly closed
131
        self.session.shutdown()
132
        self.cluster.shutdown()
133
        # Call the father method
134
        super(Export, self).exit()
135