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
|