This commit is contained in:
ducoterra
2020-04-05 14:15:31 -04:00
commit bcaf5144fb
7 changed files with 173 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.vscode/
venv/
__pycache__/

3
collect.py Executable file
View File

@@ -0,0 +1,3 @@
#!/usr/bin/env python3
from collector import *

27
collector.json Normal file
View File

@@ -0,0 +1,27 @@
{
"graphite": {
"server": "graphite.ducoterra.net",
"port": 2003
},
"os": "osx",
"data": {
"storage": [
{
"path": "/Users/ducoterra",
"name": "home"
},
{
"path": ".",
"name": "curdir"
},
{
"path": "..",
"name": "outdir"
},
{
"path": "/Users",
"name": "users"
}
]
}
}

71
collector/__init__.py Normal file
View File

@@ -0,0 +1,71 @@
import os
import sys
import json
import functools
from collector.sender import send
from collector.collector import *
from collector.helper import *
CONFIG_FILE = os.getenv("COLLECTOR_CONF", "collector.json")
REQUIRED = ["graphite","os","data"]
VALID_DATAPOINTS = ["storage"]
VALID_OS = ["linux", "osx"]
REQUIRED_STORAGE = ["path", "name"]
CONFIG = {}
HOSTNAME = get_hostname()
with open(CONFIG_FILE) as f:
CONFIG = json.loads(f.read())
# Check top level
missing = get_missing(REQUIRED, CONFIG.keys())
if len(missing) > 0:
print(f"Missing: {', '.join(missing)}")
sys.exit(1)
# Now that we know we have a graphite server
sender = functools.partial(
send,
server = CONFIG["graphite"]["server"],
port = CONFIG["graphite"]["port"]
)
# Check data exists
data = CONFIG["data"]
if type(data) != dict:
print("Config at 'data' missing values.")
sys.exit(1)
data_points = data.keys()
if not len(data_points) > 0:
print("No data points found in config.")
sys.exit(1)
unknown = get_missing(data_points, VALID_DATAPOINTS)
if len(unknown) > 0:
print(f"Unknown data: {', '.join(unknown)}")
sys.exit(1)
# Check storage
if "storage" in data_points:
storage_data = data["storage"]
# Check if storage is a list
if type(storage_data) != list:
print("storage data must be a list")
sys.exit(1)
# Check if storage is not empty
if not len(storage_data) > 0:
print("Storage data cannot be empty")
sys.exit(1)
for item in storage_data:
# Check if the storage item is a dict
if type(item) != dict:
print(f"Storage data at {item} is not an object.")
# Make sure each storage item has the required fields
missing = get_missing(REQUIRED_STORAGE, item.keys())
if len(missing) > 0:
print(f"Storage data at {item} missing: {', '.join(missing)}")
# Collect data
else:
name = item["name"]
path = item["path"]
storage_sender = functools.partial(sender, f"{HOSTNAME}.storage.{name}")
thread(collect_storage, storage_sender, path)

41
collector/collector.py Normal file
View File

@@ -0,0 +1,41 @@
#!/usr/bin/env python
import threading
import subprocess
import re
import functools
import random
import time
from .sender import send
# Disk Space
# CPU
# MEM
# Temperatures
# Network in/out
# Backups (Plus 5 day forecast)
def handle_stdout(stdout):
return stdout.decode("utf-8").strip()
def nice_run(*args, **kwargs):
run = subprocess.run(*args, capture_output=True, **kwargs)
return handle_stdout(run.stdout)
def get_hostname():
return nice_run(["hostname"])
def clean_storage(storage):
group = re.search(r"([0-9]*.?[0-9]+[\w]+)", storage)
return group.group(1)
def collect_temp():
pass
def collect_compute():
pass
def collect_storage(path):
storage = nice_run(["du", "-sk", path])
return clean_storage(storage)

14
collector/helper.py Normal file
View File

@@ -0,0 +1,14 @@
import functools
import threading
def thread(func, after, *args, **kwargs):
func = functools.partial(func, *args, **kwargs)
call = lambda after, func: after(func())
t = threading.Thread(
target = call,
args = (after, func)
)
t.start()
def get_missing(required, provided):
return list(filter(lambda item: item not in provided, required))

14
collector/sender.py Normal file
View File

@@ -0,0 +1,14 @@
#!/usr/bin/env python
import socket
import time
def send(metric, data, server = None, port = None):
received = int(time.time())
with socket.socket() as sock:
msg = f"{metric} {data} {received}\n"
# msg = f"mainframe.temp 40 {received}\n"
msg = msg.encode("utf-8")
sock.connect((server, port))
sock.sendall(msg)