remove python.d/boinc (#18397)
Ilya Mashchenko committed
Aug 23, 2024 at 18:41 UTC
dde8e19a7abaf9689236005294c5596ddf23e2f0
7 files changed
-1188
CMakeLists.txt
-2
@@ -2831,7 +2831,6 @@ install(FILES src/collectors/python.d.plugin/python.d.conf
2831
install(FILES
2832
src/collectors/python.d.plugin/am2320/am2320.conf
2833
src/collectors/python.d.plugin/anomalies/anomalies.conf
2834
- src/collectors/python.d.plugin/boinc/boinc.conf
2834
src/collectors/python.d.plugin/ceph/ceph.conf
2835
src/collectors/python.d.plugin/go_expvar/go_expvar.conf
2836
src/collectors/python.d.plugin/haproxy/haproxy.conf
@@ -2850,7 +2849,6 @@ install(FILES
2849
install(FILES
2850
src/collectors/python.d.plugin/am2320/am2320.chart.py
2851
src/collectors/python.d.plugin/anomalies/anomalies.chart.py
2853
- src/collectors/python.d.plugin/boinc/boinc.chart.py
2852
src/collectors/python.d.plugin/ceph/ceph.chart.py
2853
src/collectors/python.d.plugin/go_expvar/go_expvar.chart.py
2854
src/collectors/python.d.plugin/haproxy/haproxy.chart.py
src/collectors/python.d.plugin/boinc/README.md
deleted
-1
@@ -1 +0,0 @@
1
-integrations/boinc.md
\ No newline at end of file
src/collectors/python.d.plugin/boinc/boinc.chart.py
deleted
-168
@@ -1,168 +0,0 @@
1
-# -*- coding: utf-8 -*-
2
-# Description: BOINC netdata python.d module
3
-# Author: Austin S. Hemmelgarn (Ferroin)
4
-# SPDX-License-Identifier: GPL-3.0-or-later
5
-
6
-import socket
7
-
8
-from bases.FrameworkServices.SimpleService import SimpleService
9
-from third_party import boinc_client
10
-
11
-ORDER = [
12
- 'tasks',
13
- 'states',
14
- 'sched_states',
15
- 'process_states',
16
-]
17
-
18
-CHARTS = {
19
- 'tasks': {
20
- 'options': [None, 'Overall Tasks', 'tasks', 'boinc', 'boinc.tasks', 'line'],
21
- 'lines': [
22
- ['total', 'Total', 'absolute', 1, 1],
23
- ['active', 'Active', 'absolute', 1, 1]
24
- ]
25
- },
26
- 'states': {
27
- 'options': [None, 'Tasks per State', 'tasks', 'boinc', 'boinc.states', 'line'],
28
- 'lines': [
29
- ['new', 'New', 'absolute', 1, 1],
30
- ['downloading', 'Downloading', 'absolute', 1, 1],
31
- ['downloaded', 'Ready to Run', 'absolute', 1, 1],
32
- ['comperror', 'Compute Errors', 'absolute', 1, 1],
33
- ['uploading', 'Uploading', 'absolute', 1, 1],
34
- ['uploaded', 'Uploaded', 'absolute', 1, 1],
35
- ['aborted', 'Aborted', 'absolute', 1, 1],
36
- ['upload_failed', 'Failed Uploads', 'absolute', 1, 1]
37
- ]
38
- },
39
- 'sched_states': {
40
- 'options': [None, 'Tasks per Scheduler State', 'tasks', 'boinc', 'boinc.sched', 'line'],
41
- 'lines': [
42
- ['uninit_sched', 'Uninitialized', 'absolute', 1, 1],
43
- ['preempted', 'Preempted', 'absolute', 1, 1],
44
- ['scheduled', 'Scheduled', 'absolute', 1, 1]
45
- ]
46
- },
47
- 'process_states': {
48
- 'options': [None, 'Tasks per Process State', 'tasks', 'boinc', 'boinc.process', 'line'],
49
- 'lines': [
50
- ['uninit_proc', 'Uninitialized', 'absolute', 1, 1],
51
- ['executing', 'Executing', 'absolute', 1, 1],
52
- ['suspended', 'Suspended', 'absolute', 1, 1],
53
- ['aborting', 'Aborted', 'absolute', 1, 1],
54
- ['quit', 'Quit', 'absolute', 1, 1],
55
- ['copy_pending', 'Copy Pending', 'absolute', 1, 1]
56
- ]
57
- }
58
-}
59
-
60
-# A simple template used for pre-loading the return dictionary to make
61
-# the _get_data() method simpler.
62
-_DATA_TEMPLATE = {
63
- 'total': 0,
64
- 'active': 0,
65
- 'new': 0,
66
- 'downloading': 0,
67
- 'downloaded': 0,
68
- 'comperror': 0,
69
- 'uploading': 0,
70
- 'uploaded': 0,
71
- 'aborted': 0,
72
- 'upload_failed': 0,
73
- 'uninit_sched': 0,
74
- 'preempted': 0,
75
- 'scheduled': 0,
76
- 'uninit_proc': 0,
77
- 'executing': 0,
78
- 'suspended': 0,
79
- 'aborting': 0,
80
- 'quit': 0,
81
- 'copy_pending': 0
82
-}
83
-
84
-# Map task states to dimensions
85
-_TASK_MAP = {
86
- boinc_client.ResultState.NEW: 'new',
87
- boinc_client.ResultState.FILES_DOWNLOADING: 'downloading',
88
- boinc_client.ResultState.FILES_DOWNLOADED: 'downloaded',
89
- boinc_client.ResultState.COMPUTE_ERROR: 'comperror',
90
- boinc_client.ResultState.FILES_UPLOADING: 'uploading',
91
- boinc_client.ResultState.FILES_UPLOADED: 'uploaded',
92
- boinc_client.ResultState.ABORTED: 'aborted',
93
- boinc_client.ResultState.UPLOAD_FAILED: 'upload_failed'
94
-}
95
-
96
-# Map scheduler states to dimensions
97
-_SCHED_MAP = {
98
- boinc_client.CpuSched.UNINITIALIZED: 'uninit_sched',
99
- boinc_client.CpuSched.PREEMPTED: 'preempted',
100
- boinc_client.CpuSched.SCHEDULED: 'scheduled',
101
-}
102
-
103
-# Maps process states to dimensions
104
-_PROC_MAP = {
105
- boinc_client.Process.UNINITIALIZED: 'uninit_proc',
106
- boinc_client.Process.EXECUTING: 'executing',
107
- boinc_client.Process.SUSPENDED: 'suspended',
108
- boinc_client.Process.ABORT_PENDING: 'aborted',
109
- boinc_client.Process.QUIT_PENDING: 'quit',
110
- boinc_client.Process.COPY_PENDING: 'copy_pending'
111
-}
112
-
113
-
114
-class Service(SimpleService):
115
- def __init__(self, configuration=None, name=None):
116
- SimpleService.__init__(self, configuration=configuration, name=name)
117
- self.order = ORDER
118
- self.definitions = CHARTS
119
- self.host = self.configuration.get('host', 'localhost')
120
- self.port = self.configuration.get('port', 0)
121
- self.password = self.configuration.get('password', '')
122
- self.client = boinc_client.BoincClient(host=self.host, port=self.port, passwd=self.password)
123
- self.alive = False
124
-
125
- def check(self):
126
- return self.connect()
127
-
128
- def connect(self):
129
- self.client.connect()
130
- self.alive = self.client.connected and self.client.authorized
131
- return self.alive
132
-
133
- def reconnect(self):
134
- # The client class itself actually disconnects existing
135
- # connections when it is told to connect, so we don't need to
136
- # explicitly disconnect when we're just trying to reconnect.
137
- return self.connect()
138
-
139
- def is_alive(self):
140
- if not self.alive:
141
- return self.reconnect()
142
- return True
143
-
144
- def _get_data(self):
145
- if not self.is_alive():
146
- return None
147
-
148
- data = dict(_DATA_TEMPLATE)
149
-
150
- try:
151
- results = self.client.get_tasks()
152
- except socket.error:
153
- self.error('Connection is dead')
154
- self.alive = False
155
- return None
156
-
157
- for task in results:
158
- data['total'] += 1
159
- data[_TASK_MAP[task.state]] += 1
160
- try:
161
- if task.active_task:
162
- data['active'] += 1
163
- data[_SCHED_MAP[task.scheduler_state]] += 1
164
- data[_PROC_MAP[task.active_task_state]] += 1
165
- except AttributeError:
166
- pass
167
-
168
- return data or None
src/collectors/python.d.plugin/boinc/boinc.conf
deleted
-66
@@ -1,66 +0,0 @@
1
-# netdata python.d.plugin configuration for boinc
2
-#
3
-# This file is in YaML format. Generally the format is:
4
-#
5
-# name: value
6
-#
7
-# There are 2 sections:
8
-# - global variables
9
-# - one or more JOBS
10
-#
11
-# JOBS allow you to collect values from multiple sources.
12
-# Each source will have its own set of charts.
13
-#
14
-# JOB parameters have to be indented (using spaces only, example below).
15
-
16
-# ----------------------------------------------------------------------
17
-# Global Variables
18
-# These variables set the defaults for all JOBs, however each JOB
19
-# may define its own, overriding the defaults.
20
-
21
-# update_every sets the default data collection frequency.
22
-# If unset, the python.d.plugin default is used.
23
-# update_every: 1
24
-
25
-# priority controls the order of charts at the netdata dashboard.
26
-# Lower numbers move the charts towards the top of the page.
27
-# If unset, the default for python.d.plugin is used.
28
-# priority: 60000
29
-
30
-# penalty indicates whether to apply penalty to update_every in case of failures.
31
-# Penalty will increase every 5 failed updates in a row. Maximum penalty is 10 minutes.
32
-# penalty: yes
33
-
34
-# autodetection_retry sets the job re-check interval in seconds.
35
-# The job is not deleted if check fails.
36
-# Attempts to start the job are made once every autodetection_retry.
37
-# This feature is disabled by default.
38
-# autodetection_retry: 0
39
-
40
-# ----------------------------------------------------------------------
41
-# JOBS (data collection sources)
42
-#
43
-# The default JOBS share the same *name*. JOBS with the same name
44
-# are mutually exclusive. Only one of them will be allowed running at
45
-# any time. This allows autodetection to try several alternatives and
46
-# pick the one that works.
47
-#
48
-# Any number of jobs is supported.
49
-#
50
-# All python.d.plugin JOBS (for all its modules) support a set of
51
-# predefined parameters. These are:
52
-#
53
-# job_name:
54
-# name: myname # the JOB's name as it will appear at the
55
-# # dashboard (by default is the job_name)
56
-# # JOBs sharing a name are mutually exclusive
57
-# update_every: 1 # the JOB's data collection frequency
58
-# priority: 60000 # the JOB's order on the dashboard
59
-# penalty: yes # the JOB's penalty
60
-# autodetection_retry: 0 # the JOB's re-check interval in seconds
61
-#
62
-# Additionally to the above, boinc also supports the following:
63
-#
64
-# hostname: localhost # The host running the BOINC client
65
-# port: 31416 # The remote GUI RPC port for BOINC
66
-# password: '' # The remote GUI RPC password
src/collectors/python.d.plugin/boinc/integrations/boinc.md
deleted
-238
@@ -1,238 +0,0 @@
1
-<!--startmeta
2
-custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/collectors/python.d.plugin/boinc/README.md"
3
-meta_yaml: "https://github.com/netdata/netdata/edit/master/src/collectors/python.d.plugin/boinc/metadata.yaml"
4
-sidebar_label: "BOINC"
5
-learn_status: "Published"
6
-learn_rel_path: "Collecting Metrics/Distributed Computing Systems"
7
-most_popular: False
8
-message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE"
9
-endmeta-->
10
-
11
-# BOINC
12
-
13
-
14
-<img src="https://netdata.cloud/img/bolt.svg" width="150"/>
15
-
16
-
17
-Plugin: python.d.plugin
18
-Module: boinc
19
-
20
-<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" />
21
-
22
-## Overview
23
-
24
-This collector monitors task counts for the Berkeley Open Infrastructure Networking Computing (BOINC) distributed computing client.
25
-
26
-It uses the same RPC interface that the BOINC monitoring GUI does.
27
-
28
-This collector is supported on all platforms.
29
-
30
-This collector supports collecting metrics from multiple instances of this integration, including remote instances.
31
-
32
-
33
-### Default Behavior
34
-
35
-#### Auto-Detection
36
-
37
-By default, the module will try to auto-detect the password to the RPC interface by looking in `/var/lib/boinc` for this file (this is the location most Linux distributions use for a system-wide BOINC installation), so things may just work without needing configuration for a local system.
38
-
39
-#### Limits
40
-
41
-The default configuration for this integration does not impose any limits on data collection.
42
-
43
-#### Performance Impact
44
-
45
-The default configuration for this integration is not expected to impose a significant performance impact on the system.
46
-
47
-
48
-## Metrics
49
-
50
-Metrics grouped by *scope*.
51
-
52
-The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels.
53
-
54
-
55
-
56
-### Per BOINC instance
57
-
58
-These metrics refer to the entire monitored application.
59
-
60
-This scope has no labels.
61
-
62
-Metrics:
63
-
64
-| Metric | Dimensions | Unit |
65
-|:------|:----------|:----|
66
-| boinc.tasks | Total, Active | tasks |
67
-| boinc.states | New, Downloading, Ready to Run, Compute Errors, Uploading, Uploaded, Aborted, Failed Uploads | tasks |
68
-| boinc.sched | Uninitialized, Preempted, Scheduled | tasks |
69
-| boinc.process | Uninitialized, Executing, Suspended, Aborted, Quit, Copy Pending | tasks |
70
-
71
-
72
-
73
-## Alerts
74
-
75
-
76
-The following alerts are available:
77
-
78
-| Alert name | On metric | Description |
79
-|:------------|:----------|:------------|
80
-| [ boinc_total_tasks ](https://github.com/netdata/netdata/blob/master/src/health/health.d/boinc.conf) | boinc.tasks | average number of total tasks over the last 10 minutes |
81
-| [ boinc_active_tasks ](https://github.com/netdata/netdata/blob/master/src/health/health.d/boinc.conf) | boinc.tasks | average number of active tasks over the last 10 minutes |
82
-| [ boinc_compute_errors ](https://github.com/netdata/netdata/blob/master/src/health/health.d/boinc.conf) | boinc.states | average number of compute errors over the last 10 minutes |
83
-| [ boinc_upload_errors ](https://github.com/netdata/netdata/blob/master/src/health/health.d/boinc.conf) | boinc.states | average number of failed uploads over the last 10 minutes |
84
-
85
-
86
-## Setup
87
-
88
-### Prerequisites
89
-
90
-#### Boinc RPC interface
91
-
92
-BOINC requires use of a password to access it's RPC interface. You can find this password in the `gui_rpc_auth.cfg` file in your BOINC directory.
93
-
94
-
95
-### Configuration
96
-
97
-#### File
98
-
99
-The configuration file name for this integration is `python.d/boinc.conf`.
100
-
101
-
102
-You can edit the configuration file using the `edit-config` script from the
103
-Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory).
104
-
105
-```bash
106
-cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata
107
-sudo ./edit-config python.d/boinc.conf
108
-```
109
-#### Options
110
-
111
-There are 2 sections:
112
-
113
-* Global variables
114
-* One or more JOBS that can define multiple different instances to monitor.
115
-
116
-The following options can be defined globally: priority, penalty, autodetection_retry, update_every, but can also be defined per JOB to override the global values.
117
-
118
-Additionally, the following collapsed table contains all the options that can be configured inside a JOB definition.
119
-
120
-Every configuration JOB starts with a `job_name` value which will appear in the dashboard, unless a `name` parameter is specified.
121
-
122
-
123
-<details open><summary>Config options</summary>
124
-
125
-| Name | Description | Default | Required |
126
-|:----|:-----------|:-------|:--------:|
127
-| update_every | Sets the default data collection frequency. | 5 | no |
128
-| priority | Controls the order of charts at the netdata dashboard. | 60000 | no |
129
-| autodetection_retry | Sets the job re-check interval in seconds. | 0 | no |
130
-| penalty | Indicates whether to apply penalty to update_every in case of failures. | yes | no |
131
-| name | Job name. This value will overwrite the `job_name` value. JOBS with the same name are mutually exclusive. Only one of them will be allowed running at any time. This allows autodetection to try several alternatives and pick the one that works. | | no |
132
-| hostname | Define a hostname where boinc is running. | localhost | no |
133
-| port | The port of boinc RPC interface. | | no |
134
-| password | Provide a password to connect to a boinc RPC interface. | | no |
135
-
136
-</details>
137
-
138
-#### Examples
139
-
140
-##### Configuration of a remote boinc instance
141
-
142
-A basic JOB configuration for a remote boinc instance
143
-
144
-```yaml
145
-remote:
146
- hostname: '1.2.3.4'
147
- port: 1234
148
- password: 'some-password'
149
-
150
-```
151
-##### Multi-instance
152
-
153
-> **Note**: When you define multiple jobs, their names must be unique.
154
-
155
-Collecting metrics from local and remote instances.
156
-
157
-
158
-<details open><summary>Config</summary>
159
-
160
-```yaml
161
-localhost:
162
- name: 'local'
163
- host: '127.0.0.1'
164
- port: 1234
165
- password: 'some-password'
166
-
167
-remote_job:
168
- name: 'remote'
169
- host: '192.0.2.1'
170
- port: 1234
171
- password: some-other-password
172
-
173
-```
174
-</details>
175
-
176
-
177
-
178
-## Troubleshooting
179
-
180
-### Debug Mode
181
-
182
-
183
-To troubleshoot issues with the `boinc` collector, run the `python.d.plugin` with the debug option enabled. The output
184
-should give you clues as to why the collector isn't working.
185
-
186
-- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on
187
- your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`.
188
-
189
- ```bash
190
- cd /usr/libexec/netdata/plugins.d/
191
- ```
192
-
193
-- Switch to the `netdata` user.
194
-
195
- ```bash
196
- sudo -u netdata -s
197
- ```
198
-
199
-- Run the `python.d.plugin` to debug the collector:
200
-
201
- ```bash
202
- ./python.d.plugin boinc debug trace
203
- ```
204
-
205
-### Getting Logs
206
-
207
-If you're encountering problems with the `boinc` collector, follow these steps to retrieve logs and identify potential issues:
208
-
209
-- **Run the command** specific to your system (systemd, non-systemd, or Docker container).
210
-- **Examine the output** for any warnings or error messages that might indicate issues. These messages should provide clues about the root cause of the problem.
211
-
212
-#### System with systemd
213
-
214
-Use the following command to view logs generated since the last Netdata service restart:
215
-
216
-```bash
217
-journalctl _SYSTEMD_INVOCATION_ID="$(systemctl show --value --property=InvocationID netdata)" --namespace=netdata --grep boinc
218
-```
219
-
220
-#### System without systemd
221
-
222
-Locate the collector log file, typically at `/var/log/netdata/collector.log`, and use `grep` to filter for collector's name:
223
-
224
-```bash
225
-grep boinc /var/log/netdata/collector.log
226
-```
227
-
228
-**Note**: This method shows logs from all restarts. Focus on the **latest entries** for troubleshooting current issues.
229
-
230
-#### Docker Container
231
-
232
-If your Netdata runs in a Docker container named "netdata" (replace if different), use this command:
233
-
234
-```bash
235
-docker logs netdata 2>&1 | grep boinc
236
-```
237
-
238
-
src/collectors/python.d.plugin/boinc/metadata.yaml
deleted
-198
@@ -1,198 +0,0 @@
1
-plugin_name: python.d.plugin
2
-modules:
3
- - meta:
4
- plugin_name: python.d.plugin
5
- module_name: boinc
6
- monitored_instance:
7
- name: BOINC
8
- link: "https://boinc.berkeley.edu/"
9
- categories:
10
- - data-collection.distributed-computing-systems
11
- icon_filename: "bolt.svg"
12
- related_resources:
13
- integrations:
14
- list: []
15
- info_provided_to_referring_integrations:
16
- description: ""
17
- keywords:
18
- - boinc
19
- - distributed
20
- most_popular: false
21
- overview:
22
- data_collection:
23
- metrics_description: "This collector monitors task counts for the Berkeley Open Infrastructure Networking Computing (BOINC) distributed computing client."
24
- method_description: "It uses the same RPC interface that the BOINC monitoring GUI does."
25
- supported_platforms:
26
- include: []
27
- exclude: []
28
- multi_instance: true
29
- additional_permissions:
30
- description: ""
31
- default_behavior:
32
- auto_detection:
33
- description: "By default, the module will try to auto-detect the password to the RPC interface by looking in `/var/lib/boinc` for this file (this is the location most Linux distributions use for a system-wide BOINC installation), so things may just work without needing configuration for a local system."
34
- limits:
35
- description: ""
36
- performance_impact:
37
- description: ""
38
- setup:
39
- prerequisites:
40
- list:
41
- - title: "Boinc RPC interface"
42
- description: BOINC requires use of a password to access it's RPC interface. You can find this password in the `gui_rpc_auth.cfg` file in your BOINC directory.
43
- configuration:
44
- file:
45
- name: python.d/boinc.conf
46
- options:
47
- description: |
48
- There are 2 sections:
49
-
50
- * Global variables
51
- * One or more JOBS that can define multiple different instances to monitor.
52
-
53
- The following options can be defined globally: priority, penalty, autodetection_retry, update_every, but can also be defined per JOB to override the global values.
54
-
55
- Additionally, the following collapsed table contains all the options that can be configured inside a JOB definition.
56
-
57
- Every configuration JOB starts with a `job_name` value which will appear in the dashboard, unless a `name` parameter is specified.
58
- folding:
59
- title: "Config options"
60
- enabled: true
61
- list:
62
- - name: update_every
63
- description: Sets the default data collection frequency.
64
- default_value: 5
65
- required: false
66
- - name: priority
67
- description: Controls the order of charts at the netdata dashboard.
68
- default_value: 60000
69
- required: false
70
- - name: autodetection_retry
71
- description: Sets the job re-check interval in seconds.
72
- default_value: 0
73
- required: false
74
- - name: penalty
75
- description: Indicates whether to apply penalty to update_every in case of failures.
76
- default_value: yes
77
- required: false
78
- - name: name
79
- description: Job name. This value will overwrite the `job_name` value. JOBS with the same name are mutually exclusive. Only one of them will be allowed running at any time. This allows autodetection to try several alternatives and pick the one that works.
80
- default_value: ""
81
- required: false
82
- - name: hostname
83
- description: Define a hostname where boinc is running.
84
- default_value: "localhost"
85
- required: false
86
- - name: port
87
- description: The port of boinc RPC interface.
88
- default_value: ""
89
- required: false
90
- - name: password
91
- description: Provide a password to connect to a boinc RPC interface.
92
- default_value: ""
93
- required: false
94
- examples:
95
- folding:
96
- enabled: true
97
- title: "Config"
98
- list:
99
- - name: Configuration of a remote boinc instance
100
- description: A basic JOB configuration for a remote boinc instance
101
- folding:
102
- enabled: false
103
- config: |
104
- remote:
105
- hostname: '1.2.3.4'
106
- port: 1234
107
- password: 'some-password'
108
- - name: Multi-instance
109
- description: |
110
- > **Note**: When you define multiple jobs, their names must be unique.
111
-
112
- Collecting metrics from local and remote instances.
113
- config: |
114
- localhost:
115
- name: 'local'
116
- host: '127.0.0.1'
117
- port: 1234
118
- password: 'some-password'
119
-
120
- remote_job:
121
- name: 'remote'
122
- host: '192.0.2.1'
123
- port: 1234
124
- password: some-other-password
125
- troubleshooting:
126
- problems:
127
- list: []
128
- alerts:
129
- - name: boinc_total_tasks
130
- link: https://github.com/netdata/netdata/blob/master/src/health/health.d/boinc.conf
131
- metric: boinc.tasks
132
- info: average number of total tasks over the last 10 minutes
133
- os: "*"
134
- - name: boinc_active_tasks
135
- link: https://github.com/netdata/netdata/blob/master/src/health/health.d/boinc.conf
136
- metric: boinc.tasks
137
- info: average number of active tasks over the last 10 minutes
138
- os: "*"
139
- - name: boinc_compute_errors
140
- link: https://github.com/netdata/netdata/blob/master/src/health/health.d/boinc.conf
141
- metric: boinc.states
142
- info: average number of compute errors over the last 10 minutes
143
- os: "*"
144
- - name: boinc_upload_errors
145
- link: https://github.com/netdata/netdata/blob/master/src/health/health.d/boinc.conf
146
- metric: boinc.states
147
- info: average number of failed uploads over the last 10 minutes
148
- os: "*"
149
- metrics:
150
- folding:
151
- title: Metrics
152
- enabled: false
153
- description: ""
154
- availability: []
155
- scopes:
156
- - name: global
157
- description: "These metrics refer to the entire monitored application."
158
- labels: []
159
- metrics:
160
- - name: boinc.tasks
161
- description: Overall Tasks
162
- unit: "tasks"
163
- chart_type: line
164
- dimensions:
165
- - name: Total
166
- - name: Active
167
- - name: boinc.states
168
- description: Tasks per State
169
- unit: "tasks"
170
- chart_type: line
171
- dimensions:
172
- - name: New
173
- - name: Downloading
174
- - name: Ready to Run
175
- - name: Compute Errors
176
- - name: Uploading
177
- - name: Uploaded
178
- - name: Aborted
179
- - name: Failed Uploads
180
- - name: boinc.sched
181
- description: Tasks per Scheduler State
182
- unit: "tasks"
183
- chart_type: line
184
- dimensions:
185
- - name: Uninitialized
186
- - name: Preempted
187
- - name: Scheduled
188
- - name: boinc.process
189
- description: Tasks per Process State
190
- unit: "tasks"
191
- chart_type: line
192
- dimensions:
193
- - name: Uninitialized
194
- - name: Executing
195
- - name: Suspended
196
- - name: Aborted
197
- - name: Quit
198
- - name: Copy Pending
src/collectors/python.d.plugin/python_modules/third_party/boinc_client.py
deleted
-515
@@ -1,515 +0,0 @@
1
-#!/usr/bin/env python
2
-# -*- coding: utf-8 -*-
3
-#
4
-# client.py - Somewhat higher-level GUI_RPC API for BOINC core client
5
-#
6
-# Copyright (C) 2013 Rodrigo Silva (MestreLion) <linux@rodrigosilva.com>
7
-# Copyright (C) 2017 Austin S. Hemmelgarn
8
-#
9
-# SPDX-License-Identifier: GPL-3.0
10
-
11
-# Based on client/boinc_cmd.cpp
12
-
13
-import hashlib
14
-import socket
15
-import sys
16
-import time
17
-from functools import total_ordering
18
-from xml.etree import ElementTree
19
-
20
-GUI_RPC_PASSWD_FILE = "/var/lib/boinc/gui_rpc_auth.cfg"
21
-
22
-GUI_RPC_HOSTNAME = None # localhost
23
-GUI_RPC_PORT = 31416
24
-GUI_RPC_TIMEOUT = 1
25
-
26
-class Rpc(object):
27
- ''' Class to perform GUI RPC calls to a BOINC core client.
28
- Usage in a context manager ('with' block) is recommended to ensure
29
- disconnect() is called. Using the same instance for all calls is also
30
- recommended so it reuses the same socket connection
31
- '''
32
- def __init__(self, hostname="", port=0, timeout=0, text_output=False):
33
- self.hostname = hostname
34
- self.port = port
35
- self.timeout = timeout
36
- self.sock = None
37
- self.text_output = text_output
38
-
39
- @property
40
- def sockargs(self):
41
- return (self.hostname, self.port, self.timeout)
42
-
43
- def __enter__(self): self.connect(*self.sockargs); return self
44
- def __exit__(self, *args): self.disconnect()
45
-
46
- def connect(self, hostname="", port=0, timeout=0):
47
- ''' Connect to (hostname, port) with timeout in seconds.
48
- Hostname defaults to None (localhost), and port to 31416
49
- Calling multiple times will disconnect previous connection (if any),
50
- and (re-)connect to host.
51
- '''
52
- if self.sock:
53
- self.disconnect()
54
-
55
- self.hostname = hostname or GUI_RPC_HOSTNAME
56
- self.port = port or GUI_RPC_PORT
57
- self.timeout = timeout or GUI_RPC_TIMEOUT
58
-
59
- self.sock = socket.create_connection(self.sockargs[0:2], self.sockargs[2])
60
-
61
- def disconnect(self):
62
- ''' Disconnect from host. Calling multiple times is OK (idempotent)
63
- '''
64
- if self.sock:
65
- self.sock.close()
66
- self.sock = None
67
-
68
- def call(self, request, text_output=None):
69
- ''' Do an RPC call. Pack and send the XML request and return the
70
- unpacked reply. request can be either plain XML text or a
71
- xml.etree.ElementTree.Element object. Return ElementTree.Element
72
- or XML text according to text_output flag.
73
- Will auto-connect if not connected.
74
- '''
75
- if text_output is None:
76
- text_output = self.text_output
77
-
78
- if not self.sock:
79
- self.connect(*self.sockargs)
80
-
81
- if not isinstance(request, ElementTree.Element):
82
- request = ElementTree.fromstring(request)
83
-
84
- # pack request
85
- end = '\003'
86
- if sys.version_info[0] < 3:
87
- req = "<boinc_gui_rpc_request>\n{0}\n</boinc_gui_rpc_request>\n{1}".format(ElementTree.tostring(request).replace(' />', '/>'), end)
88
- else:
89
- req = "<boinc_gui_rpc_request>\n{0}\n</boinc_gui_rpc_request>\n{1}".format(ElementTree.tostring(request, encoding='unicode').replace(' />', '/>'), end).encode()
90
-
91
- try:
92
- self.sock.sendall(req)
93
- except (socket.error, socket.herror, socket.gaierror, socket.timeout):
94
- raise
95
-
96
- req = ""
97
- while True:
98
- try:
99
- buf = self.sock.recv(8192)
100
- if not buf:
101
- raise socket.error("No data from socket")
102
- if sys.version_info[0] >= 3:
103
- buf = buf.decode()
104
- except socket.error:
105
- raise
106
- n = buf.find(end)
107
- if not n == -1: break
108
- req += buf
109
- req += buf[:n]
110
-
111
- # unpack reply (remove root tag, ie: first and last lines)
112
- req = '\n'.join(req.strip().rsplit('\n')[1:-1])
113
-
114
- if text_output:
115
- return req
116
- else:
117
- return ElementTree.fromstring(req)
118
-
119
-def setattrs_from_xml(obj, xml, attrfuncdict={}):
120
- ''' Helper to set values for attributes of a class instance by mapping
121
- matching tags from a XML file.
122
- attrfuncdict is a dict of functions to customize value data type of
123
- each attribute. It falls back to simple int/float/bool/str detection
124
- based on values defined in __init__(). This would not be needed if
125
- Boinc used standard RPC protocol, which includes data type in XML.
126
- '''
127
- if not isinstance(xml, ElementTree.Element):
128
- xml = ElementTree.fromstring(xml)
129
- for e in list(xml):
130
- if hasattr(obj, e.tag):
131
- attr = getattr(obj, e.tag)
132
- attrfunc = attrfuncdict.get(e.tag, None)
133
- if attrfunc is None:
134
- if isinstance(attr, bool): attrfunc = parse_bool
135
- elif isinstance(attr, int): attrfunc = parse_int
136
- elif isinstance(attr, float): attrfunc = parse_float
137
- elif isinstance(attr, str): attrfunc = parse_str
138
- elif isinstance(attr, list): attrfunc = parse_list
139
- else: attrfunc = lambda x: x
140
- setattr(obj, e.tag, attrfunc(e))
141
- else:
142
- pass
143
- #print "class missing attribute '%s': %r" % (e.tag, obj)
144
- return obj
145
-
146
-
147
-def parse_bool(e):
148
- ''' Helper to convert ElementTree.Element.text to boolean.
149
- Treat '<foo/>' (and '<foo>[[:blank:]]</foo>') as True
150
- Treat '0' and 'false' as False
151
- '''
152
- if e.text is None:
153
- return True
154
- else:
155
- return bool(e.text) and not e.text.strip().lower() in ('0', 'false')
156
-
157
-
158
-def parse_int(e):
159
- ''' Helper to convert ElementTree.Element.text to integer.
160
- Treat '<foo/>' (and '<foo></foo>') as 0
161
- '''
162
- # int(float()) allows casting to int a value expressed as float in XML
163
- return 0 if e.text is None else int(float(e.text.strip()))
164
-
165
-
166
-def parse_float(e):
167
- ''' Helper to convert ElementTree.Element.text to float. '''
168
- return 0.0 if e.text is None else float(e.text.strip())
169
-
170
-
171
-def parse_str(e):
172
- ''' Helper to convert ElementTree.Element.text to string. '''
173
- return "" if e.text is None else e.text.strip()
174
-
175
-
176
-def parse_list(e):
177
- ''' Helper to convert ElementTree.Element to list. For now, simply return
178
- the list of root element's children
179
- '''
180
- return list(e)
181
-
182
-
183
-class Enum(object):
184
- UNKNOWN = -1 # Not in original API
185
-
186
- @classmethod
187
- def name(cls, value):
188
- ''' Quick-and-dirty fallback for getting the "name" of an enum item '''
189
-
190
- # value as string, if it matches an enum attribute.
191
- # Allows short usage as Enum.name("VALUE") besides Enum.name(Enum.VALUE)
192
- if hasattr(cls, str(value)):
193
- return cls.name(getattr(cls, value, None))
194
-
195
- # value not handled in subclass name()
196
- for k, v in cls.__dict__.items():
197
- if v == value:
198
- return k.lower().replace('_', ' ')
199
-
200
- # value not found
201
- return cls.name(Enum.UNKNOWN)
202
-
203
-
204
-class CpuSched(Enum):
205
- ''' values of ACTIVE_TASK::scheduler_state and ACTIVE_TASK::next_scheduler_state
206
- "SCHEDULED" is synonymous with "executing" except when CPU throttling
207
- is in use.
208
- '''
209
- UNINITIALIZED = 0
210
- PREEMPTED = 1
211
- SCHEDULED = 2
212
-
213
-
214
-class ResultState(Enum):
215
- ''' Values of RESULT::state in client.
216
- THESE MUST BE IN NUMERICAL ORDER
217
- (because of the > comparison in RESULT::computing_done())
218
- see html/inc/common_defs.inc
219
- '''
220
- NEW = 0
221
- #// New result
222
- FILES_DOWNLOADING = 1
223
- #// Input files for result (WU, app version) are being downloaded
224
- FILES_DOWNLOADED = 2
225
- #// Files are downloaded, result can be (or is being) computed
226
- COMPUTE_ERROR = 3
227
- #// computation failed; no file upload
228
- FILES_UPLOADING = 4
229
- #// Output files for result are being uploaded
230
- FILES_UPLOADED = 5
231
- #// Files are uploaded, notify scheduling server at some point
232
- ABORTED = 6
233
- #// result was aborted
234
- UPLOAD_FAILED = 7
235
- #// some output file permanent failure
236
-
237
-
238
-class Process(Enum):
239
- ''' values of ACTIVE_TASK::task_state '''
240
- UNINITIALIZED = 0
241
- #// process doesn't exist yet
242
- EXECUTING = 1
243
- #// process is running, as far as we know
244
- SUSPENDED = 9
245
- #// we've sent it a "suspend" message
246
- ABORT_PENDING = 5
247
- #// process exceeded limits; send "abort" message, waiting to exit
248
- QUIT_PENDING = 8
249
- #// we've sent it a "quit" message, waiting to exit
250
- COPY_PENDING = 10
251
- #// waiting for async file copies to finish
252
-
253
-
254
-class _Struct(object):
255
- ''' base helper class with common methods for all classes derived from
256
- BOINC's C++ structs
257
- '''
258
- @classmethod
259
- def parse(cls, xml):
260
- return setattrs_from_xml(cls(), xml)
261
-
262
- def __str__(self, indent=0):
263
- buf = '{0}{1}:\n'.format('\t' * indent, self.__class__.__name__)
264
- for attr in self.__dict__:
265
- value = getattr(self, attr)
266
- if isinstance(value, list):
267
- buf += '{0}\t{1} [\n'.format('\t' * indent, attr)
268
- for v in value: buf += '\t\t{0}\t\t,\n'.format(v)
269
- buf += '\t]\n'
270
- else:
271
- buf += '{0}\t{1}\t{2}\n'.format('\t' * indent,
272
- attr,
273
- value.__str__(indent+2)
274
- if isinstance(value, _Struct)
275
- else repr(value))
276
- return buf
277
-
278
-
279
-@total_ordering
280
-class VersionInfo(_Struct):
281
- def __init__(self, major=0, minor=0, release=0):
282
- self.major = major
283
- self.minor = minor
284
- self.release = release
285
-
286
- @property
287
- def _tuple(self):
288
- return (self.major, self.minor, self.release)
289
-
290
- def __eq__(self, other):
291
- return isinstance(other, self.__class__) and self._tuple == other._tuple
292
-
293
- def __ne__(self, other):
294
- return not self.__eq__(other)
295
-
296
- def __gt__(self, other):
297
- if not isinstance(other, self.__class__):
298
- return NotImplemented
299
- return self._tuple > other._tuple
300
-
301
- def __str__(self):
302
- return "{0}.{1}.{2}".format(self.major, self.minor, self.release)
303
-
304
- def __repr__(self):
305
- return "{0}{1}".format(self.__class__.__name__, self._tuple)
306
-
307
-
308
-class Result(_Struct):
309
- ''' Also called "task" in some contexts '''
310
- def __init__(self):
311
- # Names and values follow lib/gui_rpc_client.h @ RESULT
312
- # Order too, except when grouping contradicts client/result.cpp
313
- # RESULT::write_gui(), then XML order is used.
314
-
315
- self.name = ""
316
- self.wu_name = ""
317
- self.version_num = 0
318
- #// identifies the app used
319
- self.plan_class = ""
320
- self.project_url = "" # from PROJECT.master_url
321
- self.report_deadline = 0.0 # seconds since epoch
322
- self.received_time = 0.0 # seconds since epoch
323
- #// when we got this from server
324
- self.ready_to_report = False
325
- #// we're ready to report this result to the server;
326
- #// either computation is done and all the files have been uploaded
327
- #// or there was an error
328
- self.got_server_ack = False
329
- #// we've received the ack for this result from the server
330
- self.final_cpu_time = 0.0
331
- self.final_elapsed_time = 0.0
332
- self.state = ResultState.NEW
333
- self.estimated_cpu_time_remaining = 0.0
334
- #// actually, estimated elapsed time remaining
335
- self.exit_status = 0
336
- #// return value from the application
337
- self.suspended_via_gui = False
338
- self.project_suspended_via_gui = False
339
- self.edf_scheduled = False
340
- #// temporary used to tell GUI that this result is deadline-scheduled
341
- self.coproc_missing = False
342
- #// a coproc needed by this job is missing
343
- #// (e.g. because user removed their GPU board).
344
- self.scheduler_wait = False
345
- self.scheduler_wait_reason = ""
346
- self.network_wait = False
347
- self.resources = ""
348
- #// textual description of resources used
349
-
350
- #// the following defined if active
351
- # XML is generated in client/app.cpp ACTIVE_TASK::write_gui()
352
- self.active_task = False
353
- self.active_task_state = Process.UNINITIALIZED
354
- self.app_version_num = 0
355
- self.slot = -1
356
- self.pid = 0
357
- self.scheduler_state = CpuSched.UNINITIALIZED
358
- self.checkpoint_cpu_time = 0.0
359
- self.current_cpu_time = 0.0
360
- self.fraction_done = 0.0
361
- self.elapsed_time = 0.0
362
- self.swap_size = 0
363
- self.working_set_size_smoothed = 0.0
364
- self.too_large = False
365
- self.needs_shmem = False
366
- self.graphics_exec_path = ""
367
- self.web_graphics_url = ""
368
- self.remote_desktop_addr = ""
369
- self.slot_path = ""
370
- #// only present if graphics_exec_path is
371
-
372
- # The following are not in original API, but are present in RPC XML reply
373
- self.completed_time = 0.0
374
- #// time when ready_to_report was set
375
- self.report_immediately = False
376
- self.working_set_size = 0
377
- self.page_fault_rate = 0.0
378
- #// derived by higher-level code
379
-
380
- # The following are in API, but are NEVER in RPC XML reply. Go figure
381
- self.signal = 0
382
-
383
- self.app = None # APP*
384
- self.wup = None # WORKUNIT*
385
- self.project = None # PROJECT*
386
- self.avp = None # APP_VERSION*
387
-
388
- @classmethod
389
- def parse(cls, xml):
390
- if not isinstance(xml, ElementTree.Element):
391
- xml = ElementTree.fromstring(xml)
392
-
393
- # parse main XML
394
- result = super(Result, cls).parse(xml)
395
-
396
- # parse '<active_task>' children
397
- active_task = xml.find('active_task')
398
- if active_task is None:
399
- result.active_task = False # already the default after __init__()
400
- else:
401
- result.active_task = True # already the default after main parse
402
- result = setattrs_from_xml(result, active_task)
403
-
404
- #// if CPU time is nonzero but elapsed time is zero,
405
- #// we must be talking to an old client.
406
- #// Set elapsed = CPU
407
- #// (easier to deal with this here than in the manager)
408
- if result.current_cpu_time != 0 and result.elapsed_time == 0:
409
- result.elapsed_time = result.current_cpu_time
410
-
411
- if result.final_cpu_time != 0 and result.final_elapsed_time == 0:
412
- result.final_elapsed_time = result.final_cpu_time
413
-
414
- return result
415
-
416
- def __str__(self):
417
- buf = '{0}:\n'.format(self.__class__.__name__)
418
- for attr in self.__dict__:
419
- value = getattr(self, attr)
420
- if attr in ['received_time', 'report_deadline']:
421
- value = time.ctime(value)
422
- buf += '\t{0}\t{1}\n'.format(attr, value)
423
- return buf
424
-
425
-
426
-class BoincClient(object):
427
-
428
- def __init__(self, host="", port=0, passwd=None):
429
- self.hostname = host
430
- self.port = port
431
- self.passwd = passwd
432
- self.rpc = Rpc(text_output=False)
433
- self.version = None
434
- self.authorized = False
435
-
436
- # Informative, not authoritative. Records status of *last* RPC call,
437
- # but does not infer success about the *next* one.
438
- # Thus, it should be read *after* an RPC call, not prior to one
439
- self.connected = False
440
-
441
- def __enter__(self): self.connect(); return self
442
- def __exit__(self, *args): self.disconnect()
443
-
444
- def connect(self):
445
- try:
446
- self.rpc.connect(self.hostname, self.port)
447
- self.connected = True
448
- except socket.error:
449
- self.connected = False
450
- return
451
- self.authorized = self.authorize(self.passwd)
452
- self.version = self.exchange_versions()
453
-
454
- def disconnect(self):
455
- self.rpc.disconnect()
456
-
457
- def authorize(self, password):
458
- ''' Request authorization. If password is None and we are connecting
459
- to localhost, try to read password from the local config file
460
- GUI_RPC_PASSWD_FILE. If file can't be read (not found or no
461
- permission to read), try to authorize with a blank password.
462
- If authorization is requested and fails, all subsequent calls
463
- will be refused with socket.error 'Connection reset by peer' (104).
464
- Since most local calls do no require authorization, do not attempt
465
- it if you're not sure about the password.
466
- '''
467
- if password is None and not self.hostname:
468
- password = read_gui_rpc_password() or ""
469
- nonce = self.rpc.call('<auth1/>').text
470
- authhash = hashlib.md5('{0}{1}'.format(nonce, password).encode()).hexdigest().lower()
471
- reply = self.rpc.call('<auth2><nonce_hash>{0}</nonce_hash></auth2>'.format(authhash))
472
-
473
- if reply.tag == 'authorized':
474
- return True
475
- else:
476
- return False
477
-
478
- def exchange_versions(self):
479
- ''' Return VersionInfo instance with core client version info '''
480
- return VersionInfo.parse(self.rpc.call('<exchange_versions/>'))
481
-
482
- def get_tasks(self):
483
- ''' Same as get_results(active_only=False) '''
484
- return self.get_results(False)
485
-
486
- def get_results(self, active_only=False):
487
- ''' Get a list of results.
488
- Those that are in progress will have information such as CPU time
489
- and fraction done. Each result includes a name;
490
- Use CC_STATE::lookup_result() to find this result in the current static state;
491
- if it's not there, call get_state() again.
492
- '''
493
- reply = self.rpc.call("<get_results><active_only>{0}</active_only></get_results>".format(1 if active_only else 0))
494
- if not reply.tag == 'results':
495
- return []
496
-
497
- results = []
498
- for item in list(reply):
499
- results.append(Result.parse(item))
500
-
501
- return results
502
-
503
-
504
-def read_gui_rpc_password():
505
- ''' Read password string from GUI_RPC_PASSWD_FILE file, trim the last CR
506
- (if any), and return it
507
- '''
508
- try:
509
- with open(GUI_RPC_PASSWD_FILE, 'r') as f:
510
- buf = f.read()
511
- if buf.endswith('\n'): return buf[:-1] # trim last CR
512
- else: return buf
513
- except IOError:
514
- # Permission denied or File not found.
515
- pass