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
|
# -*- 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
|