Compare commits
No commits in common. "master" and "l4d2_the_next" have entirely different histories.
master
...
l4d2_the_n
117 changed files with 1705 additions and 7450 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -2,4 +2,3 @@
|
|||
.venv
|
||||
.cache
|
||||
*.pyc
|
||||
.bw_debug_history
|
||||
|
|
@ -1,148 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from argparse import ArgumentParser
|
||||
from time import sleep
|
||||
|
||||
from bundlewrap.exceptions import RemoteException
|
||||
from bundlewrap.utils.cmdline import get_target_nodes
|
||||
from bundlewrap.utils.ui import io
|
||||
from bundlewrap.repo import Repository
|
||||
from os.path import realpath, dirname
|
||||
|
||||
|
||||
# parse args
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument("targets", nargs="*", default=['bundle:routeros'], help="bw nodes selector")
|
||||
parser.add_argument("--yes", action="store_true", default=False, help="skip confirmation prompts")
|
||||
args = parser.parse_args()
|
||||
|
||||
|
||||
def wait_up(node):
|
||||
sleep(5)
|
||||
while True:
|
||||
try:
|
||||
node.run_routeros('/system/resource/print')
|
||||
except RemoteException:
|
||||
sleep(2)
|
||||
continue
|
||||
else:
|
||||
io.debug(f"{node.name}: is up")
|
||||
sleep(10)
|
||||
return
|
||||
|
||||
|
||||
def upgrade_switch_os(node):
|
||||
# get versions for comparison
|
||||
with io.job(f"{node.name}: checking OS version"):
|
||||
response = node.run_routeros('/system/package/update/check-for-updates').raw[-1]
|
||||
installed_os = bw.libs.version.Version(response['installed-version'])
|
||||
latest_os = bw.libs.version.Version(response['latest-version'])
|
||||
io.debug(f"{node.name}: installed: {installed_os} >= latest: {latest_os}")
|
||||
|
||||
# compare versions
|
||||
if installed_os >= latest_os:
|
||||
# os is up to date
|
||||
io.stdout(f"{node.name}: os up to date ({installed_os})")
|
||||
else:
|
||||
# confirm os upgrade
|
||||
if not args.yes and not io.ask(
|
||||
f"{node.name}: upgrade os from {installed_os} to {latest_os}?", default=True
|
||||
):
|
||||
io.stdout(f"{node.name}: skipped by user")
|
||||
return
|
||||
|
||||
# download os
|
||||
with io.job(f"{node.name}: downloading OS"):
|
||||
response = node.run_routeros('/system/package/update/download').raw[-1]
|
||||
io.debug(f"{node.name}: OS upgrade download response: {response['status']}")
|
||||
|
||||
# install and wait for reboot
|
||||
with io.job(f"{node.name}: upgrading OS"):
|
||||
try:
|
||||
response = node.run_routeros('/system/package/update/install').raw[-1]
|
||||
except RemoteException:
|
||||
pass
|
||||
wait_up(node)
|
||||
|
||||
# verify new os version
|
||||
with io.job(f"{node.name}: checking new OS version"):
|
||||
new_os = bw.libs.version.Version(node.run_routeros('/system/package/update/check-for-updates').raw[-1]['installed-version'])
|
||||
if new_os == latest_os:
|
||||
io.stdout(f"{node.name}: OS successfully upgraded from {installed_os} to {new_os}")
|
||||
else:
|
||||
raise Exception(f"{node.name}: OS upgrade failed, expected {latest_os}, got {new_os}")
|
||||
|
||||
|
||||
def upgrade_switch_firmware(node):
|
||||
# get versions for comparison
|
||||
with io.job(f"{node.name}: checking Firmware version"):
|
||||
response = node.run_routeros('/system/routerboard/print').raw[-1]
|
||||
current_firmware = bw.libs.version.Version(response['current-firmware'])
|
||||
upgrade_firmware = bw.libs.version.Version(response['upgrade-firmware'])
|
||||
io.debug(f"{node.name}: firmware installed: {current_firmware}, upgrade: {upgrade_firmware}")
|
||||
|
||||
# compare versions
|
||||
if current_firmware >= upgrade_firmware:
|
||||
# firmware is up to date
|
||||
io.stdout(f"{node.name}: firmware is up to date ({current_firmware})")
|
||||
else:
|
||||
# confirm firmware upgrade
|
||||
if not args.yes and not io.ask(
|
||||
f"{node.name}: upgrade firmware from {current_firmware} to {upgrade_firmware}?", default=True
|
||||
):
|
||||
io.stdout(f"{node.name}: skipped by user")
|
||||
return
|
||||
|
||||
# upgrade firmware
|
||||
with io.job(f"{node.name}: upgrading Firmware"):
|
||||
node.run_routeros('/system/routerboard/upgrade')
|
||||
|
||||
# reboot and wait
|
||||
with io.job(f"{node.name}: rebooting"):
|
||||
try:
|
||||
node.run_routeros('/system/reboot')
|
||||
except RemoteException:
|
||||
pass
|
||||
wait_up(node)
|
||||
|
||||
# verify firmware version
|
||||
new_firmware = bw.libs.version.Version(node.run_routeros('/system/routerboard/print').raw[-1]['current-firmware'])
|
||||
if new_firmware == upgrade_firmware:
|
||||
io.stdout(f"{node.name}: firmware successfully upgraded from {current_firmware} to {new_firmware}")
|
||||
else:
|
||||
raise Exception(f"firmware upgrade failed, expected {upgrade_firmware}, got {new_firmware}")
|
||||
|
||||
|
||||
def upgrade_switch(node):
|
||||
with io.job(f"{node.name}: checking"):
|
||||
# check if routeros
|
||||
if node.os != 'routeros':
|
||||
io.progress_advance(2)
|
||||
io.stdout(f"{node.name}: skipped, unsupported os {node.os}")
|
||||
return
|
||||
|
||||
# check switch reachability
|
||||
try:
|
||||
node.run_routeros('/system/resource/print')
|
||||
except RemoteException as error:
|
||||
io.progress_advance(2)
|
||||
io.stdout(f"{node.name}: skipped, error {error}")
|
||||
return
|
||||
|
||||
upgrade_switch_os(node)
|
||||
io.progress_advance(1)
|
||||
|
||||
upgrade_switch_firmware(node)
|
||||
io.progress_advance(1)
|
||||
|
||||
|
||||
with io:
|
||||
bw = Repository(dirname(dirname(realpath(__file__))))
|
||||
|
||||
nodes = get_target_nodes(bw, args.targets)
|
||||
|
||||
io.progress_set_total(len(nodes) * 2)
|
||||
io.stdout(f"upgrading {len(nodes)} switches: {', '.join([node.name for node in sorted(nodes)])}")
|
||||
|
||||
for node in sorted(nodes):
|
||||
upgrade_switch(node)
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from bundlewrap.repo import Repository
|
||||
from os.path import realpath, dirname
|
||||
|
||||
import argparse
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('node', help='Node to generate passwords for')
|
||||
args = parser.parse_args()
|
||||
|
||||
bw = Repository(dirname(dirname(realpath(__file__))))
|
||||
node = bw.get_node(args.node)
|
||||
|
||||
if node.password:
|
||||
print(f"password: {node.password}")
|
||||
|
||||
for metadata_key in sorted([
|
||||
'users/root/password',
|
||||
]):
|
||||
if value := node.metadata.get(metadata_key, None):
|
||||
print(f"{metadata_key}: {value}")
|
||||
|
|
@ -3,4 +3,4 @@
|
|||
from bundlewrap.repo import Repository
|
||||
from os.path import realpath, dirname
|
||||
|
||||
bw = Repository(dirname(dirname(realpath(__file__))))
|
||||
repo = Repository(dirname(dirname(realpath(__file__))))
|
||||
|
|
|
|||
|
|
@ -1,132 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from bundlewrap.repo import Repository
|
||||
from os.path import realpath, dirname
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, List
|
||||
|
||||
bw = Repository(dirname(dirname(realpath(__file__))))
|
||||
|
||||
VAULT=bw.vault.decrypt('encrypt$gAAAAABpLgX_xxb5NmNCl3cgHM0JL65GT6PHVXO5gwly7IkmWoEgkCDSuAcSAkNFB8Tb4RdnTdpzVQEUL1XppTKVto_O7_b11GjATiyQYiSfiQ8KZkTKLvk=').value
|
||||
BW_TAG = "bw"
|
||||
BUNDLEWRAP_FIELD_LABEL = "bundlewrap node id"
|
||||
|
||||
|
||||
@dataclass
|
||||
class OpResult:
|
||||
stdout: str
|
||||
stderr: str
|
||||
returncode: int
|
||||
|
||||
|
||||
def main():
|
||||
for node in bw.nodes_in_group('routeros'):
|
||||
upsert_node_item(
|
||||
node_name=node.name,
|
||||
node_uuid=node.metadata.get('id'),
|
||||
username=node.username,
|
||||
password=node.password,
|
||||
url=f'http://{node.hostname}',
|
||||
)
|
||||
|
||||
|
||||
def run_op(args):
|
||||
proc = subprocess.run(
|
||||
["op", "--vault", VAULT] + args,
|
||||
env=os.environ.copy(),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError(
|
||||
f"op {' '.join(args)} failed with code {proc.returncode}:\n"
|
||||
f"STDOUT:\n{proc.stdout}\n\nSTDERR:\n{proc.stderr}"
|
||||
)
|
||||
|
||||
return OpResult(stdout=proc.stdout, stderr=proc.stderr, returncode=proc.returncode)
|
||||
|
||||
|
||||
def op_item_list_bw():
|
||||
out = run_op([
|
||||
"item", "list",
|
||||
"--tags", BW_TAG,
|
||||
"--format", "json",
|
||||
])
|
||||
stdout = out.stdout.strip()
|
||||
return json.loads(stdout) if stdout else []
|
||||
|
||||
|
||||
def op_item_get(item_id):
|
||||
args = ["item", "get", item_id, "--format", "json"]
|
||||
return json.loads(run_op(args).stdout)
|
||||
|
||||
|
||||
def op_item_create(title, node_uuid, username, password, url):
|
||||
print(f"creating {title}")
|
||||
return json.loads(run_op([
|
||||
"item", "create",
|
||||
"--category", "LOGIN",
|
||||
"--title", title,
|
||||
"--tags", BW_TAG,
|
||||
"--url", url,
|
||||
"--format", "json",
|
||||
f"username={username}",
|
||||
f"password={password}",
|
||||
f"{BUNDLEWRAP_FIELD_LABEL}[text]={node_uuid}",
|
||||
]).stdout)
|
||||
|
||||
|
||||
def op_item_edit(item_id, title, username, password, url):
|
||||
print(f"updating {title}")
|
||||
return json.loads(run_op([
|
||||
"item", "edit",
|
||||
item_id,
|
||||
"--title", title,
|
||||
"--url", url,
|
||||
"--format", "json",
|
||||
f"username={username}",
|
||||
f"password={password}",
|
||||
]).stdout)
|
||||
|
||||
|
||||
def find_node_item_id(node_uuid):
|
||||
for summary in op_item_list_bw():
|
||||
item_id = summary.get("id")
|
||||
if not item_id:
|
||||
continue
|
||||
|
||||
item = op_item_get(item_id)
|
||||
for field in item.get("fields") or []:
|
||||
label = field.get("label")
|
||||
value = field.get("value")
|
||||
if label == BUNDLEWRAP_FIELD_LABEL and value == node_uuid:
|
||||
return item_id
|
||||
return None
|
||||
|
||||
|
||||
def upsert_node_item(node_name, node_uuid, username, password, url):
|
||||
if item_id := find_node_item_id(node_uuid):
|
||||
return op_item_edit(
|
||||
item_id=item_id,
|
||||
title=node_name,
|
||||
username=username,
|
||||
password=password,
|
||||
url=url,
|
||||
)
|
||||
else:
|
||||
return op_item_create(
|
||||
title=node_name,
|
||||
node_uuid=node_uuid,
|
||||
username=username,
|
||||
password=password,
|
||||
url=url,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
|
@ -1,216 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from subprocess import check_output, CalledProcessError
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
import json
|
||||
from argparse import ArgumentParser
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from os import cpu_count
|
||||
from time import sleep
|
||||
|
||||
EXT_GROUPS = {
|
||||
"quicktime": {".mp4", ".mov", ".heic", ".cr3"},
|
||||
"exif": {".jpg", ".jpeg", ".cr2"},
|
||||
}
|
||||
DATETIME_KEYS = [
|
||||
("Composite", "SubSecDateTimeOriginal"),
|
||||
("Composite", "SubSecCreateDate"),
|
||||
('ExifIFD', 'DateTimeOriginal'),
|
||||
('ExifIFD', 'CreateDate'),
|
||||
('XMP-xmp', 'CreateDate'),
|
||||
('Keys', 'CreationDate'),
|
||||
('QuickTime', 'CreateDate'),
|
||||
('XMP-photoshop', 'DateCreated'),
|
||||
]
|
||||
|
||||
def run(command):
|
||||
return check_output(command, text=True).strip()
|
||||
|
||||
|
||||
def mdls_timestamp(file):
|
||||
for i in range(5): # retry a few times in case of transient mdls failures
|
||||
try:
|
||||
output = run(('mdls', '-raw', '-name', 'kMDItemContentCreationDate', file))
|
||||
except CalledProcessError as e:
|
||||
print(f"{file}: Error running mdls (attempt {i+1}/5): {e}")
|
||||
continue
|
||||
|
||||
try:
|
||||
return datetime.strptime(output, "%Y-%m-%d %H:%M:%S %z")
|
||||
except ValueError as e:
|
||||
print(f"{file}: Error parsing mdls output (attempt {i+1}/5): {e}")
|
||||
continue
|
||||
|
||||
sleep(1)
|
||||
|
||||
raise RuntimeError(f"Failed to get mdls timestamp for {file} after 5 attempts")
|
||||
|
||||
|
||||
def exiftool_data(file):
|
||||
try:
|
||||
output = run((
|
||||
'exiftool',
|
||||
'-j', # json
|
||||
'-a', # unknown tags
|
||||
'-u', # unknown values
|
||||
'-g1', # group by category
|
||||
'-time:all', # all time tags
|
||||
'-api', 'QuickTimeUTC=1', # use UTC for QuickTime timestamps
|
||||
'-d', '%Y-%m-%dT%H:%M:%S%z',
|
||||
file,
|
||||
))
|
||||
except CalledProcessError as e:
|
||||
print(f"Error running exiftool: {e}")
|
||||
return None
|
||||
else:
|
||||
return json.loads(output)[0]
|
||||
|
||||
def exiftool_timestamp(file):
|
||||
data = exiftool_data(file)
|
||||
for category, key in DATETIME_KEYS:
|
||||
try:
|
||||
value = data[category][key]
|
||||
return category, key, datetime.strptime(value, '%Y-%m-%dT%H:%M:%S%z')
|
||||
except (TypeError, KeyError, ValueError) as e:
|
||||
continue
|
||||
print(f"⚠️ {file}: No timestamp found in exiftool: " + json.dumps(data, indent=2))
|
||||
return None, None, None
|
||||
|
||||
|
||||
def photo_has_embedded_timestamp(file):
|
||||
mdls_ts = mdls_timestamp(file)
|
||||
category, key, exiftool_ts = exiftool_timestamp(file)
|
||||
|
||||
if not exiftool_ts:
|
||||
print(f"⚠️ {file}: No timestamp found in exiftool")
|
||||
return False
|
||||
|
||||
# normalize timezone for comparison
|
||||
exiftool_ts = exiftool_ts.astimezone(mdls_ts.tzinfo)
|
||||
delta = abs(mdls_ts - exiftool_ts)
|
||||
|
||||
if delta < timedelta(hours=1): # allow for small differences
|
||||
print(f"✅ {file}: {mdls_ts.isoformat()} (#{category}:{key})")
|
||||
return True
|
||||
else:
|
||||
print(f"⚠️ {file}: {mdls_ts.isoformat()} != {exiftool_ts} (Δ={delta})")
|
||||
return False
|
||||
|
||||
|
||||
def photos_without_embedded_timestamps(directory):
|
||||
executor = ThreadPoolExecutor(max_workers=cpu_count()//2)
|
||||
try:
|
||||
futures = {
|
||||
executor.submit(photo_has_embedded_timestamp, file): file
|
||||
for file in directory.iterdir()
|
||||
if file.is_file()
|
||||
if file.suffix.lower() not in {".aae"}
|
||||
if not file.name.startswith('.')
|
||||
}
|
||||
|
||||
for future in as_completed(futures):
|
||||
file = futures[future]
|
||||
has_ts = future.result() # raises immediately on first failed future
|
||||
|
||||
if has_ts:
|
||||
file.rename(file.parent / 'ok' / file.name)
|
||||
else:
|
||||
yield file
|
||||
|
||||
except Exception:
|
||||
executor.shutdown(wait=False, cancel_futures=True)
|
||||
raise
|
||||
else:
|
||||
executor.shutdown(wait=True)
|
||||
|
||||
|
||||
def exiftool_write(file, assignments):
|
||||
print(f"🔵 {file}: Writing -- {assignments}")
|
||||
return run((
|
||||
"exiftool", "-overwrite_original",
|
||||
"-api", "QuickTimeUTC=1",
|
||||
*[
|
||||
f"-{group}:{tag}={value}"
|
||||
for group, tag, value in assignments
|
||||
],
|
||||
str(file),
|
||||
))
|
||||
|
||||
|
||||
def add_missing_timestamp(file):
|
||||
data = exiftool_data(file)
|
||||
mdls_ts = mdls_timestamp(file)
|
||||
|
||||
offset = mdls_ts.strftime("%z")
|
||||
offset = f"{offset[:3]}:{offset[3:]}" if len(offset) == 5 else offset
|
||||
|
||||
exif_ts = mdls_ts.strftime("%Y:%m:%d %H:%M:%S")
|
||||
qt_ts = mdls_ts.strftime("%Y:%m:%d %H:%M:%S")
|
||||
qt_ts_tz = f"{qt_ts}{offset}"
|
||||
ext = file.suffix.lower()
|
||||
|
||||
try:
|
||||
if ext in {".heic"}:
|
||||
exiftool_write(file, [
|
||||
("ExifIFD", "DateTimeOriginal", qt_ts),
|
||||
("ExifIFD", "CreateDate", qt_ts),
|
||||
("ExifIFD", "OffsetTime", offset),
|
||||
("ExifIFD", "OffsetTimeOriginal", offset),
|
||||
("ExifIFD", "OffsetTimeDigitized", offset),
|
||||
("QuickTime", "CreateDate", qt_ts_tz),
|
||||
("Keys", "CreationDate", qt_ts_tz),
|
||||
("XMP-xmp", "CreateDate", qt_ts_tz),
|
||||
])
|
||||
elif "QuickTime" in data or ext in {".mp4", ".mov", ".heic", ".cr3"}:
|
||||
exiftool_write(file, [
|
||||
("QuickTime", "CreateDate", qt_ts_tz),
|
||||
("Keys", "CreationDate", qt_ts_tz),
|
||||
])
|
||||
elif "ExifIFD" in data or ext in {".jpg", ".jpeg", ".cr2", ".webp"}:
|
||||
exiftool_write(file, [
|
||||
("ExifIFD", "DateTimeOriginal", exif_ts),
|
||||
("ExifIFD", "CreateDate", exif_ts),
|
||||
("IFD0", "ModifyDate", exif_ts),
|
||||
("ExifIFD", "OffsetTime", offset),
|
||||
("ExifIFD", "OffsetTimeOriginal", offset),
|
||||
("ExifIFD", "OffsetTimeDigitized", offset),
|
||||
])
|
||||
elif ext in {".png", ".gif", ".avif"}:
|
||||
exiftool_write(file, [
|
||||
("XMP-xmp", "CreateDate", qt_ts_tz),
|
||||
("XMP-photoshop", "DateCreated", exif_ts),
|
||||
])
|
||||
else:
|
||||
print(f"❌ {file}: unsupported type, skipped")
|
||||
return
|
||||
|
||||
if photo_has_embedded_timestamp(file):
|
||||
print(f"✅ {file}: Timestamp successfully added: {mdls_ts.isoformat()}")
|
||||
file.rename(file.parent / 'processed' / file.name)
|
||||
return
|
||||
else:
|
||||
category, key, exiftool_ts = exiftool_timestamp(file)
|
||||
print(f"❌ {file}: Timestamp still wrong/missing after write '{category}:{key}:{exiftool_ts}': #{json.dumps(data, indent=4)}")
|
||||
return
|
||||
except CalledProcessError as e:
|
||||
print(f"❌ {file}: Failed to write timestamp: {e}")
|
||||
return
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = ArgumentParser(description="Print timestamps of photos in the current directory.")
|
||||
parser.add_argument("-d", "--directory", help="Directory to scan for photos")
|
||||
args = parser.parse_args()
|
||||
|
||||
directory = Path(args.directory)
|
||||
(directory/'ok').mkdir(exist_ok=True)
|
||||
(directory/'processed').mkdir(exist_ok=True)
|
||||
|
||||
_photos_without_embedded_timestamps = list(photos_without_embedded_timestamps(directory))
|
||||
print(f"{len(_photos_without_embedded_timestamps)} photos without embedded timestamps found.")
|
||||
print("Press Enter to add missing timestamps...")
|
||||
input()
|
||||
|
||||
for file in _photos_without_embedded_timestamps:
|
||||
add_missing_timestamp(file)
|
||||
|
|
@ -4,21 +4,20 @@ from bundlewrap.repo import Repository
|
|||
from os.path import realpath, dirname
|
||||
from sys import argv
|
||||
from ipaddress import ip_network, ip_interface
|
||||
import argparse
|
||||
|
||||
if len(argv) != 3:
|
||||
print(f'usage: {argv[0]} <node> <client>')
|
||||
exit(1)
|
||||
|
||||
# get info from repo
|
||||
repo = Repository(dirname(dirname(realpath(__file__))))
|
||||
server_node = repo.get_node('htz.mails')
|
||||
available_clients = server_node.metadata.get('wireguard/clients').keys()
|
||||
server_node = repo.get_node(argv[1])
|
||||
|
||||
# parse args
|
||||
parser = argparse.ArgumentParser(description='Generate WireGuard client configuration.')
|
||||
parser.add_argument('client', choices=available_clients, help='The client name to generate the configuration for.')
|
||||
args = parser.parse_args()
|
||||
if argv[2] not in server_node.metadata.get('wireguard/clients'):
|
||||
print(f'client {argv[2]} not found in: {server_node.metadata.get("wireguard/clients").keys()}')
|
||||
exit(1)
|
||||
|
||||
data = server_node.metadata.get(f'wireguard/clients/{argv[2]}')
|
||||
|
||||
# get cert
|
||||
data = server_node.metadata.get(f'wireguard/clients/{args.client}')
|
||||
vpn_network = ip_interface(server_node.metadata.get('wireguard/my_ip')).network
|
||||
allowed_ips = [
|
||||
vpn_network,
|
||||
|
|
@ -44,15 +43,10 @@ Endpoint = {ip_interface(server_node.metadata.get('network/external/ipv4')).ip}:
|
|||
PersistentKeepalive = 10
|
||||
'''
|
||||
|
||||
answer = input("print config or qrcode? [Cq]: ").strip().upper()
|
||||
match answer:
|
||||
case '' | 'C':
|
||||
print('>>>>>>>>>>>>>>>')
|
||||
print(conf)
|
||||
print('<<<<<<<<<<<<<<<')
|
||||
case 'Q':
|
||||
print('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
|
||||
print(conf)
|
||||
print('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<')
|
||||
|
||||
if input("print qrcode? [Yn]: ").upper() in ['', 'Y']:
|
||||
import pyqrcode
|
||||
print(pyqrcode.create(conf).terminal(quiet_zone=1))
|
||||
case _:
|
||||
print(f'Invalid option "{answer}".')
|
||||
exit(1)
|
||||
|
|
@ -13,14 +13,16 @@ defaults = {
|
|||
},
|
||||
},
|
||||
'telegraf': {
|
||||
'config': {
|
||||
'inputs': {
|
||||
'exec': {
|
||||
'apcupsd': {
|
||||
repo.libs.hashable.hashable({
|
||||
'commands': ["sudo /usr/local/share/telegraf/apcupsd"],
|
||||
'name_override': "apcupsd",
|
||||
'data_format': "influx",
|
||||
'interval': '30s',
|
||||
'flush_interval': '30s',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ defaults = {
|
|||
'apt-listchanges': {
|
||||
'installed': False,
|
||||
},
|
||||
'ca-certificates': {},
|
||||
},
|
||||
'config': {
|
||||
'DPkg': {
|
||||
|
|
|
|||
|
|
@ -49,13 +49,13 @@ defaults = {
|
|||
},
|
||||
},
|
||||
'telegraf': {
|
||||
'config': {
|
||||
'inputs': {
|
||||
'bind': {
|
||||
'default': {
|
||||
'bind': [{
|
||||
'urls': ['http://localhost:8053/xml/v3'],
|
||||
'gather_memory_contexts': False,
|
||||
'gather_views': True,
|
||||
},
|
||||
}],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -112,11 +112,6 @@ def process_recording(filename):
|
|||
|
||||
sample_num += samples_per_block - overlapping_samples
|
||||
|
||||
# move to PROCESSED_RECORDINGS_DIR
|
||||
|
||||
os.makedirs(PROCESSED_RECORDINGS_DIR, exist_ok=True)
|
||||
shutil.move(os.path.join(RECORDINGS_DIR, filename), os.path.join(PROCESSED_RECORDINGS_DIR, filename))
|
||||
|
||||
|
||||
# write a spectrogram using the sound from start to end of the event
|
||||
def write_event(current_event, soundfile, samplerate):
|
||||
|
|
|
|||
|
|
@ -19,7 +19,5 @@ do
|
|||
-t "3600" \
|
||||
-c:a flac \
|
||||
-compression_level 12 \
|
||||
"recordings/current/$DATE.flac"
|
||||
|
||||
mv "recordings/current/$DATE.flac" "recordings/$DATE.flac"
|
||||
"recordings/$DATE.flac"
|
||||
done
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ urllib3.disable_warnings()
|
|||
import os
|
||||
|
||||
|
||||
HUE_IP = "${hue_ip}" # replace with your bridge IP
|
||||
HUE_IP = "10.0.0.134" # replace with your bridge IP
|
||||
HUE_APP_KEY = "${hue_app_key}" # local only
|
||||
HUE_DEVICE_ID = "31f58786-3242-4e88-b9ce-23f44ba27bbe"
|
||||
TEMPERATURE_LOG_DIR = "/opt/bootshorn/temperatures"
|
||||
|
|
|
|||
|
|
@ -7,15 +7,11 @@ directories = {
|
|||
'owner': 'ckn',
|
||||
'group': 'ckn',
|
||||
},
|
||||
'/opt/bootshorn/temperatures': {
|
||||
'owner': 'ckn',
|
||||
'group': 'ckn',
|
||||
},
|
||||
'/opt/bootshorn/recordings': {
|
||||
'owner': 'ckn',
|
||||
'group': 'ckn',
|
||||
},
|
||||
'/opt/bootshorn/recordings/current': {
|
||||
'/opt/bootshorn/temperatures': {
|
||||
'owner': 'ckn',
|
||||
'group': 'ckn',
|
||||
},
|
||||
|
|
@ -38,7 +34,6 @@ files = {
|
|||
'/opt/bootshorn/temperature': {
|
||||
'content_type': 'mako',
|
||||
'context': {
|
||||
'hue_ip': repo.get_node('home.hue').hostname,
|
||||
'hue_app_key': repo.vault.decrypt('encrypt$gAAAAABoc2WxZCLbxl-Z4IrSC97CdOeFgBplr9Fp5ujpd0WCCCPNBUY_WquHN86z8hKLq5Y04dwq8TdJW0PMSOSgTFbGgdp_P1q0jOBLEKaW9IIT1YM88h-JYwLf9QGDV_5oEfvnBCtO'),
|
||||
},
|
||||
'owner': 'ckn',
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ def ssh_keys(metadata):
|
|||
'users': {
|
||||
'build-agent': {
|
||||
'authorized_users': {
|
||||
f'build-server@{other_node.name}': {}
|
||||
f'build-server@{other_node.name}'
|
||||
for other_node in repo.nodes
|
||||
if other_node.has_bundle('build-server')
|
||||
for architecture in other_node.metadata.get('build-server/architectures').values()
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ def ssh_keys(metadata):
|
|||
'users': {
|
||||
'build-ci': {
|
||||
'authorized_users': {
|
||||
f'build-server@{other_node.name}': {}
|
||||
f'build-server@{other_node.name}'
|
||||
for other_node in repo.nodes
|
||||
if other_node.has_bundle('build-server')
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ defaults = {
|
|||
'sources': {
|
||||
'crystal': {
|
||||
# https://software.opensuse.org/download.html?project=devel%3Alanguages%3Acrystal&package=crystal
|
||||
# curl -fsSL https://download.opensuse.org/repositories/devel:/languages:/crystal/Debian_Testing/Release.key
|
||||
'urls': {
|
||||
'http://download.opensuse.org/repositories/devel:/languages:/crystal/Debian_Testing/',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ def ssh_keys(metadata):
|
|||
'users': {
|
||||
'downloads': {
|
||||
'authorized_users': {
|
||||
f'build-server@{other_node.name}': {}
|
||||
f'build-server@{other_node.name}'
|
||||
for other_node in repo.nodes
|
||||
if other_node.has_bundle('build-server')
|
||||
},
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ for dashboard_id, monitored_node in enumerate(monitored_nodes, start=1):
|
|||
panel['gridPos']['y'] = (row_id - 1) * panel['gridPos']['h']
|
||||
|
||||
if 'display_name' in panel_config:
|
||||
panel['fieldConfig']['defaults']['displayName'] = panel_config['display_name']
|
||||
panel['fieldConfig']['defaults']['displayName'] = '${'+panel_config['display_name']+'}'
|
||||
|
||||
if panel_config.get('stacked'):
|
||||
panel['fieldConfig']['defaults']['custom']['stacking']['mode'] = 'normal'
|
||||
|
|
@ -158,14 +158,13 @@ for dashboard_id, monitored_node in enumerate(monitored_nodes, start=1):
|
|||
host=monitored_node.name,
|
||||
negative=query_config.get('negative', False),
|
||||
boolean_to_int=query_config.get('boolean_to_int', False),
|
||||
over=query_config.get('over', None),
|
||||
minimum=query_config.get('minimum', None),
|
||||
filters={
|
||||
'host': monitored_node.name,
|
||||
**query_config['filters'],
|
||||
},
|
||||
exists=query_config.get('exists', []),
|
||||
function=query_config.get('function', None),
|
||||
multiply=query_config.get('multiply', None),
|
||||
).strip()
|
||||
})
|
||||
|
||||
|
|
@ -179,3 +178,4 @@ for dashboard_id, monitored_node in enumerate(monitored_nodes, start=1):
|
|||
'svc_systemd:grafana-server:restart',
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ files = {
|
|||
'/usr/local/share/telegraf/cpu_frequency': {
|
||||
'mode': '0755',
|
||||
'triggers': {
|
||||
'svc_systemd:telegraf.service:restart',
|
||||
'svc_systemd:telegraf:restart',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,18 +14,17 @@ defaults = {
|
|||
},
|
||||
},
|
||||
'telegraf': {
|
||||
'config': {
|
||||
'inputs': {
|
||||
'sensors': {
|
||||
'default': {
|
||||
'sensors': {repo.libs.hashable.hashable({
|
||||
'timeout': '2s',
|
||||
},
|
||||
},
|
||||
})},
|
||||
'exec': {
|
||||
'cpu_frequency': {
|
||||
repo.libs.hashable.hashable({
|
||||
'commands': ["sudo /usr/local/share/telegraf/cpu_frequency"],
|
||||
'name_override': "cpu_frequency",
|
||||
'data_format': "influx",
|
||||
},
|
||||
}),
|
||||
# repo.libs.hashable.hashable({
|
||||
# 'commands': ["/bin/bash -c 'expr $(cat /sys/class/thermal/thermal_zone0/temp) / 1000'"],
|
||||
# 'name_override': "cpu_temperature",
|
||||
|
|
@ -35,4 +34,5 @@ defaults = {
|
|||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1 @@
|
|||
https://github.com/SirPlease/L4D2-Competitive-Rework/blob/master/Dedicated%20Server%20Install%20Guide/README.md
|
||||
|
||||
```python
|
||||
'tick60_maps': {
|
||||
'port': 27030,
|
||||
# add command line arguments
|
||||
'arguments': ['-tickrate 60'],
|
||||
# stack overlays, first is uppermost
|
||||
'overlays': ['tickrate', 'standard'],
|
||||
# server.cfg contents
|
||||
'config': [
|
||||
# configs from overlays are accessible via server_${overlay}.cfg
|
||||
'exec server_tickrate.cfg',
|
||||
# add more options
|
||||
'sv_minupdaterate 101',
|
||||
'sv_maxupdaterate 101',
|
||||
'sv_mincmdrate 101',
|
||||
'sv_maxcmdrate 101',
|
||||
'sv_consistency 0',
|
||||
],
|
||||
},
|
||||
```
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -xeuo pipefail
|
||||
|
||||
function steam() {
|
||||
# for systemd, so it can terminate the process (for other things sudo would have been enough)
|
||||
setpriv --reuid=steam --regid=steam --init-groups "$@" <&0
|
||||
export HOME=/opt/l4d2/steam
|
||||
}
|
||||
|
||||
function workshop() {
|
||||
steam mkdir -p "/opt/l4d2/overlays/${overlay}/left4dead2/addons"
|
||||
steam /opt/l4d2/scripts/steam-workshop-download --out "/opt/l4d2/overlays/${overlay}/left4dead2/addons" "$@"
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -xeuo pipefail
|
||||
source /opt/l4d2/scripts/helpers
|
||||
overlay=$(basename "$0")
|
||||
|
||||
# https://github.com/SirPlease/L4D2-Competitive-Rework
|
||||
|
||||
steam mkdir -p /opt/l4d2/overlays/$overlay/left4dead2
|
||||
test -d /opt/l4d2/overlays/$overlay/left4dead2/cfg/cfgogl || \
|
||||
curl -L https://github.com/SirPlease/L4D2-Competitive-Rework/archive/refs/heads/master.tar.gz | steam tar -xz --strip-components=1 -C /opt/l4d2/overlays/$overlay/left4dead2
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -xeuo pipefail
|
||||
source /opt/l4d2/scripts/helpers
|
||||
overlay=$(basename "$0")
|
||||
|
||||
steam mkdir -p /opt/l4d2/overlays/$overlay/left4dead2/addons
|
||||
cd /opt/l4d2/overlays/$overlay/left4dead2/addons
|
||||
|
||||
# https://l4d2center.com/maps/servers/l4d2center_maps_sync.sh.txt ->
|
||||
|
||||
# Exit immediately if a command exits with a non-zero status.
|
||||
set -e
|
||||
|
||||
# Function to print error messages
|
||||
error_exit() {
|
||||
echo "Error: $1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if the current directory ends with /left4dead2/addons
|
||||
current_dir=$(pwd)
|
||||
expected_dir="/left4dead2/addons"
|
||||
|
||||
if [[ ! "$current_dir" == *"$expected_dir" ]]; then
|
||||
error_exit "Script must be run from your L4D2 \"addons\" folder. Current directory: $current_dir"
|
||||
fi
|
||||
|
||||
# Check for required commands
|
||||
for cmd in curl md5sum 7z; do
|
||||
if ! command -v "$cmd" >/dev/null 2>&1; then
|
||||
error_exit "Required command '$cmd' is not installed. Please install it and retry."
|
||||
fi
|
||||
done
|
||||
|
||||
# URL of the CSV file
|
||||
CSV_URL="https://l4d2center.com/maps/servers/index.csv"
|
||||
|
||||
# Temporary file to store CSV
|
||||
TEMP_CSV=$(mktemp)
|
||||
|
||||
# Ensure temporary file is removed on exit
|
||||
trap 'rm -f "$TEMP_CSV"' EXIT
|
||||
|
||||
echo "Downloading CSV from $CSV_URL..."
|
||||
curl -sSL -o "$TEMP_CSV" "$CSV_URL" || error_exit "Failed to download CSV."
|
||||
|
||||
declare -A map_md5
|
||||
declare -A map_links
|
||||
|
||||
# Read CSV and populate associative arrays
|
||||
{
|
||||
# Skip the first line (header)
|
||||
IFS= read -r header
|
||||
|
||||
while IFS=';' read -r Name Size MD5 DownloadLink || [[ $Name ]]; do
|
||||
# Trim whitespace
|
||||
Name=$(echo "$Name" | xargs)
|
||||
MD5=$(echo "$MD5" | xargs)
|
||||
DownloadLink=$(echo "$DownloadLink" | xargs)
|
||||
|
||||
# Populate associative arrays
|
||||
map_md5["$Name"]="$MD5"
|
||||
map_links["$Name"]="$DownloadLink"
|
||||
done
|
||||
} < "$TEMP_CSV"
|
||||
|
||||
# Get list of expected VPK files
|
||||
expected_vpk=("${!map_md5[@]}")
|
||||
|
||||
# Remove VPK files not in expected list or with mismatched MD5
|
||||
echo "Cleaning up existing VPK files..."
|
||||
for file in *.vpk; do
|
||||
# Check if it's a regular file
|
||||
if [[ -f "$file" ]]; then
|
||||
if [[ -z "${map_md5["$file"]}" ]]; then
|
||||
echo "Removing unexpected file: $file"
|
||||
rm -f "$file"
|
||||
else
|
||||
# Calculate MD5
|
||||
echo "Calculating MD5 for existing file: $file..."
|
||||
current_md5=$(md5sum "$file" | awk '{print $1}')
|
||||
expected_md5="${map_md5["$file"]}"
|
||||
|
||||
if [[ "$current_md5" != "$expected_md5" ]]; then
|
||||
echo "MD5 mismatch for $file. Removing."
|
||||
rm -f "$file"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Download and extract missing or updated VPK files
|
||||
echo "Processing required VPK files..."
|
||||
for vpk in "${expected_vpk[@]}"; do
|
||||
if [[ ! -f "$vpk" ]]; then
|
||||
echo "Downloading and extracting $vpk..."
|
||||
download_url="${map_links["$vpk"]}"
|
||||
|
||||
if [[ -z "$download_url" ]]; then
|
||||
echo "No download link found for $vpk. Skipping."
|
||||
continue
|
||||
fi
|
||||
|
||||
encoded_url=$(echo "$download_url" | sed 's/ /%20/g')
|
||||
|
||||
# Download the .7z file to a temporary location
|
||||
TEMP_7Z=$(mktemp --suffix=.7z)
|
||||
curl -# -L -o "$TEMP_7Z" "$encoded_url"
|
||||
|
||||
# Check if the download was successful
|
||||
if [[ $? -ne 0 ]]; then
|
||||
echo "Failed to download $download_url. Skipping."
|
||||
rm -f "$TEMP_7Z"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Extract the .7z file
|
||||
7z x -y "$TEMP_7Z" || { echo "Failed to extract $TEMP_7Z. Skipping."; rm -f "$TEMP_7Z"; continue; }
|
||||
|
||||
# Remove the temporary .7z file
|
||||
rm -f "$TEMP_7Z"
|
||||
|
||||
else
|
||||
echo "$vpk is already up to date."
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Synchronization complete."
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -xeuo pipefail
|
||||
source /opt/l4d2/scripts/helpers
|
||||
overlay=$(basename "$0")
|
||||
|
||||
# Ions Vocalizer
|
||||
workshop -i 698857882
|
||||
|
||||
# admin system
|
||||
workshop --item 2524204971
|
||||
steam mkdir -p "/opt/l4d2/overlays/${overlay}/left4dead2/ems/admin system"
|
||||
steam echo "STEAM_1:0:12376499" > "/opt/l4d2/overlays/${overlay}/left4dead2/ems/admin system/admins.txt"
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -xeuo pipefail
|
||||
source /opt/l4d2/scripts/helpers
|
||||
overlay=$(basename "$0")
|
||||
|
||||
# server config
|
||||
# https://github.com/SirPlease/L4D2-Competitive-Rework/blob/7ecc3a32a5e2180d6607a40119ff2f3c072502a9/cfg/server.cfg#L58-L69
|
||||
# https://www.programmersought.com/article/513810199514/
|
||||
steam mkdir -p /opt/l4d2/overlays/$overlay/left4dead2/cfg
|
||||
steam cat <<'EOF' > /opt/l4d2/overlays/$overlay/left4dead2/cfg/server.cfg
|
||||
# https://github.com/SirPlease/L4D2-Competitive-Rework/blob/7ecc3a32a5e2180d6607a40119ff2f3c072502a9/cfg/server.cfg#L58-L69
|
||||
sv_minrate 100000
|
||||
sv_maxrate 100000
|
||||
nb_update_frequency 0.014
|
||||
net_splitpacket_maxrate 50000
|
||||
net_maxcleartime 0.0001
|
||||
fps_max 0
|
||||
EOF
|
||||
|
||||
# install tickrate enabler
|
||||
steam mkdir -p "/opt/l4d2/overlays/${overlay}/left4dead2/addons"
|
||||
for file in tickrate_enabler.dll tickrate_enabler.so tickrate_enabler.vdf
|
||||
do
|
||||
curl -L "https://github.com/SirPlease/L4D2-Competitive-Rework/raw/refs/heads/master/addons/${file}" -o "/opt/l4d2/overlays/${overlay}/left4dead2/addons/${file}"
|
||||
done
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#!/bin/bash
|
||||
set -xeuo pipefail
|
||||
source /opt/l4d2/scripts/helpers
|
||||
overlay=$(basename "$0")
|
||||
|
||||
# workshop --collection 121115793 # Back To School
|
||||
|
||||
# workshop --item 2957035482 # hehe30-part1
|
||||
# workshop --item 2973628334 # hehe30-part2
|
||||
# workshop --item 3013844371 # hehe30-part3
|
||||
|
||||
# workshop --item 3478461158 # 虚伪黎明(Dawn's Deception)
|
||||
# workshop --item 3478934394 # 虚伪黎明(Dawn's Deception)PART2
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
// defaults
|
||||
hostname ${server_name}
|
||||
motd_enabled 0
|
||||
rcon_password ${rcon_password}
|
||||
sv_steamgroup "38347879"
|
||||
|
||||
mp_autoteambalance 0
|
||||
sv_forcepreload 1
|
||||
|
||||
// server specific
|
||||
% for line in config:
|
||||
${line}
|
||||
% endfor
|
||||
|
|
@ -2,16 +2,6 @@
|
|||
|
||||
set -xeuo pipefail
|
||||
|
||||
# -- DEFINE FUNCTIONS AND VARIABLES -- #
|
||||
|
||||
function steam() {
|
||||
# for systemd, so it can terminate the process (for other things sudo would have been enough)
|
||||
setpriv --reuid=steam --regid=steam --init-groups "$@" <&0
|
||||
export HOME=/opt/l4d2/steam
|
||||
}
|
||||
|
||||
# -- PREPARE SYSTEM -- #
|
||||
|
||||
getent passwd steam >/dev/null || useradd -M -d /opt/l4d2 -s /bin/bash steam
|
||||
mkdir -p /opt/l4d2 /tmp/dumps
|
||||
chown steam:steam /opt/l4d2 /tmp/dumps
|
||||
|
|
@ -19,10 +9,11 @@ dpkg --add-architecture i386
|
|||
apt update
|
||||
DEBIAN_FRONTEND=noninteractive apt install -y libc6:i386 lib32z1
|
||||
|
||||
# workshop downloader
|
||||
test -f /opt/l4d2/scripts/steam-workshop-download || \
|
||||
steam wget -4 https://git.sublimity.de/cronekorkn/steam-workshop-downloader/raw/branch/master/steam-workshop-download -P /opt/l4d2/scripts
|
||||
steam chmod +x /opt/l4d2/scripts/steam-workshop-download
|
||||
function steam() {
|
||||
# für systemd, damit es den prozess beenden kann
|
||||
setpriv --reuid=steam --regid=steam --init-groups "$@"
|
||||
export HOME=/opt/l4d2/steam
|
||||
}
|
||||
|
||||
# -- STEAM -- #
|
||||
|
||||
|
|
@ -58,13 +49,46 @@ steam /opt/l4d2/steam/steamcmd.sh \
|
|||
|
||||
# -- OVERLAYS -- #
|
||||
|
||||
for overlay_path in /opt/l4d2/scripts/overlays/*; do
|
||||
overlay=$(basename "$overlay_path")
|
||||
steam mkdir -p /opt/l4d2/overlays/$overlay
|
||||
bash -xeuo pipefail "$overlay_path"
|
||||
test -f /opt/l4d2/overlays/$overlay/left4dead2/cfg/server.cfg && \
|
||||
steam cp /opt/l4d2/overlays/$overlay/left4dead2/cfg/server.cfg /opt/l4d2/overlays/$overlay/left4dead2/cfg/server_$overlay.cfg
|
||||
done
|
||||
steam mkdir -p /opt/l4d2/overlays
|
||||
|
||||
# workshop downloader
|
||||
test -f /opt/l4d2/steam-workshop-download || \
|
||||
steam wget -4 https://git.sublimity.de/cronekorkn/steam-workshop-downloader/raw/branch/master/steam-workshop-download -P /opt/l4d2
|
||||
steam chmod +x /opt/l4d2/steam-workshop-download
|
||||
|
||||
# -- OVERLAY PVE -- #
|
||||
|
||||
steam mkdir -p /opt/l4d2/overlays/pve
|
||||
|
||||
# server config
|
||||
steam mkdir -p /opt/l4d2/overlays/pve/left4dead2/cfg
|
||||
steam cat <<'EOF' > /opt/l4d2/overlays/pve/left4dead2/cfg/server.cfg
|
||||
motd_enabled 0
|
||||
|
||||
sv_steamgroup "38347879"
|
||||
#sv_steamgroup_exclusive 0
|
||||
|
||||
sv_minrate 60000
|
||||
sv_maxrate 0
|
||||
net_splitpacket_maxrate 60000
|
||||
|
||||
#sv_cheats 1
|
||||
#sb_all_bot_game 1
|
||||
EOF
|
||||
|
||||
# admin system
|
||||
steam mkdir -p /opt/l4d2/overlays/pve/left4dead2/addons
|
||||
test -f /opt/l4d2/overlays/pve/left4dead2/addons/2524204971.vpk || \
|
||||
steam /opt/l4d2/steam-workshop-download 2524204971 --out /opt/l4d2/overlays/pve/left4dead2/addons
|
||||
steam mkdir -p "/opt/l4d2/overlays/pve/left4dead2/ems/admin system"
|
||||
steam echo "STEAM_1:0:12376499" > "/opt/l4d2/overlays/pve/left4dead2/ems/admin system/admins.txt"
|
||||
|
||||
# ions vocalizer
|
||||
test -f /opt/l4d2/overlays/pve/left4dead2/addons/698857882.vpk || \
|
||||
steam /opt/l4d2/steam-workshop-download 698857882 --out /opt/l4d2/overlays/pve/left4dead2/addons
|
||||
|
||||
test -f /opt/l4d2/overlays/pve/left4dead2/addons/1575673903.vpk || \
|
||||
steam /opt/l4d2/steam-workshop-download 1575673903 --out /opt/l4d2/overlays/pve/left4dead2/addons
|
||||
|
||||
# -- SERVERS -- #
|
||||
|
||||
|
|
|
|||
|
|
@ -2,41 +2,9 @@
|
|||
|
||||
set -xeuo pipefail
|
||||
|
||||
name=""
|
||||
port=""
|
||||
configfile=""
|
||||
overlays=""
|
||||
arguments=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-n|--name)
|
||||
name="$2"; shift 2
|
||||
;;
|
||||
-p|--port)
|
||||
port="$2"; shift 2
|
||||
;;
|
||||
-c|--config)
|
||||
configfile="$2"; shift 2
|
||||
;;
|
||||
-o|--overlay)
|
||||
overlays="/opt/l4d2/overlays/$2:$overlays"; shift 2
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
arguments+="$@"
|
||||
break
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: unknown argument $1"; exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
[[ -n "${name}" ]] || { echo "ERROR: -n/--name missing"; exit 1; }
|
||||
[[ -n "${port}" ]] || { echo "ERROR: -p/--port missing"; exit 1; }
|
||||
|
||||
# -- HELPER FUNCTIONS -- #
|
||||
name=$1
|
||||
overlay=$2
|
||||
port=$3
|
||||
|
||||
function steam() {
|
||||
# für systemd, damit es den prozess beenden kann
|
||||
|
|
@ -44,32 +12,17 @@ function steam() {
|
|||
export HOME=/opt/l4d2/steam
|
||||
}
|
||||
|
||||
# -- TIDY UP -- #
|
||||
|
||||
mountpoint -q "/opt/l4d2/servers/$name/merged" && umount "/opt/l4d2/servers/$name/merged"
|
||||
steam rm -rf "/opt/l4d2/servers/$name"
|
||||
|
||||
# -- CREATE DIRECTORIES -- #
|
||||
|
||||
steam mkdir -p \
|
||||
"/opt/l4d2/servers/$name" \
|
||||
"/opt/l4d2/servers/$name/work" \
|
||||
"/opt/l4d2/servers/$name/upper" \
|
||||
"/opt/l4d2/servers/$name/merged"
|
||||
|
||||
# -- MOUNT OVERLAYFS -- #
|
||||
|
||||
mount -t overlay overlay \
|
||||
-o "lowerdir=$overlays/opt/l4d2/installation,upperdir=/opt/l4d2/servers/$name/upper,workdir=/opt/l4d2/servers/$name/work" \
|
||||
-o "lowerdir=/opt/l4d2/overlays/$overlay:/opt/l4d2/installation,upperdir=/opt/l4d2/servers/$name/upper,workdir=/opt/l4d2/servers/$name/work" \
|
||||
"/opt/l4d2/servers/$name/merged"
|
||||
|
||||
# -- REPLACE SERVER.CFG -- #
|
||||
|
||||
if [[ -n "$configfile" ]]; then
|
||||
cp "$configfile" "/opt/l4d2/servers/$name/merged/left4dead2/cfg/server.cfg"
|
||||
chown steam:steam "/opt/l4d2/servers/$name/merged/left4dead2/cfg/server.cfg"
|
||||
fi
|
||||
|
||||
# -- RUN L4D2 -- #
|
||||
|
||||
steam "/opt/l4d2/servers/$name/merged/srcds_run" -norestart -pidfile "/opt/l4d2/servers/$name/pid" -game left4dead2 -ip 0.0.0.0 -port "$port" +hostname "Crone_$name" +map c1m1_hotel $arguments
|
||||
steam "/opt/l4d2/servers/$name/merged/srcds_run" -norestart -pidfile "/opt/l4d2/servers/$name/pid" -game left4dead2 -ip 0.0.0.0 -port "$port" +hostname "Crone_$name" +map c1m1_hotel
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -xeuo pipefail
|
||||
|
||||
name=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-n|--name)
|
||||
name="$2"; shift 2
|
||||
;;
|
||||
*)
|
||||
echo "ERROR: unknown argument $1"; exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
mountpoint -q "/opt/l4d2/servers/$name/merged" && umount "/opt/l4d2/servers/$name/merged"
|
||||
steam rm -rf "/opt/l4d2/servers/$name"
|
||||
|
|
@ -1,97 +1,23 @@
|
|||
users = {
|
||||
'steam': {
|
||||
'home': '/opt/l4d2/steam',
|
||||
'shell': '/bin/bash',
|
||||
},
|
||||
}
|
||||
|
||||
directories = {
|
||||
'/opt/l4d2': {
|
||||
'owner': 'steam', 'group': 'steam',
|
||||
},
|
||||
'/opt/l4d2/steam': {
|
||||
'owner': 'steam', 'group': 'steam',
|
||||
},
|
||||
'/opt/l4d2/configs': {
|
||||
'owner': 'steam', 'group': 'steam',
|
||||
'purge': True,
|
||||
},
|
||||
'/opt/l4d2/scripts': {
|
||||
'owner': 'steam', 'group': 'steam',
|
||||
},
|
||||
'/opt/l4d2/scripts/overlays': {
|
||||
'owner': 'steam', 'group': 'steam',
|
||||
'purge': True,
|
||||
},
|
||||
}
|
||||
|
||||
files = {
|
||||
'/opt/l4d2/setup': {
|
||||
'mode': '755',
|
||||
'triggers': {
|
||||
'svc_systemd:left4dead2-initialize.service:restart',
|
||||
},
|
||||
},
|
||||
'/opt/l4d2/start': {
|
||||
'mode': '755',
|
||||
'triggers': {
|
||||
f'svc_systemd:left4dead2-{server_name}.service:restart'
|
||||
for server_name in node.metadata.get('left4dead2/servers').keys()
|
||||
},
|
||||
},
|
||||
'/opt/l4d2/stop': {
|
||||
'mode': '755',
|
||||
'triggers': {
|
||||
f'svc_systemd:left4dead2-{server_name}.service:restart'
|
||||
for server_name in node.metadata.get('left4dead2/servers').keys()
|
||||
},
|
||||
},
|
||||
'/opt/l4d2/scripts/helpers': {
|
||||
'source': 'scripts/helpers',
|
||||
'mode': '755',
|
||||
'triggers': {
|
||||
'svc_systemd:left4dead2-initialize.service:restart',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for overlay in node.metadata.get('left4dead2/overlays'):
|
||||
files[f'/opt/l4d2/scripts/overlays/{overlay}'] = {
|
||||
'source': f'scripts/overlays/{overlay}',
|
||||
'mode': '755',
|
||||
'triggers': {
|
||||
'svc_systemd:left4dead2-initialize.service:restart',
|
||||
},
|
||||
}
|
||||
|
||||
svc_systemd = {
|
||||
'left4dead2-initialize.service': {
|
||||
'enabled': True,
|
||||
'running': None,
|
||||
'needs': {
|
||||
'tag:left4dead2-packages',
|
||||
'file:/opt/l4d2/setup',
|
||||
'file:/usr/local/lib/systemd/system/left4dead2-initialize.service',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for server_name, config in node.metadata.get('left4dead2/servers').items():
|
||||
files[f'/opt/l4d2/configs/{server_name}.cfg'] = {
|
||||
'source': 'server.cfg',
|
||||
'content_type': 'mako',
|
||||
'context': {
|
||||
'server_name': server_name,
|
||||
'rcon_password': repo.vault.decrypt('encrypt$gAAAAABpAdZhxwJ47I1AXotuZmBvyZP1ecVTt9IXFkLI28JiVS74LKs9QdgIBz-FC-iXtIHHh_GVGxxKQZprn4UrXZcvZ57kCKxfHBs3cE2JiGnbWE8_mfs=').value,
|
||||
'config': config.get('config', []),
|
||||
},
|
||||
'owner': 'steam',
|
||||
'mode': '644',
|
||||
'triggers': {
|
||||
f'svc_systemd:left4dead2-{server_name}.service:restart',
|
||||
},
|
||||
}
|
||||
|
||||
for server_name in node.metadata.get('left4dead2').keys():
|
||||
svc_systemd[f'left4dead2-{server_name}.service'] = {
|
||||
'enabled': True,
|
||||
'running': True,
|
||||
|
|
@ -101,5 +27,5 @@ for server_name, config in node.metadata.get('left4dead2/servers').items():
|
|||
'needs': {
|
||||
'svc_systemd:left4dead2-initialize.service',
|
||||
f'file:/usr/local/lib/systemd/system/left4dead2-{server_name}.service',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,15 @@
|
|||
from re import match
|
||||
from os import path, listdir
|
||||
|
||||
|
||||
defaults = {
|
||||
'apt': {
|
||||
'packages': {
|
||||
'libc6_i386': { # installs libc6:i386
|
||||
'tags': {'left4dead2-packages'},
|
||||
},
|
||||
'lib32z1': {
|
||||
'tags': {'left4dead2-packages'},
|
||||
},
|
||||
'unzip': {
|
||||
'tags': {'left4dead2-packages'},
|
||||
},
|
||||
'p7zip-full': { # l4d2center_maps_sync.sh
|
||||
'tags': {'left4dead2-packages'},
|
||||
},
|
||||
},
|
||||
},
|
||||
'left4dead2': {
|
||||
'overlays': set(listdir(path.join(repo.path, 'bundles/left4dead2/files/scripts/overlays'))),
|
||||
'servers': {
|
||||
# 'port': 27017,
|
||||
# 'overlays': ['competitive_rework'],
|
||||
# 'arguments': ['-tickrate 60'],
|
||||
# 'config': [
|
||||
# 'exec server_original.cfg',
|
||||
# 'sm_forcematch zonemod',
|
||||
# ],
|
||||
'libc6_i386': {}, # installs libc6:i386
|
||||
'lib32z1': {},
|
||||
'unzip': {},
|
||||
},
|
||||
},
|
||||
'left4dead2': {},
|
||||
'nftables': {
|
||||
'input': {
|
||||
'udp dport { 27005, 27020 } accept',
|
||||
|
|
@ -65,22 +44,10 @@ defaults = {
|
|||
def server_units(metadata):
|
||||
units = {}
|
||||
|
||||
for name, config in metadata.get('left4dead2/servers').items():
|
||||
for name, config in metadata.get('left4dead2').items():
|
||||
assert match(r'^[A-z0-9-_-]+$', name)
|
||||
assert config["overlay"] in {'pve'}
|
||||
assert 27000 <= config["port"] <= 27100
|
||||
for overlay in config.get('overlays', []):
|
||||
assert overlay in metadata.get('left4dead2/overlays'), f"unknown overlay {overlay}, known: {metadata.get('left4dead2/overlays')}"
|
||||
|
||||
cmd = f'/opt/l4d2/start -n {name} -p {config["port"]}'
|
||||
|
||||
if 'config' in config:
|
||||
cmd += f' -c /opt/l4d2/configs/{name}.cfg'
|
||||
|
||||
for overlay in config.get('overlays', []):
|
||||
cmd += f' -o {overlay}'
|
||||
|
||||
if 'arguments' in config:
|
||||
cmd += ' -- ' + ' '.join(config['arguments'])
|
||||
|
||||
units[f'left4dead2-{name}.service'] = {
|
||||
'Unit': {
|
||||
|
|
@ -90,8 +57,7 @@ def server_units(metadata):
|
|||
},
|
||||
'Service': {
|
||||
'Type': 'simple',
|
||||
'ExecStart': cmd,
|
||||
'ExecStopPost': f'/opt/l4d2/stop -n {name}',
|
||||
'ExecStart': f'/opt/l4d2/start {name} {config["overlay"]} {config["port"]}',
|
||||
'Restart': 'on-failure',
|
||||
'Nice': -10,
|
||||
'CPUWeight': 200,
|
||||
|
|
@ -101,9 +67,6 @@ def server_units(metadata):
|
|||
'Install': {
|
||||
'WantedBy': {'multi-user.target'},
|
||||
},
|
||||
'triggers': {
|
||||
f'svc_systemd:left4dead2-{name}.service:restart',
|
||||
},
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -117,7 +80,7 @@ def server_units(metadata):
|
|||
'nftables/input',
|
||||
)
|
||||
def nftables(metadata):
|
||||
ports = sorted(str(config["port"]) for config in metadata.get('left4dead2/servers').values())
|
||||
ports = sorted(str(config["port"]) for config in metadata.get('left4dead2', {}).values())
|
||||
|
||||
return {
|
||||
'nftables': {
|
||||
|
|
|
|||
58
bundles/left4dead2_old/README.md
Normal file
58
bundles/left4dead2_old/README.md
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
https://developer.valvesoftware.com/wiki/List_of_L4D2_Cvars
|
||||
|
||||
Dead Center c1m1_hotel
|
||||
Dead Center c1m2_streets
|
||||
Dead Center c1m3_mall
|
||||
Dead Center c1m4_atrium
|
||||
Dark Carnival c2m1_highway
|
||||
Dark Carnival c2m2_fairgrounds
|
||||
Dark Carnival c2m3_coaster
|
||||
Dark Carnival c2m4_barns
|
||||
Dark Carnival c2m5_concert
|
||||
Swamp Fever c3m1_plankcountry
|
||||
Swamp Fever c3m2_swamp
|
||||
Swamp Fever c3m3_shantytown
|
||||
Swamp Fever c3m4_plantation
|
||||
Hard Rain c4m1_milltown_a
|
||||
Hard Rain c4m2_sugarmill_a
|
||||
Hard Rain c4m3_sugarmill_b
|
||||
Hard Rain c4m4_milltown_b
|
||||
Hard Rain c4m5_milltown_escape
|
||||
The Parish c5m1_waterfront_sndscape
|
||||
The Parish c5m1_waterfront
|
||||
The Parish c5m2_park
|
||||
The Parish c5m3_cemetery
|
||||
The Parish c5m4_quarter
|
||||
The Parish c5m5_bridge
|
||||
The Passing c6m1_riverbank
|
||||
The Passing c6m2_bedlam
|
||||
The Passing c6m3_port
|
||||
The Sacrifice c7m1_docks
|
||||
The Sacrifice c7m2_barge
|
||||
The Sacrifice c7m3_port
|
||||
No Mercy c8m1_apartment
|
||||
No Mercy c8m2_subway
|
||||
No Mercy c8m3_sewers
|
||||
No Mercy c8m4_interior
|
||||
No Mercy c8m5_rooftop
|
||||
Crash Course c9m1_alleys
|
||||
Crash Course c9m2_lots
|
||||
Death Toll c10m1_caves
|
||||
Death Toll c10m2_drainage
|
||||
Death Toll c10m3_ranchhouse
|
||||
Death Toll c10m4_mainstreet
|
||||
Death Toll c10m5_houseboat
|
||||
Dead Air c11m1_greenhouse
|
||||
Dead Air c11m2_offices
|
||||
Dead Air c11m3_garage
|
||||
Dead Air c11m4_terminal
|
||||
Dead Air c11m5_runway
|
||||
Blood Harvest c12m1_hilltop
|
||||
Blood Harvest c12m2_traintunnel
|
||||
Blood Harvest c12m3_bridge
|
||||
Blood Harvest c12m4_barn
|
||||
Blood Harvest c12m5_cornfield
|
||||
Cold Stream c13m1_alpinecreek
|
||||
Cold Stream c13m2_southpinestream
|
||||
Cold Stream c13m3_memorialbridge
|
||||
Cold Stream c13m4_cutthroatcreek
|
||||
40
bundles/left4dead2_old/files/server.cfg
Normal file
40
bundles/left4dead2_old/files/server.cfg
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
hostname "CroneKorkN : ${name}"
|
||||
sv_contact "admin@sublimity.de"
|
||||
|
||||
|
||||
sv_steamgroup "${','.join(steamgroups)}"
|
||||
|
||||
rcon_password "${rcon_password}"
|
||||
|
||||
|
||||
motd_enabled 0
|
||||
|
||||
|
||||
sv_cheats 1
|
||||
|
||||
|
||||
sv_consistency 0
|
||||
|
||||
|
||||
sv_lan 0
|
||||
|
||||
|
||||
sv_allow_lobby_connect_only 0
|
||||
|
||||
|
||||
sv_gametypes "coop,realism,survival,versus,teamversus,scavenge,teamscavenge"
|
||||
|
||||
|
||||
sv_minrate 30000
|
||||
sv_maxrate 60000
|
||||
sv_mincmdrate 66
|
||||
sv_maxcmdrate 101
|
||||
|
||||
|
||||
sv_logsdir "logs-${name}" //Folder in the game directory where server logs will be stored.
|
||||
log on //Creates a logfile (on | off)
|
||||
sv_logecho 0 //default 0; Echo log information to the console.
|
||||
sv_logfile 1 //default 1; Log server information in the log file.
|
||||
sv_log_onefile 0 //default 0; Log server information to only one file.
|
||||
sv_logbans 1 //default 0;Log server bans in the server logs.
|
||||
sv_logflush 0 //default 0; Flush the log files to disk on each write (slow).
|
||||
122
bundles/left4dead2_old/items.py
Normal file
122
bundles/left4dead2_old/items.py
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
assert node.has_bundle('steam') and node.has_bundle('steam-workshop-download')
|
||||
|
||||
directories = {
|
||||
'/opt/steam/left4dead2-servers': {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
'mode': '0755',
|
||||
'purge': True,
|
||||
},
|
||||
# Current zfs doesnt support zfs upperdir. The support was added in October 2022. Move upperdir - unused anyway -
|
||||
# to another dir. Also move workdir alongside it, as it has to be on same fs.
|
||||
'/opt/steam-zfs-overlay-workarounds': {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
'mode': '0755',
|
||||
'purge': True,
|
||||
},
|
||||
}
|
||||
|
||||
# /opt/steam/steam/.steam/sdk32/steamclient.so: cannot open shared object file: No such file or directory
|
||||
symlinks = {
|
||||
'/opt/steam/steam/.steam/sdk32': {
|
||||
'target': '/opt/steam/steam/linux32',
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
}
|
||||
}
|
||||
|
||||
#
|
||||
# SERVERS
|
||||
#
|
||||
|
||||
for name, config in node.metadata.get('left4dead2/servers').items():
|
||||
|
||||
#overlay
|
||||
directories[f'/opt/steam/left4dead2-servers/{name}'] = {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
}
|
||||
directories[f'/opt/steam-zfs-overlay-workarounds/{name}/upper'] = {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
}
|
||||
directories[f'/opt/steam-zfs-overlay-workarounds/{name}/workdir'] = {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
}
|
||||
|
||||
# conf
|
||||
files[f'/opt/steam/left4dead2-servers/{name}/left4dead2/cfg/server.cfg'] = {
|
||||
'content_type': 'mako',
|
||||
'source': 'server.cfg',
|
||||
'context': {
|
||||
'name': name,
|
||||
'steamgroups': node.metadata.get('left4dead2/steamgroups'),
|
||||
'rcon_password': config['rcon_password'],
|
||||
},
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
'triggers': [
|
||||
f'svc_systemd:left4dead2-{name}.service:restart',
|
||||
],
|
||||
}
|
||||
|
||||
# service
|
||||
svc_systemd[f'left4dead2-{name}.service'] = {
|
||||
'needs': [
|
||||
f'file:/opt/steam/left4dead2-servers/{name}/left4dead2/cfg/server.cfg',
|
||||
f'file:/usr/local/lib/systemd/system/left4dead2-{name}.service',
|
||||
],
|
||||
}
|
||||
|
||||
#
|
||||
# ADDONS
|
||||
#
|
||||
|
||||
# base
|
||||
files[f'/opt/steam/left4dead2-servers/{name}/left4dead2/addons/readme.txt'] = {
|
||||
'content_type': 'any',
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
}
|
||||
directories[f'/opt/steam/left4dead2-servers/{name}/left4dead2/addons'] = {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
'purge': True,
|
||||
'triggers': [
|
||||
f'svc_systemd:left4dead2-{name}.service:restart',
|
||||
],
|
||||
}
|
||||
for id in [
|
||||
*config.get('workshop', []),
|
||||
*node.metadata.get('left4dead2/workshop'),
|
||||
]:
|
||||
files[f'/opt/steam/left4dead2-servers/{name}/left4dead2/addons/{id}.vpk'] = {
|
||||
'content_type': 'any',
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
'triggers': [
|
||||
f'svc_systemd:left4dead2-{name}.service:restart',
|
||||
],
|
||||
}
|
||||
|
||||
# admin system
|
||||
|
||||
directories[f'/opt/steam/left4dead2-servers/{name}/left4dead2/ems/admin system'] = {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
'mode': '0755',
|
||||
'triggers': [
|
||||
f'svc_systemd:left4dead2-{name}.service:restart',
|
||||
],
|
||||
}
|
||||
files[f'/opt/steam/left4dead2-servers/{name}/left4dead2/ems/admin system/admins.txt'] = {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
'mode': '0755',
|
||||
'content': '\n'.join(sorted(node.metadata.get('left4dead2/admins'))),
|
||||
'triggers': [
|
||||
f'svc_systemd:left4dead2-{name}.service:restart',
|
||||
],
|
||||
}
|
||||
127
bundles/left4dead2_old/metadata.py
Normal file
127
bundles/left4dead2_old/metadata.py
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
assert node.has_bundle('steam')
|
||||
|
||||
from shlex import quote
|
||||
|
||||
defaults = {
|
||||
'steam': {
|
||||
'games': {
|
||||
'left4dead2': 222860,
|
||||
},
|
||||
},
|
||||
'left4dead2': {
|
||||
'servers': {},
|
||||
'admins': set(),
|
||||
'workshop': set(),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'left4dead2/servers',
|
||||
)
|
||||
def rconn_password(metadata):
|
||||
# only works from localhost!
|
||||
return {
|
||||
'left4dead2': {
|
||||
'servers': {
|
||||
server: {
|
||||
'rcon_password': repo.vault.password_for(f'{node.name} left4dead2 {server} rcon', length=24),
|
||||
}
|
||||
for server in metadata.get('left4dead2/servers')
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'steam-workshop-download',
|
||||
'systemd/units',
|
||||
)
|
||||
def server_units(metadata):
|
||||
units = {}
|
||||
workshop = {}
|
||||
|
||||
for name, config in metadata.get('left4dead2/servers').items():
|
||||
# mount overlay
|
||||
mountpoint = f'/opt/steam/left4dead2-servers/{name}'
|
||||
mount_unit_name = mountpoint[1:].replace('-', '\\x2d').replace('/', '-') + '.mount'
|
||||
units[mount_unit_name] = {
|
||||
'Unit': {
|
||||
'Description': f"Mount left4dead2 server {name} overlay",
|
||||
'Conflicts': {'umount.target'},
|
||||
'Before': {'umount.target'},
|
||||
},
|
||||
'Mount': {
|
||||
'What': 'overlay',
|
||||
'Where': mountpoint,
|
||||
'Type': 'overlay',
|
||||
'Options': ','.join([
|
||||
'auto',
|
||||
'lowerdir=/opt/steam/left4dead2',
|
||||
f'upperdir=/opt/steam-zfs-overlay-workarounds/{name}/upper',
|
||||
f'workdir=/opt/steam-zfs-overlay-workarounds/{name}/workdir',
|
||||
]),
|
||||
},
|
||||
'Install': {
|
||||
'RequiredBy': {
|
||||
f'left4dead2-{name}.service',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# individual workshop
|
||||
workshop_ids = config.get('workshop', set()) | metadata.get('left4dead2/workshop', set())
|
||||
if workshop_ids:
|
||||
workshop[f'left4dead2-{name}'] = {
|
||||
'ids': workshop_ids,
|
||||
'path': f'/opt/steam/left4dead2-servers/{name}/left4dead2/addons',
|
||||
'user': 'steam',
|
||||
'requires': {
|
||||
mount_unit_name,
|
||||
},
|
||||
'required_by': {
|
||||
f'left4dead2-{name}.service',
|
||||
},
|
||||
}
|
||||
|
||||
# left4dead2 server unit
|
||||
units[f'left4dead2-{name}.service'] = {
|
||||
'Unit': {
|
||||
'Description': f'left4dead2 server {name}',
|
||||
'After': {'steam-update.service'},
|
||||
'Requires': {'steam-update.service'},
|
||||
},
|
||||
'Service': {
|
||||
'User': 'steam',
|
||||
'Group': 'steam',
|
||||
'WorkingDirectory': f'/opt/steam/left4dead2-servers/{name}',
|
||||
'ExecStart': f'/opt/steam/left4dead2-servers/{name}/srcds_run -port {config["port"]} +exec server.cfg',
|
||||
'Restart': 'on-failure',
|
||||
},
|
||||
'Install': {
|
||||
'WantedBy': {'multi-user.target'},
|
||||
},
|
||||
}
|
||||
|
||||
return {
|
||||
'steam-workshop-download': workshop,
|
||||
'systemd': {
|
||||
'units': units,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'nftables/input',
|
||||
)
|
||||
def firewall(metadata):
|
||||
ports = set(str(server['port']) for server in metadata.get('left4dead2/servers').values())
|
||||
|
||||
return {
|
||||
'nftables': {
|
||||
'input': {
|
||||
f"tcp dport {{ {', '.join(sorted(ports))} }} accept",
|
||||
f"udp dport {{ {', '.join(sorted(ports))} }} accept",
|
||||
},
|
||||
},
|
||||
}
|
||||
97
bundles/left4dead2_old2/README.md
Normal file
97
bundles/left4dead2_old2/README.md
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# https://github.com/SirPlease/L4D2-Competitive-Rework/blob/master/Dedicated%20Server%20Install%20Guide/README.md
|
||||
|
||||
getent passwd steam >/dev/null || useradd -M -d /opt/l4d2 -s /bin/bash steam
|
||||
mkdir -p /opt/l4d2 /tmp/dumps
|
||||
chown steam:steam /opt/l4d2 /tmp/dumps
|
||||
dpkg --add-architecture i386
|
||||
apt update
|
||||
DEBIAN_FRONTEND=noninteractive apt install -y libc6:i386 lib32z1
|
||||
|
||||
function steam() { sudo -Hiu steam $* }
|
||||
|
||||
# -- STEAM -- #
|
||||
|
||||
steam mkdir -p /opt/l4d2/steam
|
||||
test -f /opt/l4d2/steam/steamcmd_linux.tar.gz || \
|
||||
steam wget http://media.steampowered.com/installer/steamcmd_linux.tar.gz -P /opt/l4d2/steam
|
||||
test -f /opt/l4d2/steam/steamcmd.sh || \
|
||||
steam tar -xvzf /opt/l4d2/steam/steamcmd_linux.tar.gz -C /opt/l4d2/steam
|
||||
|
||||
# fix: /opt/l4d2/.steam/sdk32/steamclient.so: cannot open shared object file: No such file or directory
|
||||
steam mkdir -p /opt/l4d2/steam/.steam
|
||||
test -f /opt/l4d2/steam/.steam/sdk32/steamclient.so || \
|
||||
steam ln -s /opt/l4d2/steam/linux32 /opt/l4d2/steam/.steam/sdk32
|
||||
|
||||
# -- INSTALL -- #
|
||||
|
||||
# erst die windows deps zu installieren scheint ein workaround für x64 zu sein?
|
||||
steam mkdir -p /opt/l4d2/installation
|
||||
steam /opt/l4d2/steam/steamcmd.sh \
|
||||
+force_install_dir /opt/l4d2/installation \
|
||||
+login anonymous \
|
||||
+@sSteamCmdForcePlatformType windows \
|
||||
+app_update 222860 validate \
|
||||
+quit
|
||||
steam /opt/l4d2/steam/steamcmd.sh \
|
||||
+force_install_dir /opt/l4d2/installation \
|
||||
+login anonymous \
|
||||
+@sSteamCmdForcePlatformType linux \
|
||||
+app_update 222860 validate \
|
||||
+quit
|
||||
|
||||
# -- OVERLAYS -- #
|
||||
|
||||
steam mkdir -p /opt/l4d2/overlays
|
||||
|
||||
# workshop downloader
|
||||
steam wget -4 https://git.sublimity.de/cronekorkn/steam-workshop-downloader/raw/branch/master/steam-workshop-download -P /opt/l4d2
|
||||
steam chmod +x /opt/l4d2/steam-workshop-download
|
||||
|
||||
# -- OVERLAY PVE -- #
|
||||
|
||||
steam mkdir -p /opt/l4d2/overlays/pve
|
||||
|
||||
# admin system
|
||||
steam mkdir -p /opt/l4d2/overlays/pve/left4dead2/addons
|
||||
steam /opt/l4d2/steam-workshop-download 2524204971 --out /opt/l4d2/overlays/pve/left4dead2/addons
|
||||
steam mkdir -p "/opt/l4d2/overlays/pve/left4dead2/ems/admin system"
|
||||
echo "STEAM_1:0:12376499" | steam tee "/opt/l4d2/overlays/pve/left4dead2/ems/admin system/admins.txt"
|
||||
|
||||
# ions vocalizer
|
||||
steam /opt/l4d2/steam-workshop-download 698857882 --out /opt/l4d2/overlays/pve/left4dead2/addons
|
||||
|
||||
# -- OVERLAY ZONEMOD -- #
|
||||
|
||||
true
|
||||
|
||||
# -- SERVERS -- #
|
||||
|
||||
steam mkdir -p /opt/l4d2/servers
|
||||
|
||||
# -- SERVER PVE1 -- #
|
||||
|
||||
steam mkdir -p \
|
||||
/opt/l4d2/servers/pve1 \
|
||||
/opt/l4d2/servers/pve1/work \
|
||||
/opt/l4d2/servers/pve1/upper \
|
||||
/opt/l4d2/servers/pve1/merged
|
||||
|
||||
mount -t overlay overlay \
|
||||
-o lowerdir=/opt/l4d2/overlays/pve:/opt/l4d2/installation,upperdir=/opt/l4d2/servers/pve1/upper,workdir=/opt/l4d2/servers/pve1/work \
|
||||
/opt/l4d2/servers/pve1/merged
|
||||
|
||||
# run server
|
||||
steam cat <<'EOF' > /opt/l4d2/servers/pve1/merged/left4dead2/cfg/server.cfg
|
||||
hostname "CKNs Server"
|
||||
motd_enabled 0
|
||||
|
||||
sv_steamgroup "38347879"
|
||||
#sv_steamgroup_exclusive 0
|
||||
|
||||
sv_minrate 60000
|
||||
sv_maxrate 0
|
||||
net_splitpacket_maxrate 60000
|
||||
|
||||
sv_hibernate_when_empty 0
|
||||
EOF
|
||||
steam /opt/l4d2/servers/pve1/merged/srcds_run -game left4dead2 -ip 0.0.0.0 -port 27015 +map c1m1_hotel
|
||||
0
bundles/left4dead2_old2/files/server.cfg
Normal file
0
bundles/left4dead2_old2/files/server.cfg
Normal file
183
bundles/left4dead2_old2/items.py
Normal file
183
bundles/left4dead2_old2/items.py
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
from shlex import quote
|
||||
|
||||
|
||||
def steam_run(cmd):
|
||||
return f'su - steam -c {quote(cmd)}'
|
||||
|
||||
|
||||
users = {
|
||||
'steam': {
|
||||
'home': '/opt/steam',
|
||||
},
|
||||
}
|
||||
|
||||
directories = {
|
||||
'/opt/steam': {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
},
|
||||
'/opt/steam/.steam': {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
},
|
||||
'/opt/left4dead2': {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
},
|
||||
'/opt/left4dead2/left4dead2/ems/admin system': {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
},
|
||||
'/opt/left4dead2/left4dead2/addons': {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
},
|
||||
'/tmp/dumps': {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
'mode': '1770',
|
||||
},
|
||||
}
|
||||
|
||||
symlinks = {
|
||||
'/opt/steam/.steam/sdk32': {
|
||||
'target': '/opt/steam/linux32',
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
},
|
||||
}
|
||||
|
||||
files = {
|
||||
'/opt/steam-workshop-download': {
|
||||
'content_type': 'download',
|
||||
'source': 'https://git.sublimity.de/cronekorkn/steam-workshop-downloader/raw/branch/master/steam-workshop-download',
|
||||
'mode': '755',
|
||||
},
|
||||
'/opt/left4dead2/left4dead2/ems/admin system/admins.txt': {
|
||||
'unless': 'test -f /opt/left4dead2/left4dead2/ems/admin system/admins.txt',
|
||||
'content': 'STEAM_1:0:12376499',
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
},
|
||||
}
|
||||
|
||||
actions = {
|
||||
'dpkg_add_architecture': {
|
||||
'command': 'dpkg --add-architecture i386',
|
||||
'unless': 'dpkg --print-foreign-architectures | grep -q i386',
|
||||
'triggers': [
|
||||
'action:apt_update',
|
||||
],
|
||||
'needed_by': [
|
||||
'pkg_apt:libc6_i386',
|
||||
],
|
||||
},
|
||||
'download_steam': {
|
||||
'command': steam_run('wget http://media.steampowered.com/installer/steamcmd_linux.tar.gz -P /opt/steam'),
|
||||
'unless': steam_run('test -f /opt/steam/steamcmd_linux.tar.gz'),
|
||||
'needs': {
|
||||
'pkg_apt:libc6_i386',
|
||||
'directory:/opt/steam',
|
||||
}
|
||||
},
|
||||
'extract_steamcmd': {
|
||||
'command': steam_run('tar -xvzf /opt/steam/steamcmd_linux.tar.gz -C /opt/steam'),
|
||||
'unless': steam_run('test -f /opt/steam/steamcmd.sh'),
|
||||
'needs': {
|
||||
'action:download_steam',
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
for addon_id in [2524204971]:
|
||||
actions[f'download-left4dead2-addon-{addon_id}'] = {
|
||||
'command': steam_run(f'/opt/steam-workshop-download {addon_id} --out /opt/left4dead2/left4dead2/addons'),
|
||||
'unless': steam_run(f'test -f /opt/left4dead2/left4dead2/addons/{addon_id}.vpk'),
|
||||
'needs': {
|
||||
'directory:/opt/left4dead2/left4dead2/addons',
|
||||
},
|
||||
'needed_by': {
|
||||
'tag:left4dead2-servers',
|
||||
},
|
||||
}
|
||||
|
||||
svc_systemd = {
|
||||
'left4dead2-install.service': {
|
||||
'enabled': True,
|
||||
'running': False,
|
||||
'needs': {
|
||||
'file:/usr/local/lib/systemd/system/left4dead2-install.service',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for server_name, server_config in node.metadata.get('left4dead2/servers', {}).items():
|
||||
svc_systemd[f'left4dead2-{server_name}.service'] = {
|
||||
'enabled': True,
|
||||
'running': True,
|
||||
'tags': {
|
||||
'left4dead2-servers',
|
||||
},
|
||||
'needs': {
|
||||
'svc_systemd:left4dead2-install.service',
|
||||
f'file:/usr/local/lib/systemd/system/left4dead2-{server_name}.service',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
# # https://github.com/SirPlease/L4D2-Competitive-Rework/blob/master/Dedicated%20Server%20Install%20Guide/README.md
|
||||
|
||||
# mkdir /opt/steam /tmp/dumps
|
||||
# useradd -M -d /opt/steam -s /bin/bash steam
|
||||
# chown steam:steam /opt/steam /tmp/dumps
|
||||
# dpkg --add-architecture i386
|
||||
# apt update
|
||||
# apt install libc6:i386 lib32z1
|
||||
# sudo su - steam -s /bin/bash
|
||||
|
||||
# #--------
|
||||
|
||||
# wget http://media.steampowered.com/installer/steamcmd_linux.tar.gz
|
||||
# tar -xvzf steamcmd_linux.tar.gz
|
||||
|
||||
# # fix: /opt/steam/.steam/sdk32/steamclient.so: cannot open shared object file: No such file or directory
|
||||
# mkdir /opt/steam/.steam && ln -s /opt/steam/linux32 /opt/steam/.steam/sdk32
|
||||
|
||||
# # erst die windows deps zu installieren scheint ein workaround für x64 zu sein?
|
||||
# ./steamcmd.sh \
|
||||
# +force_install_dir /opt/steam/left4dead2 \
|
||||
# +login anonymous \
|
||||
# +@sSteamCmdForcePlatformType windows \
|
||||
# +app_update 222860 validate \
|
||||
# +quit
|
||||
# ./steamcmd.sh \
|
||||
# +force_install_dir /opt/steam/left4dead2 \
|
||||
# +login anonymous \
|
||||
# +@sSteamCmdForcePlatformType linux \
|
||||
# +app_update 222860 validate \
|
||||
# +quit
|
||||
|
||||
# # download admin system
|
||||
# wget -4 https://git.sublimity.de/cronekorkn/steam-workshop-downloader/raw/branch/master/steam-workshop-download
|
||||
# chmod +x steam-workshop-download
|
||||
# ./steam-workshop-download 2524204971 --out /opt/steam/left4dead2/left4dead2/addons
|
||||
# mkdir -p "/opt/steam/left4dead2/left4dead2/ems/admin system"
|
||||
# echo "STEAM_1:0:12376499" > "/opt/steam/left4dead2/left4dead2/ems/admin system/admins.txt"
|
||||
|
||||
# /opt/steam/left4dead2/srcds_run -game left4dead2 -ip 0.0.0.0 -port 27015 +map c1m1_hotel
|
||||
|
||||
|
||||
# cat <<'EOF' > /opt/steam/left4dead2/left4dead2/cfg/server.cfg
|
||||
# hostname "CKNs Server"
|
||||
# motd_enabled 0
|
||||
|
||||
# sv_steamgroup "38347879"
|
||||
# #sv_steamgroup_exclusive 0
|
||||
|
||||
# sv_minrate 60000
|
||||
# sv_maxrate 0
|
||||
# net_splitpacket_maxrate 60000
|
||||
|
||||
# sv_hibernate_when_empty 0
|
||||
# EOF
|
||||
107
bundles/left4dead2_old2/metadata.py
Normal file
107
bundles/left4dead2_old2/metadata.py
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
from re import match
|
||||
|
||||
defaults = {
|
||||
'apt': {
|
||||
'packages': {
|
||||
'libc6_i386': {}, # installs libc6:i386
|
||||
'lib32z1': {},
|
||||
'unzip': {},
|
||||
},
|
||||
},
|
||||
'left4dead2': {
|
||||
'servers': {},
|
||||
},
|
||||
'nftables': {
|
||||
'input': {
|
||||
'udp dport { 27005, 27020 } accept',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'nftables/input',
|
||||
)
|
||||
def nftables(metadata):
|
||||
ports = sorted(str(config["port"]) for config in metadata.get('left4dead2/servers', {}).values())
|
||||
|
||||
return {
|
||||
'nftables': {
|
||||
'input': {
|
||||
f'ip protocol {{ tcp, udp }} th dport {{ {", ".join(ports)} }} accept'
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'systemd/units',
|
||||
)
|
||||
def initial_unit(metadata):
|
||||
install_command = (
|
||||
'/opt/steam/steamcmd.sh '
|
||||
'+force_install_dir /opt/left4dead2 '
|
||||
'+login anonymous '
|
||||
'+@sSteamCmdForcePlatformType {platform} '
|
||||
'+app_update 222860 validate '
|
||||
'+quit '
|
||||
)
|
||||
|
||||
return {
|
||||
'systemd': {
|
||||
'units': {
|
||||
'left4dead2-install.service': {
|
||||
'Unit': {
|
||||
'Description': 'install or update left4dead2',
|
||||
'After': 'network-online.target',
|
||||
},
|
||||
'Service': {
|
||||
'Type': 'oneshot',
|
||||
'RemainAfterExit': 'yes',
|
||||
'User': 'steam',
|
||||
'Group': 'steam',
|
||||
'WorkingDirectory': '/opt/steam',
|
||||
'ExecStartPre': install_command.format(platform='windows'),
|
||||
'ExecStart': install_command.format(platform='linux'),
|
||||
},
|
||||
'Install': {
|
||||
'WantedBy': {'multi-user.target'},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'systemd/units',
|
||||
)
|
||||
def server_units(metadata):
|
||||
units = {}
|
||||
|
||||
for name, config in metadata.get('left4dead2/servers').items():
|
||||
assert match(r'^[A-z0-9-_-]+$', name)
|
||||
|
||||
units[f'left4dead2-{name}.service'] = {
|
||||
'Unit': {
|
||||
'Description': f'left4dead2 server {name}',
|
||||
'After': {'left4dead2-install.service'},
|
||||
'Requires': {'left4dead2-install.service'},
|
||||
},
|
||||
'Service': {
|
||||
'User': 'steam',
|
||||
'Group': 'steam',
|
||||
'WorkingDirectory': '/opt/left4dead2',
|
||||
'ExecStart': f'/opt/left4dead2/srcds_run -port {config["port"]} +exec server_{name}.cfg',
|
||||
'Restart': 'on-failure',
|
||||
},
|
||||
'Install': {
|
||||
'WantedBy': {'multi-user.target'},
|
||||
},
|
||||
}
|
||||
|
||||
return {
|
||||
'systemd': {
|
||||
'units': units,
|
||||
},
|
||||
}
|
||||
54
bundles/left4dead2_steam_old/items.py
Normal file
54
bundles/left4dead2_steam_old/items.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
users = {
|
||||
'steam': {
|
||||
'home': '/opt/steam/steam',
|
||||
},
|
||||
}
|
||||
|
||||
directories = {
|
||||
'/opt/steam': {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
'needs': [
|
||||
'zfs_dataset:tank/steam',
|
||||
],
|
||||
},
|
||||
'/opt/steam/steam': {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
},
|
||||
}
|
||||
for game in node.metadata.get('steam/games'):
|
||||
directories[f'/opt/steam/{game}'] = {
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
'needed_by': [
|
||||
'svc_systemd:steam-update.service',
|
||||
],
|
||||
}
|
||||
|
||||
files = {
|
||||
'/opt/steam/steam/steamcmd_linux.tar.gz': {
|
||||
'content_type': 'download',
|
||||
'source': 'https://steamcdn-a.akamaihd.net/client/installer/steamcmd_linux.tar.gz',
|
||||
'owner': 'steam',
|
||||
'group': 'steam',
|
||||
},
|
||||
}
|
||||
|
||||
actions = {
|
||||
'extract_steamcmd': {
|
||||
'command': """su - steam -c 'tar xfvz /opt/steam/steam/steamcmd_linux.tar.gz --directory /opt/steam/steam'""",
|
||||
'unless': 'test -f /opt/steam/steam/steamcmd.sh',
|
||||
'needs': [
|
||||
'file:/opt/steam/steam/steamcmd_linux.tar.gz',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
svc_systemd['steam-update.service'] = {
|
||||
'running': None,
|
||||
'enabled': True,
|
||||
'needs': {
|
||||
'file:/usr/local/lib/systemd/system/steam-update.service',
|
||||
}
|
||||
}
|
||||
52
bundles/left4dead2_steam_old/metadata.py
Normal file
52
bundles/left4dead2_steam_old/metadata.py
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
defaults = {
|
||||
'apt': {
|
||||
'packages': {
|
||||
'lib32gcc-s1': {},
|
||||
'unzip': {},
|
||||
},
|
||||
},
|
||||
'steam': {
|
||||
'games': {
|
||||
'left4dead2': 222860,
|
||||
},
|
||||
},
|
||||
'zfs': {
|
||||
'datasets': {
|
||||
'tank/steam': {
|
||||
'mountpoint': '/opt/steam',
|
||||
'backup': False,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'systemd/units',
|
||||
)
|
||||
def initial_unit(metadata):
|
||||
return {
|
||||
'systemd': {
|
||||
'units': {
|
||||
'steam-update.service': {
|
||||
'Unit': {
|
||||
'Description': 'steam: install and update games',
|
||||
'After': 'network-online.target',
|
||||
},
|
||||
'Service': {
|
||||
'Type': 'oneshot',
|
||||
'User': 'steam',
|
||||
'Group': 'steam',
|
||||
'WorkingDirectory': '/opt/steam',
|
||||
'ExecStart': {
|
||||
f'/opt/steam/steam/steamcmd.sh +force_install_dir /opt/steam/{game} +login anonymous +app_update {id} validate +quit'
|
||||
for game, id in metadata.get('steam/games').items()
|
||||
}
|
||||
},
|
||||
'Install': {
|
||||
'WantedBy': {'multi-user.target'},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
defaults = {
|
||||
'sysctl': {
|
||||
'net.ipv4.icmp_ratelimit': '100',
|
||||
},
|
||||
'sysctl': {},
|
||||
'modules-load': set(),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ def dns(metadata):
|
|||
'dns': dns,
|
||||
}
|
||||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'letsencrypt/domains',
|
||||
)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ def user(metadata):
|
|||
'users': {
|
||||
'sshmon': {
|
||||
'authorized_users': {
|
||||
'nagios@' + metadata.get('monitoring/icinga2_node'): {},
|
||||
'nagios@' + metadata.get('monitoring/icinga2_node'),
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,209 +1,78 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import base64
|
||||
import hashlib
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
#!/bin/bash
|
||||
|
||||
USER="$1"
|
||||
|
||||
ALLOWED_EXTS = {
|
||||
".png", ".jpg", ".jpeg", ".heic", ".cr2", ".cr3", ".mp4", ".mov",
|
||||
".webp", ".avif", ".gif",
|
||||
}
|
||||
REL_SOURCE_PATH="/$1/files/$2"
|
||||
ABS_SOURCE_PATH="/var/lib/nextcloud/$1/files/$2"
|
||||
|
||||
DATETIME_KEYS = [
|
||||
("Composite", "SubSecDateTimeOriginal"),
|
||||
("Composite", "SubSecCreateDate"),
|
||||
("ExifIFD", "DateTimeOriginal"),
|
||||
("ExifIFD", "CreateDate"),
|
||||
("XMP-xmp", "CreateDate"),
|
||||
("Keys", "CreationDate"),
|
||||
("QuickTime", "CreateDate"),
|
||||
("XMP-photoshop", "DateCreated"),
|
||||
]
|
||||
REL_DEST_PATH="/$1/files/$3"
|
||||
ABS_DEST_PATH="/var/lib/nextcloud/$1/files/$3"
|
||||
|
||||
REL_UNSORTABLE_PATH="/$1/files/$4"
|
||||
ABS_UNSORTABLE_PATH="/var/lib/nextcloud/$1/files/$4"
|
||||
|
||||
def run(command: list[str], check: bool = True) -> subprocess.CompletedProcess:
|
||||
return subprocess.run(command, text=True, capture_output=True, check=check)
|
||||
echo "STARTING..."
|
||||
|
||||
chown -R www-data:www-data "$ABS_SOURCE_PATH"
|
||||
chmod -R 770 "$ABS_SOURCE_PATH"
|
||||
|
||||
def exiftool_data(file: Path) -> dict | None:
|
||||
result = run([
|
||||
"exiftool",
|
||||
"-j",
|
||||
"-a",
|
||||
"-u",
|
||||
"-g1",
|
||||
"-time:all",
|
||||
"-api", "QuickTimeUTC=1",
|
||||
"-d", "%Y-%m-%dT%H:%M:%S%z",
|
||||
str(file),
|
||||
], check=False)
|
||||
if result.returncode != 0:
|
||||
return None
|
||||
try:
|
||||
data = __import__("json").loads(result.stdout)
|
||||
return data[0] if data else None
|
||||
except Exception:
|
||||
return None
|
||||
SCAN="FALSE"
|
||||
IFS=$'\n'
|
||||
for f in `find "$ABS_SOURCE_PATH" -iname *.PNG -o -iname *.JPG -o -iname *.JPEG -o -iname *.HEIC -o -iname *.CR2 -o -iname *.CR3 -o -iname *.MP4 -o -iname *.MOV`; do
|
||||
SCAN="TRUE"
|
||||
echo "PROCESSING: $f"
|
||||
|
||||
|
||||
def exiftool_timestamp(file: Path) -> datetime | None:
|
||||
data = exiftool_data(file)
|
||||
if not data:
|
||||
return None
|
||||
|
||||
for category, key in DATETIME_KEYS:
|
||||
try:
|
||||
value = data[category][key]
|
||||
except (KeyError, TypeError):
|
||||
continue
|
||||
try:
|
||||
return datetime.strptime(value, "%Y-%m-%dT%H:%M:%S%z")
|
||||
except ValueError:
|
||||
EXIF=`exiftool "$f"`
|
||||
if grep -q '^Create Date' <<< $EXIF
|
||||
then
|
||||
DATETIME=`grep -m 1 "^Create Date" <<< $EXIF | cut -d: -f2- | xargs`
|
||||
elif grep -q '^File Modification Date' <<< $EXIF
|
||||
then
|
||||
DATETIME=`grep -m 1 '^File Modification Date' <<< $EXIF | cut -d: -f2- | xargs`
|
||||
else
|
||||
RELPATH=$(realpath --relative-to="$ABS_SOURCE_PATH" "$f")
|
||||
DIRNAME=$(dirname "$ABS_UNSORTABLE_PATH/$RELPATH")
|
||||
echo "UNSORTABLE: $f"
|
||||
mkdir -p "$DIRNAME"
|
||||
mv "$f" "$DIRNAME"
|
||||
continue
|
||||
fi
|
||||
|
||||
return None
|
||||
DATE=`cut -d' ' -f1 <<< $DATETIME`
|
||||
TIME=`cut -d' ' -f2 <<< $DATETIME | cut -d'+' -f1`
|
||||
|
||||
YEAR=`cut -d':' -f1 <<< $DATE`
|
||||
MONTH=`cut -d':' -f2 <<< $DATE`
|
||||
DAY=`cut -d':' -f3 <<< $DATE`
|
||||
HOUR=`cut -d':' -f1 <<< $TIME`
|
||||
MINUTE=`cut -d':' -f2 <<< $TIME`
|
||||
SECOND=`cut -d':' -f3 <<< $TIME`
|
||||
|
||||
def short_hash(file: Path) -> str:
|
||||
h = hashlib.sha256()
|
||||
with file.open("rb") as fh:
|
||||
for chunk in iter(lambda: fh.read(1024 * 1024), b""):
|
||||
h.update(chunk)
|
||||
digest = h.digest()
|
||||
b64 = base64.b64encode(digest).decode("ascii")
|
||||
return b64[:3].replace("/", "_").replace("+", "-")
|
||||
HASH=`sha256sum "$f" | xxd -r -p | base64 | head -c 3 | tr '/+' '_-'`
|
||||
EXT=`echo "${f##*.}" | tr '[:upper:]' '[:lower:]'`
|
||||
if [[ "$EXT" = "cr2" ]] || [[ "$EXT" = "cr3" ]]
|
||||
then
|
||||
RAW="raw/"
|
||||
else
|
||||
RAW=""
|
||||
fi
|
||||
FILE="$ABS_DEST_PATH/$YEAR-$MONTH/$RAW$YEAR$MONTH$DAY"-"$HOUR$MINUTE$SECOND"_"$HASH"."$EXT"
|
||||
echo "DESTINATION: $FILE"
|
||||
mkdir -p "$(dirname "$FILE")"
|
||||
mv -v "$f" "$FILE"
|
||||
done
|
||||
|
||||
if [ "$SCAN" == "TRUE" ]; then
|
||||
echo "SCANNING..."
|
||||
# find "$ABS_SOURCE_PATH/"* -type d -empty -delete >> /var/echo/nc-picsort.echo # nextcloud app bug when deleting folders
|
||||
chown -R www-data:www-data "$ABS_DEST_PATH"
|
||||
chown -R www-data:www-data "$ABS_UNSORTABLE_PATH"
|
||||
chmod -R 770 "$ABS_DEST_PATH"
|
||||
chmod -R 770 "$ABS_UNSORTABLE_PATH"
|
||||
sudo -u www-data php /opt/nextcloud/occ files:scan --path "$REL_SOURCE_PATH"
|
||||
sudo -u www-data php /opt/nextcloud/occ files:scan --path "$REL_UNSORTABLE_PATH"
|
||||
sudo -u www-data php /opt/nextcloud/occ files:scan --path "$REL_DEST_PATH"
|
||||
#sudo -u www-data php /opt/nextcloud/occ preview:pre-generate
|
||||
fi
|
||||
|
||||
def build_destination(dest_root: Path, file: Path, ts: datetime) -> Path:
|
||||
ext = file.suffix.lower().lstrip(".")
|
||||
year = ts.strftime("%Y")
|
||||
month = ts.strftime("%m")
|
||||
day = ts.strftime("%d")
|
||||
hour = ts.strftime("%H")
|
||||
minute = ts.strftime("%M")
|
||||
second = ts.strftime("%S")
|
||||
hash_part = short_hash(file)
|
||||
|
||||
raw_subdir = "raw" if ext in {"cr2", "cr3"} else None
|
||||
month_dir = dest_root / f"{year}-{month}"
|
||||
if raw_subdir:
|
||||
month_dir = month_dir / raw_subdir
|
||||
|
||||
filename = f"{year}{month}{day}-{hour}{minute}{second}_{hash_part}.{ext}"
|
||||
return month_dir / filename
|
||||
|
||||
|
||||
def move_unsortable(file: Path, source_root: Path, unsortable_root: Path) -> None:
|
||||
relpath = file.relative_to(source_root)
|
||||
target_dir = (unsortable_root / relpath).parent
|
||||
target_dir.mkdir(parents=True, exist_ok=True)
|
||||
shutil.chown(str(target_dir), user="www-data", group="www-data")
|
||||
target = target_dir / file.name
|
||||
if target.exists():
|
||||
return
|
||||
shutil.move(str(file), str(target))
|
||||
shutil.chown(str(target), user="www-data", group="www-data")
|
||||
|
||||
|
||||
def move_sorted(file: Path, target: Path) -> None:
|
||||
target.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.chown(str(target.parent), user="www-data", group="www-data")
|
||||
shutil.move(str(file), str(target))
|
||||
shutil.chown(str(target), user="www-data", group="www-data")
|
||||
|
||||
def process_file(file: Path, source_root: Path, dest_root: Path, unsortable_root: Path) -> tuple[Path, str]:
|
||||
print(f"PROCESSING: {file}")
|
||||
ts = exiftool_timestamp(file)
|
||||
|
||||
if ts is None:
|
||||
print(f"UNSORTABLE: {file}")
|
||||
move_unsortable(file, source_root, unsortable_root)
|
||||
return file, "unsortable"
|
||||
|
||||
target = build_destination(dest_root, file, ts)
|
||||
print(f"DESTINATION: {target}")
|
||||
move_sorted(file, target)
|
||||
return file, "sorted"
|
||||
|
||||
|
||||
def scan_nextcloud(rel_source: str, rel_unsortable: str, rel_dest: str) -> None:
|
||||
print("SCANNING...")
|
||||
# run(["chown", "-R", "www-data:www-data", abs_source_path], check=True)
|
||||
# run(["chmod", "-R", "770", abs_source_path], check=True)
|
||||
|
||||
# run(["chown", "-R", "www-data:www-data", abs_dest_path], check=True)
|
||||
# run(["chown", "-R", "www-data:www-data", abs_unsortable_path], check=True)
|
||||
# run(["chmod", "-R", "770", abs_dest_path], check=True)
|
||||
# run(["chmod", "-R", "770", abs_unsortable_path], check=True)
|
||||
|
||||
run(["sudo", "-u", "www-data", "php", "/opt/nextcloud/occ", "files:scan", "--path", rel_source], check=True)
|
||||
run(["sudo", "-u", "www-data", "php", "/opt/nextcloud/occ", "files:scan", "--path", rel_unsortable], check=True)
|
||||
run(["sudo", "-u", "www-data", "php", "/opt/nextcloud/occ", "files:scan", "--path", rel_dest], check=True)
|
||||
|
||||
run(["systemctl", "start", "nextcloud-generate-new-previews.service"], check=True)
|
||||
|
||||
|
||||
def iter_files(source_root: Path):
|
||||
for path in source_root.rglob("*"):
|
||||
if path.is_file() and path.suffix.lower() in ALLOWED_EXTS:
|
||||
yield path
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Sort Nextcloud media files by embedded timestamp."
|
||||
)
|
||||
parser.add_argument("nc_user")
|
||||
parser.add_argument("source_subdir")
|
||||
parser.add_argument("dest_subdir")
|
||||
parser.add_argument("unsortable_subdir")
|
||||
parser.add_argument("--workers", type=int, default=os.cpu_count() or 1)
|
||||
args = parser.parse_args()
|
||||
|
||||
nc_user = args.nc_user
|
||||
source_subdir = args.source_subdir
|
||||
dest_subdir = args.dest_subdir
|
||||
unsortable_subdir = args.unsortable_subdir
|
||||
|
||||
rel_source_path = f"/{nc_user}/files/{source_subdir}"
|
||||
abs_source_path = f"/var/lib/nextcloud/{nc_user}/files/{source_subdir}"
|
||||
|
||||
rel_dest_path = f"/{nc_user}/files/{dest_subdir}"
|
||||
abs_dest_path = f"/var/lib/nextcloud/{nc_user}/files/{dest_subdir}"
|
||||
|
||||
rel_unsortable_path = f"/{nc_user}/files/{unsortable_subdir}"
|
||||
abs_unsortable_path = f"/var/lib/nextcloud/{nc_user}/files/{unsortable_subdir}"
|
||||
|
||||
source_root = Path(abs_source_path)
|
||||
dest_root = Path(abs_dest_path)
|
||||
unsortable_root = Path(abs_unsortable_path)
|
||||
|
||||
print("STARTING...")
|
||||
|
||||
run(["chown", "-R", "www-data:www-data", str(source_root)], check=True)
|
||||
run(["chmod", "-R", "770", str(source_root)], check=True)
|
||||
|
||||
files = list(iter_files(source_root))
|
||||
|
||||
if not files:
|
||||
print("NO MATCHING FILES FOUND.")
|
||||
print("FINISH.")
|
||||
raise SystemExit(0)
|
||||
|
||||
with ThreadPoolExecutor(max_workers=max(1, args.workers)) as executor:
|
||||
futures = {
|
||||
executor.submit(process_file, file, source_root, dest_root, unsortable_root): file
|
||||
for file in files
|
||||
}
|
||||
for future in as_completed(futures):
|
||||
future.result()
|
||||
|
||||
scan_nextcloud(rel_source_path, rel_unsortable_path, rel_dest_path)
|
||||
|
||||
print("FINISH.")
|
||||
echo "FINISH."
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
Nextcloud
|
||||
=========
|
||||
|
||||
import iphone pictures
|
||||
----------------------
|
||||
|
||||
Use Photos app on macOS
|
||||
- select library in the left sidebar
|
||||
- select the pictures
|
||||
- in menu bar open File > Export Unmodified Original for X Photos
|
||||
|
||||
The only reliable way to get some files creation time is being lost with rsync, so
|
||||
we need to embed those timestamps on macos first:
|
||||
|
||||
```sh
|
||||
PHOTOS_PATH="/Users/mwiegand/Desktop/photos"
|
||||
bin/timestamp_icloud_photos_for_nextcloud -d "$PHOTOS_PATH"
|
||||
rsync -avh --progress --rsync-path="sudo rsync" "$PHOTOS_PATH/" ckn@10.0.0.2:/var/lib/nextcloud/ckn/files/SofortUpload/AutoSort/
|
||||
```
|
||||
|
||||
preview generator
|
||||
-----------------
|
||||
|
||||
```
|
||||
sudo -u www-data php /opt/nextcloud/occ preview:generate-all -w "$(nproc)" -n -vvv
|
||||
```
|
||||
|
||||
This index speeds up preview generator dramatically:
|
||||
```sh
|
||||
CREATE INDEX CONCURRENTLY oc_filecache_path_hash_idx
|
||||
ON oc_filecache (path_hash);
|
||||
```
|
||||
|
||||
delete previews:
|
||||
```sh
|
||||
psql nextcloud -x -c "DELETE FROM oc_previews;"
|
||||
rm -rf /var/lib/nextcloud/appdata_oci6dw1woodz/preview/*
|
||||
```
|
||||
|
||||
https://docs.nextcloud.com/server/stable/admin_manual/configuration_files/previews_configuration.html#maximum-preview-size
|
||||
```php
|
||||
'preview_max_x' => 1920,
|
||||
'preview_max_y' => 1920,
|
||||
'preview_max_scale_factor' => 4,
|
||||
```
|
||||
|
||||
https://github.com/nextcloud/previewgenerator?tab=readme-ov-file#i-dont-want-to-generate-all-the-preview-sizes
|
||||
```sh
|
||||
sudo -u www-data php /opt/nextcloud/occ config:app:set --value="64 256" previewgenerator squareSizes
|
||||
sudo -u www-data php /opt/nextcloud/occ config:app:set --value="" previewgenerator fillWidthHeightSizes # changed
|
||||
sudo -u www-data php /opt/nextcloud/occ config:app:set --value="" previewgenerator widthSizes
|
||||
sudo -u www-data php /opt/nextcloud/occ config:app:set --value="" previewgenerator heightSizes
|
||||
sudo -u www-data php /opt/nextcloud/occ config:app:set preview jpeg_quality --value="75"
|
||||
sudo -u www-data php /opt/nextcloud/occ config:app:set --value=0 --type=integer previewgenerator job_max_previews # in favour of systemd timer
|
||||
```
|
||||
|
||||
gen previews
|
||||
```sh
|
||||
php /opt/nextcloud/occ preview:generate-all --workers="$(nproc)" --no-interaction -vvv
|
||||
```
|
||||
|
||||
check preview geenration
|
||||
```sh
|
||||
find /var/lib/nextcloud/appdata_oci6dw1woodz/preview
|
||||
# /var/lib/nextcloud/appdata_oci6dw1woodz/preview/6/9/1/f/7/b/4/2822419/64-64-crop.jpg
|
||||
# /var/lib/nextcloud/appdata_oci6dw1woodz/preview/6/9/1/f/7/b/4/2822419/256-256-crop.jpg
|
||||
# /var/lib/nextcloud/appdata_oci6dw1woodz/preview/6/9/1/f/7/b/4/2822419/1280-1920-max.jpg
|
||||
|
||||
du -sh /var/lib/nextcloud/appdata_oci6dw1woodz/preview
|
||||
# 28G /var/lib/nextcloud/appdata_oci6dw1woodz/preview
|
||||
```
|
||||
5
bundles/nextcloud/files/rescan
Normal file
5
bundles/nextcloud/files/rescan
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
php /opt/nextcloud/occ files:scan --all
|
||||
php /opt/nextcloud/occ files:scan-app-data
|
||||
#php /opt/nextcloud/occ preview:generate-all
|
||||
|
|
@ -146,3 +146,15 @@ actions['nextcloud_add_missing_inidces'] = {
|
|||
f'action:extract_nextcloud',
|
||||
],
|
||||
}
|
||||
|
||||
# RESCAN
|
||||
|
||||
files['/opt/nextcloud_rescan'] = {
|
||||
'source': 'rescan',
|
||||
'owner': 'www-data',
|
||||
'group': 'www-data',
|
||||
'mode': '550',
|
||||
'needs': [
|
||||
'action:extract_nextcloud',
|
||||
],
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
from shlex import quote
|
||||
|
||||
import string
|
||||
from uuid import UUID
|
||||
|
||||
defaults = {
|
||||
'apt': {
|
||||
|
|
@ -85,35 +85,11 @@ defaults = {
|
|||
'user': 'www-data',
|
||||
'kill_mode': 'process',
|
||||
},
|
||||
'nextcloud-scan-app-data': {
|
||||
'command': '/usr/bin/php /opt/nextcloud/occ files:scan-app-data',
|
||||
'when': 'yearly',
|
||||
'nextcloud-rescan': {
|
||||
'command': '/opt/nextcloud_rescan',
|
||||
'when': 'Sun 00:00:00',
|
||||
'user': 'www-data',
|
||||
},
|
||||
'nextcloud-scan-files': {
|
||||
'command': '/usr/bin/php /opt/nextcloud/occ files:scan --all',
|
||||
'when': 'weekly',
|
||||
'user': 'www-data',
|
||||
'after': {
|
||||
'nextcloud-scan-app-data.service',
|
||||
},
|
||||
},
|
||||
'nextcloud-generate-all-previews': {
|
||||
'command': '/bin/bash -c ' + quote('php /opt/nextcloud/occ preview:generate-all --workers="$(nproc)" --no-interaction -vvv'),
|
||||
'when': 'monthly',
|
||||
'user': 'www-data',
|
||||
'after': {
|
||||
'nextcloud-scan-files.service',
|
||||
},
|
||||
},
|
||||
'nextcloud-generate-new-previews': {
|
||||
'command': '/usr/bin/php /opt/nextcloud/occ preview:pre-generate --no-interaction -vvv',
|
||||
'when': '*:0/5', # every 5 minutes
|
||||
'user': 'www-data',
|
||||
'after': {
|
||||
'nextcloud-generate-all-previews.service',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -158,18 +134,10 @@ def config(metadata):
|
|||
'127.0.0.1',
|
||||
metadata.get('nextcloud/hostname'),
|
||||
],
|
||||
'enabledPreviewProviders': [
|
||||
'OC\\Preview\\Image',
|
||||
'OC\\Preview\\Movie',
|
||||
'OC\\Preview\\HEIC',
|
||||
],
|
||||
'preview_max_x': 1920,
|
||||
'preview_max_y': 1920,
|
||||
'preview_max_scale_factor': 4,
|
||||
'log_type': 'syslog',
|
||||
'syslog_tag': 'nextcloud',
|
||||
'logfile': '',
|
||||
'loglevel': 2,
|
||||
'loglevel': 3,
|
||||
'default_phone_region': 'DE',
|
||||
'versions_retention_obligation': 'auto, 90',
|
||||
'simpleSignUpLink.shown': False,
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ defaults = {
|
|||
},
|
||||
},
|
||||
'telegraf': {
|
||||
'config': {
|
||||
'inputs': {
|
||||
'postfix': {
|
||||
'default': {},
|
||||
'postfix': [{}],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -98,17 +98,17 @@ def zfs(metadata):
|
|||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'telegraf/inputs/postgresql/default',
|
||||
'telegraf/config/inputs/postgresql',
|
||||
)
|
||||
def telegraf(metadata):
|
||||
return {
|
||||
'telegraf': {
|
||||
'config': {
|
||||
'inputs': {
|
||||
'postgresql': {
|
||||
'default': {
|
||||
'postgresql': [{
|
||||
'address': f'postgres://root:{root_password}@localhost:5432/postgres',
|
||||
'databases': sorted(list(node.metadata.get('postgresql/databases').keys())),
|
||||
},
|
||||
}],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ defaults = {
|
|||
'sources': {
|
||||
'proxmox-ve': {
|
||||
'options': {
|
||||
'Architectures': 'amd64',
|
||||
'aarch': 'amd64',
|
||||
},
|
||||
'urls': {
|
||||
'http://download.proxmox.com/debian/pve',
|
||||
|
|
|
|||
|
|
@ -8,14 +8,16 @@ defaults = {
|
|||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'telegraf/agent',
|
||||
'telegraf/config/agent',
|
||||
)
|
||||
def telegraf(metadata):
|
||||
return {
|
||||
'telegraf': {
|
||||
'config': {
|
||||
'agent': {
|
||||
'flush_interval': '30s',
|
||||
'interval': '1m',
|
||||
'interval': '30s',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@ $config['enable_installer'] = true;
|
|||
$config['db_dsnw'] = '${database['provider']}://${database['user']}:${database['password']}@${database['host']}/${database['name']}';
|
||||
$config['imap_host'] = 'ssl://${imap_host}';
|
||||
$config['imap_port'] = 993;
|
||||
#$config['imap_debug'] = true;
|
||||
$config['smtp_host'] = 'tls://${imap_host}';
|
||||
$config['smtp_host'] = 'tls://localhost';
|
||||
$config['smtp_port'] = 587;
|
||||
$config['smtp_user'] = '%u';
|
||||
$config['smtp_pass'] = '%p';
|
||||
#$config['imap_debug'] = true;
|
||||
#$config['smtp_debug'] = true;
|
||||
$config['support_url'] = '';
|
||||
$config['des_key'] = '${des_key}';
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,11 +0,0 @@
|
|||
files = {
|
||||
# https://mikrotik.com/download/tools
|
||||
'/usr/share/snmp/mibs/MIKROTIK-MIB.txt': {
|
||||
'source': 'mikrotik.mib',
|
||||
'content_type': 'binary',
|
||||
'mode': '0644',
|
||||
'needed_by': {
|
||||
'svc_systemd:telegraf.service',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -1,444 +0,0 @@
|
|||
input_defaults = {
|
||||
"agents": [
|
||||
f"udp://{routeros_node.hostname}:161"
|
||||
for routeros_node in repo.nodes_in_group("routeros")
|
||||
],
|
||||
"agent_host_tag": "source",
|
||||
"version": 2,
|
||||
"community": "public",
|
||||
"max_repetitions": 5, # supposedly less spiky loads
|
||||
"tags": {
|
||||
"operating_system": "routeros",
|
||||
},
|
||||
}
|
||||
|
||||
defaults = {
|
||||
'apt': {
|
||||
'packages': {
|
||||
'snmp': {},
|
||||
'snmp-mibs-downloader': {},
|
||||
},
|
||||
},
|
||||
"telegraf": {
|
||||
"processors": {
|
||||
"enum": {
|
||||
"mikrotik_host_mapping":{
|
||||
# - measurements get switch ip as agent_host tag
|
||||
# - wie define a value mapping ip -> node name
|
||||
# - agent_host gets translated and written into host tag
|
||||
"tagpass": {
|
||||
"operating_system": ["routeros"],
|
||||
},
|
||||
"mapping": [
|
||||
{
|
||||
"tags": ["source"],
|
||||
"dest": "host",
|
||||
"default": "unknown",
|
||||
"value_mappings": {
|
||||
routeros_node.hostname: routeros_node.name
|
||||
for routeros_node in repo.nodes_in_group("routeros")
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
"inputs": {
|
||||
"snmp": {
|
||||
"mikrotik_switches_fast": {
|
||||
"interval": "2m",
|
||||
"collection_jitter": "20s",
|
||||
**input_defaults,
|
||||
"table": [
|
||||
# CPU load (HR-MIB)
|
||||
{
|
||||
"name": "mikrotik_cpu",
|
||||
"oid": "HOST-RESOURCES-MIB::hrProcessorTable",
|
||||
"field": [
|
||||
{
|
||||
"name": "frw_id",
|
||||
"oid": "HOST-RESOURCES-MIB::hrProcessorFrwID",
|
||||
"is_tag": True,
|
||||
},
|
||||
{
|
||||
"name": "load",
|
||||
"oid": "HOST-RESOURCES-MIB::hrProcessorLoad",
|
||||
},
|
||||
],
|
||||
},
|
||||
# Storage (HR-MIB)
|
||||
{
|
||||
"name": "mikrotik_storage",
|
||||
"oid": "HOST-RESOURCES-MIB::hrStorageTable",
|
||||
"field": [
|
||||
{
|
||||
"name": "index",
|
||||
"oid": "HOST-RESOURCES-MIB::hrStorageIndex",
|
||||
"is_tag": True,
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"oid": "HOST-RESOURCES-MIB::hrStorageType",
|
||||
"is_tag": True,
|
||||
},
|
||||
{
|
||||
"name": "descr",
|
||||
"oid": "HOST-RESOURCES-MIB::hrStorageDescr",
|
||||
"is_tag": True,
|
||||
},
|
||||
{
|
||||
"name": "alloc_unit",
|
||||
"oid": "HOST-RESOURCES-MIB::hrStorageAllocationUnits",
|
||||
},
|
||||
{
|
||||
"name": "size",
|
||||
"oid": "HOST-RESOURCES-MIB::hrStorageSize",
|
||||
},
|
||||
{
|
||||
"name": "used",
|
||||
"oid": "HOST-RESOURCES-MIB::hrStorageUsed",
|
||||
},
|
||||
{
|
||||
"name": "alloc_failures",
|
||||
"oid": "HOST-RESOURCES-MIB::hrStorageAllocationFailures",
|
||||
},
|
||||
],
|
||||
},
|
||||
# MikroTik Health (table)
|
||||
{
|
||||
"name": "mikrotik_health",
|
||||
"oid": "MIKROTIK-MIB::mtxrGaugeTable",
|
||||
"field": [
|
||||
{
|
||||
"name": "sensor",
|
||||
"oid": "MIKROTIK-MIB::mtxrGaugeName",
|
||||
"is_tag": True,
|
||||
},
|
||||
{
|
||||
"name": "value",
|
||||
"oid": "MIKROTIK-MIB::mtxrGaugeValue",
|
||||
},
|
||||
{
|
||||
"name": "unit",
|
||||
"oid": "MIKROTIK-MIB::mtxrGaugeUnit",
|
||||
"is_tag": True,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
"mikrotik_switches_slow": {
|
||||
"interval": "7m",
|
||||
"collection_jitter": "2m",
|
||||
**input_defaults,
|
||||
"table": [
|
||||
# Interface statistics (standard IF-MIB)
|
||||
{
|
||||
"name": "mikrotik_interface_generic",
|
||||
"oid": "IF-MIB::ifTable",
|
||||
"field": [
|
||||
# 6: ethernetCsmacd (physischer Ethernet-Port)
|
||||
# 24: softwareLoopback
|
||||
# 53: propVirtual (oft VLANs bei MikroTik)
|
||||
# 131: tunnel
|
||||
# 135: l2vlan
|
||||
# 161: ieee8023adLag (Bonding/LACP)
|
||||
# 209: bridge
|
||||
{
|
||||
"name": "ifType",
|
||||
"oid": "IF-MIB::ifType",
|
||||
"is_tag": True,
|
||||
},
|
||||
|
||||
# Labels (optional but recommended)
|
||||
{
|
||||
"name": "ifName",
|
||||
"oid": "IF-MIB::ifName",
|
||||
"is_tag": True,
|
||||
},
|
||||
{
|
||||
"name": "ifAlias",
|
||||
"oid": "IF-MIB::ifAlias",
|
||||
"is_tag": True,
|
||||
},
|
||||
|
||||
# Bytes (64-bit)
|
||||
{
|
||||
"name": "in_octets",
|
||||
"oid": "IF-MIB::ifHCInOctets",
|
||||
},
|
||||
{
|
||||
"name": "out_octets",
|
||||
"oid": "IF-MIB::ifHCOutOctets",
|
||||
},
|
||||
|
||||
# Packets (64-bit unicast)
|
||||
{
|
||||
"name": "in_ucast_pkts",
|
||||
"oid": "IF-MIB::ifHCInUcastPkts",
|
||||
},
|
||||
{
|
||||
"name": "out_ucast_pkts",
|
||||
"oid": "IF-MIB::ifHCOutUcastPkts",
|
||||
},
|
||||
{
|
||||
"name": "in_mcast_pkts",
|
||||
"oid": "IF-MIB::ifHCInMulticastPkts",
|
||||
},
|
||||
{
|
||||
"name": "in_bcast_pkts",
|
||||
"oid": "IF-MIB::ifHCInBroadcastPkts",
|
||||
},
|
||||
{
|
||||
"name": "out_mcast_pkts",
|
||||
"oid": "IF-MIB::ifHCOutMulticastPkts",
|
||||
},
|
||||
{
|
||||
"name": "out_bcast_pkts",
|
||||
"oid": "IF-MIB::ifHCOutBroadcastPkts",
|
||||
},
|
||||
|
||||
# Drops / Errors
|
||||
{
|
||||
"name": "in_discards",
|
||||
"oid": "IF-MIB::ifInDiscards",
|
||||
},
|
||||
{
|
||||
"name": "out_discards",
|
||||
"oid": "IF-MIB::ifOutDiscards",
|
||||
},
|
||||
{
|
||||
"name": "in_errors",
|
||||
"oid": "IF-MIB::ifInErrors",
|
||||
},
|
||||
{
|
||||
"name": "out_errors",
|
||||
"oid": "IF-MIB::ifOutErrors",
|
||||
},
|
||||
],
|
||||
},
|
||||
# Interface PoE
|
||||
{
|
||||
"name": "mikrotik_poe",
|
||||
"oid": "MIKROTIK-MIB::mtxrPOETable",
|
||||
"field": [
|
||||
{
|
||||
"name": "ifName",
|
||||
"oid": "IF-MIB::ifName",
|
||||
"is_tag": True,
|
||||
},
|
||||
{
|
||||
"name": "ifAlias",
|
||||
"oid": "IF-MIB::ifAlias",
|
||||
"is_tag": True,
|
||||
},
|
||||
{
|
||||
"name": "ifindex",
|
||||
"oid": "MIKROTIK-MIB::mtxrPOEInterfaceIndex",
|
||||
"is_tag": True,
|
||||
},
|
||||
{
|
||||
"name": "status",
|
||||
"oid": "MIKROTIK-MIB::mtxrPOEStatus",
|
||||
},
|
||||
{
|
||||
"name": "voltage",
|
||||
"oid": "MIKROTIK-MIB::mtxrPOEVoltage",
|
||||
},
|
||||
{
|
||||
"name": "current",
|
||||
"oid": "MIKROTIK-MIB::mtxrPOECurrent",
|
||||
},
|
||||
{
|
||||
"name": "power",
|
||||
"oid": "MIKROTIK-MIB::mtxrPOEPower",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
"mikrotik_switches_very_slow": {
|
||||
"interval": "20m",
|
||||
"collection_jitter": "5m",
|
||||
**input_defaults,
|
||||
"table": [
|
||||
# Interface statistics (MikroTik-specific mib)
|
||||
{
|
||||
"name": "mikrotik_interface_detailed",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsTable",
|
||||
"field": [
|
||||
# Join key / label (usually identical to IF-MIB ifName)
|
||||
{
|
||||
"name": "ifName",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsName",
|
||||
"is_tag": True,
|
||||
},
|
||||
|
||||
# join IF-MIB for better labels
|
||||
{
|
||||
"name": "ifAlias",
|
||||
"oid": "IF-MIB::ifAlias",
|
||||
"is_tag": True,
|
||||
},
|
||||
|
||||
# =========================
|
||||
# Physical layer (L1/L2)
|
||||
# =========================
|
||||
# CRC/FCS errors → very often cabling, connectors, SFPs, signal quality (EMI)
|
||||
{
|
||||
"name": "rx_fcs_errors",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsRxFCSError",
|
||||
},
|
||||
# Alignment errors → typically duplex mismatch or PHY problems
|
||||
{
|
||||
"name": "rx_align_errors",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsRxAlignError",
|
||||
},
|
||||
# Code errors → PHY encoding errors (signal/SFP/PHY)
|
||||
{
|
||||
"name": "rx_code_errors",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsRxCodeError",
|
||||
},
|
||||
# Carrier errors → carrier lost (copper issues, autoneg, PHY instability)
|
||||
{
|
||||
"name": "rx_carrier_errors",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsRxCarrierError",
|
||||
},
|
||||
# Jabber → extremely long invalid frames (faulty NIC/PHY, very severe)
|
||||
{
|
||||
"name": "rx_jabber",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsRxJabber",
|
||||
},
|
||||
|
||||
# ==================================
|
||||
# Length / framing anomalies (diagnostic)
|
||||
# ==================================
|
||||
# Frames shorter than minimum (noise, collisions, broken sender)
|
||||
{
|
||||
"name": "rx_too_short",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsRxTooShort",
|
||||
},
|
||||
# Frames longer than allowed (MTU mismatch, framing errors)
|
||||
{
|
||||
"name": "rx_too_long",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsRxTooLong",
|
||||
},
|
||||
# Fragments (often collision-related or duplex mismatch)
|
||||
{
|
||||
"name": "rx_fragment",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsRxFragment",
|
||||
},
|
||||
# Generic length errors
|
||||
{
|
||||
"name": "rx_length_errors",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsRxLengthError",
|
||||
},
|
||||
|
||||
# ==================
|
||||
# Drops (real packet loss)
|
||||
# ==================
|
||||
# RX drops (queue/ASIC/policy/overload) → highly alert-worthy
|
||||
{
|
||||
"name": "rx_drop",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsRxDrop",
|
||||
},
|
||||
# TX drops (buffer/queue exhaustion, scheduling, ASIC limits)
|
||||
{
|
||||
"name": "tx_drop",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsTxDrop",
|
||||
},
|
||||
|
||||
# =========================================
|
||||
# Duplex / collision indicators
|
||||
# (should be zero on full-duplex links)
|
||||
# =========================================
|
||||
# Total collisions (relevant only for half-duplex or misconfigurations)
|
||||
{
|
||||
"name": "tx_collisions",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsTxCollision",
|
||||
},
|
||||
# Late collisions → almost always duplex mismatch / bad autoneg
|
||||
{
|
||||
"name": "tx_late_collisions",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsTxLateCollision",
|
||||
},
|
||||
# Aggregate collision counter (context)
|
||||
{
|
||||
"name": "tx_total_collisions",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsTxTotalCollision",
|
||||
},
|
||||
# Excessive collisions → persistent duplex problems
|
||||
{
|
||||
"name": "tx_excessive_collisions",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsTxExcessiveCollision",
|
||||
},
|
||||
|
||||
# ==================
|
||||
# Flow control (diagnostic)
|
||||
# ==================
|
||||
# Pause frames received (peer throttling you)
|
||||
{
|
||||
"name": "rx_pause",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsRxPause",
|
||||
},
|
||||
# Pause frames sent (you throttling the peer)
|
||||
{
|
||||
"name": "tx_pause",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsTxPause",
|
||||
},
|
||||
# Pause frames actually honored
|
||||
{
|
||||
"name": "tx_pause_honored",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsTxPauseHonored",
|
||||
},
|
||||
|
||||
# ==========
|
||||
# Stability
|
||||
# ==========
|
||||
# Link-down events (loose cables, bad SFPs, PoE power drops, reboots)
|
||||
{
|
||||
"name": "link_downs",
|
||||
"oid": "MIKROTIK-MIB::mtxrInterfaceStatsLinkDowns",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# @metadata_reactor.provides(
|
||||
# 'telegraf/processors/enum',
|
||||
# )
|
||||
# def tag_important_ports(metadata):
|
||||
# # We want a graph, only for important ports. We deem ports important, if they have untagged vlans configured.
|
||||
# return {
|
||||
# "telegraf": {
|
||||
# "processors": {
|
||||
# "enum": {
|
||||
# f"mikrotik_port_mapping_{routeros_node.name}":{
|
||||
# "tagpass": {
|
||||
# "agent_host": [routeros_node.hostname],
|
||||
# },
|
||||
# "mapping": [
|
||||
# {
|
||||
# "tag": "ifName",
|
||||
# "dest": "is_infra",
|
||||
# "default": "false",
|
||||
# "value_mappings": {
|
||||
# port_name: "true"
|
||||
# for port_name, port_conf in repo.libs.mikrotik.get_netbox_config_for(routeros_node)['interfaces'].items()
|
||||
# if port_conf['mode'] == "tagged-all" or port_conf['tagged_vlans']
|
||||
# if port_conf['type'] != "lag"
|
||||
# },
|
||||
# },
|
||||
# ],
|
||||
# }
|
||||
# for routeros_node in repo.nodes_in_group("switches-mikrotik")
|
||||
# },
|
||||
# },
|
||||
# },
|
||||
# }
|
||||
|
|
@ -27,15 +27,15 @@ routeros['/system/identity'] = {
|
|||
# for topic in LOGGING_TOPICS:
|
||||
# routeros[f'/system/logging?action=memory&topics={topic}'] = {}
|
||||
|
||||
routeros['/snmp'] = {
|
||||
'enabled': True,
|
||||
}
|
||||
routeros['/snmp/community?name=public'] = {
|
||||
'addresses': '0.0.0.0/0',
|
||||
'disabled': False,
|
||||
'read-access': True,
|
||||
'write-access': False,
|
||||
}
|
||||
# routeros['/snmp'] = {
|
||||
# 'enabled': True,
|
||||
# }
|
||||
# routeros['/snmp/community?name=public'] = {
|
||||
# 'addresses': '0.0.0.0/0',
|
||||
# 'disabled': False,
|
||||
# 'read-access': True,
|
||||
# 'write-access': False,
|
||||
# }
|
||||
|
||||
routeros['/system/clock'] = {
|
||||
'time-zone-autodetect': False,
|
||||
|
|
@ -55,7 +55,7 @@ for vlan_name, vlan_id in node.metadata.get('routeros/vlans').items():
|
|||
'vlan-id': vlan_id,
|
||||
'interface': 'bridge',
|
||||
'tags': {
|
||||
'routeros-vlans',
|
||||
'routeros-vlan',
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -68,33 +68,10 @@ for vlan_name, vlan_id in node.metadata.get('routeros/vlans').items():
|
|||
'routeros-vlan-ports',
|
||||
},
|
||||
'needs': {
|
||||
'tag:routeros-vlans',
|
||||
'tag:routeros-vlan',
|
||||
},
|
||||
}
|
||||
|
||||
for port_name, port_conf in node.metadata.get('routeros/ports').items():
|
||||
untagged_vlan = node.metadata.get('routeros/vlan_groups')[port_conf.get('vlan_group')]['untagged']
|
||||
|
||||
routeros[f'/interface/bridge/port?interface={port_name}'] = {
|
||||
'disabled': False,
|
||||
'bridge': 'bridge',
|
||||
'pvid': node.metadata.get('routeros/vlans')[untagged_vlan],
|
||||
'tags': {
|
||||
'routeros-ports'
|
||||
},
|
||||
'needs': {
|
||||
'tag:routeros-vlan-ports',
|
||||
},
|
||||
}
|
||||
|
||||
routeros[f'/interface?name={port_name}'] = {
|
||||
'_comment': port_conf.get('description', ''),
|
||||
}
|
||||
|
||||
if comment := port_conf.get('comment', None):
|
||||
routeros[f'/interface/bridge/port?interface={port_name}']['_comment'] = comment
|
||||
routeros[f'/interface?name={port_name}']['_comment'] = comment
|
||||
|
||||
# create IPs
|
||||
for ip, ip_conf in node.metadata.get('routeros/ips').items():
|
||||
routeros[f'/ip/address?address={ip}'] = {
|
||||
|
|
@ -103,8 +80,7 @@ for ip, ip_conf in node.metadata.get('routeros/ips').items():
|
|||
'routeros-ip',
|
||||
},
|
||||
'needs': {
|
||||
'tag:routeros-vlans',
|
||||
'tag:routeros-ports'
|
||||
'tag:routeros-vlan',
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -114,8 +90,7 @@ routeros['/interface/bridge?name=bridge'] = {
|
|||
'priority': node.metadata.get('routeros/bridge_priority'),
|
||||
'protocol-mode': 'rstp',
|
||||
'needs': {
|
||||
'tag:routeros-vlans',
|
||||
'tag:routeros-ports',
|
||||
'tag:routeros-vlan',
|
||||
'tag:routeros-vlan-ports',
|
||||
'tag:routeros-ip',
|
||||
},
|
||||
|
|
@ -127,7 +102,7 @@ routeros['/interface/vlan'] = {
|
|||
'id-by': 'name',
|
||||
},
|
||||
'needed_by': {
|
||||
'tag:routeros-vlans',
|
||||
'tag:routeros-vlan',
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -139,6 +114,6 @@ routeros['/interface/bridge/vlan'] = {
|
|||
},
|
||||
},
|
||||
'needed_by': {
|
||||
'tag:routeros-vlans',
|
||||
'tag:routeros-vlan',
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,22 +11,24 @@ defaults = {
|
|||
},
|
||||
'smartctl': {},
|
||||
'telegraf': {
|
||||
'config': {
|
||||
'inputs': {
|
||||
'exec': {
|
||||
'smartctl_power_mode': {
|
||||
h({
|
||||
'commands': [
|
||||
f'sudo /usr/local/share/telegraf/smartctl_power_mode',
|
||||
],
|
||||
'data_format': 'influx',
|
||||
'interval': '20s',
|
||||
},
|
||||
'smartctl_errors': {
|
||||
}),
|
||||
h({
|
||||
'commands': [
|
||||
f'sudo /usr/local/share/telegraf/smartctl_errors',
|
||||
],
|
||||
'data_format': 'influx',
|
||||
'interval': '6h',
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,11 +10,7 @@ directories = {
|
|||
'purge': True,
|
||||
'mode': '0755',
|
||||
'skip': dont_touch_sshd,
|
||||
},
|
||||
'/etc/ssh/ssh_config.d': {
|
||||
'mode': '0755',
|
||||
'skip': dont_touch_sshd,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
files = {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ def users(metadata):
|
|||
'allow_users': set(
|
||||
name
|
||||
for name, conf in metadata.get('users').items()
|
||||
if conf.get('authorized_keys', []) or conf.get('authorized_users', {})
|
||||
if conf.get('authorized_keys', []) or conf.get('authorized_users', [])
|
||||
),
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
from bundlewrap.utils.dicts import merge_dict
|
||||
|
||||
files = {}
|
||||
svc_systemd = {}
|
||||
|
||||
directories = {
|
||||
'/usr/local/lib/systemd/system': {
|
||||
'purge': True,
|
||||
|
|
@ -45,9 +42,6 @@ for name, unit in node.metadata.get('systemd/units').items():
|
|||
else:
|
||||
raise Exception(f'unknown type {extension}')
|
||||
|
||||
for attribute in ['needs', 'needed_by', 'triggers', 'triggered_by']:
|
||||
if attribute in unit:
|
||||
dependencies.setdefault(attribute, []).extend(unit.pop(attribute))
|
||||
|
||||
files[path] = {
|
||||
'content': repo.libs.systemd.generate_unitfile(unit),
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ defaults = {
|
|||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'telegraf/inputs/exec',
|
||||
'telegraf/config/inputs/exec',
|
||||
)
|
||||
def telegraf(metadata):
|
||||
return {
|
||||
|
|
@ -23,11 +23,11 @@ def telegraf(metadata):
|
|||
'config': {
|
||||
'inputs': {
|
||||
'exec': {
|
||||
'tasmota_charge': {
|
||||
repo.libs.hashable.hashable({
|
||||
'commands': ["/usr/local/share/telegraf/tasmota_charge"],
|
||||
'name_override': "tasmota_charge",
|
||||
'data_format': "influx",
|
||||
},
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,53 +1,19 @@
|
|||
import tomlkit
|
||||
|
||||
|
||||
def inner_dict_to_list(dict_of_dicts):
|
||||
"""
|
||||
Example:
|
||||
{
|
||||
'cpu': {
|
||||
'default': {'something': True},
|
||||
'another': {'something': False},
|
||||
},
|
||||
}
|
||||
becomes
|
||||
{
|
||||
'cpu': [
|
||||
{'something': True},
|
||||
{'something': False},
|
||||
],
|
||||
}
|
||||
"""
|
||||
return {
|
||||
key: [value for _, value in sorted(dicts.items())]
|
||||
for key, dicts in sorted(dict_of_dicts.items())
|
||||
}
|
||||
|
||||
import json
|
||||
from bundlewrap.metadata import MetadataJSONEncoder
|
||||
|
||||
files = {
|
||||
"/etc/telegraf/telegraf.conf": {
|
||||
'owner': 'telegraf',
|
||||
'group': 'telegraf',
|
||||
'mode': '0440',
|
||||
'needs': [
|
||||
"pkg_apt:telegraf",
|
||||
'/etc/telegraf/telegraf.conf': {
|
||||
'content': tomlkit.dumps(
|
||||
json.loads(json.dumps(
|
||||
node.metadata.get('telegraf/config'),
|
||||
cls=MetadataJSONEncoder,
|
||||
)),
|
||||
sort_keys=True,
|
||||
),
|
||||
'triggers': [
|
||||
'svc_systemd:telegraf:restart',
|
||||
],
|
||||
'content': tomlkit.dumps({
|
||||
'agent': node.metadata.get('telegraf/agent'),
|
||||
'inputs': inner_dict_to_list(node.metadata.get('telegraf/inputs')),
|
||||
'processors': inner_dict_to_list(node.metadata.get('telegraf/processors')),
|
||||
'outputs': inner_dict_to_list(node.metadata.get('telegraf/outputs')),
|
||||
}),
|
||||
'triggers': {
|
||||
'svc_systemd:telegraf.service:restart',
|
||||
},
|
||||
},
|
||||
'/etc/default/telegraf': {
|
||||
'content': 'TELEGRAF_OPTS="--strict-env-handling"\n',
|
||||
'mode': '0644',
|
||||
'triggers': {
|
||||
'svc_systemd:telegraf.service:restart',
|
||||
},
|
||||
},
|
||||
'/usr/local/share/telegraf/procio': {
|
||||
'content_type': 'download',
|
||||
|
|
@ -61,26 +27,9 @@ files = {
|
|||
},
|
||||
}
|
||||
|
||||
actions = {
|
||||
'telegraf-test-config': {
|
||||
'command': "sudo -u telegraf bash -c 'telegraf config check --config /etc/telegraf/telegraf.conf --strict-env-handling'",
|
||||
'triggered': True,
|
||||
svc_systemd['telegraf'] = {
|
||||
'needs': [
|
||||
'bundle:sudo',
|
||||
'file:/etc/telegraf/telegraf.conf',
|
||||
'pkg_apt:telegraf',
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
svc_systemd = {
|
||||
'telegraf.service': {
|
||||
'needs': ['pkg_apt:telegraf'],
|
||||
'preceded_by': {
|
||||
'action:telegraf-test-config',
|
||||
},
|
||||
'needs': {
|
||||
'action:telegraf-test-config',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,29 +23,26 @@ defaults = {
|
|||
},
|
||||
},
|
||||
'telegraf': {
|
||||
'config': {
|
||||
'agent': {
|
||||
'hostname': node.name,
|
||||
'collection_jitter': '20s',
|
||||
'flush_interval': '20s',
|
||||
'flush_jitter': '5s',
|
||||
'interval': '2m',
|
||||
'collection_jitter': '0s',
|
||||
'flush_interval': '15s',
|
||||
'flush_jitter': '0s',
|
||||
'interval': '15s',
|
||||
'metric_batch_size': 1000,
|
||||
'metric_buffer_limit': 10000,
|
||||
'omit_hostname': False,
|
||||
'round_interval': True,
|
||||
'skip_processors_after_aggregators': True,
|
||||
},
|
||||
'inputs': {
|
||||
'cpu': {
|
||||
'default': {
|
||||
'cpu': {h({
|
||||
'collect_cpu_time': False,
|
||||
'percpu': True,
|
||||
'report_active': False,
|
||||
'totalcpu': True,
|
||||
},
|
||||
},
|
||||
'disk': {
|
||||
'default': {
|
||||
})},
|
||||
'disk': {h({
|
||||
'ignore_fs': [
|
||||
'tmpfs',
|
||||
'devtmpfs',
|
||||
|
|
@ -55,60 +52,42 @@ defaults = {
|
|||
'aufs',
|
||||
'squashfs',
|
||||
],
|
||||
}
|
||||
},
|
||||
'procstat': {
|
||||
'default': {
|
||||
})},
|
||||
'procstat': {h({
|
||||
'interval': '60s',
|
||||
'pattern': '.',
|
||||
'fieldinclude': [
|
||||
'cpu_usage',
|
||||
'memory_rss',
|
||||
],
|
||||
},
|
||||
},
|
||||
'diskio': {
|
||||
'default': {
|
||||
})},
|
||||
'diskio': {h({
|
||||
'device_tags': ["ID_PART_ENTRY_NUMBER"],
|
||||
}
|
||||
},
|
||||
'kernel': {
|
||||
'default': {},
|
||||
},
|
||||
'mem': {
|
||||
'default': {},
|
||||
},
|
||||
'processes': {
|
||||
'default': {},
|
||||
},
|
||||
'swap': {
|
||||
'default': {},
|
||||
},
|
||||
'system': {
|
||||
'default': {},
|
||||
},
|
||||
'net': {
|
||||
'default': {},
|
||||
},
|
||||
})},
|
||||
'kernel': {h({})},
|
||||
'mem': {h({})},
|
||||
'processes': {h({})},
|
||||
'swap': {h({})},
|
||||
'system': {h({})},
|
||||
'net': {h({})},
|
||||
'exec': {
|
||||
# h({
|
||||
# 'commands': [
|
||||
# f'sudo /usr/local/share/telegraf/procio',
|
||||
# ],
|
||||
# 'data_format': 'influx',
|
||||
# 'interval': '20s',
|
||||
# }),
|
||||
'pressure_stall': {
|
||||
h({
|
||||
'commands': [
|
||||
f'sudo /usr/local/share/telegraf/procio',
|
||||
],
|
||||
'data_format': 'influx',
|
||||
'interval': '20s',
|
||||
}),
|
||||
h({
|
||||
'commands': [
|
||||
f'/usr/local/share/telegraf/pressure_stall',
|
||||
],
|
||||
'data_format': 'influx',
|
||||
'interval': '10s',
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
'processors': {},
|
||||
'outputs': {},
|
||||
},
|
||||
'grafana_rows': {
|
||||
'cpu',
|
||||
|
|
@ -126,21 +105,21 @@ defaults = {
|
|||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'telegraf/outputs/influxdb_v2/default',
|
||||
'telegraf/config/outputs/influxdb_v2',
|
||||
)
|
||||
def influxdb(metadata):
|
||||
influxdb_metadata = repo.get_node(metadata.get('telegraf/influxdb_node')).metadata.get('influxdb')
|
||||
|
||||
return {
|
||||
'telegraf': {
|
||||
'config': {
|
||||
'outputs': {
|
||||
'influxdb_v2': {
|
||||
'default': {
|
||||
'influxdb_v2': [{
|
||||
'urls': [f"http://{influxdb_metadata['hostname']}:{influxdb_metadata['port']}"],
|
||||
'token': str(influxdb_metadata['writeonly_token']),
|
||||
'organization': influxdb_metadata['org'],
|
||||
'bucket': influxdb_metadata['bucket'],
|
||||
},
|
||||
}]
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -20,15 +20,11 @@ def authorized_users(metadata):
|
|||
users[name] = {
|
||||
'authorized_keys': set(),
|
||||
}
|
||||
for authorized_user, options in config.get('authorized_users', {}).items():
|
||||
for authorized_user in config.get('authorized_users', set()):
|
||||
authorized_user_name, authorized_user_node = authorized_user.split('@')
|
||||
authorized_user_public_key = repo.get_node(authorized_user_node).metadata.get(f'users/{authorized_user_name}/pubkey')
|
||||
|
||||
for command in options.get('commands', []):
|
||||
users[name]['authorized_keys'].add(f'command="{command}" ' + authorized_user_public_key)
|
||||
else:
|
||||
users[name]['authorized_keys'].add(authorized_user_public_key)
|
||||
|
||||
users[name]['authorized_keys'].add(
|
||||
repo.get_node(authorized_user_node).metadata.get(f'users/{authorized_user_name}/pubkey')
|
||||
)
|
||||
return {
|
||||
'users': users,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ defaults = {
|
|||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'wol-sleeper/mac',
|
||||
'wol-sleeper/wake_command',
|
||||
)
|
||||
def wake_command(metadata):
|
||||
|
|
@ -54,8 +53,7 @@ def wake_command(metadata):
|
|||
|
||||
return {
|
||||
'wol-sleeper': {
|
||||
'mac': mac,
|
||||
'wake_command': f"ssh -o StrictHostKeyChecking=no wol@{waker_hostname} '/usr/bin/wakeonlan {mac}' && while ! ping {ip} -c1 -W3; do true; done",
|
||||
'wake_command': f"ssh -o StrictHostKeyChecking=no wol@{waker_hostname} 'wakeonlan {mac} && while ! ping {ip} -c1 -W3; do true; done'",
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,25 +6,17 @@ defaults = {
|
|||
},
|
||||
}
|
||||
|
||||
|
||||
@metadata_reactor.provides(
|
||||
'users/wol/authorized_users',
|
||||
'users/wol',
|
||||
)
|
||||
def user(metadata):
|
||||
return {
|
||||
'users': {
|
||||
'wol': {
|
||||
'authorized_users': {
|
||||
f'root@{ssh_client.name}': {
|
||||
'commands': {
|
||||
'/usr/bin/wakeonlan ' + sleeper.metadata.get('wol-sleeper/mac')
|
||||
for sleeper in repo.nodes
|
||||
if sleeper.has_bundle('wol-sleeper')
|
||||
and sleeper.metadata.get('wol-sleeper/waker') == node.name
|
||||
}
|
||||
}
|
||||
for ssh_client in repo.nodes
|
||||
if ssh_client.dummy == False and ssh_client.has_bundle('ssh')
|
||||
f'root@{node.name}'
|
||||
for node in repo.nodes
|
||||
if node.dummy == False and node.has_bundle('ssh')
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -59,9 +59,9 @@ defaults = {
|
|||
},
|
||||
},
|
||||
'telegraf': {
|
||||
'config': {
|
||||
'inputs': {
|
||||
'zfs': {
|
||||
'default': {},
|
||||
'zfs': [{}],
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ KHyP5XgRU/pIOyOo3g6+qIkhgynHVYIBuPbFQGEbOuUg7noAwTC9B9pYXSRFq9wk
|
|||
T/q8rqOBiyO9SWB9gMiem8HNAzUo5TbVp9xPv2pl3mNXwe5te92pjlWdktOsBZuy
|
||||
TfTgoj3y0HUY48He/z85aJ5j7gX5PU/6arxdABEBAAG0UGRldmVsOmxhbmd1YWdl
|
||||
czpjcnlzdGFsIE9CUyBQcm9qZWN0IDxkZXZlbDpsYW5ndWFnZXM6Y3J5c3RhbEBi
|
||||
dWlsZC5vcGVuc3VzZS5vcmc+iQE+BBMBCAAoBQJodLPOAhsDBQkMCLQ6BgsJCAcD
|
||||
AgYVCAIJCgsEFgIDAQIeAQIXgAAKCRDkVq5yhW0Udi/iB/9pzVWeChRvk7+bC2p3
|
||||
QXjc+KRmkev7yC3QglBX/17qDG+nW/z1SptFpIUKMllH/xu0GXIWOW/rxshRdKRK
|
||||
422wnT7KA2AqxArsHfvu0/nGBXAI1DnHuwP0j6xNmmw+uob2nWiUZZNgKydxcGSF
|
||||
fgRfIJcsHBKweasy9G/Fpdur/BFSBNQ8BP6CnB9qx0Z1LgQ6bQQNY1LKH4EzmiNA
|
||||
rBowUcuVjUzXUW8rc0Old/ffymH3TBM9xQXnsGVZb5+E6NKpcdt0lnWkrtHQK3RX
|
||||
ohNmaLwMQe/wMzWN3u/5XshQD8mMQjxEg4QSt2gAEXJdIzI+VgLrGqcfbrk/qhVM
|
||||
D+c+iEYEExECAAYFAmCKr5QACgkQOzARt2udZSNdFQCgtpRzGoKr9VWnhv+/k4pk
|
||||
dWlsZC5vcGVuc3VzZS5vcmc+iQE+BBMBCAAoBQJkq9RAAhsDBQkIP9SsBgsJCAcD
|
||||
AgYVCAIJCgsEFgIDAQIeAQIXgAAKCRDkVq5yhW0UdsH4CACAMuwfsUTlUVmdMBw5
|
||||
wktrrdwfwN6TiG5tPDjzTcMQNL+RSCh1gNRvaJjNHAy9sAsruGwTyX76K1p942EG
|
||||
F99DrYd/PMBK4oOWe7HHouYIMrLqZFT38shv/tbyJvUfxqfMHSPQJSFPVGtInn3h
|
||||
iKtDeIc88Hl+dsmBhWxDdaoHTGKgIcQTLN1OaX6SsT6WuMo7B4kPxHerwFp/n5bO
|
||||
hqyLLkTY0oxJpZlzCj2tYDytHhjkPnYtcPpQ8LnQpGKogUxYDYZ+o4zYvIcT/J5+
|
||||
cLx1xpf4fI7ZoE+dpIpAGKzN8MoQQ+fjgSheXar35p+8lOKrvrk7MmbQJlBQO+rM
|
||||
IHdJiEYEExECAAYFAmCKr5QACgkQOzARt2udZSNdFQCgtpRzGoKr9VWnhv+/k4pk
|
||||
Cmp9fycAn0pdJ2xIEsqxOjPBFVDh7Sahecuq
|
||||
=v2my
|
||||
=yIwD
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
|
|
|||
|
|
@ -1,186 +1,186 @@
|
|||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
ugNdPbTx5TQVD48tsKiSIOPP1g==
|
||||
=UqDn
|
||||
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
|
||||
bn5U7DwupeFEycZrqQEKsjwFjLxa
|
||||
=QzR4
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
|
|
|||
|
|
@ -1,186 +1,186 @@
|
|||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
JTBXMe98MDmvUA==
|
||||
=OEKh
|
||||
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
|
||||
NlB2T6bKGcYGqL7L
|
||||
=UUyy
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
|
|
|||
|
|
@ -9,16 +9,16 @@ Dts4PNx4Wr9CktHIvbypT4Lk2oJEPWjcCJQHqpPQZXbnclXRlK5Ea0NVpaQdGK+v
|
|||
JS4HGxFFjSkvTKAZYgwOk93qlpFeDML3TuSgWxuw4NIDitvewudnaWzfl9tDIoVS
|
||||
Bb16nwJ8bMDzovC/RBE14rRKYtMLmBsRzGYHWd0NnX+FitAS9uURHuFxghv9GFPh
|
||||
eTaXvc4glM94HBUAEQEAAbQmR3JhZmFuYSBMYWJzIDxlbmdpbmVlcmluZ0BncmFm
|
||||
YW5hLmNvbT6JAdQEEwEKAD4CGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQS1
|
||||
Oud7rbYwpoMEYAWWP6J3EEWFRQUCaKhvPQUJB4NP1AAKCRCWP6J3EEWFRUjOC/9Y
|
||||
dWOWJLJVKzLx8uv5YVzebyw15HevhKahbznJX5fHnE8irjkiPFltVEZ4T37s5afR
|
||||
GBEJnR1UFd80s7jzwbuoZh/zEB3jN8q50g64AznuzDa0PWKzaY7Tgkssx3+hs6TS
|
||||
vIwV4z8T7f56lDudeHxHXx+htRnZ3ebKNPCJS7+G12GF6W3C3znpdjgvhVUB0uxd
|
||||
+42V0fRqk2GLNZeKS9988fi5dYRAy9Ozwced7ByCFjde9FBgUtrH3mG1/ibzLEh0
|
||||
4k02nYjc8mrH32t4UCWpxQEJ1vZA2vT2HN3/cH/4uyFdyU6OHkMyMbz6lmeXe71d
|
||||
F5hOB4+/RP6Ndyj7ViRNDbm70NRBaFne/+YOJvmMfJTCh7YbF5qEn1ihGkJJ0ohE
|
||||
u2IB+EGEhyiDm8SIsj1uMw7n17iIPNtbsU5GgnmLtfguP/WbwKV2UeuxTpiOeYb6
|
||||
blDwRlh48uHMlA5HBW+487Jktw3iPj1IKhdtAC9CU3xAvzDcseMbgmM6Xj2bSQG5
|
||||
YW5hLmNvbT6JAdQEEwEKAD4WIQS1Oud7rbYwpoMEYAWWP6J3EEWFRQUCZOeGaQIb
|
||||
AwUJA8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRCWP6J3EEWFRUiADACa
|
||||
i+xytv2keEFJWjXNnFAx6/obnHRcXOI3w6nH/zL8gNI7YN5jcdQT2NYvKVYTb3fW
|
||||
GuMsjHWgat5Gq3AtJrOKABpZ6qeYNPk0Axn/dKtOTwXjZ4pKX3bbUYvVfs0fCEZv
|
||||
B0HHIj2wI9kgMpoTrkj22LE8layZTPOoQ+3/FbLzS8hN3CYZj25mHN7bpZq8EbV3
|
||||
8FW9EU0HM0tg6CvoxkRiVqAuAC0KnVIZAdhD4dlYKuncq64nMvT1A5wxSYbnE+uf
|
||||
mnWQQhhS6BOwRqN054yw1FrWNDFsvnOSHmr8dIiriv+aZYvx5JQFJ7oZP3LwdYyg
|
||||
ocQcAJA8HFTIk3P6uJiIF/zdDzocgdKs+IYDoId0hxX7sGCvqdrsveq8n3m7uQiN
|
||||
7FvSiV0eXIdV4F7340kc8EKiYwpuYSaZX0UWKLenzlUvD+W4pZCWtoXzPsW7PKUt
|
||||
q1xdW0+NY+AGLCvSJCc5F4S5kFCObfBAYBbldjwwJFocdq/YOvvWYTPyV7kJeJS5
|
||||
AY0EZOeGaQEMALNIFUricEIwtZiX7vSDjwxobbqPKqzdek8x3ud0CyYlrbGHy0k+
|
||||
FDEXstjJQQ1s9rjJSu3sv5wyg9GDAUH3nzO976n/ZZvKPti3p2XU2UFx5gYkaaFV
|
||||
D56yYxqGY0YU5ft6BG+RUz3iEPg3UBUzt0sCIYnG9+CsDqGOnRYIIa46fu2/H9Vu
|
||||
|
|
@ -27,15 +27,15 @@ D56yYxqGY0YU5ft6BG+RUz3iEPg3UBUzt0sCIYnG9+CsDqGOnRYIIa46fu2/H9Vu
|
|||
3zht8luFOYpJr2lVzp7n3NwB4zW08RptTzTgFAaW/NH2JjYI+rDvQm4jNs08Dtsp
|
||||
nm4OQvBA9Df/6qwMEOZ9i10ixqk+55UpQFJ3nf4uKlSUM7bKXXVcD/odq804Y/K4
|
||||
y3csE059YVIyaPexEvYSYlHE2odJWRg2Q1VehmrOSC8Qps3xpU7dTHXD74ZpaYbr
|
||||
haViRS5v/lCsiwARAQABiQG8BBgBCgAmAhsMFiEEtTrne622MKaDBGAFlj+idxBF
|
||||
hUUFAmiobzkFCQeDT9AACgkQlj+idxBFhUVsmQwA0PA/zd7NqtnZ/Z8857gp2Wq2
|
||||
/e4EX8nRjsW2ZlrZfbU5oMQv9OZZ4z1UjIKEUV+TnCwXEKXTMJomdekQSSayVVx/
|
||||
u5w+0YM8gRuQGrG8hW0GRR8sHIeuwBFlyQrlwxUwXvDOPDYyieETjaQqMucupIKo
|
||||
IPm3CjFySvfizvSWUVSWBnGmQfpv6OiGYawvwfewcQHUdLMgWN3lYlzGQJL4+OMm
|
||||
7XcB8VNTa586Q00fmjDfktHYvGpmhqr3gsd4gS3AjTk0zI65qXBRJkdqVnwUrMUD
|
||||
8TcxXYNXf90mhR0NWkLmp6kBYiW8+QY6ndMmRVpodg1A87qgMYaZUAAlxCS4XKTU
|
||||
r+/YMDYOWgLN6i4UeYG/3/hsnAEHm5ITojfh6cLfdlhjohFTnD0IYw3AsNJXRzKB
|
||||
1g5FTBKLLLIdXgS/3rWV1qjAd3drQVIMCku6HKl/vT4ftrBHeSyV7eLwOYbe3/bw
|
||||
8VMx+lmMheD8/qJMia1om0iBBRSXRjY//f+Lllqm
|
||||
=TH3J
|
||||
haViRS5v/lCsiwARAQABiQG8BBgBCgAmFiEEtTrne622MKaDBGAFlj+idxBFhUUF
|
||||
AmTnhmkCGwwFCQPCZwAACgkQlj+idxBFhUUNbQv8DCcfi3GbWfvp9pfY0EJuoFJX
|
||||
LNgci7z7smXq7aqDp2huYQ+MulnPAydjRCVW2fkHItF2Ks6l+2/8t5Xz0eesGxST
|
||||
xTyR31ARENMXaq78Lq+itZ+usOSDNuwJcEmJM6CceNMLs4uFkX2GRYhchkry7P0C
|
||||
lkLxUTiB43ooi+CqILtlNxH7kM1O4Ncs6UGZMXf2IiG9s3JDCsYVPkC5QDMOPkTy
|
||||
2ZriF56uPerlJveF0dC61RZ6RlM3iSJ9Fwvea0Oy4rwkCcs5SHuwoDTFyxiyz0QC
|
||||
9iqi3fG3iSbLvY9UtJ6X+BtDqdXLAT9Pq527mukPP3LwpEqFVyNQKnGLdLOu2YXc
|
||||
TWWWseSQkHRzBmjD18KTD74mg4aXxEabyT4snrXpi5+UGLT4KXGV5syQO6Lc0OGw
|
||||
9O/0qAIU+YW7ojbKv8fr+NB31TGhGYWASjYlN1NvPotRAK6339O0/Rqr9xGgy3AY
|
||||
SR+ic2Y610IM7xccKuTVAW9UofKQwJZChqae9VVZ
|
||||
=J9CI
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
|
|
|||
|
|
@ -1,99 +1,29 @@
|
|||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
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
|
||||
AHMnjg==
|
||||
=UiOS
|
||||
ZGF0YS5jb20+iQJVBBMBCAA/BgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUJBaOk
|
||||
/BYhBJ1TnZDTMo3H1sjTudj/jh99+LB+BQJjyB9PAhsDAAoJENj/jh99+LB+klgQ
|
||||
AKOKdwTyKOr6+mnRrACz5U3EFxfAXXFGan9Ka7Nzgz4K+FOnTtT1gWwqrPPmTKQk
|
||||
epNUMcelfX1kCA08yCm0nyw2niqxES40W33ergKUj6jlDx7UQYXWsDQGD9IKksa8
|
||||
MWfZlJ3zlrsGKXA4oa+kfY+vltWDVP8WhLcQzm2LywbKvr3WgY80GZbnRjoekiBK
|
||||
oMKztQVMJG5yNZBo9B4JrqB3wMpnXZxEtqZcBPsJJdXTFKHsQ7kB9TMNorbUvDNH
|
||||
ohwsprgMw84vHikEk9jyCypXpYq/E/wvkM0CeIUJ36S2vGvACib7BiY6Xv0BQbM4
|
||||
rWq2Rrjag1y5vVAF9gJkeo/3rhM6lE1ahDCRq0QcBMVzbxiE+3COIzRPmz14J3Yn
|
||||
0pkvzlVkNj5UZR8q91ESl+UxkFCP1wzcXgs0dpJWirQIOZ9E2eYv3LcjE68xjW1k
|
||||
c5q1GOGvJI7aXADxUZ4lFbz+NUb4Ts4HXHc8gV1Gm0vvmIqv2YfAvL5DXbKLdZxh
|
||||
73CxKvBMmTXIEQ+vQJ3p1ZnUnb+l6DoxEFWg/hXHmE5jY3P6HIVFdliXF5FEs1lr
|
||||
9snU2Pn1BDL+TBN7SX0QbKqArWA4qyn6eGH8Z1ULoUVBPCjwC9QuInp/9fqifFYo
|
||||
OM3A51MDGyc/HCVG6jNJEI5h71QGHlPfyQybpjy7rQSe
|
||||
=YwXc
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -8,21 +8,16 @@ from(bucket: "${bucket}")
|
|||
|> filter(fn: (r) => exists r["${exist}"]) // WTF
|
||||
% endfor
|
||||
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false) // aggregate early for best performance
|
||||
% if over is not None:
|
||||
|> filter(fn: (r) => r._value > ${over})
|
||||
% if minimum:
|
||||
|> filter(fn: (r) => r._value > ${minimum})
|
||||
% endif
|
||||
% if function == 'derivative':
|
||||
|> derivative(nonNegative: true)
|
||||
% elif function == 'difference':
|
||||
|> difference(nonNegative: true)
|
||||
% endif
|
||||
% if boolean_to_int:
|
||||
|> map(fn: (r) => ({r with _value: if r._value == true then 1 else 0 }))
|
||||
% endif
|
||||
% if negative:
|
||||
|> map(fn: (r) => ({r with _value: r._value * - 1.0}))
|
||||
% endif
|
||||
% if multiply is not None:
|
||||
|> map(fn: (r) => ({r with _value: r._value * ${multiply}}))
|
||||
% endif
|
||||
|> yield(name: "mean")
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
},
|
||||
'min': 0,
|
||||
'soft_max': 3,
|
||||
'display_name': '${__field.labels.resource}',
|
||||
'display_name': '__field.labels.resource',
|
||||
'unit': 'percent',
|
||||
'tooltip': 'multi',
|
||||
'legend': {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
},
|
||||
},
|
||||
'unit': 'Bps',
|
||||
'display_name': '${__field.labels.name}',
|
||||
'display_name': '__field.labels.name',
|
||||
'tooltip': 'multi',
|
||||
},
|
||||
'write': {
|
||||
|
|
@ -36,7 +36,7 @@
|
|||
},
|
||||
},
|
||||
'unit': 'Bps',
|
||||
'display_name': '${__field.labels.name}',
|
||||
'display_name': '__field.labels.name',
|
||||
'tooltip': 'multi',
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
},
|
||||
'tooltip': 'multi',
|
||||
'unit': 'MHz',
|
||||
'display_name': '${__field.labels.cpu}',
|
||||
'display_name': '__field.labels.cpu',
|
||||
'min': 0,
|
||||
},
|
||||
# 'temperature': {
|
||||
|
|
@ -57,6 +57,6 @@
|
|||
},
|
||||
'tooltip': 'multi',
|
||||
'unit': 'degrees',
|
||||
'display_name': '${__field.labels.chip}',
|
||||
'display_name': '__field.labels.chip',
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
},
|
||||
},
|
||||
'unit': 'Bps',
|
||||
'display_name': '${__field.labels.interface}',
|
||||
'display_name': '__field.labels.interface',
|
||||
'tooltip': 'multi',
|
||||
},
|
||||
'out': {
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
},
|
||||
},
|
||||
'unit': 'Bps',
|
||||
'display_name': '${__field.labels.interface}',
|
||||
'display_name': '__field.labels.interface',
|
||||
'tooltip': 'multi',
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
'function': 'max',
|
||||
},
|
||||
},
|
||||
'display_name': '${__field.labels.queue}'
|
||||
'display_name': '__field.labels.queue'
|
||||
},
|
||||
'size': {
|
||||
'stacked': True,
|
||||
|
|
@ -27,7 +27,7 @@
|
|||
'function': 'max',
|
||||
},
|
||||
},
|
||||
'display_name': '${__field.labels.queue}'
|
||||
'display_name': '__field.labels.queue'
|
||||
},
|
||||
'age': {
|
||||
'stacked': True,
|
||||
|
|
@ -42,6 +42,6 @@
|
|||
'function': 'max',
|
||||
},
|
||||
},
|
||||
'display_name': '${__field.labels.queue}'
|
||||
'display_name': '__field.labels.queue'
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,11 +9,11 @@
|
|||
'cpu_usage',
|
||||
],
|
||||
},
|
||||
'over': 0.2,
|
||||
'minimum': 0.2,
|
||||
},
|
||||
},
|
||||
'unit': 'percent',
|
||||
'display_name': '${__field.labels.process_name}',
|
||||
'display_name': '__field.labels.process_name',
|
||||
'legend': {
|
||||
'displayMode': 'table',
|
||||
'placement': 'right',
|
||||
|
|
@ -32,11 +32,11 @@
|
|||
'memory_rss',
|
||||
],
|
||||
},
|
||||
'over': 10*(10**6),
|
||||
'minimum': 10*(10**6),
|
||||
},
|
||||
},
|
||||
'unit': 'bytes',
|
||||
'display_name': '${__field.labels.process_name}',
|
||||
'display_name': '__field.labels.process_name',
|
||||
'legend': {
|
||||
'displayMode': 'table',
|
||||
'placement': 'right',
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@
|
|||
],
|
||||
},
|
||||
'function': 'derivative',
|
||||
'over': 1024,
|
||||
'minimum': 1024,
|
||||
},
|
||||
},
|
||||
'unit': 'bytes',
|
||||
'display_name': '${__field.labels.comm}',
|
||||
'display_name': '__field.labels.comm',
|
||||
'legend': {
|
||||
'displayMode': 'table',
|
||||
'placement': 'right',
|
||||
|
|
@ -34,11 +34,11 @@
|
|||
],
|
||||
},
|
||||
'function': 'derivative',
|
||||
'over': 1,
|
||||
'minimum': 1,
|
||||
},
|
||||
},
|
||||
'unit': 'bytes',
|
||||
'display_name': '${__field.labels.comm}',
|
||||
'display_name': '__field.labels.comm',
|
||||
'legend': {
|
||||
'displayMode': 'table',
|
||||
'placement': 'right',
|
||||
|
|
|
|||
|
|
@ -1,97 +0,0 @@
|
|||
{
|
||||
'critical': {
|
||||
'stacked': True,
|
||||
'queries': {
|
||||
'generic': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_interface_generic',
|
||||
'_field': [
|
||||
'in_errors',
|
||||
'out_errors',
|
||||
],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'function': 'difference',
|
||||
'over': 0,
|
||||
},
|
||||
'mikrotik': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_interface_detailed',
|
||||
'_field': [
|
||||
'rx_fcs_errors',
|
||||
'rx_align_errors',
|
||||
'rx_code_errors',
|
||||
'rx_carrier_errors',
|
||||
'rx_jabber',
|
||||
'rx_fragment',
|
||||
'rx_length_errors',
|
||||
'tx_late_collisions',
|
||||
'tx_excessive_collisions',
|
||||
'link_downs',
|
||||
],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'function': 'difference',
|
||||
'over': 0,
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'cps',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.name} ${__field.labels.ifName} ${__field.labels.ifAlias}',
|
||||
'legend': {
|
||||
'displayMode': 'table',
|
||||
'placement': 'right',
|
||||
'calcs': [
|
||||
'max',
|
||||
],
|
||||
},
|
||||
},
|
||||
'warning': {
|
||||
'stacked': True,
|
||||
'queries': {
|
||||
'generic': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_interface_generic',
|
||||
'_field': [
|
||||
'in_discards',
|
||||
'out_discards',
|
||||
],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'function': 'difference',
|
||||
'over': 0,
|
||||
},
|
||||
'mikrotik': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_interface_detailed',
|
||||
'_field': [
|
||||
'rx_too_short',
|
||||
'rx_too_long',
|
||||
'rx_drop',
|
||||
'tx_drop',
|
||||
'rx_pause',
|
||||
'tx_pause',
|
||||
'tx_pause_honored',
|
||||
'tx_collisions',
|
||||
'tx_total_collisions',
|
||||
],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'function': 'difference',
|
||||
'over': 0,
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'cps',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.name} ${__field.labels.ifName} ${__field.labels.ifAlias}',
|
||||
'legend': {
|
||||
'displayMode': 'table',
|
||||
'placement': 'right',
|
||||
'calcs': [
|
||||
'max',
|
||||
],
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
{
|
||||
'temperature': {
|
||||
'stacked': False,
|
||||
'queries': {
|
||||
'temp': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_health',
|
||||
'sensor': [
|
||||
'temperature',
|
||||
'cpu-temperature',
|
||||
'switch-temperature',
|
||||
'board-temperature1',
|
||||
'sfp-temperature',
|
||||
],
|
||||
'_field': [
|
||||
'value',
|
||||
],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'celsius',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.labels.sensor}',
|
||||
'legend': {
|
||||
'displayMode': 'hidden',
|
||||
},
|
||||
},
|
||||
'fan': {
|
||||
'stacked': False,
|
||||
'queries': {
|
||||
'temp': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_health',
|
||||
'sensor': [
|
||||
'fan1-speed',
|
||||
'fan2-speed',
|
||||
],
|
||||
'_field': [
|
||||
'value',
|
||||
],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'rpm',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.labels.sensor}',
|
||||
'legend': {
|
||||
'displayMode': 'hidden',
|
||||
},
|
||||
},
|
||||
'psu_current': {
|
||||
'stacked': False,
|
||||
'queries': {
|
||||
'temp': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_health',
|
||||
'sensor': [
|
||||
'psu1-current',
|
||||
'psu2-current',
|
||||
],
|
||||
'_field': [
|
||||
'value',
|
||||
],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'multiply': 0.1,
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'ampere',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.labels.sensor}',
|
||||
'legend': {
|
||||
'displayMode': 'hidden',
|
||||
},
|
||||
},
|
||||
'psu_voltage': {
|
||||
'stacked': False,
|
||||
'queries': {
|
||||
'temp': {
|
||||
'filters': {
|
||||
'_measurement': 'hw',
|
||||
'sensor': [
|
||||
'psu1-voltage',
|
||||
'psu2-voltage',
|
||||
],
|
||||
'_field': [
|
||||
'value',
|
||||
],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'multiply': 0.1,
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'volt',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.labels.sensor}',
|
||||
'legend': {
|
||||
'displayMode': 'hidden',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
{
|
||||
'in': {
|
||||
'stacked': True,
|
||||
'queries': {
|
||||
'in': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_interface_generic',
|
||||
'_field': [
|
||||
'in_ucast_pkts',
|
||||
'in_mcast_pkts',
|
||||
'in_bcast_pkts',
|
||||
],
|
||||
'ifType': [6],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'function': 'derivative',
|
||||
'over': 0,
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'pps',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.labels.ifName} - ${__field.labels.ifAlias}',
|
||||
'legend': {
|
||||
'displayMode': 'hidden',
|
||||
},
|
||||
},
|
||||
'out': {
|
||||
'stacked': True,
|
||||
'queries': {
|
||||
'out': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_interface_generic',
|
||||
'_field': [
|
||||
'out_ucast_pkts',
|
||||
'out_mcast_pkts',
|
||||
'out_bcast_pkts',
|
||||
],
|
||||
'ifType': [6],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'function': 'derivative',
|
||||
'over': 0,
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'pps',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.labels.ifName} - ${__field.labels.ifAlias}',
|
||||
'legend': {
|
||||
'displayMode': 'hidden',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
{
|
||||
'power': {
|
||||
'stacked': True,
|
||||
'queries': {
|
||||
'power': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_poe',
|
||||
'_field': ['power'],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'function': 'mean',
|
||||
'multiply': 0.1,
|
||||
'over': 0,
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'watt',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.labels.ifName} - ${__field.labels.ifAlias}',
|
||||
'legend': {
|
||||
'displayMode': 'hidden',
|
||||
},
|
||||
},
|
||||
'current': {
|
||||
'stacked': True,
|
||||
'queries': {
|
||||
'voltage': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_poe',
|
||||
'_field': ['current'],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'function': 'mean',
|
||||
'multiply': 0.1,
|
||||
'over': 0,
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'ampere',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.labels.ifName} - ${__field.labels.ifAlias}',
|
||||
'legend': {
|
||||
'displayMode': 'hidden',
|
||||
},
|
||||
},
|
||||
'voltage': {
|
||||
'stacked': False,
|
||||
'queries': {
|
||||
'voltage': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_poe',
|
||||
'_field': ['voltage'],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'function': 'mean',
|
||||
'multiply': 0.1,
|
||||
'over': 0,
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'volt',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.labels.ifName} - ${__field.labels.ifAlias}',
|
||||
'legend': {
|
||||
'displayMode': 'hidden',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
{
|
||||
'in': {
|
||||
'stacked': True,
|
||||
'queries': {
|
||||
'in': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_interface_generic',
|
||||
'_field': ['in_octets'],
|
||||
'ifType': [6],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'function': 'derivative',
|
||||
'over': 0,
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'bps',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.labels.ifName} - ${__field.labels.ifAlias}',
|
||||
'legend': {
|
||||
'displayMode': 'hidden',
|
||||
},
|
||||
},
|
||||
'out': {
|
||||
'stacked': True,
|
||||
'queries': {
|
||||
'out': {
|
||||
'filters': {
|
||||
'_measurement': 'mikrotik_interface_generic',
|
||||
'_field': ['out_octets'],
|
||||
'ifType': [6],
|
||||
'operating_system': 'routeros',
|
||||
},
|
||||
'function': 'derivative',
|
||||
'over': 0,
|
||||
},
|
||||
},
|
||||
'min': 0,
|
||||
'unit': 'bps',
|
||||
'tooltip': 'multi',
|
||||
'display_name': '${__field.labels.ifName} - ${__field.labels.ifAlias}',
|
||||
'legend': {
|
||||
'displayMode': 'hidden',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
'function': 'mean',
|
||||
},
|
||||
},
|
||||
'display_name': '${__field.labels.device}',
|
||||
'display_name': '__field.labels.device',
|
||||
'min': 0,
|
||||
'unit': 'celsius',
|
||||
'tooltip': 'multi',
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
'function': 'last',
|
||||
},
|
||||
},
|
||||
'display_name': '${__field.labels.device}',
|
||||
'display_name': '__field.labels.device',
|
||||
'min': 0,
|
||||
'tooltip': 'multi',
|
||||
},
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
},
|
||||
},
|
||||
},
|
||||
'display_name': '${__field.labels.device} ${__field.name}',
|
||||
'display_name': '__field.labels.device} ${__field.name',
|
||||
'min': 0,
|
||||
'tooltip': 'multi',
|
||||
'legend': {
|
||||
|
|
|
|||
|
|
@ -1,9 +1 @@
|
|||
{
|
||||
'metadata': {
|
||||
'nftables': {
|
||||
'input': {
|
||||
'udp dport 161 accept',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
{}
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@
|
|||
},
|
||||
},
|
||||
'php': {
|
||||
'version': '8.4',
|
||||
'version': '8.2',
|
||||
},
|
||||
'postgresql': {
|
||||
'version': '17',
|
||||
'version': '15',
|
||||
},
|
||||
'os_codename': 'trixie',
|
||||
'os_codename': 'bookworm',
|
||||
},
|
||||
'os_version': (13,),
|
||||
'os_version': (12,),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
'supergroups': [
|
||||
'debian',
|
||||
'debian-13-common',
|
||||
],
|
||||
'bundles': [
|
||||
'ifupdown',
|
||||
'proxmox-ve',
|
||||
],
|
||||
}
|
||||
|
|
@ -9,13 +9,6 @@
|
|||
'routeros',
|
||||
],
|
||||
'metadata': {
|
||||
'grafana_rows': {
|
||||
'routeros_errors',
|
||||
'routeros_throughput',
|
||||
'routeros_poe',
|
||||
'routeros_packets',
|
||||
'routeros_health',
|
||||
},
|
||||
'routeros': {
|
||||
'gateway': '10.0.0.1',
|
||||
'bridge_priority': '0x8000',
|
||||
|
|
@ -25,15 +18,10 @@
|
|||
'iot': '2',
|
||||
'internet': '3',
|
||||
'proxmox': '4',
|
||||
'wokeonlan': '5',
|
||||
'gast': '9',
|
||||
'rolf': '51',
|
||||
},
|
||||
'vlan_groups': {
|
||||
'home': {
|
||||
'untagged': 'home',
|
||||
'tagged': set(),
|
||||
},
|
||||
'infra': {
|
||||
'untagged': 'home',
|
||||
'tagged': {
|
||||
|
|
@ -42,23 +30,15 @@
|
|||
'proxmox',
|
||||
'gast',
|
||||
'rolf',
|
||||
'wokeonlan',
|
||||
},
|
||||
},
|
||||
'internet': {
|
||||
'untagged': 'internet',
|
||||
'tagged': set(),
|
||||
},
|
||||
'wokeonlan': {
|
||||
'untagged': 'wokeonlan',
|
||||
'tagged': set(),
|
||||
},
|
||||
},
|
||||
'vlan_ports': {},
|
||||
},
|
||||
'telegraf': {
|
||||
'influxdb_node': 'home.server',
|
||||
},
|
||||
},
|
||||
'os': 'routeros',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +0,0 @@
|
|||
#! /usr/bin/env python3
|
||||
|
||||
import requests
|
||||
from datetime import datetime, timedelta, timezone
|
||||
|
||||
BASE = "https://homeassistant.ckn.li"
|
||||
TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI1YjY0ZWE5N2FiMzM0NTQ0OGMyNjhmZTIxYzAxZTE1MSIsImlhdCI6MTc1NjAzOTAxNCwiZXhwIjoyMDcxMzk5MDE0fQ.X-sQli-NTpCjeXpn19zf-maPRDldkSeTuhKZua1k8uM"
|
||||
ENTITY = "sensor.hue_outdoor_motion_sensor_2_temperature"
|
||||
|
||||
HEADERS = {
|
||||
"Authorization": f"Bearer {TOKEN}",
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
begin = datetime(2025, 7, 1, 0, 0, 0, tzinfo=timezone.utc)
|
||||
current = begin
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
while current < now:
|
||||
current += timedelta(hours=1)
|
||||
resp = requests.get(
|
||||
f"{BASE}/api/history/period/{current.isoformat()}",
|
||||
params={
|
||||
"end_time": current.isoformat(),
|
||||
"filter_entity_id": ENTITY
|
||||
},
|
||||
headers=HEADERS,
|
||||
timeout=15,
|
||||
)
|
||||
print(current, resp.json())
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
from subprocess import check_output
|
||||
|
||||
|
||||
def test_node(repo, node, **kwargs):
|
||||
for node in repo.nodes_in_group('mailserver'):
|
||||
domain = node.metadata.get('mailserver/hostname')
|
||||
expected_ptr_record = f"{domain}."
|
||||
expected_a_record = node.hostname
|
||||
|
||||
# check A record
|
||||
actual_a_record = check_output(['dig', '+short', 'A', domain, '@9.9.9.9'], text=True).strip()
|
||||
if actual_a_record != expected_a_record:
|
||||
raise AssertionError(f"A record for {expected_a_record} on node {node.name} is {actual_a_record}, expected {expected_a_record}")
|
||||
|
||||
# check otr record
|
||||
actual_ptr_record = check_output(['dig', '+short', '-x', expected_a_record, '@9.9.9.9'], text=True).strip()
|
||||
if actual_ptr_record != expected_ptr_record:
|
||||
raise AssertionError(f"PTR record for {expected_a_record} on node {node.name} is {actual_ptr_record}, expected {expected_ptr_record}")
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
def test_unique_node_ids(repo):
|
||||
ids = {}
|
||||
for node in repo.nodes:
|
||||
if node.metadata.get('id') in ids:
|
||||
raise ValueError(f"Duplicate node ID found: {node.metadata.get('id')} in node {node.name} and {ids[node.metadata.get('id')]}")
|
||||
ids[node.metadata.get('id')] = node.name
|
||||
|
||||
|
||||
def apply_start(repo, target, nodes, interactive=False, **kwargs):
|
||||
test_unique_node_ids(repo)
|
||||
|
||||
|
||||
def test(repo, **kwargs):
|
||||
test_unique_node_ids(repo)
|
||||
|
|
@ -1,8 +1,5 @@
|
|||
def wake_on_lan(node):
|
||||
node.repo.libs.wol.wake(node)
|
||||
|
||||
def node_apply_start(repo, node, **kwargs):
|
||||
wake_on_lan(node)
|
||||
repo.libs.wol.wake(node)
|
||||
|
||||
def node_run_start(repo, node, cmd, **kwargs):
|
||||
wake_on_lan(node)
|
||||
repo.libs.wol.wake(node)
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue