Skip to content

Commit

Permalink
Merge pull request #4 from danielringch/release/1.1.0
Browse files Browse the repository at this point in the history
Release/1.1.0
  • Loading branch information
danielringch authored Mar 29, 2023
2 parents cb79722 + 36d8ef3 commit 61d716c
Show file tree
Hide file tree
Showing 19 changed files with 509 additions and 233 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM python:3.11-slim
FROM python:3.9

WORKDIR /

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ The hardware related plugins will only work on linux. All other should run on an
- Storj
- [storjnode](docu/plugin/storjnode.md): Storj node monitoring using the storj API. Includes storage and traffic statistics and financial reporting.
- Drive management
- [diskfree](docu/plugin/diskfree.md): Disk free space monitoring.
- [pingdrive](docu/plugin/pingdrive.md): Supervises disk activity and pings drives if too inactive. Prevents head parking and sends alerts in case of drives going offline.
- [smartctl](docu/plugin/smartctl.md): Checks drive health using S.M.A.R.T. and provides some logging.
- General
Expand Down
10 changes: 10 additions & 0 deletions config/plugin/diskfree.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: "my_diskfree" #unique name
check_interval: "0 0 * * *" #cron schedule expression
alert_mute_interval: 24 #hours
drives:
- "/mnt/foo": #optional
minimum_space: "10G" #bytes or percent
delete: "/mnt/foo/*.txt" #optional
- "/mnt/bar": #optional
minimum_space: "5%" #bytes or percent
delete: "/mnt/bar/*.zip" #optional
7 changes: 5 additions & 2 deletions config/plugin/flexpool.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,8 @@ check_interval: "0 * * * *" #cron schedule expression
alert_mute_interval: 24 #hours
address: "xch1fh6f088cxcvqscy4xtxfq7762vhsh9mjcql6m3svfhmlxsc3jd4sd37xdl"
currency: "USD"
worker_blacklist: #optional
- "my_unimportant_worker"
workers:
my_worker_1:
maximum_offline_time: 0.5 #hours
my_worker_2:
maximum_offline_time: 1.0 #hours
39 changes: 39 additions & 0 deletions docu/plugin/diskfree.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# The Xiamon diskfree plugin

This plugin checks the free space at configured locations and can also delete files based on a pattern if necessary.
This plugin is mainly intented to be used with expendable data which can be removed if more space is needed. E.g. the free space of a drive used by Sia or Storj may be used by Chia plot files.

## **Configuration template**

The basic configuration information can be found [here](../config_basics.md).

```yaml
name: "my_diskfree" #unique name
check_interval: "0 0 * * *" #cron schedule expression
alert_mute_interval: 24 #hours
drives:
- "/mnt/foo": #optional
minimum_space: "10G" #bytes or percent
delete: "/mnt/foo/*.txt" #optional
- "/mnt/bar": #optional
minimum_space: "5%" #bytes or percent
delete: "/mnt/bar/*.zip" #optional
```
## **Setup**
The locations to check are added as list item to the key **drives**. The path is used as key.
Per location, the **minimum_space** can be configured as either a relative (suffix: %) or an absolute (optional suffix: k, M, G, T, P) value.
If the key **delete** is given, files matching the pattern are deleted until the minimum free space is reached again.
## **Check**
The plugin checks the free space of all configured locations.
If a file gets deleted, a message is sent to the **info** channel.
If the free space of a location falls below its minimum value, an **alert** is sent.
The [execution interval](../config_basics.md) is set by the key **check_interval**.
7 changes: 5 additions & 2 deletions docu/plugin/flexfarmer.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ output_path: "~/myArchive"
The path of the flexfarmer log file is set by the key **database**.
All entries looking like an error message are archived by the plugin. This makes it possible to spot things like corrupt plot files etc. easily. The directory to the archive is set by the key **output_path**.
All entries looking like a relevant error message are archived by the plugin. This makes it possible to spot things like corrupt plot files etc. easily. The directory to the archive is set by the key **output_path**.
## **Summary**
Expand All @@ -26,6 +26,9 @@ A summary is sent to the **info** channel and contains the following information
- Accepted partials
- Stale partials
- Invalid partials
- Lookup times
The k-size of the plots is taken into account for partials calculation, while the difficulty is not. This means that a partial from a k33 plot with difficulty of 10 is recognized as 2 partials by this plugin, but as 20 partials by flexpool.
The lookup times for signage points and partials are sent to the **debug** channel.
The [execution interval](../config_basics.md) is set by the key **interval**.
13 changes: 9 additions & 4 deletions docu/plugin/flexpool.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@ check_interval: "0 * * * *" #cron schedule expression
alert_mute_interval: 24 #hours
address: "xch1fh6f088cxcvqscy4xtxfq7762vhsh9mjcql6m3svfhmlxsc3jd4sd37xdl"
currency: "USD"
worker_blacklist: #optional
- "my_unimportant_worker"
workers:
my_worker_1:
maximum_offline_time: 0.5 #hours
my_worker_2:
maximum_offline_time: 1.0 #hours
```
## **Basic setup**
Expand All @@ -23,11 +26,13 @@ The farm is configured by its payout address with the key **address**.
The desired fiat currency is set by the key **currency**. The currencies `EUR` and `USD` are supported.

If the netspace of a worker is too small, it might get detected offline by flexpool from time to time. In this case, it can be added to the **worker_blacklist**.
Workers which are added to the key **workers** get monitored for their online status.

High difficulty settings can make flexpools offline worker detection unreliable. For that reason, this plugin calculates its own online status based on the timestamp of the last submitted partial. The maximum time period a worker can not send a partial before being detected as offline is set per worker by the key **maximum_offline_time**.

## **Check**

The plugin checks the status of all workers and sends an alert if a worker is detected as offline by flexpool.
The plugin checks the status of all configured workers and sends an alert if a worker is detected as offline.

The [execution interval](../config_basics.md) is set by the key **check_interval**.

Expand Down
18 changes: 18 additions & 0 deletions xiamon/src/core/conversions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import re
from datetime import datetime, timedelta
from enum import Enum

Expand Down Expand Up @@ -26,6 +27,16 @@

class Conversions:

@staticmethod
def to_seconds(time):
value, unit = re.match('([\\d\\.]+)(\\D+)', time).groups()
if unit == 's':
return float(value)
elif unit == 'ms':
return float(value) / 1000.0
else:
raise ValueError()

@staticmethod
def byte_to_megabyte(bytes):
return bytes / 1048576
Expand Down Expand Up @@ -56,6 +67,13 @@ def byte_to_auto(bytes, binary=True):
def bit_to_auto(bits):
value, prefix = Conversions.autorange(bits, 1024)
return value, f'{prefix}bit'

@staticmethod
def to_byte(bytes, unit, binary=True):
if unit not in prefixes_upwards:
return None
factor = ((1024 if binary else 1000) ** prefixes_upwards[unit])
return bytes * factor

@staticmethod
def mojo_to_xch(mojo):
Expand Down
12 changes: 10 additions & 2 deletions xiamon/src/interfaces/logfile/logfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,20 @@
from .datesorter import Datesorter
from .pluginsorter import Pluginsorter

LOGFILE_INSTANCE_COUNT = 0

class Logfile(Interface):
def __init__(self, config, scheduler):
super(Logfile, self).__init__()
config_data = Config(config)
print('[logfile] Logfile loading')

global LOGFILE_INSTANCE_COUNT
unique_name = f'logfile_{LOGFILE_INSTANCE_COUNT}'
LOGFILE_INSTANCE_COUNT += 1
flush_job = f'{unique_name}-flush'
daychange_job = f'{unique_name}-daychange'

self.__date_sorters = otherdefaultdict(lambda x: Datesorter(x))
self.__plugin_sorters = otherdefaultdict(lambda x: Pluginsorter(x))
self.__channels = {}
Expand All @@ -27,8 +35,8 @@ def __init__(self, config, scheduler):
config_data.get(None, name, 'whitelist'),
config_data.get(None, name, 'blacklist'))

scheduler.add_job('logfile-flush', self.__flush, "* * * * *")
scheduler.add_job('logfile-daychange' ,self.__handle_day_change, '0 0 * * *')
scheduler.add_job(flush_job, self.__flush, "* * * * *")
scheduler.add_job(daychange_job ,self.__handle_day_change, '0 0 * * *')

async def start(self):
channels = ','.join(self.channel_names[x] for x in self.__channels.keys())
Expand Down
1 change: 1 addition & 0 deletions xiamon/src/plugins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .chiaharvester import *
from .chianode import *
from .chiawallet import *
from .diskfree import *
from .flexfarmer import *
from .flexpool import *
from .pingdrive import *
Expand Down
2 changes: 2 additions & 0 deletions xiamon/src/plugins/diskfree/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .diskfree import Diskfree
from .filleddisk import FilledDisk
24 changes: 24 additions & 0 deletions xiamon/src/plugins/diskfree/diskfree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

from ...core import Plugin, Config
from .filleddisk import FilledDisk

class Diskfree(Plugin):

def __init__(self, config, scheduler, outputs):
config_data = Config(config)
name = config_data.get('diskfree', 'name')
super(Diskfree, self).__init__(name, outputs)
self.print(f'Plugin diskfree; name: {name}')

alert_mute_intervall = config_data.get(24, 'alert_mute_interval')
self.__drives = {}

for drive_block in config_data.data['drives']:
for path, drive_config in drive_block.items():
self.__drives[path] = FilledDisk(self, path, drive_config, alert_mute_intervall)

scheduler.add_job(f'{name}-check', self.check, config_data.get('0 * * * *', 'check_interval'))

async def check(self):
for drive in self.__drives.values():
drive.check()
64 changes: 64 additions & 0 deletions xiamon/src/plugins/diskfree/filleddisk.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import os, shutil, glob
from ...core.conversions import Conversions
from ...core.alert import Alert

class FilledDisk:

def __init__(self, plugin, path, config, mute_interval):

self.__plugin = plugin
self.__path = path
self.__full_alert = Alert(plugin, mute_interval)
raw_minimum_space = config['minimum_space']
if raw_minimum_space.endswith('%'):
abs_space, _, _ = shutil.disk_usage(self.__path)
self.__min_space = abs_space * float(raw_minimum_space[:-1]) / 100.0
else:
if raw_minimum_space[-1].isdigit():
unit = ""
bytes = float(raw_minimum_space)
else:
unit = raw_minimum_space[-1]
bytes = float(raw_minimum_space[:-1])
self.__min_space = Conversions.to_byte(bytes, unit)
self.__delete = config.setdefault('delete', None)

def check(self):
while True:
_, _, free_space = shutil.disk_usage(self.__path)

if free_space >= self.__min_space:
self.__plugin.msg.debug('Free space at {0}: {1[0]:.2f} {1[1]}'.format(self.__path, Conversions.byte_to_auto(free_space)))
self.__full_alert.reset(f'Free space at {self.__path} meets its minimum value again.')
break;

normalized_free_space = Conversions.byte_to_auto(free_space)
normalized_min_space = Conversions.bit_to_auto(self.__min_space)
low_space_message = 'Low free space at {0}: {1[0]:.2f} {1[1]} required, {2[0]:.2f} {2[1]} available.'.format(
self.__path,
normalized_min_space,
normalized_free_space
)
self.__plugin.msg.debug(low_space_message)

if not self.__try_delete():
self.__full_alert.send(low_space_message)
break

def __try_delete(self):
if self.__delete is None:
return False
candidates = glob.glob(self.__delete)
if len(candidates) == 0:
return False
file_to_delete = candidates[0]
try:
os.remove(file_to_delete)
delete_message = f'Deleted file {file_to_delete}.'
self.__plugin.msg.debug(delete_message)
self.__plugin.msg.info(delete_message)
return True
except:
self.__plugin.msg.error(f'Failed to delete file {file_to_delete}')
return False

Loading

0 comments on commit 61d716c

Please sign in to comment.