Compare commits

..

6 commits

Author SHA1 Message Date
mwiegand
f78c2bdd41 wip 2022-03-27 19:29:39 +02:00
mwiegand
3cc463999f wip 2022-03-27 18:19:44 +02:00
mwiegand
c3fbdfda72 wip 2022-03-27 18:15:38 +02:00
mwiegand
9cf17d2a4e wip 2022-03-27 18:15:38 +02:00
mwiegand
5bd0cece48 wip 2022-03-27 18:15:38 +02:00
mwiegand
91e4fee518 wip 2022-03-27 18:15:38 +02:00
85 changed files with 466 additions and 1411 deletions

View file

@ -1,22 +0,0 @@
root = true
[*]
end_of_line = lf
[*.py]
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
insert_final_newline = true
[*.toml]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true
[*.yaml]
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
insert_final_newline = true

4
.envrc
View file

@ -2,11 +2,7 @@
python3 -m venv .venv
source ./.venv/bin/activate
PATH_add .venv/bin
PATH_add bin
python3 -m pip install --upgrade pip
rm -rf .cache/bw/git_deploy
export BW_GIT_DEPLOY_CACHE=.cache/bw/git_deploy
export EXPERIMENTAL_UPLOAD_VIA_CAT=1
mkdir -p "$BW_GIT_DEPLOY_CACHE"

1
.gitignore vendored
View file

@ -1,4 +1,3 @@
.secrets.cfg*
.venv
.cache
*.pyc

1
.python-version Normal file
View file

@ -0,0 +1 @@
3.9.0

View file

@ -12,26 +12,3 @@ Raspberry pi as soundcard
- gadget mode
- OTG g_audio
- https://audiosciencereview.com/forum/index.php?threads/raspberry-pi-as-usb-to-i2s-adapter.8567/post-215824
# install bw fork
pip3 install --editable git+file:///Users/mwiegand/Projekte/bundlewrap-fork#egg=bundlewrap
# monitor timers
```sh
Timer=backup
Triggers=$(systemctl show ${Timer}.timer --property=Triggers --value)
echo $Triggers
if systemctl is-failed "$Triggers"
then
InvocationID=$(systemctl show "$Triggers" --property=InvocationID --value)
echo $InvocationID
ExitCode=$(systemctl show "$Triggers" -p ExecStartEx --value | sed 's/^{//' | sed 's/}$//' | tr ';' '\n' | xargs -n 1 | grep '^status=' | cut -d '=' -f 2)
echo $ExitCode
journalctl INVOCATION_ID="$InvocationID" --output cat
fi
```
telegraf: execd for daemons

View file

@ -7,10 +7,9 @@ from ipaddress import ip_interface
repo = Repository(dirname(dirname(realpath(__file__))))
nodes = [
node
for node in sorted(repo.nodes_in_group('debian'))
for node in repo.nodes_in_group('debian')
if not node.dummy
]
reboot_nodes = []
print('updating nodes:', sorted(node.name for node in nodes))
@ -22,16 +21,13 @@ for node in nodes:
print('--------------------------------------')
repo.libs.wol.wake(node)
print(node.run('DEBIAN_FRONTEND=noninteractive apt update').stdout.decode())
print(node.run('DEBIAN_FRONTEND=noninteractive apt list --upgradable').stdout.decode())
if int(node.run('DEBIAN_FRONTEND=noninteractive apt list --upgradable 2> /dev/null | grep upgradable | wc -l').stdout.decode()):
print(node.run('DEBIAN_FRONTEND=noninteractive apt -y dist-upgrade').stdout.decode())
reboot_nodes.append(node)
print(node.run('DEBIAN_FRONTEND=noninteractive apt -y dist-upgrade').stdout.decode())
# REBOOT IN ORDER
wireguard_servers = [
node
for node in reboot_nodes
for node in nodes
if node.has_bundle('wireguard')
and (
ip_interface(node.metadata.get('wireguard/my_ip')).network.prefixlen <
@ -41,7 +37,7 @@ wireguard_servers = [
wireguard_s2s = [
node
for node in reboot_nodes
for node in nodes
if node.has_bundle('wireguard')
and (
ip_interface(node.metadata.get('wireguard/my_ip')).network.prefixlen ==
@ -51,11 +47,12 @@ wireguard_s2s = [
everything_else = [
node
for node in reboot_nodes
for node in nodes
if not node.has_bundle('wireguard')
]
print('======================================')
print(len(everything_else), len(wireguard_s2s), len(wireguard_servers))
for node in [
*everything_else,
@ -63,7 +60,4 @@ for node in [
*wireguard_servers,
]:
print('rebooting', node.name)
try:
print(node.run('systemctl reboot').stdout.decode())
except Exception as e:
print(e)
print(node.run('systemctl reboot').stdout.decode())

View file

@ -1,9 +0,0 @@
#!/usr/bin/env python3
from bundlewrap.repo import Repository
from os.path import realpath, dirname
from sys import argv
repo = Repository(dirname(dirname(realpath(__file__))))
repo.libs.wol.wake(repo.get_node(argv[1]))

View file

@ -21,9 +21,7 @@ for peer in server_node.metadata.get('wireguard/s2s').values():
allowed_ips.append(ip_network(network))
conf = \
f'''>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
[Interface]
f'''[Interface]
PrivateKey = {repo.libs.wireguard.privkey(data['peer_id'])}
ListenPort = 51820
Address = {data['peer_ip']}
@ -34,12 +32,10 @@ PublicKey = {repo.libs.wireguard.pubkey(server_node.metadata.get('id'))}
PresharedKey = {repo.libs.wireguard.psk(data['peer_id'], server_node.metadata.get('id'))}
AllowedIPs = {', '.join(str(client_route) for client_route in sorted(allowed_ips))}
Endpoint = {ip_interface(server_node.metadata.get('network/external/ipv4')).ip}:51820
PersistentKeepalive = 10
PersistentKeepalive = 10'''
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'''
print(conf)
if input("print qrcode? [yN]: ").upper() == 'Y':
if input("as test or qrcode? [Tq]: ") in 'Qq':
import pyqrcode
print(pyqrcode.create(conf).terminal(quiet_zone=1))
else:
print(conf)

View file

@ -2,9 +2,7 @@
date=$(date --utc +%s%N)
METRICS=$(apcaccess)
for METRIC in TIMELEFT LOADPCT BCHARGE
for metric in TIMELEFT LOADPCT BCHARGE
do
echo "apcupsd $METRIC=$(grep $METRIC <<< $METRICS | cut -d ':' -f 2 | xargs | cut -d ' ' -f 1 ) $date"
echo "apcupsd $metric=$(apcaccess -p $metric | cut -d' ' -f1) $date"
done

View file

@ -20,8 +20,6 @@ defaults = {
'commands': ["sudo /usr/local/share/telegraf/apcupsd"],
'name_override': "apcupsd",
'data_format': "influx",
'interval': '30s',
'flush_interval': '30s',
}),
},
},

View file

@ -48,8 +48,8 @@ hosts = {}
for source_string in node.metadata.get('apt/sources'):
source = repo.libs.apt.AptSource(source_string)
hosts\
.setdefault(source.url.hostname, list())\
.append(source)
.setdefault(source.url.hostname, set())\
.add(source)
# create sources lists and keyfiles
@ -61,13 +61,12 @@ for host, sources in hosts.items():
source.options['signed-by'] = [destination_path]
files[f'/etc/apt/sources.list.d/{host}.list'] = {
'content': '\n'.join(sorted(set(
str(source).format(
release=node.metadata.get('os_release'),
version=node.os_version[0], # WIP crystal
)
for source in sources
))),
'content': '\n'.join(
str(source) for source in sorted(sources)
).format(
release=node.metadata.get('os_release'),
version=node.os_version[0], # WIP crystal
),
'triggers': {
'action:apt_update',
},

View file

@ -33,7 +33,7 @@ zfs snap "$source_dataset@$new_bookmark"
if zfs list -t bookmark -H -o name | grep "^$source_dataset#$bookmark_prefix" | wc -l | grep -q "^0$"
then
echo "INITIAL BACKUP"
# do in subshell, otherwise ctr+c will lead to 0 exitcode
# do in subshell, otherwise ctr+c will lead to 0 exitcode
$(zfs send -v "$source_dataset@$new_bookmark" | $ssh sudo zfs recv -F "$target_dataset")
else
echo "INCREMENTAL BACKUP"
@ -44,21 +44,8 @@ fi
if [[ "$?" == "0" ]]
then
# delete old local bookmarks
for destroyable_bookmark in $(zfs list -t bookmark -H -o name "$dataset" | grep "^$dataset#$bookmark_prefix")
do
zfs destroy "$destroyable_bookmark"
done
# delete snapshots from bookmarks (except newest, even of not necessary; maybe for resuming tho)
for destroyable_snapshot in $($ssh sudo zfs list -t snapshot -H -o name "$dataset" | grep "^$dataset@$bookmark_prefix" | grep -v "$new_bookmark")
do
$ssh sudo zfs destroy "$destroyable_snapshot"
done
zfs bookmark "$source_dataset@$new_bookmark" "$source_dataset#$new_bookmark"
zfs destroy "$source_dataset@$new_bookmark" # keep snapshots?
#zfs destroy "$source_dataset@$new_bookmark" # keep snapshots?
echo "SUCCESS"
else
zfs destroy "$source_dataset@$new_bookmark"

View file

@ -114,6 +114,6 @@ for name, conf in node.metadata.get('flask').items():
svc_systemd[name] = {
'needs': [
f'action:flask_{name}_pip_install',
f'file:/usr/local/lib/systemd/system/{name}.service',
f'file:/etc/systemd/system/{name}.service',
],
}

View file

@ -11,6 +11,10 @@ downloads['/usr/local/bin/gitea'] = {
},
}
users['git'] = {
'home': '/home/git',
}
directories['/var/lib/gitea'] = {
'owner': 'git',
'mode': '0700',

View file

@ -1,15 +1,6 @@
database_password = repo.vault.password_for(f'{node.name} postgresql gitea')
defaults = {
'apt': {
'packages': {
'git': {
'needed_by': {
'svc_systemd:gitea',
}
},
},
},
'gitea': {
'database': {
'host': 'localhost',
@ -61,32 +52,16 @@ defaults = {
},
},
},
'users': {
'git': {
'home': '/home/git',
'zfs': {
'datasets': {
'tank/gitea': {
'mountpoint': '/var/lib/gitea',
},
},
},
}
@metadata_reactor.provides(
'zfs/datasets',
)
def zfs(metadata):
if not node.has_bundle('zfs'):
return {}
return {
'zfs': {
'datasets': {
f"{metadata.get('zfs/storage_classes/ssd')}/gitea": {
'mountpoint': '/var/lib/gitea',
},
},
},
}
@metadata_reactor.provides(
'nginx/vhosts',
)

View file

@ -101,11 +101,11 @@ for dashboard_id, monitored_node in enumerate(monitored_nodes, start=1):
dashboard['title'] = monitored_node.name
dashboard['uid'] = monitored_node.metadata.get('id')
panel_id = count(start=1)
for row_id, row_name in enumerate(sorted(monitored_node.metadata.get('grafana_rows')), start=1):
with open(repo.path.join([f'data/grafana/rows/{row_name}.py'])) as file:
row = eval(file.read())
for panel_in_row, (panel_name, panel_config) in enumerate(row.items()):
panel = deepcopy(panel_template)
panel['id'] = next(panel_id)
@ -113,7 +113,7 @@ for dashboard_id, monitored_node in enumerate(monitored_nodes, start=1):
panel['gridPos']['w'] = 24 // len(row)
panel['gridPos']['x'] = (24 // len(row)) * panel_in_row
panel['gridPos']['y'] = (row_id - 1) * panel['gridPos']['h']
if 'display_name' in panel_config:
panel['fieldConfig']['defaults']['displayName'] = '${'+panel_config['display_name']+'}'
@ -127,17 +127,13 @@ for dashboard_id, monitored_node in enumerate(monitored_nodes, start=1):
panel['fieldConfig']['defaults']['min'] = panel_config['min']
if 'max' in panel_config:
panel['fieldConfig']['defaults']['max'] = panel_config['max']
if 'soft_max' in panel_config:
panel['fieldConfig']['defaults']['custom']['axisSoftMax'] = panel_config['soft_max']
if 'legend' in panel_config:
panel['options']['legend'].update(panel_config['legend'])
if 'tooltip' in panel_config:
panel['options']['tooltip']['mode'] = panel_config['tooltip']
if panel_config['tooltip'] == 'multi':
panel['options']['tooltip']['sort'] = 'desc'
for query_name, query_config in panel_config['queries'].items():
panel['targets'].append({
'refId': query_name,
@ -146,22 +142,22 @@ 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),
resolution=query_config.get('resolution', 1) * 4,
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),
).strip()
})
dashboard['panels'].append(panel)
files[f'/var/lib/grafana/dashboards/{monitored_node.name}.json'] = {
'content': json.dumps(dashboard, indent=4),
'triggers': [
'svc_systemd:grafana-server:restart',
]
}

View file

@ -55,20 +55,6 @@ defaults = {
}
@metadata_reactor.provides(
'grafana/config/server/domain',
)
def domain(metadata):
return {
'grafana': {
'config': {
'server': {
'domain': metadata.get('grafana/hostname'),
},
},
},
}
@metadata_reactor.provides(
'grafana/datasources',
)
@ -129,7 +115,10 @@ def nginx(metadata):
'nginx': {
'vhosts': {
metadata.get('grafana/hostname'): {
'content': 'grafana/vhost.conf',
'content': 'nginx/proxy_pass.conf',
'context': {
'target': 'http://127.0.0.1:8300',
}
},
},
},

View file

@ -1,5 +0,0 @@
GRUB_DEFAULT=0
GRUB_TIMEOUT=1
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="${' '.join(kernel_params)}"
GRUB_CMDLINE_LINUX=""

View file

@ -1,20 +0,0 @@
files = {
'/etc/default/grub': {
'content_type': 'mako',
'context': {
'timeout': node.metadata.get('grub/timeout'),
'kernel_params': node.metadata.get('grub/kernel_params'),
},
'mode': '0644',
'triggers': {
'action:update-grub',
},
}
}
actions = {
'update-grub': {
'command': 'update-grub',
'triggered': True,
},
}

View file

@ -1,6 +0,0 @@
defaults = {
'grub': {
'timeout': 1,
'kernel_params': set(),
},
}

View file

@ -2,7 +2,6 @@ defaults = {
'apt': {
'packages': {
'lm-sensors': {},
'console-data': {}, # leykeys de
},
},
'grafana_rows': {

View file

@ -1,39 +0,0 @@
# Beware! This file is rewritten by htop when settings are changed in the interface.
# The parser is also very primitive, and not human-friendly.
fields=0 48 17 18 38 39 40 2 46 47 109 110 49 1
sort_key=46
sort_direction=-1
tree_sort_key=0
tree_sort_direction=1
hide_kernel_threads=0
hide_userland_threads=0
shadow_other_users=0
show_thread_names=0
show_program_path=1
highlight_base_name=0
highlight_megabytes=1
highlight_threads=1
highlight_changes=0
highlight_changes_delay_secs=5
find_comm_in_cmdline=1
strip_exe_from_cmdline=1
show_merged_command=0
tree_view=0
tree_view_always_by_pid=0
header_margin=1
detailed_cpu_time=0
cpu_count_from_one=1
show_cpu_usage=0
show_cpu_frequency=0
show_cpu_temperature=0
degree_fahrenheit=0
update_process_names=0
account_guest_in_cpu_meter=0
color_scheme=0
enable_mouse=1
delay=20
left_meters=Hostname Tasks DiskIO NetworkIO Blank CPU Memory Swap Blank LeftCPUs${cpus_per_row}
left_meter_modes=2 2 2 2 2 1 1 1 2 1
right_meters=CPU Blank PressureStallCPUSome PressureStallMemorySome PressureStallIOSome Blank RightCPUs${cpus_per_row}
right_meter_modes=3 2 1 1 1 2 1
hide_function_bar=0

View file

@ -1,8 +0,0 @@
files = {
'/etc/htoprc.global': {
'content_type': 'mako',
'context': {
'cpus_per_row': 4 if node.metadata.get('vm/threads', node.metadata.get('vm/cores', 1)) > 8 else 2,
},
},
}

View file

@ -1,7 +0,0 @@
defaults = {
'apt': {
'packages': {
'htop': {},
},
},
}

View file

@ -5,7 +5,7 @@ directories['/var/lib/influxdb'] = {
'owner': 'influxdb',
'group': 'influxdb',
'needs': [
f"zfs_dataset:{node.metadata.get('zfs/storage_classes/ssd')}/influxdb",
'zfs_dataset:tank/influxdb',
],
}

View file

@ -4,7 +4,6 @@ defaults = {
'apt': {
'packages': {
'influxdb2': {},
'influxdb2-cli': {},
},
'sources': {
'deb https://repos.influxdata.com/debian {release} stable',
@ -22,6 +21,15 @@ defaults = {
'http-bind-address': ':8200',
},
},
'zfs': {
'datasets': {
'tank/influxdb': {
'mountpoint': '/var/lib/influxdb',
'recordsize': '8192',
'atime': 'off',
},
},
},
}
@metadata_reactor.provides(
@ -37,26 +45,6 @@ def admin_password(metadata):
}
@metadata_reactor.provides(
'zfs/datasets',
)
def zfs(metadata):
if not node.has_bundle('zfs'):
return {}
return {
'zfs': {
'datasets': {
f"{metadata.get('zfs/storage_classes/ssd')}/influxdb": {
'mountpoint': '/var/lib/influxdb',
'recordsize': '8192',
'atime': 'off',
},
},
},
}
@metadata_reactor.provides(
'dns',
)

View file

@ -6,7 +6,6 @@ defaults = {
'version': {
10: 11,
11: 17,
12: 17,
}[node.os_version[0]],
},
}

View file

@ -70,7 +70,7 @@ for name, config in node.metadata.get('left4dead2/servers').items():
}
svc_systemd[f'left4dead2-server-{name}'] = {
'needs': [
f'file:/usr/local/lib/systemd/system/left4dead2-server-{name}.service',
f'file:/etc/systemd/system/left4dead2-server-{name}.service',
],
}
server_units.add(f'left4dead2-server-{name}')
@ -87,7 +87,7 @@ for id in node.metadata.get('left4dead2/workshop'):
# TIDYUP
find_obsolete_units = (
'find /usr/local/lib/systemd/system -type f -name "left4dead2-server-*.service" ' +
'find /etc/systemd/system -type f -name "left4dead2-server-*.service" ' +
' '.join(f"! -name '{name}.service'" for name in server_units)
)
actions['remove_obsolete_left4dead2_units'] = {

View file

@ -10,9 +10,6 @@ files = {
'content': '\n'.join(
f'{locale} {type}' for locale, type in installed_locales
),
'needs': {
'pkg_apt:locales',
},
'triggers': {
'action:locale-gen',
},

View file

@ -1,9 +1,7 @@
#!/bin/bash
USER="$1"
REL_SOURCE_PATH="/$1/files/$2"
ABS_SOURCE_PATH="/var/lib/nextcloud/$1/files/$2"
SOURCEPATH="/var/lib/nextcloud/$1/files/$2"
REL_DEST_PATH="/$1/files/$3"
ABS_DEST_PATH="/var/lib/nextcloud/$1/files/$3"
@ -13,63 +11,52 @@ ABS_UNSORTABLE_PATH="/var/lib/nextcloud/$1/files/$4"
echo "STARTING..."
chown -R www-data:www-data "$ABS_SOURCE_PATH"
chmod -R 770 "$ABS_SOURCE_PATH"
chown -R www-data:www-data "$SOURCEPATH"
chmod -R 770 "$SOURCEPATH"
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
for f in `find "$SOURCEPATH" -iname *.PNG -o -iname *.JPG -o -iname *.CR2 -o -iname *.CR3 -o -iname *.MP4 -o -iname *.MOV`; do
SCAN="TRUE"
echo "PROCESSING: $f"
EXIF=`exiftool "$f"`
if grep -q '^Create Date' <<< $EXIF
DATE=`exiftool "$f" | grep -m 1 "Create Date"`
if ! echo "$DATE" | grep "Create Date" >/dev/null
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")
RELPATH=$(realpath --relative-to="$SOURCEPATH" "$f")
DIRNAME=$(dirname "$ABS_UNSORTABLE_PATH/$RELPATH")
echo "UNSORTABLE: $f"
mkdir -p "$DIRNAME"
mv "$f" "$DIRNAME"
continue
fi
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`
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=""
YEAR=`echo $DATE | cut -d':' -f2 | cut -c 2-`
MONTH=`echo $DATE | cut -d':' -f3`
DAY=`echo $DATE | cut -d':' -f4 | cut -d' ' -f1`
HOUR=`echo $DATE | cut -d':' -f4 | cut -d' ' -f2`
MINUTE=`echo $DATE | cut -d':' -f5`
SECOND=`echo $DATE | cut -d':' -f6`
SECOND=`echo $SECOND | cut -d'+' -f1` # remove timezone
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"
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
# find "$SOURCEPATH/"* -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

View file

@ -1,15 +1,6 @@
from shlex import quote as q
defaults = {
'apt': {
'packages': {
'libimage-exiftool-perl': {},
},
},
}
@metadata_reactor.provides(
'systemd-timers',
)

View file

@ -28,15 +28,4 @@ $CONFIG = array (
"redis" => [
"host" => "/var/run/redis/nextcloud.sock",
],
'trusted_domains' =>
array (
0 => 'localhost',
1 => '127.0.0.1',
2 => '${hostname}',
),
"log_type" => "syslog",
"syslog_tag" => "nextcloud",
"logfile" => "",
"loglevel" => 3,
"default_phone_region" => "DE",
);

View file

@ -75,7 +75,6 @@ files = {
'mode': '640',
'context': {
'db_password': node.metadata.get('postgresql/roles/nextcloud/password'),
'hostname': node.metadata.get('nextcloud/hostname'),
},
'needs': [
'directory:/etc/nextcloud',
@ -127,7 +126,7 @@ files['/opt/nextcloud_upgrade_status.php'] = {
actions['upgrade_nextcloud'] = {
'command': repo.libs.nextcloud.occ('upgrade'),
'unless': 'sudo -u www-data php /opt/nextcloud_upgrade_status.php; test $? -ne 99',
'unless': 'sudo -u www-data php /opt/nextcloud/upgrade_status.php; test $? -ne 99',
'needs': [
'file:/opt/nextcloud_upgrade_status.php',
'action:install_nextcloud',

View file

@ -5,7 +5,6 @@ defaults = {
'apt': {
'packages': {
'php': {},
'php-redis': {},
'php-fpm': {},
'php-curl': {},
'php-gd': {},
@ -16,15 +15,6 @@ defaults = {
'php-cgi': {},
'php-zip': {},
'php-pgsql': {},
'php-bz2': {}, # face recognition
'php-intl': {},
'php-imagick': {},
'libmagickcore-6.q16-6-extra': {},
'php-gmp': {},
'php-bcmath': {},
},
'sources': {
'deb https://repo.delellis.com.ar {release} {release}', # face recognition
},
},
'archive': {
@ -60,11 +50,6 @@ defaults = {
'env[TMPDIR]': '/tmp',
'env[TEMP]': '/tmp',
},
'php.ini': {
'PHP': {
'memory_limit': '3G', # face recognition requires 2G
},
},
},
'postgresql': {
'roles': {
@ -92,11 +77,6 @@ defaults = {
'when': 'Sun 00:00:00',
'user': 'www-data',
},
'nextcloud-face-recognition': {
'command': '/usr/bin/php -f /opt/nextcloud/occ face:background_job -t 1800',
'when': '*:0/10',
'user': 'www-data',
},
},
'zfs': {
'datasets': {
@ -127,16 +107,3 @@ def vhost(metadata):
},
},
}
@metadata_reactor.provides(
'nginx/vhosts'
)
def pdlib(metadata):
return {
'apt': {
'packages': {
f"php{metadata.get('php/version')}-pdlib": {}, # face recognition
},
},
}

110
bundles/php/files/php.ini Normal file
View file

@ -0,0 +1,110 @@
[PHP]
; Only needed for libapache2-mod-php?
engine = On
short_open_tag = Off
precision = 14
output_buffering = 4096
zlib.output_compression = Off
implicit_flush = Off
serialize_precision = -1
ignore_user_abort = Off
zend.enable_gc = On
expose_php = Off
max_execution_time = 300
max_input_time = 600
memory_limit = 1G
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_startup_errors = Off
log_errors = On
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
html_errors = On
error_log = syslog
syslog.ident = php7.4
syslog.filter = ascii
arg_separator.output = "&amp;"
variables_order = "GPCS"
request_order = "GP"
register_argc_argv = Off
auto_globals_jit = On
post_max_size = ${post_max_size}
default_mimetype = "text/html"
default_charset = "UTF-8"
enable_dl = Off
file_uploads = On
upload_max_filesize = ${post_max_size}
max_file_uploads = 2000
allow_url_fopen = On
allow_url_include = Off
default_socket_timeout = 10
[CLI Server]
cli_server.color = On
[mail function]
mail.add_x_header = Off
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1
odbc.defaultlrl = 4096
odbc.defaultbinmode = 1
[PostgreSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[bcmath]
bcmath.scale = 0
[Session]
session.save_handler = files
session.use_strict_mode = 0
session.use_cookies = 1
session.use_only_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /
session.cookie_domain =
session.cookie_httponly =
session.cookie_samesite =
session.serialize_handler = php
session.gc_probability = 1
session.gc_divisor = 1000
session.gc_maxlifetime = 1440
session.referer_check =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
session.sid_length = 32
session.trans_sid_tags = "a=href,area=href,frame=src,form="
session.sid_bits_per_character = 6
[Assertion]
zend.assertions = -1
[Date]
date.timezone = Europe/London
[opcache]
opcache.enable = 1
opcache.interned_strings_buffer = 32
opcache.max_accelerated_files = 20000
opcache.memory_consumption = 1024
opcache.save_comments = 1
opcache.validate_timestamps = 1
opcache.revalidate_freq = 60

View file

@ -1,21 +1,22 @@
from os.path import join
import json
from bundlewrap.utils.dicts import merge_dict
version = node.metadata.get('php/version')
php_ini_context = {
'num_cpus': node.metadata.get('vm/cores'),
'post_max_size': node.metadata.get('php/post_max_size'),
}
files = {
f'/etc/php/{version}/cli/php.ini': {
'content': repo.libs.ini.dumps(node.metadata.get('php/php.ini')),
'content_type': 'mako',
'context': php_ini_context,
'needs': {
f'pkg_apt:php{version}',
f'pkg_apt:php{version}-fpm',
},
},
f'/etc/php/{version}/fpm/php.ini': {
'content': repo.libs.ini.dumps(node.metadata.get('php/php.ini')),
'content_type': 'mako',
'context': php_ini_context,
'needs': {
f'pkg_apt:php{version}',
f'pkg_apt:php{version}-fpm',

View file

@ -1,153 +1,29 @@
defaults = {
'php': {
'post_max_size': '32G',
},
}
@metadata_reactor.provides(
'php/php.ini',
)
def php_ini(metadata):
conf = {
'PHP': {
'engine': 'On',
'short_open_tag': 'Off',
'precision': '14',
'output_buffering': '4096',
'zlib.output_compression': 'Off',
'implicit_flush': 'Off',
'serialize_precision': '-1',
'ignore_user_abort': 'Off',
'zend.enable_gc': 'On',
'expose_php': 'Off',
'max_execution_time': '300',
'max_input_time': '600',
'memory_limit': '512M',
'error_reporting': '"E_ALL & ~E_DEPRECATED & ~E_STRICT"',
'display_startup_errors': 'Off',
'log_errors': 'On',
'log_errors_max_len': '1024',
'ignore_repeated_errors': 'Off',
'ignore_repeated_source': 'Off',
'report_memleaks': 'On',
'html_errors': 'On',
'error_log': 'syslog',
'syslog.ident': 'php',
'syslog.filter': 'ascii',
'arg_separator.output': '"&amp;"',
'variables_order': 'GPCS',
'request_order': 'GP',
'register_argc_argv': 'Off',
'auto_globals_jit': 'On',
'post_max_size': '32g',
'default_mimetype': 'text/html',
'default_charset': 'UTF-8',
'enable_dl': 'Off',
'file_uploads': 'On',
'upload_max_filesize': '32g',
'max_file_uploads': '2000',
'allow_url_fopen': 'On',
'allow_url_include': 'Off',
'default_socket_timeout': '10',
},
'CLI Server': {
'cli_server.color': 'On',
},
'mail function': {
'mail.add_x_header': 'Off',
},
'ODBC': {
'odbc.allow_persistent': 'On',
'odbc.check_persistent': 'On',
'odbc.max_persistent': '-1',
'odbc.max_links': '-1',
'odbc.defaultlrl': '4096',
'odbc.defaultbinmode': '1',
},
'PostgreSQL': {
'pgsql.allow_persistent': 'On',
'pgsql.auto_reset_persistent': 'Off',
'pgsql.max_persistent': '-1',
'pgsql.max_links': '-1',
'pgsql.ignore_notice': '0',
'pgsql.log_notice': '0',
},
'bcmath': {
'bcmath.scale': '0',
},
'Session': {
'session.save_handler': 'files',
'session.use_strict_mode': '0',
'session.use_cookies': '1',
'session.use_only_cookies': '1',
'session.name': 'PHPSESSID',
'session.auto_start': '0',
'session.cookie_lifetime': '0',
'session.cookie_path': '/',
'session.cookie_domain': '',
'session.cookie_httponly': '',
'session.cookie_samesite': '',
'session.serialize_handler': 'php',
'session.gc_probability': '1',
'session.gc_divisor': '1000',
'session.gc_maxlifetime': '1440',
'session.referer_check': '',
'session.cache_limiter': 'nocache',
'session.cache_expire': '180',
'session.use_trans_sid': '0',
'session.sid_length': '32',
'session.trans_sid_tags': '"a=href,area=href,frame=src,form="',
'session.sid_bits_per_character': '6',
},
'Assertion': {
'zend.assertions': '-1',
},
'Date': {
'date.timezone': 'Europe/London',
},
'opcache': {
'opcache.enable': '1',
'opcache.interned_strings_buffer': '32',
'opcache.max_accelerated_files': '20000',
'opcache.memory_consumption': '1024',
'opcache.save_comments': '1',
'opcache.validate_timestamps': '1',
'opcache.revalidate_freq': '60',
},
}
return {
'php': {
'php.ini': {
section: {
key: value
for key, value in options.items()
if not metadata.get(f'php/php.ini/{section}/{key}', None)
}
for section, options in conf.items()
}
},
}
@metadata_reactor.provides(
'php/www.conf',
)
def www_conf(metadata):
threads = metadata.get('vm/threads', metadata.get('vm/cores', 4))
version = metadata.get('php/version')
return {
'php': {
'www.conf': {
'user': 'www-data',
'group': 'www-data',
'listen': f"/run/php/php{metadata.get('php/version')}-fpm.sock",
'listen': f'/run/php/php{version}-fpm.sock',
'listen.owner': 'www-data',
'listen.group': 'www-data',
'pm': 'dynamic',
'pm.max_children': int(threads*2),
'pm.start_servers': int(threads),
'pm.min_spare_servers': int(threads/2),
'pm.max_spare_servers': int(threads),
'pm.max_requests': int(threads*32),
'pm.max_children': '60',
'pm.start_servers': '20',
'pm.min_spare_servers': '10',
'pm.max_spare_servers': '20',
'pm.max_requests': '500',
},
},
}
@ -157,11 +33,12 @@ def www_conf(metadata):
'apt/packages',
)
def apt(metadata):
version = metadata.get('php/version')
return {
'apt': {
'packages': {
f"php{metadata.get('php/version')}": {},
f"php{metadata.get('php/version')}-fpm": {},
f'php{version}': {},
f'php{version}-fpm': {},
},
},
}

View file

@ -1,15 +1,12 @@
from bundlewrap.utils.dicts import merge_dict
version = node.metadata.get('postgresql/version')
directories = {
'/var/lib/postgresql': {
'owner': 'postgres',
'group': 'postgres',
'needs': [
'pkg_apt:postgresql',
f"zfs_dataset:{node.metadata.get('zfs/storage_classes/ssd')}/postgresql",
'zfs_dataset:tank/postgresql',
],
'needed_by': [
'svc_systemd:postgresql',
@ -17,22 +14,6 @@ directories = {
}
}
files = {
f"/etc/postgresql/{version}/main/conf.d/managed.conf": {
'content': '\n'.join(
f'{key} = {value}'
for key, value in sorted(node.metadata.get('postgresql/conf').items())
) + '\n',
'owner': 'postgres',
'group': 'postgres',
'needed_by': [
'svc_systemd:postgresql',
],
'triggers': [
'svc_systemd:postgresql:restart',
],
},
}
svc_systemd['postgresql'] = {
'needs': [

View file

@ -1,6 +1,3 @@
import builtins
root_password = repo.vault.password_for(f'{node.name} postgresql root')
defaults = {
@ -15,7 +12,6 @@ defaults = {
},
},
'postgresql': {
'conf': {},
'roles': {
'root': {
'password': root_password,
@ -27,48 +23,13 @@ defaults = {
'grafana_rows': set(),
}
@metadata_reactor.provides(
'postgresql/conf',
)
def conf(metadata):
conf = {}
def limit(value, min=float('-inf'), max=float('inf'), unit=None):
result = int(builtins.max([builtins.min([max, value]), min]))
return str(result) + unit if unit else result
ram = metadata.get('vm/ram', None)
if ram:
conf['max_connections'] = limit(ram/50, min=100)
conf['shared_buffers'] = limit(ram/20, min=128, unit='MB')
conf['work_mem'] = limit(ram/500, min=4, max=64, unit='MB')
conf['temp_buffers'] = limit(ram/500, min=8, max=64, unit='MB')
conf['effective_cache_size'] = limit(ram/3, min=4096, unit='MB')
conf['maintenance_work_mem'] = limit(ram/50, min=64, unit='MB')
return {
'postgresql': {
'conf': conf,
},
}
@metadata_reactor.provides(
'zfs/datasets',
)
def zfs(metadata):
if not node.has_bundle('zfs'):
return {}
return {
'zfs': {
'datasets': {
f"{metadata.get('zfs/storage_classes/ssd')}/postgresql": {
'mountpoint': '/var/lib/postgresql',
'recordsize': '8192',
'atime': 'off',
},
if node.has_bundle('zfs'):
defaults['zfs'] = {
'datasets': {
'tank/postgresql': {
'mountpoint': '/var/lib/postgresql',
'recordsize': '8192',
'atime': 'off',
},
},
}

View file

@ -4,6 +4,3 @@ Host *
GSSAPIAuthentication yes
StrictHostKeyChecking yes
GlobalKnownHostsFile /etc/ssh/ssh_known_hosts
ControlMaster auto
ControlPath ~/.ssh/multiplex-%C
ControlPersist 5m

View file

@ -1,48 +0,0 @@
directories = {
'/opt/steam_chat_logger': {
'owner': 'steam_chat_logger',
},
'/var/lib/steam_chat_logger': {
'owner': 'steam_chat_logger',
'mode': '0755',
'needs': [
'zfs_dataset:tank/steam-chat-logger'
],
},
'/var/lib/steam_chat_logger/steamuserimages': {
'owner': 'steam_chat_logger',
'mode': '0755',
'needs': [
'zfs_dataset:tank/steam-chat-logger'
],
},
}
git_deploy = {
'/opt/steam_chat_logger': {
'repo': 'https://git.sublimity.de/cronekorkn/steam_chat_logger.git',
'rev': 'master',
}
}
pkg_pip = {
'steam': {},
'beautifulsoup4': {},
'pytz': {},
'pg8000': {},
}
# TODO
'''
CREATE TABLE IF NOT EXISTS messages (
id SERIAL PRIMARY KEY,
checksum VARCHAR(64) UNIQUE NOT NULL,
from_url VARCHAR(255) NOT NULL,
from_name VARCHAR(255) NOT NULL,
to_url VARCHAR(255) NOT NULL,
to_name VARCHAR(255) NOT NULL,
date TIMESTAMP WITH TIME ZONE NOT NULL,
message TEXT NOT NULL
)
'''

View file

@ -1,51 +0,0 @@
defaults = {
'apt': {
'packages': {
'python3-pip': {},
},
},
'postgresql': {
'roles': {
'steam_chat_logger': {
'password': repo.vault.password_for(f'{node.name} postgresql steam_chat_logger'),
},
},
'databases': {
'steam_chat_logger': {
'owner': 'steam_chat_logger',
},
},
},
'users': {
'steam_chat_logger': {},
},
'zfs': {
'datasets': {
'tank/steam-chat-logger': {
'mountpoint': '/var/lib/steam_chat_logger',
},
},
},
}
@metadata_reactor.provides(
'systemd-timers/steam-chat-logger',
)
def systemd_timer(metadata):
return {
'systemd-timers': {
f'steam-chat-logger': {
'command': '/opt/steam_chat_logger/steam_chat_logger.py',
'when': 'hourly',
'user': 'steam_chat_logger',
'env': {
'DB_NAME': 'steam_chat_logger',
'DB_USER': 'steam_chat_logger',
'DB_PASSWORD': metadata.get('postgresql/roles/steam_chat_logger/password'),
**metadata.get('steam_chat_logger'),
},
'working_dir': '/var/lib/steam_chat_logger',
},
},
}

View file

@ -1,55 +0,0 @@
from ipaddress import ip_interface
defaults = {
'flask': {
'steam-chat-viewer' : {
'git_url': "https://git.sublimity.de/cronekorkn/steam-chat-viewer.git",
'port': 4001,
'app_module': 'steam_chat_viewer',
'user': 'steam_chat_viewer',
'group': 'steam_chat_viewer',
'timeout': 900,
'env': {
'DB_HOST': 'localhost',
'DB_NAME': 'steam_chat_logger',
'DB_USER': 'steam_chat_logger',
},
},
},
'users': {
'steam_chat_viewer': {},
},
}
@metadata_reactor.provides(
'flask/steam-chat-viewer/env/DB_PASSWORD',
)
def agent_conf(metadata):
return {
'flask': {
'steam-chat-viewer': {
'env': {
'DB_PASSWORD': metadata.get('postgresql/roles/steam_chat_logger/password'),
},
},
},
}
@metadata_reactor.provides(
'nginx/vhosts',
)
def nginx(metadata):
return {
'nginx': {
'vhosts': {
metadata.get('steam-chat-viewer/hostname'): {
'content': 'steam-chat-viewer/vhost.conf',
'context': {
'target': 'http://127.0.0.1:4001',
},
},
},
},
}

View file

@ -54,6 +54,6 @@ actions = {
svc_systemd['steam-update'] = {
'running': False,
'needs': {
'file:/usr/local/lib/systemd/system/steam-update.service',
'file:/etc/systemd/system/steam-update.service',
}
}

View file

@ -1,56 +1,49 @@
size_mb = node.metadata.get('systemd-swap')//1_000_000
size = node.metadata.get('systemd-swap')
assert isinstance(size, int)
actions = {
'stop_swap': {
'command': f'systemctl stop swapfile.swap',
'unless': f'! systemctl is-active swapfile.swap',
'unless': f'rm /swapfile',
'triggered': True,
},
'remove_swapfile': {
'command': f'rm /swapfile',
'unless': f'! test -e /swapfile',
'triggered': True,
'needs': {
'action:stop_swap',
},
},
'create_swapfile': {
'command': f'dd if=/dev/zero of=/swapfile bs=1000000 count={size_mb}',
'unless': f'stat -c %s /swapfile | grep ^{size_mb*1_000_000}$',
'command': f'dd if=/dev/zero of=/swapfile bs={size} count=1',
'unless': f'stat -c %s /swapfile | grep ^{size}$',
'preceded_by': {
'action:stop_swap',
'action:remove_swapfile',
},
'triggers': {
'action:initialize_swapfile',
'svc_systemd:swapfile.swap:restart',
},
},
'swapfile_mode': {
'command': f'chmod 600 /swapfile',
'unless': f'stat -c "%a" /swapfile | grep -q "^600$"',
'needs': {
'action:create_swapfile',
},
'triggers': {
'svc_systemd:swapfile.swap:restart',
},
},
'initialize_swapfile': {
'command': f'mkswap /swapfile',
'triggered': True,
'needs': {
'action:swapfile_mode',
'action:create_swapfile',
}
},
}
files = {
'/swapfile': {
'content_type': 'any',
'mode': '600',
'triggers': {
'svc_systemd:swapfile.swap:restart',
},
}
}
svc_systemd = {
'swapfile.swap': {
'preceded_by': {
'action:initialize_swapfile',
},
'needs': {
'file:/swapfile',
'action:initialize_swapfile',
'action:systemd-reload',
},

View file

@ -22,7 +22,7 @@ def systemd(metadata):
'Persistent': config.get('persistent', False),
'Unit': f'{name}.service',
},
},
},
f'{name}.service': {
'Unit':{
'Description': f'{name} timer service',
@ -30,18 +30,11 @@ def systemd(metadata):
'Service': {
'User': config.get('user', 'root'),
'ExecStart': config['command'],
'Environment': config.get('env'),
'Nice': config.get('nice', 10),
},
},
})
if config.get('working_dir'):
units[f'{name}.service']['Service']['WorkingDirectory'] = config['working_dir']
if config.get('success_exit_status'):
units[f'{name}.service']['Service']['SuccessExitStatus'] = config['success_exit_status']
services[f'{name}.timer'] = {}
return {
'systemd': {
'units': units,

View file

@ -1,11 +1,5 @@
# SYSTEMD
## show unit paths
```
systemctl --no-pager --property=UnitPath show | tr ' ' '\n'
```
## metadata
```python

View file

@ -1,14 +1,5 @@
from bundlewrap.utils.dicts import merge_dict
directories = {
'/usr/local/lib/systemd/system': {
'purge': True,
'triggers': [
"action:systemd-reload",
],
},
}
actions = {
'systemd-reload': {
'command': 'systemctl daemon-reload',
@ -31,7 +22,7 @@ for name, unit in node.metadata.get('systemd/units').items():
],
}
elif extension in ['timer', 'service', 'mount', 'swap']:
path = f'/usr/local/lib/systemd/system/{name}'
path = f'/etc/systemd/system/{name}'
dependencies = {
'triggers': [
"action:systemd-reload",

View file

@ -1,23 +1,14 @@
# Phone
- install termux from F-Droid
- install termux::api from F-Droid
- install termux from Play Store
- install termux::api from Play Store
- open termux
- run `pkg update`
- run `pkg install termux-api openssh`
- run `passwd` and set a password
- run `whoami` to get the username
- run `sshd` to start ssh server
- run `su - tasmota-charge -c 'ssh-copy-id -p 8022 u0_a233@10.0.0.175'` on server node
- acquire wakelock for the termux session in notifications
- install termux::boot from F-Droid
- create file ~/.termux/boot/start-sshd:
```shell
#!/data/data/com.termux/files/usr/bin/sh
termux-wake-lock
sshd
```
# Server
- you can run something like `su - tasmota-charge -c 'ssh -p 8022 u0_a233@10.0.0.175'`
- you can run something like `su - tasmota-charge -c 'ssh-copy-id -p 8022 u0_q194@10.0.0.166'`

View file

@ -6,26 +6,16 @@ PLUG_IP=${plug_ip}
MIN=${min}
MAX=${max}
if ! ssh -o 'StrictHostKeyChecking no' -p 8022 $PHONE_USER@$PHONE_IP 'true'
then
echo "ERROR: cant connect to phone via ssh"
exit 51
fi
AKKU=$(ssh -o 'StrictHostKeyChecking no' -p 8022 $PHONE_USER@$PHONE_IP termux-battery-status | jq -r .percentage)
echo "akku is at $AKKU% ($MIN%/$MAX%)"
AKKU=$(ssh -p 8022 $PHONE_USER@$PHONE_IP termux-battery-status | jq -r .percentage)
echo "akku is at $AKKU%"
if ! curl --head --silent --fail "http://$PLUG_IP/cm?cmnd=Power" --output /dev/null
then
echo "ERROR: cant connect to plug via http"
exit 52
fi
PLUG_IS=$(curl -s "http://$PLUG_IP/cm?cmnd=Power" | jq -r .POWER)
echo "plug is $PLUG_IS"
if [[ $AKKU -lt $MIN ]] && [[ $PLUG_IS = OFF ]]
if [[ $AKKU < $MIN ]] && [[ $PLUG_IS = OFF ]]
then
TURN_PLUG=ON
elif [[ $AKKU -gt $MAX ]] && [[ $PLUG_IS = ON ]]
elif [[ $AKKU > $MAX ]] && [[ $PLUG_IS = ON ]]
then
TURN_PLUG=OFF
else
@ -34,11 +24,4 @@ else
fi
echo "turning plug $TURN_PLUG"
if curl --silent "http://$PLUG_IP/cm?cmnd=Power%20$TURN_PLUG" | jq -r .POWER | grep -q "^$TURN_PLUG\$"
then
echo "SUCCESS"
exit 0
else
echo "ERROR"
exit 53
fi
curl -s "http://$PLUG_IP/cm?cmnd=Power%20$TURN_PLUG"

View file

@ -20,11 +20,6 @@ files = {
'source': f"https://dl.sublimity.de/telegraf-procio/telegraf-procio-{node.metadata.get('system/architecture')}-latest",
'mode': '0755',
},
'/usr/local/share/telegraf/pressure_stall': {
'content_type': 'download',
'source': f"https://dl.sublimity.de/telegraf-pressure-stall/telegraf-pressure-stall-{node.metadata.get('system/architecture')}-latest",
'mode': '0755',
},
}
svc_systemd['telegraf'] = {

View file

@ -5,6 +5,9 @@ defaults = {
'packages': {
'telegraf': {},
},
'sources': {
'deb https://repos.influxdata.com/debian {release} stable',
},
},
'telegraf': {
'config': {
@ -45,31 +48,20 @@ defaults = {
'memory_rss',
],
})},
'diskio': {h({
'device_tags': ["ID_PART_ENTRY_NUMBER"],
})},
'diskio': {h({})},
'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',
}),
h({
'commands': [
f'/usr/local/share/telegraf/pressure_stall',
],
'data_format': 'influx',
'interval': '10s',
}),
},
'exec': {h({
'commands': [
f'sudo /usr/local/share/telegraf/procio',
],
'data_format': 'influx',
'interval': '20s',
})},
},
},
},
@ -79,7 +71,8 @@ defaults = {
'disk_io',
'disk_usage',
'net_io',
'proc_cpu_ram',
'proc_cpu',
'proc_ram',
'proc_io',
},
'sudoers': {
@ -88,28 +81,6 @@ defaults = {
}
@metadata_reactor.provides(
'apt/sources',
)
def apt(metadata):
release = {
'buster': 'buster',
'bullseye': 'bullseye',
'bookworm': 'bullseye',
}[metadata.get('os_release')]
return {
'apt': {
'packages': {
'telegraf': {},
},
'sources': {
f"deb https://repos.influxdata.com/debian {release} stable",
},
},
}
@metadata_reactor.provides(
'telegraf/config/outputs/influxdb_v2',
)

View file

@ -1,73 +1,40 @@
#!/bin/bash
# CHECK UPTIME
RESUMED_TIMESTAMP_MICRO=$(journalctl -t systemd-sleep -b 0 -o json MESSAGE="System resumed." -n1 | jq -r .__REALTIME_TIMESTAMP)
if [[ -z "$RESUMED_TIMESTAMP_MICRO" ]]
then
UPTIME=$(cat /proc/uptime | cut -d' ' -f1 | cut -d'.' -f1)
else
RESUMED_TIMESTAMP=$(expr $RESUMED_TIMESTAMP_MICRO / 1000000)
NOW_TIMESTAMP=$(date +%s)
UPTIME=$(expr $NOW_TIMESTAMP - $RESUMED_TIMESTAMP)
fi
WOKE=$(expr $(journalctl -t systemd-sleep -b 0 -o json MESSAGE="System resumed." -n1 | jq -r .__REALTIME_TIMESTAMP) / 1000000)
NOW=$(date +%s)
UPTIME=$(expr $NOW - $WOKE)
MIN_UPTIME=$(expr 60 \* 15)
if [[ "$UPTIME" -lt "$MIN_UPTIME" ]]
then
echo "ABORT: uptime of ${UPTIME}s is lower than minimum of ${MIN_UPTIME}s"
exit 75
echo "ABORT: uptime ($UPTIME s) lower than minimum ($MIN_UPTIME s)"
exit 0
fi
# CHECK FOR RUNNING TIMERS
MY_SERVICE="$2"
for SERVICE in $(systemctl list-timers --no-pager --no-legend --state active -o json | jq -r '.[] | .activates')
do
if [[ "$SERVICE" = "$THIS_SERVICE" ]]
if [[ "$SERVICE" = "$MY_SERVICE" ]]
then
continue
elif systemctl is-active "$SERVICE" --quiet
then
echo "ABORT: service $SERVICE is running by timer"
exit 75
exit 0
fi
done
# CHECK FOR ACTIVE LOGINS
LOGINS=$(netstat -tnpa | grep 'ESTABLISHED.*sshd' | tr -s ' ' | cut -d' ' -f5,7-8 | paste -d',' -s | sed 's/,/, /')
if ! [[ -z "$LOGINS" ]]
LOGINS=$(netstat -tnpa | grep 'ESTABLISHED.*sshd' | wc -l)
if [[ "$LOGINS" -gt 0 ]]
then
echo "ABORT: users logged in: $LOGINS"
exit 75
echo "ABORT: $LOGINS user logins"
exit 0
fi
# SUSPEND!
if [[ "$1" = check ]]
if [[ "$1" = now ]]
then
echo "WOULD SESPEND"
exit 0
else
echo "SESPENDING AFTER TIMEOUT"
for i in 1 2 3 4 5 6
do
echo "TIMEOUT ${i} success"
sleep 10
# check if condition is still met
if "$0" check
then
continue
else
echo "SESPENSION ABORTED"
exit 75
fi
done
echo "SESPENDING"
sleep 60
systemctl suspend
exit 0
else
echo "WOULD SESPEND"
fi

View file

@ -3,7 +3,7 @@ if not waker_node.has_bundle('wol-waker'):
raise Exception(f'waker node {waker_node.name} does not have bundle wol-waker')
files = {
'/usr/local/bin/suspend_if_idle': {
'/opt/suspend_if_idle': {
'mode': '550',
},
}

View file

@ -5,8 +5,6 @@ defaults = {
'apt': {
'packages': {
'jq': {},
'ethtool': {},
'net-tools': {},
},
},
}
@ -16,15 +14,12 @@ defaults = {
'systemd-timers/suspend-if-idle',
)
def timer(metadata):
name = 'suspend-if-idle'#
return {
'systemd-timers': {
'suspend-if-idle': {
'command': f'suspend_if_idle',
name: {
'command': f'/opt/suspend_if_idle now {name}.service',
'when': 'minutely',
'success_exit_status': '75',
'env': {
'THIS_SERVICE': 'suspend-if-idle.service',
},
},
},
}
@ -37,7 +32,7 @@ def wake_command(metadata):
waker_hostname = repo.get_node(metadata.get('wol-sleeper/waker')).hostname
mac = metadata.get(f"network/{metadata.get('wol-sleeper/network')}/mac")
ip = ip_interface(metadata.get(f"network/{metadata.get('wol-sleeper/network')}/ipv4")).ip
return {
'wol-sleeper': {
'wake_command': f"ssh -o StrictHostKeyChecking=no wol@{waker_hostname} 'wakeonlan {mac} && while ! ping {ip} -c1 -W3; do true; done'",
@ -46,13 +41,19 @@ def wake_command(metadata):
@metadata_reactor.provides(
'apt/packages/ethtool',
'systemd/units/enable-wol.service',
'systemd/services/enable-wol.service',
)
def systemd(metadata):
interface = metadata.get(f"network/{metadata.get('wol-sleeper/network')}/interface")
return {
'apt': {
'packages': {
'ethtool': {},
},
},
'systemd': {
'units': {
'enable-wol.service': {

View file

@ -1,11 +1,3 @@
defaults = {
'apt': {
'packages': {
'wakeonlan': {},
},
},
}
@metadata_reactor.provides(
'users/wol',
)

View file

@ -2,14 +2,14 @@
set -exu
ssh="ssh -o ConnectTimeout=5 root@${server_ip}"
ssh="ssh -o StrictHostKeyChecking=no -o ConnectTimeout=5 root@${server_ip}"
bookmark_prefix="auto-mirror_"
new_bookmark="$bookmark_prefix$(date +"%Y-%m-%d_%H:%M:%S")"
for dataset in $(zfs list -t filesystem -H -o name)
do
echo "MIRRORING $dataset"
if ! $ssh sudo zfs list -t filesystem -H -o name | grep -q "^$dataset$"
then
echo "CREATING PARENT DATASET..."
@ -17,11 +17,11 @@ do
fi
zfs snap "$dataset@$new_bookmark"
if zfs list -t bookmark -H -o name | grep "^$dataset#$bookmark_prefix" | wc -l | grep -q "^0$"
then
echo "INITIAL BACKUP"
# do in subshell, otherwise ctr+c will lead to 0 exitcode
# do in subshell, otherwise ctr+c will lead to 0 exitcode
$(zfs send -v "$dataset@$new_bookmark" | $ssh sudo zfs recv -F "$dataset" -o mountpoint=none)
else
echo "INCREMENTAL BACKUP"
@ -32,19 +32,6 @@ do
if [[ "$?" == "0" ]]
then
# delete old local bookmarks
for destroyable_bookmark in $(zfs list -t bookmark -H -o name "$dataset" | grep "^$dataset#$bookmark_prefix")
do
zfs destroy "$destroyable_bookmark"
done
# delete snapshots from bookmarks (except newest, even of not necessary; maybe for resuming tho)
for destroyable_snapshot in $($ssh sudo zfs list -t snapshot -H -o name "$dataset" | grep "^$dataset@$bookmark_prefix" | grep -v "$new_bookmark")
do
$ssh sudo zfs destroy "$destroyable_snapshot"
done
zfs bookmark "$dataset@$new_bookmark" "$dataset#$new_bookmark"
zfs destroy "$dataset@$new_bookmark"
echo "SUCCESS $dataset"

View file

@ -45,6 +45,24 @@ defaults = {
'when': '*-2,4,6,8,10,12-1 02:00',
'persistent': True,
},
'zfs-auto-snapshot-hourly': {
'command': '/usr/sbin/zfs-auto-snapshot --quiet --syslog --label=hourly --keep=24 //',
'when': 'hourly',
},
'zfs-auto-snapshot-daily': {
'command': '/usr/sbin/zfs-auto-snapshot --quiet --syslog --label=daily --keep=7 //',
'when': 'daily',
},
'zfs-auto-snapshot-weekly': {
'command': '/usr/sbin/zfs-auto-snapshot --quiet --syslog --label=weekly --keep=4 //',
'when': 'weekly',
'persistent': True,
},
'zfs-auto-snapshot-monthly': {
'command': '/usr/sbin/zfs-auto-snapshot --quiet --syslog --label=monthly --keep=24 //',
'when': 'monthly',
'persistent': True,
},
},
'telegraf': {
'config': {
@ -60,19 +78,9 @@ defaults = {
'datasets': {},
'pools': {},
'kernel_params': {},
'storage_classes': {
'ssd': 'tank',
},
'auto_snapshots': {
'hourly': 24,
'daily': 7,
'weekly': 4,
'monthly': 24,
},
},
}
@metadata_reactor.provides(
'zfs/datasets'
)
@ -112,7 +120,7 @@ def headers(metadata):
arch = 'arm64'
else:
arch = 'amd64'
return {
'apt': {
'packages': {
@ -124,62 +132,3 @@ def headers(metadata):
},
},
}
@metadata_reactor.provides(
'zfs/kernel_params/zfs_arc_max',
)
def arc_size(metadata):
arc_percent = metadata.get('zfs/zfs_arc_max_percent', None)
if arc_percent:
return {
'zfs': {
'kernel_params': {
'zfs_arc_max': str(int(
metadata.get('vm/ram') * 1024 * 1024 * (arc_percent/100)
)),
},
},
}
else:
return {}
@metadata_reactor.provides(
'systemd-timers/zfs-auto-snapshot-hourly',
'systemd-timers/zfs-auto-snapshot-daily',
'systemd-timers/zfs-auto-snapshot-weekly',
'systemd-timers/zfs-auto-snapshot-monthly',
)
def auto_snapshots(metadata):
hourly = metadata.get('zfs/auto_snapshots/hourly')
daily = metadata.get('zfs/auto_snapshots/daily')
weekly = metadata.get('zfs/auto_snapshots/weekly')
monthly = metadata.get('zfs/auto_snapshots/monthly')
# cant be 0
assert hourly > 0 and daily > 0 and weekly > 0 and monthly > 0
return {
'systemd-timers': {
'zfs-auto-snapshot-hourly': {
'command': f'/usr/sbin/zfs-auto-snapshot --quiet --syslog --label=hourly --keep={hourly} //',
'when': 'hourly',
},
'zfs-auto-snapshot-daily': {
'command': f'/usr/sbin/zfs-auto-snapshot --quiet --syslog --label=daily --keep={daily} //',
'when': 'daily',
},
'zfs-auto-snapshot-weekly': {
'command': f'/usr/sbin/zfs-auto-snapshot --quiet --syslog --label=weekly --keep={weekly} //',
'when': 'weekly',
'persistent': True,
},
'zfs-auto-snapshot-monthly': {
'command': f'/usr/sbin/zfs-auto-snapshot --quiet --syslog --label=monthly --keep={monthly} //',
'when': 'monthly',
'persistent': True,
},
},
}

View file

@ -1,4 +1,4 @@
function zsh_spwd {
function spwd {
paths=(${(s:/:)PWD})
cur_path='/'
@ -21,20 +21,9 @@ function zsh_spwd {
echo
}
function zsh_root_color {
if test "$EUID" -eq 0
then
echo "%{$fg_bold[green]%}"
else
echo "%{$fg_bold[yellow]%}"
fi
}
function zsh_exitcode_color {
echo "%(?:%{$fg_bold[green]%}:%{$fg_bold[red]%})"
}
PROMPT='$(zsh_root_color)$(whoami)%{$reset_color%}@$(zsh_exitcode_color)$(hostname -s) %{$fg[cyan]%}$(zsh_spwd)%{$reset_color%} $(git_prompt_info)'
indicator="$(hostname -s)"
local ret_status="%(?:%{$fg_bold[green]%}$indicator:%{$fg_bold[red]%}$indicator)"
PROMPT='${ret_status} %{$fg[cyan]%}$(spwd)%{$reset_color%} $(git_prompt_info)'
ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[blue]%}git:(%{$fg[red]%}"
ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} "

View file

@ -1,22 +0,0 @@
# /etc/zsh/zprofile: system-wide .zprofile file for zsh(1).
#
# This file is sourced only for login shells (i.e. shells
# invoked with "-" as the first character of argv[0], and
# shells invoked with the -l flag.)
#
# Global Order: zshenv, zprofile, zshrc, zlogin
alias s='sudo su - root -s /usr/bin/zsh'
function hhtop {
mkdir -p ~/.config/htop
cp /etc/htoprc.global ~/.config/htop/htoprc
htop
}
ZSH_THEME=bw
DISABLE_AUTO_UPDATE=true
plugins=(
zsh-autosuggestions
)
source /etc/zsh/oh-my-zsh/oh-my-zsh.sh

6
bundles/zsh/files/zshrc Normal file
View file

@ -0,0 +1,6 @@
export ZSH=~/.zsh/oh-my-zsh
ZSH_THEME=bw
plugins=(
zsh-autosuggestions
)
source $ZSH/oh-my-zsh.sh

View file

@ -1,44 +1,46 @@
from os.path import join
directories = {
'/etc/zsh/oh-my-zsh': {},
'/etc/zsh/oh-my-zsh/custom/plugins': {
'mode': '0755',
'needs': [
f"git_deploy:/etc/zsh/oh-my-zsh",
]
},
'/etc/zsh/oh-my-zsh/custom/plugins/zsh-autosuggestions': {
'needs': [
f"git_deploy:/etc/zsh/oh-my-zsh",
]
},
}
git_deploy = {
'/etc/zsh/oh-my-zsh': {
'repo': 'https://github.com/ohmyzsh/ohmyzsh.git',
'rev': 'master',
},
'/etc/zsh/oh-my-zsh/custom/plugins/zsh-autosuggestions': {
'repo': 'https://github.com/zsh-users/zsh-autosuggestions.git',
'rev': 'master',
},
}
files = {
'/etc/zsh/zprofile': {},
'/etc/zsh/oh-my-zsh/themes/bw.zsh-theme': {
'needs': [
f"git_deploy:/etc/zsh/oh-my-zsh",
]
},
}
for name, user_config in node.metadata.get('users').items():
if user_config.get('shell', None) != '/usr/bin/zsh':
files[join(user_config['home'], '.zshrc')] = {
continue
directories = {
join(user_config['home'], '.zsh'): {
'owner': name,
'group': name,
'content': '# bw managed',
}
},
join(user_config['home'], '.zsh/oh-my-zsh'): {
'owner': name,
},
join(user_config['home'], '.zsh/oh-my-zsh/custom/plugins/zsh-autosuggestions'): {
'owner': name,
'needs': [
f"git_deploy:{join(user_config['home'], '.zsh/oh-my-zsh')}",
]
},
}
git_deploy = {
join(user_config['home'], '.zsh/oh-my-zsh'): {
'repo': 'https://github.com/ohmyzsh/ohmyzsh.git',
'rev': 'master',
},
join(user_config['home'], '.zsh/oh-my-zsh/custom/plugins/zsh-autosuggestions'): {
'repo': 'https://github.com/zsh-users/zsh-autosuggestions.git',
'rev': 'master',
},
}
files = {
join(user_config['home'], '.zshrc'): {
'owner': name,
'source': 'zshrc',
},
join(user_config['home'], '.zsh/oh-my-zsh/themes/bw.zsh-theme'): {
'owner': name,
'needs': [
f"git_deploy:{join(user_config['home'], '.zsh/oh-my-zsh')}",
]
},
}

View file

@ -1,41 +0,0 @@
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQGNBF5qU5ABDAC5P4yAxACWwvknjaREtCjSpqwpVKbP+HCQcaho3ao/ls2mUQ7K
WzqoAknFljZACkoQT6D+9t0Wx+aYhSb8kc/RHDoQQN5w7sAxBCsUS0/unF7PQxZH
px3YTJgTlkl7cB79pbK5mu/Ybj/AhtjLwuu5CO8xPK19K2Xl1TT14sWlfxVmNxJ1
X62w2lPfHuS1GJKw5k32ee3UeZB2FAuwzO84FlvlmoSgiGgOSW+OPLxapZA0glO3
M/FpjF/ergaQqbU3nAaPkj3J7by7+j2r81RJZ49s9RXPUHie8d5TDB53KWaOTHPh
ONF3pssaWeEMP3Ju23s1t9dV1hPtwzdTiXu3lQp+0eZy4X085tEGsz4oYxAXlG2X
gXKR9wO8AhzN6E2UJRDPjiXD8APDh5SDxNreFFTv9orh+dRHjaFQuds0erkDVc9g
CDkczKy8zi14BEdWolPHNp6rVdbtyFKhiCrr9MOQEGJ04FgIB6HDbaAAXEUe7oU4
0v1i0BXFrCVDNx8AEQEAAbQlTWF0aWFzIERlIGxlbGxpcyA8bWF0aTg2ZGxAZ21h
aWwuY29tPokB1AQTAQgAPgIbAwULCQgHAgYVCAkKCwIEFgIDAQIeAQIXgBYhBIMH
yrK2G/QHU3ipTjkheTntPQfbBQJiOGH3BQkHkHVnAAoJEDkheTntPQfbQ28MAIw3
yz+CJWP60ypv/W4ErUif0bhwMsSG+5YPligOcSmgzw9x3xysPSLpBrBR5cpLCx8Z
voqFa5PJbu8cKhmHGQMvH7duVPL6gRX4dQG9t9qtKd9DYmsD9GweyCWFIhVFTId4
VyDeEqx1IWAHyLoJmfnCQAIZHwhPrZKVU2hui8YjqZ4bpuP/xKGBiREgkPP5yv/T
J0GPoH9JOe67V9pDDN71cJzJpbFG7bPwH5LkzhO2fS6StyLKG7rMJHo6y2B9tWET
4V18WKotn1rT2gBunoCE3NsazwnXFf1C/KnHZF8zYAtLZfFa2gz4JgLk4kCgKeUO
vKubOoF44BFad6hgXA2yFiY7LXZmUhydlIdMp9P67jdmosW6Rbjz3st/nqg6pmjM
pMFEoc2jybdbiWkppRmrQlwRD76ir1Fcu71eEDZIPCfHpBNEyMgtdL/zyJnUbtGl
Bp8Jpfg9Y3CqDXtBkUug6KQ77S61zRnaenD91V2NrMnHVQsoiNP42h//7feTiLkB
jQRealOQAQwA2YM6vfJbo+BkFSmjwpuvY65DzVDyz4nRO1NvHBHeuMJKeWgF5pKe
e/TOJWcjlsBT2xwsqi8NhT1O2BpVBXOGN2Ck6YLQ0WPaxfsmAEGCyVFsJIBuWOQ7
j0VXyvbHbUGrcLg5sA3VS0zzqquMf7dAwHI7earp1HsOd8DvRs518leRx18wiDap
6UbPqpu3yFqNY4oeZ7oBpII6olm9YtGGP0mHquPYpWq9ZlN1vjPbLgjY1IPs2OMl
DGE1eaEWeygyL1tRgjAGpgsdLS3BOgF1fY0OpTRyZnez+W8eWqTB12yF17FpErWC
VeO8h6LosfjcQ8Bg2WQnFrzJJgXzVxrvwygbtggvN/feEPzWJg92TEQLzMFRf8I9
rCju5SOR5WBTPmvnq7f9VT/2rg0WSBjkVxGq9wMVyXmOOkYUB6hx5ynDEM9cIzG3
Jmvm+rz1lQiILwnpFXUtTWnQbMuUmdPWFM2f2XKRY0RE0EvJ4K5ve49bz+SvOUip
ewVowQ46z0LZABEBAAGJAbwEGAEIACYCGwwWIQSDB8qythv0B1N4qU45IXk57T0H
2wUCYjhiLwUJB5B1nwAKCRA5IXk57T0H2/7jDACqur/sIYzTSxUEn73yyde6S8za
ZzcnzV9JIIi9vTVd50J5ngWjg06PPYe6NXSf6J/EXxHOp2TKy58FPyMnxBENzycM
P+9GyH4UH3nOK8ywgZ7nkyXYjJKzZ+88F9HcUgO3xSwsMy6kpeIdxXI3fpEOVXBn
lAsHM6CF1Nk5O4oxgJwgbXwf5ntYDeXwcpm6NCdDTorYLy5JvhDg8XiTeMl6fFki
uDSrNF0UNkkhutS/66FVLUlq5grSWH7mYviau6Ju2C2Tq2GijvRcvkQcA37Mx//x
x4ydNydSmu5kxfB6JorgAnK8sLTIHU+RWgmJRly5YY/G6RXm2QsYs+RvObgIablW
k1ZXNcb3qEyn3D91sXUsvp7qMAnQjWp2UkV4KygMc6C4i54JkOTcZiGhynjB6pL9
FgpIgjjhC9B+hToo9uuLC2Ox58TA+7l1sR4JG0XCNW0Z+5swBnWyrlt/ZwWxFqoB
oxYE/j3yxh9TmgHv54/j2ZzU8tiJHW01AGlbbxo=
=cWkh
-----END PGP PUBLIC KEY BLOCK-----

View file

@ -4,10 +4,6 @@ from(bucket: "${bucket}")
<% values = values if isinstance(values, list) else [values] %>\
|> filter(fn: (r) => ${' or '.join(f'r["{key}"] == "{value}"' for value in values)})
% endfor
% for exist in exists:
|> filter(fn: (r) => exists r["${exist}"]) // WTF
% endfor
|> aggregateWindow(every: v.windowPeriod, fn: mean, createEmpty: false) // aggregate early for best performance
% if minimum:
|> filter(fn: (r) => r._value > ${minimum})
% endif
@ -17,6 +13,7 @@ from(bucket: "${bucket}")
% if boolean_to_int:
|> map(fn: (r) => ({r with _value: if r._value == true then 1 else 0 }))
% endif
|> aggregateWindow(every: duration(v: int(v: v.windowPeriod)*${resolution}), fn: mean, createEmpty: false)
% if negative:
|> map(fn: (r) => ({r with _value: r._value * - 1.0}))
% endif

View file

@ -1,19 +1,13 @@
{
'usage': {
'stacked': True,
'stacked': False,
'queries': {
'usage': {
'filters': {
'_measurement': 'cpu',
'cpu': 'cpu-total',
'_field': [
'usage_guest',
'usage_guest_nice',
'usage_iowait',
'usage_irq',
'usage_nice',
'usage_softirq',
'usage_steal',
'usage_system',
'usage_user',
],
@ -22,12 +16,7 @@
},
},
'min': 0,
'soft_max': 3,
'unit': 'percent',
'tooltip': 'multi',
'legend': {
'displayMode': 'hidden',
},
'max': 100,
},
'load': {
'stacked': False,
@ -44,40 +33,5 @@
'function': 'mean',
},
},
'min': 0,
'soft_max': 3,
'unit': 'percent',
'tooltip': 'multi',
'legend': {
'displayMode': 'hidden',
},
},
'pressure_stall': {
'queries': {
'pressure_stall': {
'filters': {
'_measurement': 'pressure_stall',
'resource': [
'cpu',
'io',
'memory',
],
'type': [
'some',
],
'_field': [
'avg10',
],
},
},
},
'min': 0,
'soft_max': 3,
'display_name': '__field.labels.resource',
'unit': 'percent',
'tooltip': 'multi',
'legend': {
'displayMode': 'hidden',
},
},
}

View file

@ -9,15 +9,11 @@
'read_bytes',
],
},
'exists': [
'ID_PART_ENTRY_NUMBER',
],
'function': 'derivative',
},
},
'unit': 'Bps',
'display_name': '__field.labels.name',
'tooltip': 'multi',
'unit': 'decbytes',
'display_name': '__field.labels.name'
},
'write': {
'stacked': True,
@ -29,14 +25,10 @@
'write_bytes',
],
},
'exists': [
'ID_PART_ENTRY_NUMBER',
],
'function': 'derivative',
},
},
'unit': 'Bps',
'display_name': '__field.labels.name',
'tooltip': 'multi',
'unit': 'decbytes',
'display_name': '__field.labels.name'
},
}

View file

@ -16,7 +16,6 @@
},
'min': 0,
'unit': 'bytes',
'tooltip': 'multi',
},
'root_inodes': {
'stacked': True,
@ -34,6 +33,5 @@
},
},
'min': 0,
'tooltip': 'multi',
},
}

View file

@ -16,7 +16,6 @@
},
},
'unit': 'decbytes',
'tooltip': 'multi',
},
'swp': {
'stacked': True,
@ -33,6 +32,5 @@
},
},
'unit': 'decbytes',
'tooltip': 'multi',
},
}

View file

@ -12,9 +12,8 @@
'function': 'derivative',
},
},
'unit': 'Bps',
'display_name': '__field.labels.interface',
'tooltip': 'multi',
'unit': 'decbytes',
'display_name': '__field.labels.interface'
},
'out': {
'stacked': True,
@ -29,8 +28,7 @@
'function': 'derivative',
},
},
'unit': 'Bps',
'display_name': '__field.labels.interface',
'tooltip': 'multi',
'unit': 'decbytes',
'display_name': '__field.labels.interface'
},
}

View file

@ -9,7 +9,7 @@
'length',
],
},
'function': 'max',
'function': 'mean',
},
},
'display_name': '__field.labels.queue'
@ -24,7 +24,7 @@
'size',
],
},
'function': 'max',
'function': 'mean',
},
},
'display_name': '__field.labels.queue'
@ -39,7 +39,7 @@
'age',
],
},
'function': 'max',
'function': 'mean',
},
},
'display_name': '__field.labels.queue'

View file

@ -0,0 +1,27 @@
{
'process_cpu': {
'stacked': True,
'queries': {
'cpu': {
'filters': {
'_measurement': 'procstat',
'_field': [
'cpu_usage',
],
},
'minimum': 1,
'resolution': 2,
},
},
'unit': 'percent',
'display_name': '__field.labels.process_name',
'legend': {
'displayMode': 'table',
'placement': 'right',
'calcs': [
'mean',
'max',
],
},
},
}

View file

@ -1,48 +0,0 @@
{
'cpu': {
'stacked': True,
'queries': {
'cpu': {
'filters': {
'_measurement': 'procstat',
'_field': [
'cpu_usage',
],
},
'minimum': 0.2,
},
},
'unit': 'percent',
'display_name': '__field.labels.process_name',
'legend': {
'displayMode': 'table',
'placement': 'right',
'calcs': [
'last',
],
},
},
'ram': {
'stacked': True,
'queries': {
'ram': {
'filters': {
'_measurement': 'procstat',
'_field': [
'memory_rss',
],
},
'minimum': 10*(10**6),
},
},
'unit': 'bytes',
'display_name': '__field.labels.process_name',
'legend': {
'displayMode': 'table',
'placement': 'right',
'calcs': [
'last',
],
},
},
}

View file

@ -19,7 +19,8 @@
'displayMode': 'table',
'placement': 'right',
'calcs': [
'last',
'mean',
'max',
],
},
},
@ -43,7 +44,8 @@
'displayMode': 'table',
'placement': 'right',
'calcs': [
'last',
'mean',
'max',
],
},
},

View file

@ -0,0 +1,27 @@
{
'process_ram': {
'stacked': True,
'queries': {
'ram': {
'filters': {
'_measurement': 'procstat',
'_field': [
'memory_rss',
],
},
'minimum': 10*(10**6),
'resolution': 2,
},
},
'unit': 'bytes',
'display_name': '__field.labels.process_name',
'legend': {
'displayMode': 'table',
'placement': 'right',
'calcs': [
'mean',
'max',
],
},
},
}

View file

@ -80,6 +80,6 @@
'negative': True,
},
},
'unit': 'Bps',
'unit': 'bytes',
},
}

View file

@ -1,28 +0,0 @@
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name ${server_name};
ssl_certificate /var/lib/dehydrated/certs/${server_name}/fullchain.pem;
ssl_certificate_key /var/lib/dehydrated/certs/${server_name}/privkey.pem;
location / {
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8300/;
}
# Proxy Grafana Live WebSocket connections.
location /api/live {
rewrite ^/(.*) /$1 break;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header Host $http_host;
proxy_pass http://127.0.0.1:8300/;
}
}

View file

@ -1,20 +0,0 @@
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name ${server_name};
ssl_certificate /var/lib/dehydrated/certs/${server_name}/fullchain.pem;
ssl_certificate_key /var/lib/dehydrated/certs/${server_name}/privkey.pem;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_pass http://127.0.0.1:4001;
}
location /steamuserimages/ {
root /var/lib/steam_chat_logger/steamuserimages;
rewrite ^/steamuserimages(.*)$ $1 break;
autoindex on;
}
}

View file

@ -1,20 +0,0 @@
{
'supergroups': [
'debian',
],
'metadata': {
'apt': {
'sources': {
'deb http://security.debian.org/ {release}-security main contrib non-free',
},
},
'php': {
'version': '8.1',
},
'postgresql': {
'version': '14',
},
'os_release': 'bookworm',
},
'os_version': (12,),
}

View file

@ -5,7 +5,6 @@
'bundles': [
'hostname',
'hosts',
'htop',
'locale',
'network',
'ssh',
@ -31,15 +30,9 @@
],
},
'users': {
'ckn': {
'root': {
'shell': '/usr/bin/zsh',
'authorized_keys': {
'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEU1l2ijW3ZqzFGZcdWg2ESgTGehdNfBTfafxsjWvWdS mwiegand@macbook',
},
},
},
'sudoers': {
'ckn': {'ALL'},
},
},
}

View file

@ -1,5 +1,2 @@
def node_apply_start(repo, node, **kwargs):
repo.libs.wol.wake(node)
def node_run_start(repo, node, cmd, **kwargs):
def node_apply_start(repo, node, interactive=False, **kwargs):
repo.libs.wol.wake(node)

View file

@ -8,7 +8,6 @@
'monitored',
],
'bundles': [
'grub',
'smartctl',
'wol-sleeper',
'zfs',
@ -18,10 +17,10 @@
'id': '9cf52515-63a1-4659-a8ec-6c3c881727e5',
'network': {
'internal': {
'interface': 'enp0s31f6',
'interface': 'enp1s0',
'ipv4': '10.0.0.5/24',
'gateway4': '10.0.0.1',
'mac': '4c:cc:6a:d5:96:f8',
'mac': 'd8:cb:8a:e7:be:c6',
},
},
'backup-server': {
@ -56,12 +55,6 @@
],
},
},
'auto_snapshots': {
'hourly': 1,
'daily': 7,
'weekly': 4,
'monthly': 24,
},
},
},
}

View file

@ -17,6 +17,7 @@
'zfs',
],
'metadata': {
'FIXME_dont_touch_sshd': True,
'id': '34199b24-4621-42f4-85ae-ec354f9c43e6',
'network': {
'internal': {

View file

@ -16,19 +16,17 @@
'build-agent',
'crystal',
'gitea',
# 'gollum',
'gollum',
'grafana',
'icinga2',
'icingadb',
'icingaweb2',
'influxdb2',
'mirror',
'mosquitto',
'postgresql',
'redis',
'smartctl',
'steam-chat-logger',
'steam-chat-viewer',
'systemd-swap',
'raspberrymatic-cert',
'tasmota-charge',
'wireguard',
@ -39,7 +37,7 @@
'id': 'af96709e-b13f-4965-a588-ef2cd476437a',
'network': {
'internal': {
'interface': 'enp42s0',
'interface': 'enp1s0f0',
'ipv4': '10.0.0.2/24',
'gateway4': '10.0.0.1',
},
@ -59,8 +57,8 @@
'download_server': 'netcup.mails',
},
'gitea': {
'version': '1.16.5',
'sha256': 'c0fb4107dc4debf08e6e27fd3383e06dc232ccb410123179c7ae8d7cec60765f',
'version': '1.16.2',
'sha256': 'ec9b01d119cfe47df44d580c1d321132ce054ff139b05b0a35da91268ca2bcbe',
'domain': 'git.sublimity.de',
},
'gollum': {
@ -92,7 +90,7 @@
},
'nextcloud': {
'hostname': 'cloud.sublimity.de',
'version': '24.0.4',
'version': '23.0.2',
},
'nextcloud-picsort': {
'ckn': {
@ -105,22 +103,10 @@
'domain': 'homematic.ckn.li',
'node': 'home.homematic',
},
'steam_chat_logger': {
'STEAM_USERNAME': 'snake_452',
'STEAM_ID': 'STEAM_0:0:12376499',
'STEAM_PASSWORD': '!decrypt:encrypt$gAAAAABiUzERrXVNxzDaDW_4MgEmPtXkMHlTiz5uqCbu-22-2yKHRHMKvuGqAygpGbnwZucZcmZMox9KM89a6qlVKlE1ZPizTA==',
'IMAP_HOST': 'mail.sublimity.de',
'IMAP_USER': 'i@ckn.li',
'IMAP_PASSWORD': '!decrypt:encrypt$gAAAAABiUzcTVRL-Xb4RDjcwciZawYlmOa9Qy_hKz6sVWDlwZqUFLGRD8ERWoFCOWCM22Sq73Gc4nFuAblBB6wpbH5YEltLA6hmROGKpOFhI63ESLFwNgbY=',
},
'steam-chat-viewer': {
'hostname': 'steam-chats.ckn.li',
},
'systemd-swap': 4_000_000_000,
'tasmota-charge': {
'phone': {
'ip': '10.0.0.175',
'user': 'u0_a233',
'ip': '10.0.0.166',
'user': 'u0_q194',
'password': 'november',
},
'plug': {
@ -130,9 +116,8 @@
},
},
'vm': {
'cores': 16,
'threads': 32,
'ram': 49152,
'cores': 2,
'ram': 16192,
},
'wireguard': {
'my_ip': '172.30.0.2/32',
@ -147,10 +132,6 @@
},
},
'zfs': {
'zfs_arc_max_percent': 80,
'storage_classes': {
'ssd': 'ssd',
},
'pools': {
'tank': {
'type': 'mirror',
@ -159,17 +140,6 @@
'/dev/disk/by-partlabel/zfs-data-2',
],
},
'ssd': {
'devices': [
'/dev/disk/by-id/nvme-SAMSUNG_MZVL22T0HBLB-00B00_S677NF0RA01551-part3',
],
},
},
'datasets': {
'ssd/nextcloud-appdata': {
'mountpoint': '/var/lib/nextcloud/appdata_oci6dw1woodz',
'backup': False,
}
},
},
},

View file

@ -12,6 +12,8 @@
'wpa-supplicant',
],
'metadata': {
'FIXME_dont_touch_sshd': True,
'id': 'dd521b8a-dc03-43f5-b29f-068f948ba3b8',
'network': {
'internal': {

View file

@ -54,6 +54,11 @@
'device': '/dev/disk/by-id/ata-TOSHIBA_MG06ACA10TE_61C0A1B1FKQE',
},
},
'smartctl': {
'/dev/disk/by-id/ata-TOSHIBA_MG06ACA10TE_61C0A1B1FKQE': {
'apm': 1,
},
},
'zfs': {
'pools': {
'tank': {
@ -62,12 +67,6 @@
],
},
},
'auto_snapshots': {
'hourly': 1,
'daily': 1,
'weekly': 4,
'monthly': 24,
},
},
},
}