init
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.vscode/
|
||||||
|
venv/
|
||||||
|
__pycache__/
|
||||||
3
collect.py
Executable file
3
collect.py
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
from collector import *
|
||||||
27
collector.json
Normal file
27
collector.json
Normal 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
71
collector/__init__.py
Normal 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
41
collector/collector.py
Normal 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
14
collector/helper.py
Normal 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
14
collector/sender.py
Normal 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)
|
||||||
Reference in New Issue
Block a user