summaryrefslogtreecommitdiffstats
path: root/collectors/python.d.plugin/boinc/boinc.chart.py
blob: e10b28ceaf873907e66435183674dd178525afe8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# -*- coding: utf-8 -*-
# Description: BOINC netdata python.d module
# Author: Austin S. Hemmelgarn (Ferroin)
# SPDX-License-Identifier: GPL-3.0-or-later

import socket

from bases.FrameworkServices.SimpleService import SimpleService

from third_party import boinc_client


ORDER = [
    'tasks',
    'states',
    'sched_states',
    'process_states',
]

CHARTS = {
    'tasks': {
        'options': [None, 'Overall Tasks', 'tasks', 'boinc', 'boinc.tasks', 'line'],
        'lines': [
            ['total', 'Total', 'absolute', 1, 1],
            ['active', 'Active', 'absolute', 1, 1]
        ]
    },
    'states': {
        'options': [None, 'Tasks per State', 'tasks', 'boinc', 'boinc.states', 'line'],
        'lines': [
            ['new', 'New', 'absolute', 1, 1],
            ['downloading', 'Downloading', 'absolute', 1, 1],
            ['downloaded', 'Ready to Run', 'absolute', 1, 1],
            ['comperror', 'Compute Errors', 'absolute', 1, 1],
            ['uploading', 'Uploading', 'absolute', 1, 1],
            ['uploaded', 'Uploaded', 'absolute', 1, 1],
            ['aborted', 'Aborted', 'absolute', 1, 1],
            ['upload_failed', 'Failed Uploads', 'absolute', 1, 1]
        ]
    },
    'sched_states': {
        'options': [None, 'Tasks per Scheduler State', 'tasks', 'boinc', 'boinc.sched', 'line'],
        'lines': [
            ['uninit_sched', 'Uninitialized', 'absolute', 1, 1],
            ['preempted', 'Preempted', 'absolute', 1, 1],
            ['scheduled', 'Scheduled', 'absolute', 1, 1]
        ]
    },
    'process_states': {
        'options': [None, 'Tasks per Process State', 'tasks', 'boinc', 'boinc.process', 'line'],
        'lines': [
            ['uninit_proc', 'Uninitialized', 'absolute', 1, 1],
            ['executing', 'Executing', 'absolute', 1, 1],
            ['suspended', 'Suspended', 'absolute', 1, 1],
            ['aborting', 'Aborted', 'absolute', 1, 1],
            ['quit', 'Quit', 'absolute', 1, 1],
            ['copy_pending', 'Copy Pending', 'absolute', 1, 1]
        ]
    }
}

# A simple template used for pre-loading the return dictionary to make
# the _get_data() method simpler.
_DATA_TEMPLATE = {
    'total': 0,
    'active': 0,
    'new': 0,
    'downloading': 0,
    'downloaded': 0,
    'comperror': 0,
    'uploading': 0,
    'uploaded': 0,
    'aborted': 0,
    'upload_failed': 0,
    'uninit_sched': 0,
    'preempted': 0,
    'scheduled': 0,
    'uninit_proc': 0,
    'executing': 0,
    'suspended': 0,
    'aborting': 0,
    'quit': 0,
    'copy_pending': 0
}

# Map task states to dimensions
_TASK_MAP = {
    boinc_client.ResultState.NEW: 'new',
    boinc_client.ResultState.FILES_DOWNLOADING: 'downloading',
    boinc_client.ResultState.FILES_DOWNLOADED: 'downloaded',
    boinc_client.ResultState.COMPUTE_ERROR: 'comperror',
    boinc_client.ResultState.FILES_UPLOADING: 'uploading',
    boinc_client.ResultState.FILES_UPLOADED: 'uploaded',
    boinc_client.ResultState.ABORTED: 'aborted',
    boinc_client.ResultState.UPLOAD_FAILED: 'upload_failed'
}

# Map scheduler states to dimensions
_SCHED_MAP = {
    boinc_client.CpuSched.UNINITIALIZED: 'uninit_sched',
    boinc_client.CpuSched.PREEMPTED: 'preempted',
    boinc_client.CpuSched.SCHEDULED: 'scheduled',
}

# Maps process states to dimensions
_PROC_MAP = {
    boinc_client.Process.UNINITIALIZED: 'uninit_proc',
    boinc_client.Process.EXECUTING: 'executing',
    boinc_client.Process.SUSPENDED: 'suspended',
    boinc_client.Process.ABORT_PENDING: 'aborted',
    boinc_client.Process.QUIT_PENDING: 'quit',
    boinc_client.Process.COPY_PENDING: 'copy_pending'
}


class Service(SimpleService):
    def __init__(self, configuration=None, name=None):
        SimpleService.__init__(self, configuration=configuration, name=name)
        self.order = ORDER
        self.definitions = CHARTS
        self.host = self.configuration.get('host', 'localhost')
        self.port = self.configuration.get('port', 0)
        self.password = self.configuration.get('password', '')
        self.client = boinc_client.BoincClient(host=self.host, port=self.port, passwd=self.password)
        self.alive = False

    def check(self):
        return self.connect()

    def connect(self):
        self.client.connect()
        self.alive = self.client.connected and self.client.authorized
        return self.alive

    def reconnect(self):
        # The client class itself actually disconnects existing
        # connections when it is told to connect, so we don't need to
        # explicitly disconnect when we're just trying to reconnect.
        return self.connect()

    def is_alive(self):
        if not self.alive:
            return self.reconnect()
        return True

    def _get_data(self):
        if not self.is_alive():
            return None

        data = dict(_DATA_TEMPLATE)

        try:
            results = self.client.get_tasks()
        except socket.error:
            self.error('Connection is dead')
            self.alive = False
            return None

        for task in results:
            data['total'] += 1
            data[_TASK_MAP[task.state]] += 1
            try:
                if task.active_task:
                    data['active'] += 1
                    data[_SCHED_MAP[task.scheduler_state]] += 1
                    data[_PROC_MAP[task.active_task_state]] += 1
            except AttributeError:
                pass

        return data or None