Compare commits
173 commits
icinga2_no
...
master
Author | SHA1 | Date | |
---|---|---|---|
dcd2ebc49c | |||
555350eab7 | |||
e117acac04 | |||
16313b9e40 | |||
033a1cf6e5 | |||
8befec9769 | |||
d22add5bfd | |||
69fb93a664 | |||
f4b59dc702 | |||
17aa3d7e48 | |||
8bb9dae45c | |||
c244645020 | |||
64029d2147 | |||
8081f12315 | |||
4ec2d5192a | |||
0e78afea6a | |||
f0d1cf9861 | |||
e17b023503 | |||
a3ba06bcb0 | |||
01bcfd8638 | |||
c0944f9fa2 | |||
dedbffa107 | |||
67d5a4bff8 | |||
6d64a5e52d | |||
07e9eb4d8f | |||
1f53ff63a9 | |||
0eaed67334 | |||
fd5e4180fa | |||
ab87fe6f96 | |||
95efe10ef6 | |||
e47c709f39 | |||
24d346962a | |||
3e2cae42e6 | |||
6e410bfc25 | |||
8ebf4e0ec0 | |||
8e8f77e546 | |||
c128b8a1ca | |||
53d2928de2 | |||
4996f98cd1 | |||
5b254b1b28 | |||
4348e6045e | |||
28e9d69571 | |||
32011c5b1f | |||
5c8e28ddb5 | |||
d62e609863 | |||
ff51b41c38 | |||
76cf14a9ef | |||
301889ab8b | |||
1a163ce9f0 | |||
15a78737cb | |||
d90e0a18e8 | |||
a55ec37d21 | |||
ee23f3ef6e | |||
de67571f5e | |||
a04163b72f | |||
fc7f7e2c23 | |||
e18306058a | |||
e982f1e076 | |||
a2639bc370 | |||
fd1d0ac976 | |||
e3fe0eeb79 | |||
782b3fbe0b | |||
3d8a77f9e4 | |||
535ec252b5 | |||
d1bd92e6cc | |||
4f990f8d6f | |||
cd9a7e172e | |||
206e62e698 | |||
57aa3b8433 | |||
70091eca8c | |||
fdd35e0a2c | |||
ccc54b53a5 | |||
1222eb813d | |||
054087fa1c | |||
b64470b160 | |||
0dabb39ca4 | |||
d302a22d3e | |||
1f3740dd59 | |||
919f5f2c08 | |||
a6f1695e4e | |||
8f45a39967 | |||
0eb37a909e | |||
2211571689 | |||
6cb4275e31 | |||
5373954567 | |||
a5ec5eca7a | |||
b459821a8d | |||
4415bc32f5 | |||
5cb5396817 | |||
85673abb29 | |||
29be9d9896 | |||
c4da3ee013 | |||
9288836b3a | |||
66624141f8 | |||
9c639b4977 | |||
98e05fc151 | |||
402dca9b31 | |||
89d6b6d93c | |||
33a6e2a979 | |||
14715fdab7 | |||
13d91fa512 | |||
0e8afa29e5 | |||
d300866bc8 | |||
aede8d21c1 | |||
1fe2e0710f | |||
fe884f446a | |||
637ab05590 | |||
843712d7bf | |||
4aa8a18b4f | |||
83cc936c82 | |||
e1e1920ffb | |||
34d55f0849 | |||
594b7d3c86 | |||
49b05fe8b8 | |||
789897acf6 | |||
1233da8dd6 | |||
fce2425c56 | |||
219bbf9983 | |||
d3b90cfe89 | |||
b5d48db4dd | |||
b81b6472fd | |||
d380701703 | |||
b2aadeb98c | |||
b8675adf99 | |||
0463637d9f | |||
9b7171864a | |||
964b248de3 | |||
c756729cac | |||
49498c0ca9 | |||
be26672b85 | |||
0f4b01f996 | |||
bb0f123e02 | |||
a4fd08a8cd | |||
4a5711a570 | |||
0cf83d0744 | |||
5e66318c38 | |||
53d22e8c67 | |||
3256329064 | |||
d2f8df88bf | |||
5259e13eef | |||
ab01562c85 | |||
4d440bcb5b | |||
0fb1899322 | |||
cb463350b4 | |||
5dd6e56ca9 | |||
e8a5379ccd | |||
226b152fa0 | |||
4e9c6bf67b | |||
c0ccd78517 | |||
5b6d31742e | |||
04a271a1e5 | |||
0f74cc8c7e | |||
a0dc65f568 | |||
5fa4969cfe | |||
11754a362f | |||
fcb6c9bd8e | |||
534b7142a8 | |||
fac893f34a | |||
8bdf675b47 | |||
d451a70db8 | |||
6a90f605cc | |||
d03a4fd554 | |||
d8963141fc | |||
0667304dd7 | |||
ff9acf9638 | |||
233760d7a8 | |||
fc115345a0 | |||
7403f31ac5 | |||
66b0492343 | |||
73a5175a6d | |||
904a4d0e40 | |||
c227c38875 | |||
84207ee82b |
171 changed files with 3719 additions and 821 deletions
15
.envrc
15
.envrc
|
@ -1,16 +1,7 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
python3 -m venv .venv
|
|
||||||
source ./.venv/bin/activate
|
|
||||||
PATH_add .venv/bin
|
|
||||||
PATH_add bin
|
PATH_add bin
|
||||||
python3 -m pip install --upgrade pip
|
|
||||||
|
|
||||||
rm -rf .cache/bw/git_deploy
|
source_env ~/.local/share/direnv/pyenv
|
||||||
export BW_GIT_DEPLOY_CACHE=.cache/bw/git_deploy
|
source_env ~/.local/share/direnv/venv
|
||||||
mkdir -p "$BW_GIT_DEPLOY_CACHE"
|
source_env ~/.local/share/direnv/bundlewrap
|
||||||
export EXPERIMENTAL_UPLOAD_VIA_CAT=1
|
|
||||||
export BW_ITEM_WORKERS=32
|
|
||||||
export BW_NODE_WORKERS=12
|
|
||||||
export DISK_CACHE_DIR=.cache/cache_to_disk
|
|
||||||
unset PS1
|
|
||||||
|
|
|
@ -37,3 +37,12 @@ fi
|
||||||
telegraf: execd for daemons
|
telegraf: execd for daemons
|
||||||
|
|
||||||
TEST
|
TEST
|
||||||
|
|
||||||
|
# git signing
|
||||||
|
|
||||||
|
git config --global gpg.format ssh
|
||||||
|
git config --global commit.gpgsign true
|
||||||
|
|
||||||
|
git config user.name CroneKorkN
|
||||||
|
git config user.email i@ckn.li
|
||||||
|
git config user.signingkey "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILMVroYmswD4tLk6iH+2tvQiyaMe42yfONDsPDIdFv6I"
|
||||||
|
|
|
@ -10,7 +10,6 @@ nodes = [
|
||||||
for node in sorted(repo.nodes_in_group('debian'))
|
for node in sorted(repo.nodes_in_group('debian'))
|
||||||
if not node.dummy
|
if not node.dummy
|
||||||
]
|
]
|
||||||
reboot_nodes = []
|
|
||||||
|
|
||||||
print('updating nodes:', sorted(node.name for node in nodes))
|
print('updating nodes:', sorted(node.name for node in nodes))
|
||||||
|
|
||||||
|
@ -24,14 +23,13 @@ for node in nodes:
|
||||||
print(node.run('DEBIAN_FRONTEND=noninteractive apt update').stdout.decode())
|
print(node.run('DEBIAN_FRONTEND=noninteractive apt update').stdout.decode())
|
||||||
print(node.run('DEBIAN_FRONTEND=noninteractive apt list --upgradable').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()):
|
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())
|
print(node.run('DEBIAN_FRONTEND=noninteractive apt -qy full-upgrade').stdout.decode())
|
||||||
reboot_nodes.append(node)
|
|
||||||
|
|
||||||
# REBOOT IN ORDER
|
# REBOOT IN ORDER
|
||||||
|
|
||||||
wireguard_servers = [
|
wireguard_servers = [
|
||||||
node
|
node
|
||||||
for node in reboot_nodes
|
for node in nodes
|
||||||
if node.has_bundle('wireguard')
|
if node.has_bundle('wireguard')
|
||||||
and (
|
and (
|
||||||
ip_interface(node.metadata.get('wireguard/my_ip')).network.prefixlen <
|
ip_interface(node.metadata.get('wireguard/my_ip')).network.prefixlen <
|
||||||
|
@ -41,7 +39,7 @@ wireguard_servers = [
|
||||||
|
|
||||||
wireguard_s2s = [
|
wireguard_s2s = [
|
||||||
node
|
node
|
||||||
for node in reboot_nodes
|
for node in nodes
|
||||||
if node.has_bundle('wireguard')
|
if node.has_bundle('wireguard')
|
||||||
and (
|
and (
|
||||||
ip_interface(node.metadata.get('wireguard/my_ip')).network.prefixlen ==
|
ip_interface(node.metadata.get('wireguard/my_ip')).network.prefixlen ==
|
||||||
|
@ -51,7 +49,7 @@ wireguard_s2s = [
|
||||||
|
|
||||||
everything_else = [
|
everything_else = [
|
||||||
node
|
node
|
||||||
for node in reboot_nodes
|
for node in nodes
|
||||||
if not node.has_bundle('wireguard')
|
if not node.has_bundle('wireguard')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -62,8 +60,11 @@ for node in [
|
||||||
*wireguard_s2s,
|
*wireguard_s2s,
|
||||||
*wireguard_servers,
|
*wireguard_servers,
|
||||||
]:
|
]:
|
||||||
print('rebooting', node.name)
|
|
||||||
try:
|
try:
|
||||||
print(node.run('systemctl reboot').stdout.decode())
|
if node.run('test -e /var/run/reboot-required', may_fail=True).return_code == 0:
|
||||||
|
print('rebooting', node.name)
|
||||||
|
print(node.run('systemctl reboot').stdout.decode())
|
||||||
|
else:
|
||||||
|
print('not rebooting', node.name)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(e)
|
print(e)
|
||||||
|
|
|
@ -5,9 +5,17 @@ from os.path import realpath, dirname
|
||||||
from sys import argv
|
from sys import argv
|
||||||
from ipaddress import ip_network, ip_interface
|
from ipaddress import ip_network, ip_interface
|
||||||
|
|
||||||
repo = Repository(dirname(dirname(realpath(__file__))))
|
if len(argv) != 3:
|
||||||
|
print(f'usage: {argv[0]} <node> <client>')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
repo = Repository(dirname(dirname(realpath(__file__))))
|
||||||
server_node = repo.get_node(argv[1])
|
server_node = repo.get_node(argv[1])
|
||||||
|
|
||||||
|
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]}')
|
data = server_node.metadata.get(f'wireguard/clients/{argv[2]}')
|
||||||
|
|
||||||
vpn_network = ip_interface(server_node.metadata.get('wireguard/my_ip')).network
|
vpn_network = ip_interface(server_node.metadata.get('wireguard/my_ip')).network
|
||||||
|
@ -20,9 +28,7 @@ for peer in server_node.metadata.get('wireguard/s2s').values():
|
||||||
if not ip_network(network).subnet_of(vpn_network):
|
if not ip_network(network).subnet_of(vpn_network):
|
||||||
allowed_ips.append(ip_network(network))
|
allowed_ips.append(ip_network(network))
|
||||||
|
|
||||||
conf = \
|
conf = f'''
|
||||||
f'''>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
|
||||||
|
|
||||||
[Interface]
|
[Interface]
|
||||||
PrivateKey = {repo.libs.wireguard.privkey(data['peer_id'])}
|
PrivateKey = {repo.libs.wireguard.privkey(data['peer_id'])}
|
||||||
ListenPort = 51820
|
ListenPort = 51820
|
||||||
|
@ -35,11 +41,12 @@ PresharedKey = {repo.libs.wireguard.psk(data['peer_id'], server_node.metadata.ge
|
||||||
AllowedIPs = {', '.join(str(client_route) for client_route in sorted(allowed_ips))}
|
AllowedIPs = {', '.join(str(client_route) for client_route in sorted(allowed_ips))}
|
||||||
Endpoint = {ip_interface(server_node.metadata.get('network/external/ipv4')).ip}:51820
|
Endpoint = {ip_interface(server_node.metadata.get('network/external/ipv4')).ip}:51820
|
||||||
PersistentKeepalive = 10
|
PersistentKeepalive = 10
|
||||||
|
'''
|
||||||
|
|
||||||
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<'''
|
print('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>')
|
||||||
|
|
||||||
print(conf)
|
print(conf)
|
||||||
|
print('<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<')
|
||||||
|
|
||||||
if input("print qrcode? [yN]: ").upper() == 'Y':
|
if input("print qrcode? [Yn]: ").upper() in ['', 'Y']:
|
||||||
import pyqrcode
|
import pyqrcode
|
||||||
print(pyqrcode.create(conf).terminal(quiet_zone=1))
|
print(pyqrcode.create(conf).terminal(quiet_zone=1))
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
# https://manpages.debian.org/latest/apt/sources.list.5.de.html
|
||||||
|
# https://repolib.readthedocs.io/en/latest/deb822-format.html
|
||||||
|
|
||||||
```python
|
```python
|
||||||
{
|
{
|
||||||
'apt': {
|
'apt': {
|
||||||
|
@ -5,8 +8,29 @@
|
||||||
'apt-transport-https': {},
|
'apt-transport-https': {},
|
||||||
},
|
},
|
||||||
'sources': {
|
'sources': {
|
||||||
# place key under data/apt/keys/packages.cloud.google.com.{asc|gpg}
|
'debian': {
|
||||||
'deb https://packages.cloud.google.com/apt cloud-sdk main',
|
'types': { # optional, defaults to `{'deb'}``
|
||||||
|
'deb',
|
||||||
|
'deb-src',
|
||||||
|
},
|
||||||
|
'urls': {
|
||||||
|
'https://deb.debian.org/debian',
|
||||||
|
},
|
||||||
|
'suites': { # at least one
|
||||||
|
'{codename}',
|
||||||
|
'{codename}-updates',
|
||||||
|
'{codename}-backports',
|
||||||
|
},
|
||||||
|
'components': { # optional
|
||||||
|
'main',
|
||||||
|
'contrib',
|
||||||
|
'non-frese',
|
||||||
|
},
|
||||||
|
# key:
|
||||||
|
# - optional, defaults to source name (`debian` in this example)
|
||||||
|
# - place key under data/apt/keys/debian-12.{asc|gpg}
|
||||||
|
'key': 'debian-{version}',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
APT::Periodic::Update-Package-Lists "1";
|
|
||||||
APT::Periodic::Unattended-Upgrade "1";
|
|
|
@ -1,3 +0,0 @@
|
||||||
Unattended-Upgrade::Origins-Pattern {
|
|
||||||
"origin=*";
|
|
||||||
};
|
|
|
@ -1,35 +1,64 @@
|
||||||
# TODO pin repo: https://superuser.com/a/1595920
|
# TODO pin repo: https://superuser.com/a/1595920
|
||||||
|
|
||||||
from os.path import join
|
|
||||||
from urllib.parse import urlparse
|
|
||||||
from glob import glob
|
|
||||||
from os.path import join, basename
|
from os.path import join, basename
|
||||||
|
|
||||||
directories = {
|
directories = {
|
||||||
'/etc/apt/sources.list.d': {
|
'/etc/apt': {
|
||||||
'purge': True,
|
'purge': True,
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'action:apt_update',
|
'action:apt_update',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'/etc/apt/trusted.gpg.d': {
|
'/etc/apt/apt.conf.d': {
|
||||||
|
# existance is expected
|
||||||
'purge': True,
|
'purge': True,
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'action:apt_update',
|
'action:apt_update',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'/etc/apt/keyrings': {
|
||||||
|
# https://askubuntu.com/a/1307181
|
||||||
|
'purge': True,
|
||||||
|
'triggers': {
|
||||||
|
'action:apt_update',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
# '/etc/apt/listchanges.conf.d': {
|
||||||
|
# 'purge': True,
|
||||||
|
# 'triggers': {
|
||||||
|
# 'action:apt_update',
|
||||||
|
# },
|
||||||
|
# },
|
||||||
'/etc/apt/preferences.d': {
|
'/etc/apt/preferences.d': {
|
||||||
'purge': True,
|
'purge': True,
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'action:apt_update',
|
'action:apt_update',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'/etc/apt/sources.list.d': {
|
||||||
|
'purge': True,
|
||||||
|
'triggers': {
|
||||||
|
'action:apt_update',
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
files = {
|
files = {
|
||||||
'/etc/apt/sources.list': {
|
'/etc/apt/apt.conf': {
|
||||||
'content': '# managed'
|
'content': repo.libs.apt.render_apt_conf(node.metadata.get('apt/config')),
|
||||||
|
'triggers': {
|
||||||
|
'action:apt_update',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
'/etc/apt/sources.list': {
|
||||||
|
'content': '# managed by bundlewrap\n',
|
||||||
|
'triggers': {
|
||||||
|
'action:apt_update',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
# '/etc/apt/listchanges.conf': {
|
||||||
|
# 'content': repo.libs.ini.dumps(node.metadata.get('apt/list_changes')),
|
||||||
|
# },
|
||||||
'/usr/lib/nagios/plugins/check_apt_upgradable': {
|
'/usr/lib/nagios/plugins/check_apt_upgradable': {
|
||||||
'mode': '0755',
|
'mode': '0755',
|
||||||
},
|
},
|
||||||
|
@ -37,7 +66,7 @@ files = {
|
||||||
|
|
||||||
actions = {
|
actions = {
|
||||||
'apt_update': {
|
'apt_update': {
|
||||||
'command': 'apt-get update -o APT::Update::Error-Mode=any',
|
'command': 'apt-get update',
|
||||||
'needed_by': {
|
'needed_by': {
|
||||||
'pkg_apt:',
|
'pkg_apt:',
|
||||||
},
|
},
|
||||||
|
@ -46,41 +75,22 @@ actions = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
# group sources by apt server hostname
|
# create sources.lists and respective keyfiles
|
||||||
|
|
||||||
hosts = {}
|
for name, config in node.metadata.get('apt/sources').items():
|
||||||
|
# place keyfile
|
||||||
for source_string in node.metadata.get('apt/sources'):
|
keyfile_destination_path = repo.libs.apt.format_variables(node, config['options']['Signed-By'])
|
||||||
source = repo.libs.apt.AptSource(source_string)
|
files[keyfile_destination_path] = {
|
||||||
hosts\
|
'source': join(repo.path, 'data', 'apt', 'keys', basename(keyfile_destination_path)),
|
||||||
.setdefault(source.url.hostname, list())\
|
'content_type': 'binary',
|
||||||
.append(source)
|
|
||||||
|
|
||||||
# create sources lists and keyfiles
|
|
||||||
|
|
||||||
for host, sources in hosts.items():
|
|
||||||
keyfile = basename(glob(join(repo.path, 'data', 'apt', 'keys', f'{host}.*'))[0])
|
|
||||||
destination_path = f'/etc/apt/trusted.gpg.d/{keyfile}'
|
|
||||||
|
|
||||||
for source in sources:
|
|
||||||
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
|
|
||||||
))),
|
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'action:apt_update',
|
'action:apt_update',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
files[destination_path] = {
|
# place sources.list
|
||||||
'source': join(repo.path, 'data', 'apt', 'keys', keyfile),
|
files[f'/etc/apt/sources.list.d/{name}.sources'] = {
|
||||||
'content_type': 'binary',
|
'content': repo.libs.apt.render_source(node, name),
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'action:apt_update',
|
'action:apt_update',
|
||||||
},
|
},
|
||||||
|
@ -95,7 +105,7 @@ for package, options in node.metadata.get('apt/packages', {}).items():
|
||||||
files[f'/etc/apt/preferences.d/{package}'] = {
|
files[f'/etc/apt/preferences.d/{package}'] = {
|
||||||
'content': '\n'.join([
|
'content': '\n'.join([
|
||||||
f"Package: {package}",
|
f"Package: {package}",
|
||||||
f"Pin: release a={node.metadata.get('os_release')}-backports",
|
f"Pin: release a={node.metadata.get('os_codename')}-backports",
|
||||||
f"Pin-Priority: 900",
|
f"Pin-Priority: 900",
|
||||||
]),
|
]),
|
||||||
'needed_by': [
|
'needed_by': [
|
||||||
|
@ -112,8 +122,6 @@ for package, options in node.metadata.get('apt/packages', {}).items():
|
||||||
# apt-daily.timer: performs apt update
|
# apt-daily.timer: performs apt update
|
||||||
# apt-daily-upgrade.timer: performs apt upgrade
|
# apt-daily-upgrade.timer: performs apt upgrade
|
||||||
|
|
||||||
files['/etc/apt/apt.conf.d/20auto-upgrades'] = {}
|
|
||||||
files['/etc/apt/apt.conf.d/50unattended-upgrades'] = {}
|
|
||||||
svc_systemd['unattended-upgrades.service'] = {
|
svc_systemd['unattended-upgrades.service'] = {
|
||||||
'needs': [
|
'needs': [
|
||||||
'pkg_apt:unattended-upgrades',
|
'pkg_apt:unattended-upgrades',
|
||||||
|
|
|
@ -1,9 +1,55 @@
|
||||||
defaults = {
|
defaults = {
|
||||||
'apt': {
|
'apt': {
|
||||||
'packages': {
|
'packages': {
|
||||||
'unattended-upgrades': {},
|
'apt-listchanges': {
|
||||||
|
'installed': False,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'sources': set(),
|
'config': {
|
||||||
|
'DPkg': {
|
||||||
|
'Pre-Install-Pkgs': {
|
||||||
|
'/usr/sbin/dpkg-preconfigure --apt || true',
|
||||||
|
},
|
||||||
|
'Post-Invoke': {
|
||||||
|
# keep package cache empty
|
||||||
|
'/bin/rm -f /var/cache/apt/archives/*.deb || true',
|
||||||
|
},
|
||||||
|
'Options': {
|
||||||
|
# https://unix.stackexchange.com/a/642541/357916
|
||||||
|
'--force-confold',
|
||||||
|
'--force-confdef',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'APT': {
|
||||||
|
'NeverAutoRemove': {
|
||||||
|
'^firmware-linux.*',
|
||||||
|
'^linux-firmware$',
|
||||||
|
'^linux-image-[a-z0-9]*$',
|
||||||
|
'^linux-image-[a-z0-9]*-[a-z0-9]*$',
|
||||||
|
},
|
||||||
|
'VersionedKernelPackages': {
|
||||||
|
# kernels
|
||||||
|
'linux-.*',
|
||||||
|
'kfreebsd-.*',
|
||||||
|
'gnumach-.*',
|
||||||
|
# (out-of-tree) modules
|
||||||
|
'.*-modules',
|
||||||
|
'.*-kernel',
|
||||||
|
},
|
||||||
|
'Never-MarkAuto-Sections': {
|
||||||
|
'metapackages',
|
||||||
|
'tasks',
|
||||||
|
},
|
||||||
|
'Move-Autobit-Sections': {
|
||||||
|
'oldlibs',
|
||||||
|
},
|
||||||
|
'Update': {
|
||||||
|
# https://unix.stackexchange.com/a/653377/357916
|
||||||
|
'Error-Mode': 'any',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'sources': {},
|
||||||
},
|
},
|
||||||
'monitoring': {
|
'monitoring': {
|
||||||
'services': {
|
'services': {
|
||||||
|
@ -23,3 +69,109 @@ defaults = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'apt/sources',
|
||||||
|
)
|
||||||
|
def key(metadata):
|
||||||
|
return {
|
||||||
|
'apt': {
|
||||||
|
'sources': {
|
||||||
|
source_name: {
|
||||||
|
'key': source_name,
|
||||||
|
}
|
||||||
|
for source_name, source_config in metadata.get('apt/sources').items()
|
||||||
|
if 'key' not in source_config
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'apt/sources',
|
||||||
|
)
|
||||||
|
def signed_by(metadata):
|
||||||
|
return {
|
||||||
|
'apt': {
|
||||||
|
'sources': {
|
||||||
|
source_name: {
|
||||||
|
'options': {
|
||||||
|
'Signed-By': '/etc/apt/keyrings/' + metadata.get(f'apt/sources/{source_name}/key') + '.' + repo.libs.apt.find_keyfile_extension(node, metadata.get(f'apt/sources/{source_name}/key')),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for source_name in metadata.get('apt/sources')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'apt/config',
|
||||||
|
'apt/packages',
|
||||||
|
)
|
||||||
|
def unattended_upgrades(metadata):
|
||||||
|
return {
|
||||||
|
'apt': {
|
||||||
|
'config': {
|
||||||
|
'APT': {
|
||||||
|
'Periodic': {
|
||||||
|
'Update-Package-Lists': '1',
|
||||||
|
'Unattended-Upgrade': '1',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'Unattended-Upgrade': {
|
||||||
|
'Origins-Pattern': {
|
||||||
|
"origin=*",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'packages': {
|
||||||
|
'unattended-upgrades': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# @metadata_reactor.provides(
|
||||||
|
# 'apt/config',
|
||||||
|
# 'apt/list_changes',
|
||||||
|
# )
|
||||||
|
# def listchanges(metadata):
|
||||||
|
# return {
|
||||||
|
# 'apt': {
|
||||||
|
# 'config': {
|
||||||
|
# 'DPkg': {
|
||||||
|
# 'Pre-Install-Pkgs': {
|
||||||
|
# '/usr/bin/apt-listchanges --apt || test $? -lt 10',
|
||||||
|
# },
|
||||||
|
# 'Tools': {
|
||||||
|
# 'Options': {
|
||||||
|
# '/usr/bin/apt-listchanges': {
|
||||||
|
# 'Version': '2',
|
||||||
|
# 'InfoFD': '20',
|
||||||
|
# },
|
||||||
|
# },
|
||||||
|
# },
|
||||||
|
# },
|
||||||
|
# 'Dir': {
|
||||||
|
# 'Etc': {
|
||||||
|
# 'apt-listchanges-main': 'listchanges.conf',
|
||||||
|
# 'apt-listchanges-parts': 'listchanges.conf.d',
|
||||||
|
# },
|
||||||
|
# },
|
||||||
|
# },
|
||||||
|
# 'list_changes': {
|
||||||
|
# 'apt': {
|
||||||
|
# 'frontend': 'pager',
|
||||||
|
# 'which': 'news',
|
||||||
|
# 'email_address': 'root',
|
||||||
|
# 'email_format': 'text',
|
||||||
|
# 'confirm': 'false',
|
||||||
|
# 'headers': 'false',
|
||||||
|
# 'reverse': 'false',
|
||||||
|
# 'save_seen': '/var/lib/apt/listchanges.db',
|
||||||
|
# },
|
||||||
|
# },
|
||||||
|
# },
|
||||||
|
# }
|
||||||
|
|
|
@ -36,7 +36,7 @@ for dataset in config['datasets']:
|
||||||
|
|
||||||
if snapshot_datetime < two_days_ago:
|
if snapshot_datetime < two_days_ago:
|
||||||
days_ago = (now - snapshot_datetime).days
|
days_ago = (now - snapshot_datetime).days
|
||||||
errors.add(f'dataset "{dataset}" has no backups sind {days_ago} days')
|
errors.add(f'dataset "{dataset}" has not been backed up for {days_ago} days')
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if errors:
|
if errors:
|
||||||
|
|
|
@ -25,7 +25,8 @@ def backup_freshness_check(metadata):
|
||||||
'datasets': {
|
'datasets': {
|
||||||
f"{other_node.metadata.get('id')}/{dataset}"
|
f"{other_node.metadata.get('id')}/{dataset}"
|
||||||
for other_node in repo.nodes
|
for other_node in repo.nodes
|
||||||
if other_node.has_bundle('backup')
|
if not other_node.dummy
|
||||||
|
and other_node.has_bundle('backup')
|
||||||
and other_node.has_bundle('zfs')
|
and other_node.has_bundle('zfs')
|
||||||
and other_node.metadata.get('backup/server') == metadata.get('backup-freshness-check/server')
|
and other_node.metadata.get('backup/server') == metadata.get('backup-freshness-check/server')
|
||||||
for dataset, options in other_node.metadata.get('zfs/datasets').items()
|
for dataset, options in other_node.metadata.get('zfs/datasets').items()
|
||||||
|
|
|
@ -35,6 +35,7 @@ def zfs(metadata):
|
||||||
|
|
||||||
for other_node in repo.nodes:
|
for other_node in repo.nodes:
|
||||||
if (
|
if (
|
||||||
|
not other_node.dummy and
|
||||||
other_node.has_bundle('backup') and
|
other_node.has_bundle('backup') and
|
||||||
other_node.metadata.get('backup/server') == node.name
|
other_node.metadata.get('backup/server') == node.name
|
||||||
):
|
):
|
||||||
|
|
|
@ -1,13 +1,31 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -exu
|
set -u
|
||||||
|
|
||||||
# FIXME: inelegant
|
# FIXME: inelegant
|
||||||
% if wol_command:
|
% if wol_command:
|
||||||
${wol_command}
|
${wol_command}
|
||||||
% endif
|
% endif
|
||||||
|
|
||||||
|
exit=0
|
||||||
|
failed_paths=""
|
||||||
|
|
||||||
for path in $(jq -r '.paths | .[]' < /etc/backup/config.json)
|
for path in $(jq -r '.paths | .[]' < /etc/backup/config.json)
|
||||||
do
|
do
|
||||||
|
echo backing up $path
|
||||||
/opt/backup/backup_path "$path"
|
/opt/backup/backup_path "$path"
|
||||||
|
# set exit to 1 if any backup fails
|
||||||
|
if [ $? -ne 0 ]
|
||||||
|
then
|
||||||
|
echo ERROR: backing up $path failed >&2
|
||||||
|
exit=5
|
||||||
|
failed_paths="$failed_paths $path"
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
if [ $exit -ne 0 ]
|
||||||
|
then
|
||||||
|
echo "ERROR: failed to backup paths: $failed_paths" >&2
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit $exit
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
set -exu
|
set -eu
|
||||||
|
|
||||||
path=$1
|
path=$1
|
||||||
uuid=$(jq -r .client_uuid < /etc/backup/config.json)
|
uuid=$(jq -r .client_uuid < /etc/backup/config.json)
|
||||||
|
|
|
@ -19,7 +19,7 @@ directories[f'/var/lib/bind'] = {
|
||||||
'svc_systemd:bind9',
|
'svc_systemd:bind9',
|
||||||
],
|
],
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:bind9:restart',
|
'svc_systemd:bind9:reload',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ files['/etc/default/bind9'] = {
|
||||||
'svc_systemd:bind9',
|
'svc_systemd:bind9',
|
||||||
],
|
],
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:bind9:restart',
|
'svc_systemd:bind9:reload',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ files['/etc/bind/named.conf'] = {
|
||||||
'svc_systemd:bind9',
|
'svc_systemd:bind9',
|
||||||
],
|
],
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:bind9:restart',
|
'svc_systemd:bind9:reload',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ files['/etc/bind/named.conf.options'] = {
|
||||||
'svc_systemd:bind9',
|
'svc_systemd:bind9',
|
||||||
],
|
],
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:bind9:restart',
|
'svc_systemd:bind9:reload',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ files['/etc/bind/named.conf.local'] = {
|
||||||
'svc_systemd:bind9',
|
'svc_systemd:bind9',
|
||||||
],
|
],
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:bind9:restart',
|
'svc_systemd:bind9:reload',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +106,7 @@ for view_name, view_conf in master_node.metadata.get('bind/views').items():
|
||||||
'svc_systemd:bind9',
|
'svc_systemd:bind9',
|
||||||
],
|
],
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:bind9:restart',
|
'svc_systemd:bind9:reload',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,7 +127,7 @@ for view_name, view_conf in master_node.metadata.get('bind/views').items():
|
||||||
'svc_systemd:bind9',
|
'svc_systemd:bind9',
|
||||||
],
|
],
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:bind9:restart',
|
'svc_systemd:bind9:reload',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +139,6 @@ actions['named-checkconf'] = {
|
||||||
'unless': 'named-checkconf -z',
|
'unless': 'named-checkconf -z',
|
||||||
'needs': [
|
'needs': [
|
||||||
'svc_systemd:bind9',
|
'svc_systemd:bind9',
|
||||||
'svc_systemd:bind9:restart',
|
'svc_systemd:bind9:reload',
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
from shlex import quote
|
from shlex import quote
|
||||||
|
|
||||||
|
|
||||||
|
defaults = {
|
||||||
|
'build-ci': {},
|
||||||
|
}
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
@metadata_reactor.provides(
|
||||||
'users/build-ci/authorized_users',
|
'users/build-ci/authorized_users',
|
||||||
'sudoers/build-ci',
|
'sudoers/build-ci',
|
||||||
|
@ -18,7 +22,7 @@ def ssh_keys(metadata):
|
||||||
},
|
},
|
||||||
'sudoers': {
|
'sudoers': {
|
||||||
'build-ci': {
|
'build-ci': {
|
||||||
f"/usr/bin/chown -R build-ci\:{quote(ci['group'])} {quote(ci['path'])}"
|
f"/usr/bin/chown -R build-ci\\:{quote(ci['group'])} {quote(ci['path'])}"
|
||||||
for ci in metadata.get('build-ci').values()
|
for ci in metadata.get('build-ci').values()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
|
debian_version = min([node.os_version, (11,)])[0] # FIXME
|
||||||
|
|
||||||
defaults = {
|
defaults = {
|
||||||
'apt': {
|
'apt': {
|
||||||
'packages': {
|
'packages': {
|
||||||
'crystal': {},
|
'crystal': {},
|
||||||
},
|
},
|
||||||
'sources': {
|
'sources': {
|
||||||
'deb https://download.opensuse.org/repositories/devel:/languages:/crystal/Debian_{version}/ /',
|
'crystal': {
|
||||||
|
# https://software.opensuse.org/download.html?project=devel%3Alanguages%3Acrystal&package=crystal
|
||||||
|
'urls': {
|
||||||
|
'http://download.opensuse.org/repositories/devel:/languages:/crystal/Debian_Testing/',
|
||||||
|
},
|
||||||
|
'suites': {
|
||||||
|
'/',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ ssl_cert = </var/lib/dehydrated/certs/${node.metadata.get('mailserver/hostname')
|
||||||
ssl_key = </var/lib/dehydrated/certs/${node.metadata.get('mailserver/hostname')}/privkey.pem
|
ssl_key = </var/lib/dehydrated/certs/${node.metadata.get('mailserver/hostname')}/privkey.pem
|
||||||
ssl_dh = </etc/dovecot/dhparam.pem
|
ssl_dh = </etc/dovecot/dhparam.pem
|
||||||
ssl_client_ca_dir = /etc/ssl/certs
|
ssl_client_ca_dir = /etc/ssl/certs
|
||||||
mail_location = maildir:~
|
mail_location = maildir:${node.metadata.get('mailserver/maildir')}/%u:INDEX=${node.metadata.get('mailserver/maildir')}/index/%u
|
||||||
mail_plugins = fts fts_xapian
|
mail_plugins = fts fts_xapian
|
||||||
|
|
||||||
namespace inbox {
|
namespace inbox {
|
||||||
|
|
|
@ -20,6 +20,10 @@ directories = {
|
||||||
'owner': 'vmail',
|
'owner': 'vmail',
|
||||||
'group': 'vmail',
|
'group': 'vmail',
|
||||||
},
|
},
|
||||||
|
'/var/vmail/index': {
|
||||||
|
'owner': 'vmail',
|
||||||
|
'group': 'vmail',
|
||||||
|
},
|
||||||
'/var/vmail/sieve': {
|
'/var/vmail/sieve': {
|
||||||
'owner': 'vmail',
|
'owner': 'vmail',
|
||||||
'group': 'vmail',
|
'group': 'vmail',
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
# directories = {
|
|
||||||
# '/var/lib/downloads': {
|
|
||||||
# 'owner': 'downloads',
|
|
||||||
# 'group': 'www-data',
|
|
||||||
# }
|
|
||||||
# }
|
|
23
bundles/freescout/README.md
Normal file
23
bundles/freescout/README.md
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
Pg Pass workaround: set manually:
|
||||||
|
|
||||||
|
```
|
||||||
|
root@freescout /ro psql freescout
|
||||||
|
psql (15.6 (Debian 15.6-0+deb12u1))
|
||||||
|
Type "help" for help.
|
||||||
|
|
||||||
|
freescout=# \password freescout
|
||||||
|
Enter new password for user "freescout":
|
||||||
|
Enter it again:
|
||||||
|
freescout=#
|
||||||
|
\q
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
# problems
|
||||||
|
|
||||||
|
# check if /opt/freescout/.env is resettet
|
||||||
|
# ckeck `psql -h localhost -d freescout -U freescout -W`with pw from .env
|
||||||
|
# chown -R www-data:www-data /opt/freescout
|
||||||
|
# sudo su - www-data -c 'php /opt/freescout/artisan freescout:clear-cache' -s /bin/bash
|
||||||
|
# javascript funny? `sudo su - www-data -c 'php /opt/freescout/artisan storage:link' -s /bin/bash`
|
||||||
|
# benutzer bilder weg? aus dem backup holen: `/opt/freescout/.zfs/snapshot/zfs-auto-snap_hourly-2024-11-22-1700/storage/app/public/users` `./customers`
|
66
bundles/freescout/items.py
Normal file
66
bundles/freescout/items.py
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
# https://github.com/freescout-helpdesk/freescout/wiki/Installation-Guide
|
||||||
|
run_as = repo.libs.tools.run_as
|
||||||
|
php_version = node.metadata.get('php/version')
|
||||||
|
|
||||||
|
|
||||||
|
directories = {
|
||||||
|
'/opt/freescout': {
|
||||||
|
'owner': 'www-data',
|
||||||
|
'group': 'www-data',
|
||||||
|
# chown -R www-data:www-data /opt/freescout
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
actions = {
|
||||||
|
# 'clone_freescout': {
|
||||||
|
# 'command': run_as('www-data', 'git clone https://github.com/freescout-helpdesk/freescout.git /opt/freescout'),
|
||||||
|
# 'unless': 'test -e /opt/freescout/.git',
|
||||||
|
# 'needs': [
|
||||||
|
# 'pkg_apt:git',
|
||||||
|
# 'directory:/opt/freescout',
|
||||||
|
# ],
|
||||||
|
# },
|
||||||
|
# 'pull_freescout': {
|
||||||
|
# 'command': run_as('www-data', 'git -C /opt/freescout fetch origin dist && git -C /opt/freescout reset --hard origin/dist && git -C /opt/freescout clean -f'),
|
||||||
|
# 'unless': run_as('www-data', 'git -C /opt/freescout fetch origin && git -C /opt/freescout status -uno | grep -q "Your branch is up to date"'),
|
||||||
|
# 'needs': [
|
||||||
|
# 'action:clone_freescout',
|
||||||
|
# ],
|
||||||
|
# 'triggers': [
|
||||||
|
# 'action:freescout_artisan_update',
|
||||||
|
# f'svc_systemd:php{php_version}-fpm.service:restart',
|
||||||
|
# ],
|
||||||
|
# },
|
||||||
|
# 'freescout_artisan_update': {
|
||||||
|
# 'command': run_as('www-data', 'php /opt/freescout/artisan freescout:after-app-update'),
|
||||||
|
# 'triggered': True,
|
||||||
|
# 'needs': [
|
||||||
|
# f'svc_systemd:php{php_version}-fpm.service:restart',
|
||||||
|
# 'action:pull_freescout',
|
||||||
|
# ],
|
||||||
|
# },
|
||||||
|
}
|
||||||
|
|
||||||
|
# svc_systemd = {
|
||||||
|
# f'freescout-cron.service': {},
|
||||||
|
# }
|
||||||
|
|
||||||
|
# files = {
|
||||||
|
# '/opt/freescout/.env': {
|
||||||
|
# # https://github.com/freescout-helpdesk/freescout/blob/dist/.env.example
|
||||||
|
# # Every time you are making changes in .env file, in order changes to take an effect you need to run:
|
||||||
|
# # ´sudo su - www-data -c 'php /opt/freescout/artisan freescout:clear-cache' -s /bin/bash´
|
||||||
|
# 'owner': 'www-data',
|
||||||
|
# 'content': '\n'.join(
|
||||||
|
# f'{k}={v}' for k, v in
|
||||||
|
# sorted(node.metadata.get('freescout/env').items())
|
||||||
|
# ) + '\n',
|
||||||
|
# 'needs': [
|
||||||
|
# 'directory:/opt/freescout',
|
||||||
|
# 'action:clone_freescout',
|
||||||
|
# ],
|
||||||
|
# },
|
||||||
|
# }
|
||||||
|
|
||||||
|
#sudo su - www-data -s /bin/bash -c 'php /opt/freescout/artisan freescout:create-user --role admin --firstName M --lastName W --email freescout@freibrief.net --password gyh.jzv2bnf6hvc.HKG --no-interaction'
|
||||||
|
#sudo su - www-data -s /bin/bash -c 'php /opt/freescout/artisan freescout:create-user --role admin --firstName M --lastName W --email freescout@freibrief.net --password gyh.jzv2bnf6hvc.HKG --no-interaction'
|
121
bundles/freescout/metadata.py
Normal file
121
bundles/freescout/metadata.py
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
from base64 import b64decode
|
||||||
|
|
||||||
|
# hash: SCRAM-SHA-256$4096:tQNfqQi7seqNDwJdHqCHbg==$r3ibECluHJaY6VRwpvPqrtCjgrEK7lAkgtUO8/tllTU=:+eeo4M0L2SowfyHFxT2FRqGzezve4ZOEocSIo11DATA=
|
||||||
|
database_password = repo.vault.password_for(f'{node.name} postgresql freescout').value
|
||||||
|
|
||||||
|
defaults = {
|
||||||
|
'apt': {
|
||||||
|
'packages': {
|
||||||
|
'git': {},
|
||||||
|
'php': {},
|
||||||
|
'php-pgsql': {},
|
||||||
|
'php-fpm': {},
|
||||||
|
'php-mbstring': {},
|
||||||
|
'php-xml': {},
|
||||||
|
'php-imap': {},
|
||||||
|
'php-zip': {},
|
||||||
|
'php-gd': {},
|
||||||
|
'php-curl': {},
|
||||||
|
'php-intl': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'freescout': {
|
||||||
|
'env': {
|
||||||
|
'APP_TIMEZONE': 'Europe/Berlin',
|
||||||
|
'DB_CONNECTION': 'pgsql',
|
||||||
|
'DB_HOST': '127.0.0.1',
|
||||||
|
'DB_PORT': '5432',
|
||||||
|
'DB_DATABASE': 'freescout',
|
||||||
|
'DB_USERNAME': 'freescout',
|
||||||
|
'DB_PASSWORD': database_password,
|
||||||
|
'APP_KEY': 'base64:' + repo.vault.random_bytes_as_base64_for(f'{node.name} freescout APP_KEY', length=32).value
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'php': {
|
||||||
|
'php.ini': {
|
||||||
|
'cgi': {
|
||||||
|
'fix_pathinfo': '0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'postgresql': {
|
||||||
|
'roles': {
|
||||||
|
'freescout': {
|
||||||
|
'password_hash': repo.libs.postgres.generate_scram_sha_256(
|
||||||
|
database_password,
|
||||||
|
b64decode(repo.vault.random_bytes_as_base64_for(f'{node.name} postgres freescout', length=16).value.encode()),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'databases': {
|
||||||
|
'freescout': {
|
||||||
|
'owner': 'freescout',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
# 'systemd': {
|
||||||
|
# 'units': {
|
||||||
|
# f'freescout-cron.service': {
|
||||||
|
# 'Unit': {
|
||||||
|
# 'Description': 'Freescout Cron',
|
||||||
|
# 'After': 'network.target',
|
||||||
|
# },
|
||||||
|
# 'Service': {
|
||||||
|
# 'User': 'www-data',
|
||||||
|
# 'Nice': 10,
|
||||||
|
# 'ExecStart': f"/usr/bin/php /opt/freescout/artisan schedule:run"
|
||||||
|
# },
|
||||||
|
# 'Install': {
|
||||||
|
# 'WantedBy': {
|
||||||
|
# 'multi-user.target'
|
||||||
|
# }
|
||||||
|
# },
|
||||||
|
# }
|
||||||
|
# },
|
||||||
|
# },
|
||||||
|
'systemd-timers': {
|
||||||
|
'freescout-cron': {
|
||||||
|
'command': '/usr/bin/php /opt/freescout/artisan schedule:run',
|
||||||
|
'when': '*-*-* *:*:00',
|
||||||
|
'RuntimeMaxSec': '180',
|
||||||
|
'user': 'www-data',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'zfs': {
|
||||||
|
'datasets': {
|
||||||
|
'tank/freescout': {
|
||||||
|
'mountpoint': '/opt/freescout',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'freescout/env/APP_URL',
|
||||||
|
)
|
||||||
|
def freescout(metadata):
|
||||||
|
return {
|
||||||
|
'freescout': {
|
||||||
|
'env': {
|
||||||
|
'APP_URL': 'https://' + metadata.get('freescout/domain') + '/',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'nginx/vhosts',
|
||||||
|
)
|
||||||
|
def nginx(metadata):
|
||||||
|
return {
|
||||||
|
'nginx': {
|
||||||
|
'vhosts': {
|
||||||
|
metadata.get('freescout/domain'): {
|
||||||
|
'content': 'freescout/vhost.conf',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -8,7 +8,15 @@ defaults = {
|
||||||
'python3-crcmod': {},
|
'python3-crcmod': {},
|
||||||
},
|
},
|
||||||
'sources': {
|
'sources': {
|
||||||
'deb https://packages.cloud.google.com/apt cloud-sdk main',
|
'google-cloud': {
|
||||||
|
'url': 'https://packages.cloud.google.com/apt/',
|
||||||
|
'suites': {
|
||||||
|
'cloud-sdk',
|
||||||
|
},
|
||||||
|
'components': {
|
||||||
|
'main',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,14 @@ from os.path import join
|
||||||
from bundlewrap.utils.dicts import merge_dict
|
from bundlewrap.utils.dicts import merge_dict
|
||||||
|
|
||||||
|
|
||||||
version = version=node.metadata.get('gitea/version')
|
version = node.metadata.get('gitea/version')
|
||||||
|
assert not version.startswith('v')
|
||||||
|
arch = node.metadata.get('system/architecture')
|
||||||
|
|
||||||
downloads['/usr/local/bin/gitea'] = {
|
downloads['/usr/local/bin/gitea'] = {
|
||||||
'url': f'https://dl.gitea.io/gitea/{version}/gitea-{version}-linux-amd64',
|
# https://forgejo.org/releases/
|
||||||
'sha256': node.metadata.get('gitea/sha256'),
|
'url': f'https://codeberg.org/forgejo/forgejo/releases/download/v{version}/forgejo-{version}-linux-{arch}',
|
||||||
|
'sha256_url': '{url}.sha256',
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'svc_systemd:gitea:restart',
|
'svc_systemd:gitea:restart',
|
||||||
},
|
},
|
||||||
|
@ -45,6 +48,7 @@ files['/etc/gitea/app.ini'] = {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
'owner': 'git',
|
'owner': 'git',
|
||||||
|
'mode': '0600',
|
||||||
'context': node.metadata['gitea'],
|
'context': node.metadata['gitea'],
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'svc_systemd:gitea:restart',
|
'svc_systemd:gitea:restart',
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
database_password = repo.vault.password_for(f'{node.name} postgresql gitea')
|
database_password = repo.vault.password_for(f'{node.name} postgresql gitea').value
|
||||||
|
|
||||||
defaults = {
|
defaults = {
|
||||||
'apt': {
|
'apt': {
|
||||||
|
@ -11,7 +11,20 @@ defaults = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'gitea': {
|
'gitea': {
|
||||||
'conf': {},
|
'conf': {
|
||||||
|
'DEFAULT': {
|
||||||
|
'WORK_PATH': '/var/lib/gitea',
|
||||||
|
},
|
||||||
|
'database': {
|
||||||
|
'DB_TYPE': 'postgres',
|
||||||
|
'HOST': 'localhost:5432',
|
||||||
|
'NAME': 'gitea',
|
||||||
|
'USER': 'gitea',
|
||||||
|
'PASSWD': database_password,
|
||||||
|
'SSL_MODE': 'disable',
|
||||||
|
'LOG_SQL': 'false',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
'postgresql': {
|
'postgresql': {
|
||||||
'roles': {
|
'roles': {
|
||||||
|
@ -30,8 +43,7 @@ defaults = {
|
||||||
'gitea.service': {
|
'gitea.service': {
|
||||||
'Unit': {
|
'Unit': {
|
||||||
'Description': 'gitea',
|
'Description': 'gitea',
|
||||||
'After': 'syslog.target',
|
'After': {'syslog.target', 'network.target'},
|
||||||
'After': 'network.target',
|
|
||||||
'Requires': 'postgresql.service',
|
'Requires': 'postgresql.service',
|
||||||
},
|
},
|
||||||
'Service': {
|
'Service': {
|
||||||
|
@ -84,15 +96,6 @@ def conf(metadata):
|
||||||
'INTERNAL_TOKEN': repo.vault.password_for(f'{node.name} gitea internal_token'),
|
'INTERNAL_TOKEN': repo.vault.password_for(f'{node.name} gitea internal_token'),
|
||||||
'SECRET_KEY': repo.vault.password_for(f'{node.name} gitea security_secret_key'),
|
'SECRET_KEY': repo.vault.password_for(f'{node.name} gitea security_secret_key'),
|
||||||
},
|
},
|
||||||
'database': {
|
|
||||||
'DB_TYPE': 'postgres',
|
|
||||||
'HOST': 'localhost:5432',
|
|
||||||
'NAME': 'gitea',
|
|
||||||
'USER': 'gitea',
|
|
||||||
'PASSWD': database_password,
|
|
||||||
'SSL_MODE': 'disable',
|
|
||||||
'LOG_SQL': 'false',
|
|
||||||
},
|
|
||||||
'service': {
|
'service': {
|
||||||
'NO_REPLY_ADDRESS': f'noreply.{domain}',
|
'NO_REPLY_ADDRESS': f'noreply.{domain}',
|
||||||
},
|
},
|
||||||
|
@ -115,7 +118,7 @@ def nginx(metadata):
|
||||||
'content': 'nginx/proxy_pass.conf',
|
'content': 'nginx/proxy_pass.conf',
|
||||||
'context': {
|
'context': {
|
||||||
'target': 'http://127.0.0.1:3500',
|
'target': 'http://127.0.0.1:3500',
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -18,7 +18,7 @@ admin_password = node.metadata.get('grafana/config/security/admin_password')
|
||||||
port = node.metadata.get('grafana/config/server/http_port')
|
port = node.metadata.get('grafana/config/server/http_port')
|
||||||
actions['reset_grafana_admin_password'] = {
|
actions['reset_grafana_admin_password'] = {
|
||||||
'command': f"grafana-cli admin reset-admin-password {quote(admin_password)}",
|
'command': f"grafana-cli admin reset-admin-password {quote(admin_password)}",
|
||||||
'unless': f"curl http://admin:{quote(admin_password)}@localhost:{port}/api/org",
|
'unless': f"sleep 5 && curl http://admin:{quote(admin_password)}@localhost:{port}/api/org --fail",
|
||||||
'needs': [
|
'needs': [
|
||||||
'svc_systemd:grafana-server',
|
'svc_systemd:grafana-server',
|
||||||
],
|
],
|
||||||
|
@ -26,15 +26,23 @@ actions['reset_grafana_admin_password'] = {
|
||||||
|
|
||||||
directories = {
|
directories = {
|
||||||
'/etc/grafana': {},
|
'/etc/grafana': {},
|
||||||
'/etc/grafana/provisioning': {},
|
'/etc/grafana/provisioning': {
|
||||||
|
'owner': 'grafana',
|
||||||
|
'group': 'grafana',
|
||||||
|
},
|
||||||
'/etc/grafana/provisioning/datasources': {
|
'/etc/grafana/provisioning/datasources': {
|
||||||
'purge': True,
|
'purge': True,
|
||||||
},
|
},
|
||||||
'/etc/grafana/provisioning/dashboards': {
|
'/etc/grafana/provisioning/dashboards': {
|
||||||
'purge': True,
|
'purge': True,
|
||||||
},
|
},
|
||||||
'/var/lib/grafana': {},
|
'/var/lib/grafana': {
|
||||||
|
'owner': 'grafana',
|
||||||
|
'group': 'grafana',
|
||||||
|
},
|
||||||
'/var/lib/grafana/dashboards': {
|
'/var/lib/grafana/dashboards': {
|
||||||
|
'owner': 'grafana',
|
||||||
|
'group': 'grafana',
|
||||||
'purge': True,
|
'purge': True,
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:grafana-server:restart',
|
'svc_systemd:grafana-server:restart',
|
||||||
|
@ -45,6 +53,8 @@ directories = {
|
||||||
files = {
|
files = {
|
||||||
'/etc/grafana/grafana.ini': {
|
'/etc/grafana/grafana.ini': {
|
||||||
'content': repo.libs.ini.dumps(node.metadata.get('grafana/config')),
|
'content': repo.libs.ini.dumps(node.metadata.get('grafana/config')),
|
||||||
|
'owner': 'grafana',
|
||||||
|
'group': 'grafana',
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:grafana-server:restart',
|
'svc_systemd:grafana-server:restart',
|
||||||
],
|
],
|
||||||
|
@ -54,6 +64,8 @@ files = {
|
||||||
'apiVersion': 1,
|
'apiVersion': 1,
|
||||||
'datasources': list(node.metadata.get('grafana/datasources').values()),
|
'datasources': list(node.metadata.get('grafana/datasources').values()),
|
||||||
}),
|
}),
|
||||||
|
'owner': 'grafana',
|
||||||
|
'group': 'grafana',
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:grafana-server:restart',
|
'svc_systemd:grafana-server:restart',
|
||||||
],
|
],
|
||||||
|
@ -70,6 +82,8 @@ files = {
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
}),
|
}),
|
||||||
|
'owner': 'grafana',
|
||||||
|
'group': 'grafana',
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:grafana-server:restart',
|
'svc_systemd:grafana-server:restart',
|
||||||
],
|
],
|
||||||
|
@ -158,6 +172,8 @@ for dashboard_id, monitored_node in enumerate(monitored_nodes, start=1):
|
||||||
|
|
||||||
files[f'/var/lib/grafana/dashboards/{monitored_node.name}.json'] = {
|
files[f'/var/lib/grafana/dashboards/{monitored_node.name}.json'] = {
|
||||||
'content': json.dumps(dashboard, indent=4),
|
'content': json.dumps(dashboard, indent=4),
|
||||||
|
'owner': 'grafana',
|
||||||
|
'group': 'grafana',
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:grafana-server:restart',
|
'svc_systemd:grafana-server:restart',
|
||||||
]
|
]
|
||||||
|
|
|
@ -8,8 +8,19 @@ defaults = {
|
||||||
'grafana': {},
|
'grafana': {},
|
||||||
},
|
},
|
||||||
'sources': {
|
'sources': {
|
||||||
'deb https://packages.grafana.com/oss/deb stable main',
|
'grafana': {
|
||||||
|
'urls': {
|
||||||
|
'https://packages.grafana.com/oss/deb',
|
||||||
|
},
|
||||||
|
'suites': {
|
||||||
|
'stable',
|
||||||
|
},
|
||||||
|
'components': {
|
||||||
|
'main',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
'grafana': {
|
'grafana': {
|
||||||
'config': {
|
'config': {
|
||||||
|
|
23
bundles/homeassistant-supervised/README.md
Normal file
23
bundles/homeassistant-supervised/README.md
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
https://github.com/home-assistant/supervised-installer?tab=readme-ov-file
|
||||||
|
https://github.com/home-assistant/os-agent/tree/main?tab=readme-ov-file#using-home-assistant-supervised-on-debian
|
||||||
|
https://docs.docker.com/engine/install/debian/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
https://www.home-assistant.io/installation/linux#install-home-assistant-supervised
|
||||||
|
https://github.com/home-assistant/supervised-installer
|
||||||
|
https://github.com/home-assistant/architecture/blob/master/adr/0014-home-assistant-supervised.md
|
||||||
|
|
||||||
|
DATA_SHARE=/usr/share/hassio dpkg --force-confdef --force-confold -i homeassistant-supervised.deb
|
||||||
|
|
||||||
|
neu debian
|
||||||
|
ha installieren
|
||||||
|
gucken ob geht
|
||||||
|
dann bw drüberbügeln
|
||||||
|
|
||||||
|
|
||||||
|
https://www.home-assistant.io/integrations/http/#ssl_certificate
|
||||||
|
|
||||||
|
`wget "$(curl -L https://api.github.com/repos/home-assistant/supervised-installer/releases/latest | jq -r '.assets[0].browser_download_url')" -O homeassistant-supervised.deb && dpkg -i homeassistant-supervised.deb`
|
30
bundles/homeassistant-supervised/items.py
Normal file
30
bundles/homeassistant-supervised/items.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
from shlex import quote
|
||||||
|
|
||||||
|
|
||||||
|
version = node.metadata.get('homeassistant/os_agent_version')
|
||||||
|
|
||||||
|
directories = {
|
||||||
|
'/usr/share/hassio': {},
|
||||||
|
}
|
||||||
|
|
||||||
|
actions = {
|
||||||
|
'install_os_agent': {
|
||||||
|
'command': ' && '.join([
|
||||||
|
f'wget -O /tmp/os-agent.deb https://github.com/home-assistant/os-agent/releases/download/{quote(version)}/os-agent_{quote(version)}_linux_aarch64.deb',
|
||||||
|
'DEBIAN_FRONTEND=noninteractive dpkg -i /tmp/os-agent.deb',
|
||||||
|
]),
|
||||||
|
'unless': f'test "$(apt -qq list os-agent | cut -d" " -f2)" = "{quote(version)}"',
|
||||||
|
'needs': {
|
||||||
|
'pkg_apt:',
|
||||||
|
'zfs_dataset:tank/homeassistant',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'install_homeassistant_supervised': {
|
||||||
|
'command': 'wget -O /tmp/homeassistant-supervised.deb https://github.com/home-assistant/supervised-installer/releases/latest/download/homeassistant-supervised.deb && apt install /tmp/homeassistant-supervised.deb',
|
||||||
|
'unless': 'apt -qq list homeassistant-supervised | grep -q "installed"',
|
||||||
|
'needs': {
|
||||||
|
'action:install_os_agent',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
65
bundles/homeassistant-supervised/metadata.py
Normal file
65
bundles/homeassistant-supervised/metadata.py
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
defaults = {
|
||||||
|
'apt': {
|
||||||
|
'packages': {
|
||||||
|
# homeassistant-supervised
|
||||||
|
'apparmor': {},
|
||||||
|
'bluez': {},
|
||||||
|
'cifs-utils': {},
|
||||||
|
'curl': {},
|
||||||
|
'dbus': {},
|
||||||
|
'jq': {},
|
||||||
|
'libglib2.0-bin': {},
|
||||||
|
'lsb-release': {},
|
||||||
|
'network-manager': {},
|
||||||
|
'nfs-common': {},
|
||||||
|
'systemd-journal-remote': {},
|
||||||
|
'systemd-resolved': {},
|
||||||
|
'udisks2': {},
|
||||||
|
'wget': {},
|
||||||
|
# docker
|
||||||
|
'docker-ce': {},
|
||||||
|
'docker-ce-cli': {},
|
||||||
|
'containerd.io': {},
|
||||||
|
'docker-buildx-plugin': {},
|
||||||
|
'docker-compose-plugin': {},
|
||||||
|
},
|
||||||
|
'sources': {
|
||||||
|
# docker: https://docs.docker.com/engine/install/debian/#install-using-the-repository
|
||||||
|
'docker': {
|
||||||
|
'urls': {
|
||||||
|
'https://download.docker.com/linux/debian',
|
||||||
|
},
|
||||||
|
'suites': {
|
||||||
|
'{codename}',
|
||||||
|
},
|
||||||
|
'components': {
|
||||||
|
'stable',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'zfs': {
|
||||||
|
'datasets': {
|
||||||
|
'tank/homeassistant': {
|
||||||
|
'mountpoint': '/usr/share/hassio',
|
||||||
|
'needed_by': {
|
||||||
|
'directory:/usr/share/hassio',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'nginx/vhosts',
|
||||||
|
)
|
||||||
|
def nginx(metadata):
|
||||||
|
return {
|
||||||
|
'nginx': {
|
||||||
|
'vhosts': {
|
||||||
|
metadata.get('homeassistant/domain'): {
|
||||||
|
'content': 'homeassistant/vhost.conf',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
users = {
|
|
||||||
'homeassistant': {
|
|
||||||
'home': '/var/lib/homeassistant',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
directories = {
|
|
||||||
'/var/lib/homeassistant': {
|
|
||||||
'owner': 'homeassistant',
|
|
||||||
},
|
|
||||||
'/var/lib/homeassistant/config': {
|
|
||||||
'owner': 'homeassistant',
|
|
||||||
},
|
|
||||||
'/var/lib/homeassistant/venv': {
|
|
||||||
'owner': 'homeassistant',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# https://wiki.instar.com/de/Software/Linux/Home_Assistant/
|
|
|
@ -1,20 +0,0 @@
|
||||||
defaults = {
|
|
||||||
'apt': {
|
|
||||||
'packages': {
|
|
||||||
'python3': {},
|
|
||||||
'python3-dev': {},
|
|
||||||
'python3-pip': {},
|
|
||||||
'python3-venv': {},
|
|
||||||
'libffi-dev': {},
|
|
||||||
'libssl-dev': {},
|
|
||||||
'libjpeg-dev': {},
|
|
||||||
'zlib1g-dev': {},
|
|
||||||
'autoconf': {},
|
|
||||||
'build-essential': {},
|
|
||||||
'libopenjp2-7': {},
|
|
||||||
'libtiff5': {},
|
|
||||||
'libturbojpeg0-dev': {},
|
|
||||||
'tzdata': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -24,7 +24,7 @@ header_margin=1
|
||||||
detailed_cpu_time=0
|
detailed_cpu_time=0
|
||||||
cpu_count_from_one=1
|
cpu_count_from_one=1
|
||||||
show_cpu_usage=0
|
show_cpu_usage=0
|
||||||
show_cpu_frequency=0
|
show_cpu_frequency=1
|
||||||
show_cpu_temperature=0
|
show_cpu_temperature=0
|
||||||
degree_fahrenheit=0
|
degree_fahrenheit=0
|
||||||
update_process_names=0
|
update_process_names=0
|
||||||
|
|
|
@ -13,9 +13,9 @@ apply Notification "mail-icingaadmin" to Host {
|
||||||
user_groups = host.vars.notification.mail.groups
|
user_groups = host.vars.notification.mail.groups
|
||||||
users = host.vars.notification.mail.users
|
users = host.vars.notification.mail.users
|
||||||
|
|
||||||
//interval = 2h
|
|
||||||
|
|
||||||
//vars.notification_logtosyslog = true
|
|
||||||
|
|
||||||
|
|
||||||
assign where host.vars.notification.mail
|
assign where host.vars.notification.mail
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@ apply Notification "mail-icingaadmin" to Service {
|
||||||
user_groups = host.vars.notification.mail.groups
|
user_groups = host.vars.notification.mail.groups
|
||||||
users = host.vars.notification.mail.users
|
users = host.vars.notification.mail.users
|
||||||
|
|
||||||
//interval = 2h
|
|
||||||
|
|
||||||
//vars.notification_logtosyslog = true
|
|
||||||
|
|
||||||
|
|
||||||
assign where host.vars.notification.mail
|
assign where host.vars.notification.mail
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,7 +269,7 @@ svc_systemd = {
|
||||||
'icinga2.service': {
|
'icinga2.service': {
|
||||||
'needs': [
|
'needs': [
|
||||||
'pkg_apt:icinga2-ido-pgsql',
|
'pkg_apt:icinga2-ido-pgsql',
|
||||||
'svc_systemd:postgresql',
|
'svc_systemd:postgresql.service',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,21 @@ defaults = {
|
||||||
'monitoring-plugins': {},
|
'monitoring-plugins': {},
|
||||||
},
|
},
|
||||||
'sources': {
|
'sources': {
|
||||||
'deb https://packages.icinga.com/debian icinga-{release} main',
|
'icinga': {
|
||||||
|
'types': {
|
||||||
|
'deb',
|
||||||
|
'deb-src',
|
||||||
|
},
|
||||||
|
'urls': {
|
||||||
|
'https://packages.icinga.com/debian',
|
||||||
|
},
|
||||||
|
'suites': {
|
||||||
|
'icinga-{codename}',
|
||||||
|
},
|
||||||
|
'components': {
|
||||||
|
'main',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'icinga2': {
|
'icinga2': {
|
||||||
|
|
|
@ -4,18 +4,27 @@ directories = {
|
||||||
'owner': 'www-data',
|
'owner': 'www-data',
|
||||||
'group': 'icingaweb2',
|
'group': 'icingaweb2',
|
||||||
'mode': '2770',
|
'mode': '2770',
|
||||||
|
'needs': [
|
||||||
|
'pkg_apt:icingaweb2',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
'/etc/icingaweb2/enabledModules': {
|
'/etc/icingaweb2/enabledModules': {
|
||||||
# 'purge': True,
|
# 'purge': True,
|
||||||
'owner': 'www-data',
|
'owner': 'www-data',
|
||||||
'group': 'icingaweb2',
|
'group': 'icingaweb2',
|
||||||
'mode': '2770',
|
'mode': '2770',
|
||||||
|
'needs': [
|
||||||
|
'pkg_apt:icingaweb2',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
'/etc/icingaweb2/modules': {
|
'/etc/icingaweb2/modules': {
|
||||||
# 'purge': True,
|
# 'purge': True,
|
||||||
'owner': 'www-data',
|
'owner': 'www-data',
|
||||||
'group': 'icingaweb2',
|
'group': 'icingaweb2',
|
||||||
'mode': '2770',
|
'mode': '2770',
|
||||||
|
'needs': [
|
||||||
|
'pkg_apt:icingaweb2',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +34,9 @@ files = {
|
||||||
'owner': 'www-data',
|
'owner': 'www-data',
|
||||||
'group': 'icingaweb2',
|
'group': 'icingaweb2',
|
||||||
'mode': '0660',
|
'mode': '0660',
|
||||||
|
'needs': [
|
||||||
|
'pkg_apt:icingaweb2',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +45,9 @@ symlinks = {
|
||||||
'target': '/usr/share/icingaweb2/modules/monitoring',
|
'target': '/usr/share/icingaweb2/modules/monitoring',
|
||||||
'owner': 'www-data',
|
'owner': 'www-data',
|
||||||
'group': 'icingaweb2',
|
'group': 'icingaweb2',
|
||||||
|
'needs': [
|
||||||
|
'pkg_apt:icingaweb2',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,6 +63,9 @@ for name in [
|
||||||
'owner': 'www-data',
|
'owner': 'www-data',
|
||||||
'group': 'icingaweb2',
|
'group': 'icingaweb2',
|
||||||
'mode': '0660',
|
'mode': '0660',
|
||||||
|
'needs': [
|
||||||
|
'pkg_apt:icingaweb2',
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
for name in [
|
for name in [
|
||||||
|
@ -60,4 +78,7 @@ for name in [
|
||||||
'owner': 'www-data',
|
'owner': 'www-data',
|
||||||
'group': 'icingaweb2',
|
'group': 'icingaweb2',
|
||||||
'mode': '0660',
|
'mode': '0660',
|
||||||
|
'needs': [
|
||||||
|
'pkg_apt:icingaweb2',
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,24 @@ defaults = {
|
||||||
'php-imagick': {},
|
'php-imagick': {},
|
||||||
'php-pgsql': {},
|
'php-pgsql': {},
|
||||||
'icingaweb2': {},
|
'icingaweb2': {},
|
||||||
'icingaweb2-module-monitoring': {},
|
#'icingaweb2-module-monitoring': {}, # ?
|
||||||
},
|
},
|
||||||
'sources': {
|
'sources': {
|
||||||
'deb https://packages.icinga.com/debian icinga-{release} main',
|
'icinga': {
|
||||||
|
'types': {
|
||||||
|
'deb',
|
||||||
|
'deb-src',
|
||||||
|
},
|
||||||
|
'urls': {
|
||||||
|
'https://packages.icinga.com/debian',
|
||||||
|
},
|
||||||
|
'suites': {
|
||||||
|
'icinga-{codename}',
|
||||||
|
},
|
||||||
|
'components': {
|
||||||
|
'main',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'icingaweb2': {
|
'icingaweb2': {
|
||||||
|
@ -163,6 +177,7 @@ def nginx(metadata):
|
||||||
metadata.get('icingaweb2/hostname'): {
|
metadata.get('icingaweb2/hostname'): {
|
||||||
'content': 'icingaweb2/vhost.conf',
|
'content': 'icingaweb2/vhost.conf',
|
||||||
'context': {
|
'context': {
|
||||||
|
'php_version': metadata.get('php/version'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,6 +4,7 @@ from shlex import quote
|
||||||
directories['/var/lib/influxdb'] = {
|
directories['/var/lib/influxdb'] = {
|
||||||
'owner': 'influxdb',
|
'owner': 'influxdb',
|
||||||
'group': 'influxdb',
|
'group': 'influxdb',
|
||||||
|
'mode': '0750',
|
||||||
'needs': [
|
'needs': [
|
||||||
'zfs_dataset:tank/influxdb',
|
'zfs_dataset:tank/influxdb',
|
||||||
],
|
],
|
||||||
|
|
|
@ -7,7 +7,17 @@ defaults = {
|
||||||
'influxdb2-cli': {},
|
'influxdb2-cli': {},
|
||||||
},
|
},
|
||||||
'sources': {
|
'sources': {
|
||||||
'deb https://repos.influxdata.com/debian {release} stable',
|
'influxdata': {
|
||||||
|
'urls': {
|
||||||
|
'https://repos.influxdata.com/debian',
|
||||||
|
},
|
||||||
|
'suites': {
|
||||||
|
'stable',
|
||||||
|
},
|
||||||
|
'components': {
|
||||||
|
'main',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'nftables': {
|
'nftables': {
|
||||||
|
|
|
@ -19,7 +19,7 @@ def apt(metadata):
|
||||||
return {
|
return {
|
||||||
'apt': {
|
'apt': {
|
||||||
'packages': {
|
'packages': {
|
||||||
f'openjdk-{metadata.get("java/version")}-jre': {},
|
f'openjdk-{metadata.get("java/version")}-jre-headless': {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
21
bundles/kea-dhcpd/items.py
Normal file
21
bundles/kea-dhcpd/items.py
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
from json import dumps
|
||||||
|
from bundlewrap.metadata import MetadataJSONEncoder
|
||||||
|
|
||||||
|
files = {
|
||||||
|
'/etc/kea/kea-dhcp4.conf': {
|
||||||
|
'content': dumps(node.metadata.get('kea'), indent=4, sort_keys=True, cls=MetadataJSONEncoder),
|
||||||
|
'triggers': [
|
||||||
|
'svc_systemd:kea-dhcp4-server:restart',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
svc_systemd = {
|
||||||
|
'kea-dhcp4-server': {
|
||||||
|
'needs': [
|
||||||
|
'pkg_apt:kea-dhcp4-server',
|
||||||
|
'file:/etc/kea/kea-dhcp4.conf',
|
||||||
|
'svc_systemd:systemd-networkd:restart',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
96
bundles/kea-dhcpd/metadata.py
Normal file
96
bundles/kea-dhcpd/metadata.py
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
from ipaddress import ip_interface, ip_network
|
||||||
|
|
||||||
|
hashable = repo.libs.hashable.hashable
|
||||||
|
|
||||||
|
|
||||||
|
defaults = {
|
||||||
|
'apt': {
|
||||||
|
'packages': {
|
||||||
|
'kea-dhcp4-server': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'kea': {
|
||||||
|
'Dhcp4': {
|
||||||
|
'interfaces-config': {
|
||||||
|
'interfaces': set(),
|
||||||
|
},
|
||||||
|
'lease-database': {
|
||||||
|
'type': 'memfile',
|
||||||
|
'lfc-interval': 3600
|
||||||
|
},
|
||||||
|
'subnet4': set(),
|
||||||
|
'loggers': set([
|
||||||
|
hashable({
|
||||||
|
'name': 'kea-dhcp4',
|
||||||
|
'output_options': [
|
||||||
|
{
|
||||||
|
'output': 'syslog',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'severity': 'INFO',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'kea/Dhcp4/interfaces-config/interfaces',
|
||||||
|
'kea/Dhcp4/subnet4',
|
||||||
|
)
|
||||||
|
def subnets(metadata):
|
||||||
|
subnet4 = set()
|
||||||
|
interfaces = set()
|
||||||
|
reservations = set(
|
||||||
|
hashable({
|
||||||
|
'hw-address': network_conf['mac'],
|
||||||
|
'ip-address': str(ip_interface(network_conf['ipv4']).ip),
|
||||||
|
})
|
||||||
|
for other_node in repo.nodes
|
||||||
|
for network_conf in other_node.metadata.get('network', {}).values()
|
||||||
|
if 'mac' in network_conf
|
||||||
|
)
|
||||||
|
|
||||||
|
for network_name, network_conf in metadata.get('network').items():
|
||||||
|
dhcp_server_config = network_conf.get('dhcp_server_config', None)
|
||||||
|
|
||||||
|
if dhcp_server_config:
|
||||||
|
_network = ip_network(dhcp_server_config['subnet'])
|
||||||
|
|
||||||
|
subnet4.add(hashable({
|
||||||
|
'subnet': dhcp_server_config['subnet'],
|
||||||
|
'pools': [
|
||||||
|
{
|
||||||
|
'pool': f'{dhcp_server_config['pool_from']} - {dhcp_server_config['pool_to']}',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'option-data': [
|
||||||
|
{
|
||||||
|
'name': 'routers',
|
||||||
|
'data': dhcp_server_config['router'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'name': 'domain-name-servers',
|
||||||
|
'data': '10.0.10.2',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'reservations': set(
|
||||||
|
reservation
|
||||||
|
for reservation in reservations
|
||||||
|
if ip_interface(reservation['ip-address']).ip in _network
|
||||||
|
),
|
||||||
|
}))
|
||||||
|
|
||||||
|
interfaces.add(network_conf.get('interface', network_name))
|
||||||
|
|
||||||
|
return {
|
||||||
|
'kea': {
|
||||||
|
'Dhcp4': {
|
||||||
|
'interfaces-config': {
|
||||||
|
'interfaces': interfaces,
|
||||||
|
},
|
||||||
|
'subnet4': subnet4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -1,36 +1,36 @@
|
||||||
hostname "CroneKorkN : ${name}"
|
hostname "CroneKorkN : ${name}"
|
||||||
sv_contact "admin@sublimity.de"
|
sv_contact "admin@sublimity.de"
|
||||||
|
|
||||||
// assign serevr to steam group
|
|
||||||
sv_steamgroup "${','.join(steamgroups)}"
|
sv_steamgroup "${','.join(steamgroups)}"
|
||||||
|
|
||||||
rcon_password "${rcon_password}"
|
rcon_password "${rcon_password}"
|
||||||
|
|
||||||
// no annoying message of the day
|
|
||||||
motd_enabled 0
|
motd_enabled 0
|
||||||
|
|
||||||
// enable cheats
|
|
||||||
sv_cheats 1
|
sv_cheats 1
|
||||||
|
|
||||||
// allow inconsistent files on clients (weapon mods for example)
|
|
||||||
sv_consistency 0
|
sv_consistency 0
|
||||||
|
|
||||||
// connect from internet
|
|
||||||
sv_lan 0
|
sv_lan 0
|
||||||
|
|
||||||
// join game at any point
|
|
||||||
sv_allow_lobby_connect_only 0
|
sv_allow_lobby_connect_only 0
|
||||||
|
|
||||||
// allowed modes
|
|
||||||
sv_gametypes "coop,realism,survival,versus,teamversus,scavenge,teamscavenge"
|
sv_gametypes "coop,realism,survival,versus,teamversus,scavenge,teamscavenge"
|
||||||
|
|
||||||
// network
|
|
||||||
sv_minrate 30000
|
sv_minrate 30000
|
||||||
sv_maxrate 60000
|
sv_maxrate 60000
|
||||||
sv_mincmdrate 66
|
sv_mincmdrate 66
|
||||||
sv_maxcmdrate 101
|
sv_maxcmdrate 101
|
||||||
|
|
||||||
// logging
|
|
||||||
sv_logsdir "logs-${name}" //Folder in the game directory where server logs will be stored.
|
sv_logsdir "logs-${name}" //Folder in the game directory where server logs will be stored.
|
||||||
log on //Creates a logfile (on | off)
|
log on //Creates a logfile (on | off)
|
||||||
sv_logecho 0 //default 0; Echo log information to the console.
|
sv_logecho 0 //default 0; Echo log information to the console.
|
||||||
|
|
|
@ -4,7 +4,7 @@ set -o pipefail
|
||||||
|
|
||||||
deploy_challenge() {
|
deploy_challenge() {
|
||||||
echo "
|
echo "
|
||||||
server 10.0.11.3
|
server ${server}
|
||||||
zone ${zone}.
|
zone ${zone}.
|
||||||
update add $1.${zone}. 60 IN TXT \"$3\"
|
update add $1.${zone}. 60 IN TXT \"$3\"
|
||||||
send
|
send
|
||||||
|
@ -13,7 +13,7 @@ deploy_challenge() {
|
||||||
|
|
||||||
clean_challenge() {
|
clean_challenge() {
|
||||||
echo "
|
echo "
|
||||||
server 10.0.11.3
|
server ${server}
|
||||||
zone ${zone}.
|
zone ${zone}.
|
||||||
update delete $1.${zone}. TXT
|
update delete $1.${zone}. TXT
|
||||||
send
|
send
|
||||||
|
|
|
@ -56,6 +56,7 @@ for domain in node.metadata.get('letsencrypt/domains').keys():
|
||||||
'unless': f'/etc/dehydrated/letsencrypt-ensure-some-certificate {domain} true',
|
'unless': f'/etc/dehydrated/letsencrypt-ensure-some-certificate {domain} true',
|
||||||
'needs': {
|
'needs': {
|
||||||
'file:/etc/dehydrated/letsencrypt-ensure-some-certificate',
|
'file:/etc/dehydrated/letsencrypt-ensure-some-certificate',
|
||||||
|
'pkg_apt:dehydrated',
|
||||||
},
|
},
|
||||||
'needed_by': {
|
'needed_by': {
|
||||||
'svc_systemd:nginx',
|
'svc_systemd:nginx',
|
||||||
|
|
41
bundles/linux/items.py
Normal file
41
bundles/linux/items.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
from shlex import quote
|
||||||
|
|
||||||
|
def generate_sysctl_key_value_pairs_from_json(json_data, parents=[]):
|
||||||
|
if isinstance(json_data, dict):
|
||||||
|
for key, value in json_data.items():
|
||||||
|
yield from generate_sysctl_key_value_pairs_from_json(value, [*parents, key])
|
||||||
|
elif isinstance(json_data, list):
|
||||||
|
raise ValueError(f"List not supported: '{json_data}'")
|
||||||
|
else:
|
||||||
|
# If it's a leaf node, yield the path
|
||||||
|
yield (parents, json_data)
|
||||||
|
|
||||||
|
key_value_pairs = generate_sysctl_key_value_pairs_from_json(node.metadata.get('sysctl'))
|
||||||
|
|
||||||
|
|
||||||
|
files= {
|
||||||
|
'/etc/sysctl.conf': {
|
||||||
|
'content': '\n'.join(
|
||||||
|
sorted(
|
||||||
|
f"{'.'.join(path)}={value}"
|
||||||
|
for path, value in key_value_pairs
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'triggers': [
|
||||||
|
'svc_systemd:systemd-sysctl.service:restart',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
svc_systemd = {
|
||||||
|
'systemd-sysctl.service': {},
|
||||||
|
}
|
||||||
|
|
||||||
|
for path, value in key_value_pairs:
|
||||||
|
actions[f'reload_sysctl.conf_{path}'] = {
|
||||||
|
'command': f"sysctl --values {'.'.join(path)} | grep -q {quote('^'+value+'$')}",
|
||||||
|
'needs': [
|
||||||
|
f'action:systemd-sysctl.service',
|
||||||
|
f'action:systemd-sysctl.service:restart',
|
||||||
|
],
|
||||||
|
}
|
3
bundles/linux/metadata.py
Normal file
3
bundles/linux/metadata.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
defaults = {
|
||||||
|
'sysctl': {},
|
||||||
|
}
|
|
@ -20,18 +20,19 @@ files = {
|
||||||
}
|
}
|
||||||
|
|
||||||
actions = {
|
actions = {
|
||||||
|
'systemd-locale': {
|
||||||
|
'command': f'localectl set-locale LANG="{default_locale}"',
|
||||||
|
'unless': f'localectl | grep -Fi "system locale" | grep -Fi "{default_locale}"',
|
||||||
|
'triggers': {
|
||||||
|
'action:locale-gen',
|
||||||
|
},
|
||||||
|
},
|
||||||
'locale-gen': {
|
'locale-gen': {
|
||||||
'command': 'locale-gen',
|
'command': 'locale-gen',
|
||||||
'triggered': True,
|
'triggered': True,
|
||||||
'needs': {
|
'needs': {
|
||||||
'pkg_apt:locales',
|
'pkg_apt:locales',
|
||||||
},
|
'action:systemd-locale',
|
||||||
},
|
|
||||||
'systemd-locale': {
|
|
||||||
'command': f'localectl set-locale LANG="{default_locale}"',
|
|
||||||
'unless': f'localectl | grep -Fi "system locale" | grep -Fi "{default_locale}"',
|
|
||||||
'preceded_by': {
|
|
||||||
'action:locale-gen',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
6
bundles/macbook/files/bundlewrap
Normal file
6
bundles/macbook/files/bundlewrap
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
cd "$OLDPWD"
|
||||||
|
|
||||||
|
export BW_ITEM_WORKERS=$(expr "$(sysctl -n hw.logicalcpu)" '*' 12 '/' 10)
|
||||||
|
export BW_NODE_WORKERS=$(expr 320 '/' "$BW_ITEM_WORKERS")
|
6
bundles/macbook/files/gnu
Normal file
6
bundles/macbook/files/gnu
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
cd "$OLDPWD"
|
||||||
|
|
||||||
|
PATH_add "/opt/homebrew/opt/gnu-sed/libexec/gnubin"
|
||||||
|
PATH_add "/opt/homebrew/opt/grep/libexec/gnubin"
|
|
@ -1,5 +1,16 @@
|
||||||
#!/bin/bash -l
|
#!/bin/bash -l
|
||||||
|
|
||||||
|
sudo tee /etc/pam.d/sudo << EOT
|
||||||
|
# sudo: auth account password session
|
||||||
|
auth sufficient pam_tid.so
|
||||||
|
auth sufficient pam_smartcard.so
|
||||||
|
auth required pam_opendirectory.so
|
||||||
|
account required pam_permit.so
|
||||||
|
password required pam_deny.so
|
||||||
|
session required pam_permit.so
|
||||||
|
EOT
|
||||||
|
|
||||||
|
sudo xcodebuild -license accept
|
||||||
xcode-select --install
|
xcode-select --install
|
||||||
|
|
||||||
git -C ~/.zsh/oh-my-zsh pull
|
git -C ~/.zsh/oh-my-zsh pull
|
||||||
|
@ -7,6 +18,8 @@ git -C ~/.zsh/oh-my-zsh pull
|
||||||
brew upgrade
|
brew upgrade
|
||||||
brew upgrade --cask --greedy
|
brew upgrade --cask --greedy
|
||||||
|
|
||||||
|
pyenv install --skip-existing
|
||||||
|
|
||||||
sudo softwareupdate -ia --verbose
|
sudo softwareupdate -ia --verbose
|
||||||
|
|
||||||
if test "$(defaults read com.apple.dock autohide-time-modifier)" == 0.16
|
if test "$(defaults read com.apple.dock autohide-time-modifier)" == 0.16
|
||||||
|
@ -29,3 +42,5 @@ fi
|
||||||
sudo systemsetup -setremotelogin on # enable ssh
|
sudo systemsetup -setremotelogin on # enable ssh
|
||||||
|
|
||||||
pip install --upgrade pip
|
pip install --upgrade pip
|
||||||
|
|
||||||
|
# https://sysadmin-journal.com/apache-directory-studio-on-the-apple-m1/
|
||||||
|
|
9
bundles/macbook/files/pyenv
Normal file
9
bundles/macbook/files/pyenv
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
cd "$OLDPWD"
|
||||||
|
|
||||||
|
if test -f .venv/bin/python && test "$(realpath .venv/bin/python)" != "$(realpath "$(pyenv which python)")"
|
||||||
|
then
|
||||||
|
echo "rebuilding venv für new python version"
|
||||||
|
rm -rf .venv .pip_upgrade_timestamp
|
||||||
|
fi
|
3
bundles/macbook/files/ssh
Normal file
3
bundles/macbook/files/ssh
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
cd "$OLDPWD"
|
27
bundles/macbook/files/venv
Normal file
27
bundles/macbook/files/venv
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
cd "$OLDPWD"
|
||||||
|
|
||||||
|
python3 -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
PATH_add .venv/bin
|
||||||
|
|
||||||
|
NOW=$(date +%s)
|
||||||
|
if test -e .pip_upgrade_timestamp
|
||||||
|
then
|
||||||
|
LAST=$(cat .pip_upgrade_timestamp)
|
||||||
|
else
|
||||||
|
LAST=0
|
||||||
|
fi
|
||||||
|
DELTA=$(expr "$NOW" - "$LAST")
|
||||||
|
echo "last pip upgrade $DELTA seconds ago"
|
||||||
|
if test "$DELTA" -gt 86400
|
||||||
|
then
|
||||||
|
python3 -m pip --require-virtualenv install pip wheel --upgrade
|
||||||
|
python3 -m pip --require-virtualenv install -r requirements.txt --upgrade
|
||||||
|
if test -e optional-requirements.txt
|
||||||
|
then
|
||||||
|
python3 -m pip --require-virtualenv install -r optional-requirements.txt --upgrade
|
||||||
|
fi
|
||||||
|
date +%s > .pip_upgrade_timestamp
|
||||||
|
fi
|
33
bundles/macbook/files/zshrc
Normal file
33
bundles/macbook/files/zshrc
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
export PATH=~/.bin:$PATH
|
||||||
|
export PATH=~/.cargo/bin:$PATH
|
||||||
|
|
||||||
|
export ZSH=~/.zsh/oh-my-zsh
|
||||||
|
export ZSH_HOSTNAME='sm'
|
||||||
|
ZSH_THEME="bw"
|
||||||
|
HIST_STAMPS="yyyy/mm/dd"
|
||||||
|
plugins=(
|
||||||
|
zsh-autosuggestions
|
||||||
|
git
|
||||||
|
)
|
||||||
|
source $ZSH/oh-my-zsh.sh
|
||||||
|
|
||||||
|
ulimit -S -n 24000
|
||||||
|
|
||||||
|
antivir() {
|
||||||
|
printf 'scanning for viruses' && sleep 1 && printf '.' && sleep 1 && printf '.' && sleep 1 && printf '.' &&
|
||||||
|
sleep 1 && echo '\nyour computer is safe!'
|
||||||
|
}
|
||||||
|
|
||||||
|
eval "$(rbenv init -)"
|
||||||
|
eval "$(pyenv init -)"
|
||||||
|
eval "$(direnv hook zsh)"
|
||||||
|
eval "$(op completion zsh)"; compdef _op op
|
||||||
|
|
||||||
|
# //S/M
|
||||||
|
|
||||||
|
sshn() {
|
||||||
|
ssh "$(tr '.' ' ' <<< "$1" | tac -s ' ' | xargs | tr ' ' '.').smhss.de"
|
||||||
|
}
|
||||||
|
pingn() {
|
||||||
|
ping "$(tr '.' ' ' <<< "$1" | tac -s ' ' | xargs | tr ' ' '.').smhss.de"
|
||||||
|
}
|
|
@ -1,9 +1,42 @@
|
||||||
|
# brew install
|
||||||
|
|
||||||
|
actions['brew_install'] = {
|
||||||
|
'command': '/opt/homebrew/bin/brew install ' + ' '.join(node.metadata.get('brew')),
|
||||||
|
'unless': f"""PKGS=$(/opt/homebrew/bin/brew leaves); for p in {' '.join(node.metadata.get('brew'))}; do grep -q "$p" <<< $PKGS || exit 9; done"""
|
||||||
|
}
|
||||||
|
|
||||||
|
# bw init
|
||||||
|
|
||||||
directories['/Users/mwiegand/.config/bundlewrap/lock'] = {}
|
directories['/Users/mwiegand/.config/bundlewrap/lock'] = {}
|
||||||
|
|
||||||
|
# home
|
||||||
|
|
||||||
|
files['/Users/mwiegand/.zshrc'] = {
|
||||||
|
'source': 'zshrc',
|
||||||
|
'mode': '0644',
|
||||||
|
}
|
||||||
|
|
||||||
|
# updater
|
||||||
|
|
||||||
files['/Users/mwiegand/.bin/macbook-update'] = {
|
files['/Users/mwiegand/.bin/macbook-update'] = {
|
||||||
'mode': '755',
|
'mode': '755',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with open(f'{repo.path}/bundles/zsh/files/bw.zsh-theme') as f:
|
||||||
|
files['/Users/mwiegand/.zsh/oh-my-zsh/themes/bw.zsh-theme'] = {
|
||||||
|
'content': f.read(),
|
||||||
|
'mode': '0644',
|
||||||
|
}
|
||||||
|
|
||||||
|
# direnv
|
||||||
|
|
||||||
|
directories['/Users/mwiegand/.local/share/direnv'] = {}
|
||||||
|
files['/Users/mwiegand/.local/share/direnv/gnu'] = {}
|
||||||
|
files['/Users/mwiegand/.local/share/direnv/pyenv'] = {}
|
||||||
|
files['/Users/mwiegand/.local/share/direnv/venv'] = {}
|
||||||
|
files['/Users/mwiegand/.local/share/direnv/bundlewrap'] = {}
|
||||||
|
|
||||||
|
|
||||||
##################
|
##################
|
||||||
|
|
||||||
for element in [*files.values(), *directories.values()]:
|
for element in [*files.values(), *directories.values()]:
|
||||||
|
|
|
@ -1 +1,3 @@
|
||||||
defaults = {}
|
defaults = {
|
||||||
|
'brew': {},
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// https://raw.githubusercontent.com/Radiergummi/autodiscover/master/autodiscover/autodiscover.php
|
|
||||||
|
|
||||||
/********************************
|
/********************************
|
||||||
* Autodiscover responder
|
* Autodiscover responder
|
||||||
|
@ -8,45 +8,45 @@
|
||||||
* This PHP script is intended to respond to any request to http(s)://mydomain.com/autodiscover/autodiscover.xml.
|
* This PHP script is intended to respond to any request to http(s)://mydomain.com/autodiscover/autodiscover.xml.
|
||||||
* If configured properly, it will send a spec-complient autodiscover XML response, pointing mail clients to the
|
* If configured properly, it will send a spec-complient autodiscover XML response, pointing mail clients to the
|
||||||
* appropriate mail services.
|
* appropriate mail services.
|
||||||
* If you use MAPI or ActiveSync, stick with the Autodiscover service your mail server provides for you. But if
|
* If you use MAPI or ActiveSync, stick with the Autodiscover service your mail server provides for you. But if
|
||||||
* you use POP/IMAP servers, this will provide autoconfiguration to Outlook, Apple Mail and mobile devices.
|
* you use POP/IMAP servers, this will provide autoconfiguration to Outlook, Apple Mail and mobile devices.
|
||||||
*
|
*
|
||||||
* To work properly, you'll need to set the service (sub)domains below in the settings section to the correct
|
* To work properly, you'll need to set the service (sub)domains below in the settings section to the correct
|
||||||
* domain names, adjust ports and SSL.
|
* domain names, adjust ports and SSL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//get raw POST data so we can extract the email address
|
|
||||||
$request = file_get_contents("php://input");
|
$request = file_get_contents("php://input");
|
||||||
|
|
||||||
// optional debug log
|
|
||||||
# file_put_contents( 'request.log', $request, FILE_APPEND );
|
# file_put_contents( 'request.log', $request, FILE_APPEND );
|
||||||
|
|
||||||
// retrieve email address from client request
|
|
||||||
preg_match( "/\<EMailAddress\>(.*?)\<\/EMailAddress\>/", $request, $email );
|
preg_match( "/\<EMailAddress\>(.*?)\<\/EMailAddress\>/", $request, $email );
|
||||||
|
|
||||||
// check for invalid mail, to prevent XSS
|
|
||||||
if (filter_var($email[1], FILTER_VALIDATE_EMAIL) === false) {
|
if (filter_var($email[1], FILTER_VALIDATE_EMAIL) === false) {
|
||||||
throw new Exception('Invalid E-Mail provided');
|
throw new Exception('Invalid E-Mail provided');
|
||||||
}
|
}
|
||||||
|
|
||||||
// get domain from email address
|
|
||||||
$domain = substr( strrchr( $email[1], "@" ), 1 );
|
$domain = substr( strrchr( $email[1], "@" ), 1 );
|
||||||
|
|
||||||
/**************************************
|
/**************************************
|
||||||
* Port and server settings below *
|
* Port and server settings below *
|
||||||
**************************************/
|
**************************************/
|
||||||
|
|
||||||
// IMAP settings
|
|
||||||
$imapServer = 'imap.' . $domain; // imap.example.com
|
$imapServer = 'imap.' . $domain; // imap.example.com
|
||||||
$imapPort = 993;
|
$imapPort = 993;
|
||||||
$imapSSL = true;
|
$imapSSL = true;
|
||||||
|
|
||||||
// SMTP settings
|
|
||||||
$smtpServer = 'smtp.' . $domain; // smtp.example.com
|
$smtpServer = 'smtp.' . $domain; // smtp.example.com
|
||||||
$smtpPort = 587;
|
$smtpPort = 587;
|
||||||
$smtpSSL = true;
|
$smtpSSL = true;
|
||||||
|
|
||||||
//set Content-Type
|
|
||||||
header( 'Content-Type: application/xml' );
|
header( 'Content-Type: application/xml' );
|
||||||
?>
|
?>
|
||||||
<?php echo '<?xml version="1.0" encoding="utf-8" ?>'; ?>
|
<?php echo '<?xml version="1.0" encoding="utf-8" ?>'; ?>
|
||||||
|
|
|
@ -33,6 +33,12 @@ defaults = {
|
||||||
'mountpoint': '/var/vmail',
|
'mountpoint': '/var/vmail',
|
||||||
'compression': 'on',
|
'compression': 'on',
|
||||||
},
|
},
|
||||||
|
'tank/vmail/index': {
|
||||||
|
'mountpoint': '/var/vmail/index',
|
||||||
|
'compression': 'on',
|
||||||
|
'com.sun:auto-snapshot': 'false',
|
||||||
|
'backup': False,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -43,12 +49,30 @@ defaults = {
|
||||||
)
|
)
|
||||||
def dns(metadata):
|
def dns(metadata):
|
||||||
dns = {}
|
dns = {}
|
||||||
|
|
||||||
for domain in metadata.get('mailserver/domains'):
|
for domain in metadata.get('mailserver/domains'):
|
||||||
dns[domain] = {
|
dns[domain] = {
|
||||||
'MX': [f"5 {metadata.get('mailserver/hostname')}."],
|
'MX': [f"5 {metadata.get('mailserver/hostname')}."],
|
||||||
'TXT': ['v=spf1 a mx -all'],
|
'TXT': ['v=spf1 a mx -all'],
|
||||||
}
|
}
|
||||||
|
report_email = metadata.get('mailserver/dmarc_report_email')
|
||||||
|
dns[f'_dmarc.{domain}'] = {
|
||||||
|
'TXT': ['; '.join(f'{k}={v}' for k, v in {
|
||||||
|
# dmarc version
|
||||||
|
'v': 'DMARC1',
|
||||||
|
# reject on failure
|
||||||
|
'p': 'reject',
|
||||||
|
# standard reports
|
||||||
|
'rua': f'mailto:{report_email}',
|
||||||
|
# forensic reports
|
||||||
|
'fo': 1,
|
||||||
|
'ruf': f'mailto:{report_email}',
|
||||||
|
# require alignment between the DKIM domain and the parent Header From domain
|
||||||
|
'adkim': 's',
|
||||||
|
# require alignment between the SPF domain (the sender) and the Header From domain
|
||||||
|
'aspf': 's',
|
||||||
|
}.items())]
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'dns': dns,
|
'dns': dns,
|
||||||
|
@ -66,4 +90,4 @@ def letsencrypt(metadata):
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
1
bundles/mariadb/README.md
Normal file
1
bundles/mariadb/README.md
Normal file
|
@ -0,0 +1 @@
|
||||||
|
https://mariadb.com/kb/en/systemd/#configuring-mariadb-to-write-the-error-log-to-syslog
|
11
bundles/mariadb/files/override.conf
Normal file
11
bundles/mariadb/files/override.conf
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
% for section, options in sorted(conf.items()):
|
||||||
|
[${section}]
|
||||||
|
% for key, value in sorted(options.items()):
|
||||||
|
% if value is None:
|
||||||
|
${key}
|
||||||
|
% else:
|
||||||
|
${key} = ${value}
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
% endfor
|
91
bundles/mariadb/items.py
Normal file
91
bundles/mariadb/items.py
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
from shlex import quote
|
||||||
|
|
||||||
|
def mariadb(sql, **kwargs):
|
||||||
|
kwargs_string = ''.join(f" --{k} {v}" for k, v in kwargs.items())
|
||||||
|
return f"mariadb{kwargs_string} -Bsr --execute {quote(sql)}"
|
||||||
|
|
||||||
|
directories = {
|
||||||
|
'/var/lib/mysql': {
|
||||||
|
'owner': 'mysql',
|
||||||
|
'group': 'mysql',
|
||||||
|
'needs': [
|
||||||
|
'zfs_dataset:tank/mariadb',
|
||||||
|
],
|
||||||
|
'needed_by': [
|
||||||
|
'pkg_apt:mariadb-server',
|
||||||
|
'pkg_apt:mariadb-client',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
files = {
|
||||||
|
'/etc/mysql/conf.d/override.conf': {
|
||||||
|
'context': {
|
||||||
|
'conf': node.metadata.get('mariadb/conf'),
|
||||||
|
},
|
||||||
|
'content_type': 'mako',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
svc_systemd = {
|
||||||
|
'mariadb.service': {
|
||||||
|
'needs': [
|
||||||
|
'pkg_apt:mariadb-server',
|
||||||
|
'pkg_apt:mariadb-client',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
actions = {
|
||||||
|
'mariadb_sec_remove_anonymous_users': {
|
||||||
|
'command': mariadb("DELETE FROM mysql.global_priv WHERE User=''"),
|
||||||
|
'unless': mariadb("SELECT count(0) FROM mysql.global_priv WHERE User = ''") + " | grep -q '^0$'",
|
||||||
|
'needs': [
|
||||||
|
'svc_systemd:mariadb.service',
|
||||||
|
],
|
||||||
|
'triggers': [
|
||||||
|
'svc_systemd:mariadb.service:restart',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'mariadb_sec_remove_remote_root': {
|
||||||
|
'command': mariadb("DELETE FROM mysql.global_priv WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')"),
|
||||||
|
'unless': mariadb("SELECT count(0) FROM mysql.global_priv WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')") + " | grep -q '^0$'",
|
||||||
|
'needs': [
|
||||||
|
'svc_systemd:mariadb.service',
|
||||||
|
],
|
||||||
|
'triggers': [
|
||||||
|
'svc_systemd:mariadb.service:restart',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for db, conf in node.metadata.get('mariadb/databases', {}).items():
|
||||||
|
actions[f'mariadb_create_database_{db}'] = {
|
||||||
|
'command': mariadb(f"CREATE DATABASE {db}"),
|
||||||
|
'unless': mariadb(f"SHOW DATABASES LIKE '{db}'") + f" | grep -q '^{db}$'",
|
||||||
|
'needs': [
|
||||||
|
'svc_systemd:mariadb.service',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
actions[f'mariadb_user_{db}_create'] = {
|
||||||
|
'command': mariadb(f"CREATE USER {db}"),
|
||||||
|
'unless': mariadb(f"SELECT User FROM mysql.user WHERE User = '{db}'") + f" | grep -q '^{db}$'",
|
||||||
|
'needs': [
|
||||||
|
f'action:mariadb_create_database_{db}',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
pw = conf['password']
|
||||||
|
actions[f'mariadb_user_{db}_password'] = {
|
||||||
|
'command': mariadb(f"SET PASSWORD FOR {db} = PASSWORD('{conf['password']}')"),
|
||||||
|
'unless': f'echo {quote(pw)} | mariadb -u {db} -e quit -p',
|
||||||
|
'needs': [
|
||||||
|
f'action:mariadb_user_{db}_create',
|
||||||
|
],
|
||||||
|
}
|
||||||
|
actions[f'mariadb_grant_privileges_to_{db}'] = {
|
||||||
|
'command': mariadb(f"GRANT ALL PRIVILEGES ON {db}.* TO '{db}'", database=db),
|
||||||
|
'unless': mariadb(f"SHOW GRANTS FOR {db}") + f" | grep -q '^GRANT ALL PRIVILEGES ON `{db}`.* TO `{db}`@`%`'",
|
||||||
|
'needs': [
|
||||||
|
f'action:mariadb_user_{db}_create',
|
||||||
|
],
|
||||||
|
}
|
45
bundles/mariadb/metadata.py
Normal file
45
bundles/mariadb/metadata.py
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
defaults = {
|
||||||
|
'apt': {
|
||||||
|
'packages': {
|
||||||
|
'mariadb-server': {
|
||||||
|
'needs': {
|
||||||
|
'zfs_dataset:tank/mariadb',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'mariadb-client': {
|
||||||
|
'needs': {
|
||||||
|
'zfs_dataset:tank/mariadb',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'mariadb': {
|
||||||
|
'databases': {},
|
||||||
|
'conf': {
|
||||||
|
# https://www.reddit.com/r/zfs/comments/u1xklc/mariadbmysql_database_settings_for_zfs
|
||||||
|
'mysqld': {
|
||||||
|
'skip-innodb_doublewrite': None,
|
||||||
|
'innodb_flush_method': 'fsync',
|
||||||
|
'innodb_doublewrite': '0',
|
||||||
|
'innodb_use_atomic_writes': '0',
|
||||||
|
'innodb_use_native_aio': '0',
|
||||||
|
'innodb_read_io_threads': '10',
|
||||||
|
'innodb_write_io_threads': '10',
|
||||||
|
'innodb_buffer_pool_size': '26G',
|
||||||
|
'innodb_flush_log_at_trx_commit': '1',
|
||||||
|
'innodb_log_file_size': '1G',
|
||||||
|
'innodb_flush_neighbors': '0',
|
||||||
|
'innodb_fast_shutdown': '2',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'zfs': {
|
||||||
|
'datasets': {
|
||||||
|
'tank/mariadb': {
|
||||||
|
'mountpoint': '/var/lib/mysql',
|
||||||
|
'recordsize': '16384',
|
||||||
|
'atime': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
|
@ -5,38 +5,89 @@ defaults = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'network',
|
||||||
|
)
|
||||||
|
def dhcp(metadata):
|
||||||
|
networks = {}
|
||||||
|
|
||||||
|
for network_name, network_conf in metadata.get('network').items():
|
||||||
|
_interface = ip_interface(network_conf['ipv4'])
|
||||||
|
_ip = _interface.ip
|
||||||
|
_network = _interface.network
|
||||||
|
_hosts = list(_network.hosts())
|
||||||
|
|
||||||
|
if network_conf.get('dhcp_server', False):
|
||||||
|
networks[network_name] = {
|
||||||
|
'dhcp_server_config': {
|
||||||
|
'subnet': str(_network),
|
||||||
|
'pool_from': str(_hosts[len(_hosts)//2]),
|
||||||
|
'pool_to': str(_hosts[-3]),
|
||||||
|
'router': str(_ip),
|
||||||
|
'domain-name-servers': str(_ip),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
'network': networks,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
@metadata_reactor.provides(
|
||||||
'systemd/units',
|
'systemd/units',
|
||||||
)
|
)
|
||||||
def units(metadata):
|
def units(metadata):
|
||||||
units = {}
|
units = {}
|
||||||
|
|
||||||
for type, network in metadata.get('network').items():
|
for network_name, network_conf in metadata.get('network').items():
|
||||||
units[f'{type}.network'] = {
|
interface_type = network_conf.get('type', None)
|
||||||
|
|
||||||
|
# network
|
||||||
|
|
||||||
|
units[f'{network_name}.network'] = {
|
||||||
'Match': {
|
'Match': {
|
||||||
'Name': network['interface'],
|
'Name': network_name if interface_type == 'vlan' else network_conf['interface'],
|
||||||
},
|
},
|
||||||
'Network': {
|
'Network': {
|
||||||
'DHCP': 'no',
|
'DHCP': network_conf.get('dhcp', 'no'),
|
||||||
'IPv6AcceptRA': 'no',
|
'IPv6AcceptRA': network_conf.get('dhcp', 'no'),
|
||||||
|
'VLAN': set(network_conf.get('vlans', set()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# type
|
||||||
|
|
||||||
|
if interface_type:
|
||||||
|
units[f'{network_name}.network']['Match']['Type'] = interface_type
|
||||||
|
|
||||||
|
# ips
|
||||||
|
|
||||||
for i in [4, 6]:
|
for i in [4, 6]:
|
||||||
if network.get(f'ipv{i}', None):
|
if network_conf.get(f'ipv{i}', None):
|
||||||
units[f'{type}.network'].update({
|
units[f'{network_name}.network'].update({
|
||||||
f'Address#ipv{i}': {
|
f'Address#ipv{i}': {
|
||||||
'Address': network[f'ipv{i}'],
|
'Address': network_conf[f'ipv{i}'],
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if f'gateway{i}' in network:
|
if f'gateway{i}' in network_conf:
|
||||||
units[f'{type}.network'].update({
|
units[f'{network_name}.network'].update({
|
||||||
f'Route#ipv{i}': {
|
f'Route#ipv{i}': {
|
||||||
'Gateway': network[f'gateway{i}'],
|
'Gateway': network_conf[f'gateway{i}'],
|
||||||
'GatewayOnlink': 'yes',
|
'GatewayOnlink': 'yes',
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# as vlan
|
||||||
|
|
||||||
|
if interface_type == 'vlan':
|
||||||
|
units[f"{network_name}.netdev"] = {
|
||||||
|
'NetDev': {
|
||||||
|
'Name': network_name,
|
||||||
|
'Kind': 'vlan',
|
||||||
|
},
|
||||||
|
'VLAN': {
|
||||||
|
'Id': network_conf['id'],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'systemd': {
|
'systemd': {
|
||||||
|
|
|
@ -29,8 +29,8 @@ defaults = {
|
||||||
'exclude': [
|
'exclude': [
|
||||||
'^appdata_',
|
'^appdata_',
|
||||||
'^updater-',
|
'^updater-',
|
||||||
'^nextcloud\.log',
|
'^nextcloud\\.log',
|
||||||
'^updater\.log',
|
'^updater\\.log',
|
||||||
'^[^/]+/cache',
|
'^[^/]+/cache',
|
||||||
'^[^/]+/files_versions',
|
'^[^/]+/files_versions',
|
||||||
'^[^/]+/files_trashbin',
|
'^[^/]+/files_trashbin',
|
||||||
|
@ -123,9 +123,9 @@ def config(metadata):
|
||||||
],
|
],
|
||||||
'cache_path': '/var/lib/nextcloud/.cache',
|
'cache_path': '/var/lib/nextcloud/.cache',
|
||||||
'upgrade.disable-web': True,
|
'upgrade.disable-web': True,
|
||||||
'memcache.local': '\OC\Memcache\Redis',
|
'memcache.local': '\\OC\\Memcache\\Redis',
|
||||||
'memcache.locking': '\OC\Memcache\Redis',
|
'memcache.locking': '\\OC\\Memcache\\Redis',
|
||||||
'memcache.distributed': '\OC\Memcache\Redis',
|
'memcache.distributed': '\\OC\\Memcache\\Redis',
|
||||||
'redis': {
|
'redis': {
|
||||||
'host': '/var/run/redis/nextcloud.sock'
|
'host': '/var/run/redis/nextcloud.sock'
|
||||||
},
|
},
|
||||||
|
@ -142,6 +142,7 @@ def config(metadata):
|
||||||
'versions_retention_obligation': 'auto, 90',
|
'versions_retention_obligation': 'auto, 90',
|
||||||
'simpleSignUpLink.shown': False,
|
'simpleSignUpLink.shown': False,
|
||||||
'allow_local_remote_servers': True, # FIXME?
|
'allow_local_remote_servers': True, # FIXME?
|
||||||
|
'maintenance_window_start': 1, # https://docs.nextcloud.com/server/29/admin_manual/configuration_server/background_jobs_configuration.html#maintenance-window-start
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,12 @@ defaults = {
|
||||||
'tcp dport 1936 accept',
|
'tcp dport 1936 accept',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'nginx': {
|
||||||
|
'modules': {
|
||||||
|
'rtmp',
|
||||||
|
'stream',
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,12 @@ fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
|
||||||
|
|
||||||
fastcgi_param REMOTE_ADDR $remote_addr;
|
fastcgi_param REMOTE_ADDR $remote_addr;
|
||||||
fastcgi_param REMOTE_PORT $remote_port;
|
fastcgi_param REMOTE_PORT $remote_port;
|
||||||
|
fastcgi_param REMOTE_USER $remote_user;
|
||||||
fastcgi_param SERVER_ADDR $server_addr;
|
fastcgi_param SERVER_ADDR $server_addr;
|
||||||
fastcgi_param SERVER_PORT $server_port;
|
fastcgi_param SERVER_PORT $server_port;
|
||||||
fastcgi_param SERVER_NAME $server_name;
|
fastcgi_param SERVER_NAME $server_name;
|
||||||
|
|
||||||
|
# PHP only, required if PHP was built with --enable-force-cgi-redirect
|
||||||
fastcgi_param REDIRECT_STATUS 200;
|
fastcgi_param REDIRECT_STATUS 200;
|
||||||
|
|
||||||
# This is the only thing that's different to the debian default.
|
# This is the only thing that's different to the debian default.
|
95
bundles/nginx/files/mime.types
Normal file
95
bundles/nginx/files/mime.types
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
types {
|
||||||
|
text/html html htm shtml;
|
||||||
|
text/css css;
|
||||||
|
text/xml xml;
|
||||||
|
image/gif gif;
|
||||||
|
image/jpeg jpeg jpg;
|
||||||
|
application/javascript js;
|
||||||
|
application/atom+xml atom;
|
||||||
|
application/rss+xml rss;
|
||||||
|
|
||||||
|
text/mathml mml;
|
||||||
|
text/plain txt;
|
||||||
|
text/vnd.sun.j2me.app-descriptor jad;
|
||||||
|
text/vnd.wap.wml wml;
|
||||||
|
text/x-component htc;
|
||||||
|
|
||||||
|
image/avif avif;
|
||||||
|
image/png png;
|
||||||
|
image/svg+xml svg svgz;
|
||||||
|
image/tiff tif tiff;
|
||||||
|
image/vnd.wap.wbmp wbmp;
|
||||||
|
image/webp webp;
|
||||||
|
image/x-icon ico;
|
||||||
|
image/x-jng jng;
|
||||||
|
image/x-ms-bmp bmp;
|
||||||
|
|
||||||
|
font/woff woff;
|
||||||
|
font/woff2 woff2;
|
||||||
|
|
||||||
|
application/java-archive jar war ear;
|
||||||
|
application/json json;
|
||||||
|
application/mac-binhex40 hqx;
|
||||||
|
application/msword doc;
|
||||||
|
application/pdf pdf;
|
||||||
|
application/postscript ps eps ai;
|
||||||
|
application/rtf rtf;
|
||||||
|
application/vnd.apple.mpegurl m3u8;
|
||||||
|
application/vnd.google-earth.kml+xml kml;
|
||||||
|
application/vnd.google-earth.kmz kmz;
|
||||||
|
application/vnd.ms-excel xls;
|
||||||
|
application/vnd.ms-fontobject eot;
|
||||||
|
application/vnd.ms-powerpoint ppt;
|
||||||
|
application/vnd.oasis.opendocument.graphics odg;
|
||||||
|
application/vnd.oasis.opendocument.presentation odp;
|
||||||
|
application/vnd.oasis.opendocument.spreadsheet ods;
|
||||||
|
application/vnd.oasis.opendocument.text odt;
|
||||||
|
application/vnd.openxmlformats-officedocument.presentationml.presentation pptx;
|
||||||
|
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx;
|
||||||
|
application/vnd.openxmlformats-officedocument.wordprocessingml.document docx;
|
||||||
|
application/vnd.wap.wmlc wmlc;
|
||||||
|
application/wasm wasm;
|
||||||
|
application/x-7z-compressed 7z;
|
||||||
|
application/x-cocoa cco;
|
||||||
|
application/x-java-archive-diff jardiff;
|
||||||
|
application/x-java-jnlp-file jnlp;
|
||||||
|
application/x-makeself run;
|
||||||
|
application/x-perl pl pm;
|
||||||
|
application/x-pilot prc pdb;
|
||||||
|
application/x-rar-compressed rar;
|
||||||
|
application/x-redhat-package-manager rpm;
|
||||||
|
application/x-sea sea;
|
||||||
|
application/x-shockwave-flash swf;
|
||||||
|
application/x-stuffit sit;
|
||||||
|
application/x-tcl tcl tk;
|
||||||
|
application/x-x509-ca-cert der pem crt;
|
||||||
|
application/x-xpinstall xpi;
|
||||||
|
application/xhtml+xml xhtml;
|
||||||
|
application/xspf+xml xspf;
|
||||||
|
application/zip zip;
|
||||||
|
|
||||||
|
application/octet-stream bin exe dll;
|
||||||
|
application/octet-stream deb;
|
||||||
|
application/octet-stream dmg;
|
||||||
|
application/octet-stream iso img;
|
||||||
|
application/octet-stream msi msp msm;
|
||||||
|
|
||||||
|
audio/midi mid midi kar;
|
||||||
|
audio/mpeg mp3;
|
||||||
|
audio/ogg ogg;
|
||||||
|
audio/x-m4a m4a;
|
||||||
|
audio/x-realaudio ra;
|
||||||
|
|
||||||
|
video/3gpp 3gpp 3gp;
|
||||||
|
video/mp2t ts;
|
||||||
|
video/mp4 mp4;
|
||||||
|
video/mpeg mpeg mpg;
|
||||||
|
video/quicktime mov;
|
||||||
|
video/webm webm;
|
||||||
|
video/x-flv flv;
|
||||||
|
video/x-m4v m4v;
|
||||||
|
video/x-mng mng;
|
||||||
|
video/x-ms-asf asx asf;
|
||||||
|
video/x-ms-wmv wmv;
|
||||||
|
video/x-msvideo avi;
|
||||||
|
}
|
|
@ -1,8 +1,11 @@
|
||||||
pid /var/run/nginx.pid;
|
pid /var/run/nginx.pid;
|
||||||
user www-data;
|
user www-data;
|
||||||
worker_processes 10;
|
worker_processes ${worker_processes};
|
||||||
|
|
||||||
|
% for module in sorted(modules):
|
||||||
|
load_module modules/ngx_${module}_module.so;
|
||||||
|
% endfor
|
||||||
|
|
||||||
include /etc/nginx/modules-enabled/*;
|
|
||||||
include /etc/nginx/conf.d/*;
|
include /etc/nginx/conf.d/*;
|
||||||
|
|
||||||
events {
|
events {
|
||||||
|
@ -18,6 +21,9 @@ http {
|
||||||
server_names_hash_bucket_size 128;
|
server_names_hash_bucket_size 128;
|
||||||
tcp_nopush on;
|
tcp_nopush on;
|
||||||
client_max_body_size 32G;
|
client_max_body_size 32G;
|
||||||
|
ssl_dhparam "/etc/ssl/certs/dhparam.pem";
|
||||||
|
# dont show nginx version
|
||||||
|
server_tokens off;
|
||||||
|
|
||||||
% if node.has_bundle('php'):
|
% if node.has_bundle('php'):
|
||||||
upstream php-handler {
|
upstream php-handler {
|
||||||
|
|
4
bundles/nginx/files/proxy
Normal file
4
bundles/nginx/files/proxy
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
16
bundles/nginx/files/scgi
Normal file
16
bundles/nginx/files/scgi
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
scgi_param REQUEST_METHOD $request_method;
|
||||||
|
scgi_param REQUEST_URI $request_uri;
|
||||||
|
scgi_param QUERY_STRING $query_string;
|
||||||
|
scgi_param CONTENT_TYPE $content_type;
|
||||||
|
|
||||||
|
scgi_param DOCUMENT_URI $document_uri;
|
||||||
|
scgi_param DOCUMENT_ROOT $document_root;
|
||||||
|
scgi_param SCGI 1;
|
||||||
|
scgi_param SERVER_PROTOCOL $server_protocol;
|
||||||
|
scgi_param REQUEST_SCHEME $scheme;
|
||||||
|
scgi_param HTTPS $https if_not_empty;
|
||||||
|
|
||||||
|
scgi_param REMOTE_ADDR $remote_addr;
|
||||||
|
scgi_param REMOTE_PORT $remote_port;
|
||||||
|
scgi_param SERVER_PORT $server_port;
|
||||||
|
scgi_param SERVER_NAME $server_name;
|
16
bundles/nginx/files/uwsgi
Normal file
16
bundles/nginx/files/uwsgi
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
uwsgi_param QUERY_STRING $query_string;
|
||||||
|
uwsgi_param REQUEST_METHOD $request_method;
|
||||||
|
uwsgi_param CONTENT_TYPE $content_type;
|
||||||
|
uwsgi_param CONTENT_LENGTH $content_length;
|
||||||
|
|
||||||
|
uwsgi_param REQUEST_URI $request_uri;
|
||||||
|
uwsgi_param PATH_INFO $document_uri;
|
||||||
|
uwsgi_param DOCUMENT_ROOT $document_root;
|
||||||
|
uwsgi_param SERVER_PROTOCOL $server_protocol;
|
||||||
|
uwsgi_param REQUEST_SCHEME $scheme;
|
||||||
|
uwsgi_param HTTPS $https if_not_empty;
|
||||||
|
|
||||||
|
uwsgi_param REMOTE_ADDR $remote_addr;
|
||||||
|
uwsgi_param REMOTE_PORT $remote_port;
|
||||||
|
uwsgi_param SERVER_PORT $server_port;
|
||||||
|
uwsgi_param SERVER_NAME $server_name;
|
|
@ -3,25 +3,26 @@ from mako.template import Template
|
||||||
from os.path import join
|
from os.path import join
|
||||||
|
|
||||||
directories = {
|
directories = {
|
||||||
|
'/etc/nginx': {
|
||||||
|
'purge': True,
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:nginx:restart',
|
||||||
|
},
|
||||||
|
},
|
||||||
'/etc/nginx/sites': {
|
'/etc/nginx/sites': {
|
||||||
'purge': True,
|
'purge': True,
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'svc_systemd:nginx:restart',
|
'svc_systemd:nginx:restart',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'/etc/nginx/conf.d': {
|
'/etc/nginx/params': {
|
||||||
'purge': True,
|
|
||||||
'triggers': {
|
|
||||||
'svc_systemd:nginx:restart',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'/etc/nginx/ssl': {
|
|
||||||
'purge': True,
|
'purge': True,
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'svc_systemd:nginx:restart',
|
'svc_systemd:nginx:restart',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'/var/www': {
|
'/var/www': {
|
||||||
|
'purge': True,
|
||||||
'owner': 'www-data',
|
'owner': 'www-data',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -29,11 +30,35 @@ directories = {
|
||||||
files = {
|
files = {
|
||||||
'/etc/nginx/nginx.conf': {
|
'/etc/nginx/nginx.conf': {
|
||||||
'content_type': 'mako',
|
'content_type': 'mako',
|
||||||
|
'context': {
|
||||||
|
'modules': node.metadata.get('nginx/modules'),
|
||||||
|
'worker_processes': node.metadata.get('vm/cores'),
|
||||||
|
},
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'svc_systemd:nginx:restart',
|
'svc_systemd:nginx:restart',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'/etc/nginx/fastcgi.conf': {
|
'/etc/nginx/params/fastcgi': {
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:nginx:restart',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'/etc/nginx/params/proxy': {
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:nginx:restart',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'/etc/nginx/params/uwsgi': {
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:nginx:restart',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'/etc/nginx/params/scgi': {
|
||||||
|
'triggers': {
|
||||||
|
'svc_systemd:nginx:restart',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'/etc/nginx/mime.types': {
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'svc_systemd:nginx:restart',
|
'svc_systemd:nginx:restart',
|
||||||
},
|
},
|
||||||
|
@ -48,23 +73,11 @@ files = {
|
||||||
'svc_systemd:nginx:restart',
|
'svc_systemd:nginx:restart',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'/etc/nginx/sites-available': {
|
|
||||||
'delete': True,
|
|
||||||
'needs': {
|
|
||||||
'pkg_apt:nginx',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'/etc/nginx/sites-enabled': {
|
|
||||||
'delete': True,
|
|
||||||
'needs': {
|
|
||||||
'pkg_apt:nginx',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
actions = {
|
actions = {
|
||||||
'nginx-generate-dhparam': {
|
'nginx-generate-dhparam': {
|
||||||
'command': 'openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048',
|
'command': 'openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096',
|
||||||
'unless': 'test -f /etc/ssl/certs/dhparam.pem',
|
'unless': 'test -f /etc/ssl/certs/dhparam.pem',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
from shlex import quote
|
from shlex import quote
|
||||||
from ipaddress import ip_interface
|
|
||||||
|
|
||||||
|
|
||||||
defaults = {
|
defaults = {
|
||||||
'apt': {
|
'apt': {
|
||||||
'packages': {
|
'packages': {
|
||||||
'nginx': {},
|
'nginx': {},
|
||||||
|
'apache2': {
|
||||||
|
'installed': False,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'nftables': {
|
'nftables': {
|
||||||
|
@ -14,15 +16,8 @@ defaults = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'nginx': {
|
'nginx': {
|
||||||
'vhosts': {
|
'vhosts': {},
|
||||||
# '80': {
|
'modules': set(),
|
||||||
# 'content': 'nginx/80.conf',
|
|
||||||
# },
|
|
||||||
# 'stub_status': {
|
|
||||||
# 'content': 'nginx/stub_status.conf',
|
|
||||||
# },
|
|
||||||
},
|
|
||||||
'includes': {},
|
|
||||||
},
|
},
|
||||||
'systemd': {
|
'systemd': {
|
||||||
'units': {
|
'units': {
|
||||||
|
@ -36,24 +31,6 @@ defaults = {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
|
||||||
'nginx/includes',
|
|
||||||
)
|
|
||||||
def includes(metadata):
|
|
||||||
return {
|
|
||||||
'nginx': {
|
|
||||||
'includes': {
|
|
||||||
'php': {
|
|
||||||
'location ~ \.php$': {
|
|
||||||
'include': 'fastcgi.conf',
|
|
||||||
'fastcgi_split_path_info': '^(.+\.php)(/.+)$',
|
|
||||||
'fastcgi_pass': f"unix:/run/php/php{metadata.get('php/version')}-fpm.sock",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
@metadata_reactor.provides(
|
||||||
'nginx/vhosts',
|
'nginx/vhosts',
|
||||||
|
@ -96,7 +73,6 @@ def dns(metadata):
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
@metadata_reactor.provides(
|
||||||
'letsencrypt/domains',
|
'letsencrypt/domains',
|
||||||
'letsencrypt/reload_after',
|
|
||||||
)
|
)
|
||||||
def letsencrypt(metadata):
|
def letsencrypt(metadata):
|
||||||
return {
|
return {
|
||||||
|
@ -125,3 +101,17 @@ def monitoring(metadata):
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'apt/packages',
|
||||||
|
)
|
||||||
|
def modules(metadata):
|
||||||
|
return {
|
||||||
|
'apt': {
|
||||||
|
'packages': {
|
||||||
|
f'libnginx-mod-{module}': {}
|
||||||
|
for module in metadata.get('nginx/modules')
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -23,8 +23,19 @@ def sources(metadata):
|
||||||
return {
|
return {
|
||||||
'apt': {
|
'apt': {
|
||||||
'sources': {
|
'sources': {
|
||||||
f'deb https://deb.nodesource.com/node_{version}.x {{release}} main',
|
'nodesource': {
|
||||||
f'deb-src https://deb.nodesource.com/node_{version}.x {{release}} main',
|
'types': {
|
||||||
|
'deb',
|
||||||
|
'deb-src',
|
||||||
|
},
|
||||||
|
'url': 'https://deb.nodesource.com/node_{version}.x',
|
||||||
|
'suites': {
|
||||||
|
'{codename}',
|
||||||
|
},
|
||||||
|
'components': {
|
||||||
|
'main',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,17 @@ defaults = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'sources': {
|
'sources': {
|
||||||
'deb https://openhab.jfrog.io/artifactory/openhab-linuxpkg stable main',
|
'jfrog': {
|
||||||
|
'urls': {
|
||||||
|
'https://openhab.jfrog.io/artifactory/openhab-linuxpkg',
|
||||||
|
},
|
||||||
|
'suites': {
|
||||||
|
'stable',
|
||||||
|
},
|
||||||
|
'components': {
|
||||||
|
'main',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'zfs': {
|
'zfs': {
|
||||||
|
|
|
@ -1,9 +1,3 @@
|
||||||
from os.path import join
|
|
||||||
import json
|
|
||||||
|
|
||||||
from bundlewrap.utils.dicts import merge_dict
|
|
||||||
|
|
||||||
|
|
||||||
version = node.metadata.get('php/version')
|
version = node.metadata.get('php/version')
|
||||||
|
|
||||||
files = {
|
files = {
|
||||||
|
@ -21,7 +15,7 @@ files = {
|
||||||
f'pkg_apt:php{version}-fpm',
|
f'pkg_apt:php{version}-fpm',
|
||||||
},
|
},
|
||||||
'triggers': {
|
'triggers': {
|
||||||
f'svc_systemd:php{version}-fpm:restart',
|
f'svc_systemd:php{version}-fpm.service:restart',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
f'/etc/php/{version}/fpm/pool.d/www.conf': {
|
f'/etc/php/{version}/fpm/pool.d/www.conf': {
|
||||||
|
@ -33,13 +27,13 @@ files = {
|
||||||
f'pkg_apt:php{version}-fpm',
|
f'pkg_apt:php{version}-fpm',
|
||||||
},
|
},
|
||||||
'triggers': {
|
'triggers': {
|
||||||
f'svc_systemd:php{version}-fpm:restart',
|
f'svc_systemd:php{version}-fpm.service:restart',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_systemd = {
|
svc_systemd = {
|
||||||
f'php{version}-fpm': {
|
f'php{version}-fpm.service': {
|
||||||
'needs': {
|
'needs': {
|
||||||
'pkg_apt:',
|
'pkg_apt:',
|
||||||
f'file:/etc/php/{version}/fpm/php.ini',
|
f'file:/etc/php/{version}/fpm/php.ini',
|
||||||
|
|
|
@ -113,7 +113,7 @@ def php_ini(metadata):
|
||||||
'opcache.revalidate_freq': '60',
|
'opcache.revalidate_freq': '60',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'php': {
|
'php': {
|
||||||
'php.ini': {
|
'php.ini': {
|
||||||
|
@ -145,7 +145,7 @@ def www_conf(metadata):
|
||||||
'pm': 'dynamic',
|
'pm': 'dynamic',
|
||||||
'pm.max_children': int(threads*2),
|
'pm.max_children': int(threads*2),
|
||||||
'pm.start_servers': int(threads),
|
'pm.start_servers': int(threads),
|
||||||
'pm.min_spare_servers': int(threads/2),
|
'pm.min_spare_servers': max([1, int(threads/2)]),
|
||||||
'pm.max_spare_servers': int(threads),
|
'pm.max_spare_servers': int(threads),
|
||||||
'pm.max_requests': int(threads*32),
|
'pm.max_requests': int(threads*32),
|
||||||
},
|
},
|
||||||
|
|
|
@ -44,7 +44,9 @@ smtpd_tls_mandatory_protocols = !SSLv2, !SSLv3, !TLSv1, !TLSv1.1
|
||||||
smtpd_restriction_classes = mua_sender_restrictions, mua_client_restrictions, mua_helo_restrictions
|
smtpd_restriction_classes = mua_sender_restrictions, mua_client_restrictions, mua_helo_restrictions
|
||||||
mua_client_restrictions = permit_sasl_authenticated, reject
|
mua_client_restrictions = permit_sasl_authenticated, reject
|
||||||
mua_sender_restrictions = permit_sasl_authenticated, reject
|
mua_sender_restrictions = permit_sasl_authenticated, reject
|
||||||
mua_helo_restrictions = permit_mynetworks, reject_non_fqdn_hostname, reject_invalid_hostname, permit
|
## MS Outlook, incompatible with reject_non_fqdn_hostname and/or reject_invalid_hostname
|
||||||
|
## https://unix.stackexchange.com/a/91753/357916
|
||||||
|
mua_helo_restrictions = permit_mynetworks, permit
|
||||||
|
|
||||||
smtpd_milters = inet:localhost:8891 inet:127.0.0.1:11332
|
smtpd_milters = inet:localhost:8891 inet:127.0.0.1:11332
|
||||||
non_smtpd_milters = inet:localhost:8891 inet:127.0.0.1:11332
|
non_smtpd_milters = inet:localhost:8891 inet:127.0.0.1:11332
|
||||||
|
|
|
@ -86,6 +86,8 @@ if node.has_bundle('telegraf'):
|
||||||
'needs': [
|
'needs': [
|
||||||
'pkg_apt:acl',
|
'pkg_apt:acl',
|
||||||
'svc_systemd:postfix',
|
'svc_systemd:postfix',
|
||||||
|
'svc_systemd:postfix:reload',
|
||||||
|
'svc_systemd:postfix:restart',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
actions['postfix_setfacl_default_telegraf'] = {
|
actions['postfix_setfacl_default_telegraf'] = {
|
||||||
|
@ -94,5 +96,7 @@ if node.has_bundle('telegraf'):
|
||||||
'needs': [
|
'needs': [
|
||||||
'pkg_apt:acl',
|
'pkg_apt:acl',
|
||||||
'svc_systemd:postfix',
|
'svc_systemd:postfix',
|
||||||
|
'svc_systemd:postfix:reload',
|
||||||
|
'svc_systemd:postfix:restart',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ directories = {
|
||||||
'zfs_dataset:tank/postgresql',
|
'zfs_dataset:tank/postgresql',
|
||||||
],
|
],
|
||||||
'needed_by': [
|
'needed_by': [
|
||||||
'svc_systemd:postgresql',
|
'svc_systemd:postgresql.service',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,16 +25,19 @@ files = {
|
||||||
) + '\n',
|
) + '\n',
|
||||||
'owner': 'postgres',
|
'owner': 'postgres',
|
||||||
'group': 'postgres',
|
'group': 'postgres',
|
||||||
|
'needs': [
|
||||||
|
'pkg_apt:postgresql',
|
||||||
|
],
|
||||||
'needed_by': [
|
'needed_by': [
|
||||||
'svc_systemd:postgresql',
|
'svc_systemd:postgresql.service',
|
||||||
],
|
],
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:postgresql:restart',
|
'svc_systemd:postgresql.service:restart',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
svc_systemd['postgresql'] = {
|
svc_systemd['postgresql.service'] = {
|
||||||
'needs': [
|
'needs': [
|
||||||
'pkg_apt:postgresql',
|
'pkg_apt:postgresql',
|
||||||
],
|
],
|
||||||
|
@ -43,13 +46,13 @@ svc_systemd['postgresql'] = {
|
||||||
for user, config in node.metadata.get('postgresql/roles').items():
|
for user, config in node.metadata.get('postgresql/roles').items():
|
||||||
postgres_roles[user] = merge_dict(config, {
|
postgres_roles[user] = merge_dict(config, {
|
||||||
'needs': [
|
'needs': [
|
||||||
'svc_systemd:postgresql',
|
'svc_systemd:postgresql.service',
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
for database, config in node.metadata.get('postgresql/databases').items():
|
for database, config in node.metadata.get('postgresql/databases').items():
|
||||||
postgres_dbs[database] = merge_dict(config, {
|
postgres_dbs[database] = merge_dict(config, {
|
||||||
'needs': [
|
'needs': [
|
||||||
'svc_systemd:postgresql',
|
'svc_systemd:postgresql.service',
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
|
@ -6,7 +6,11 @@ root_password = repo.vault.password_for(f'{node.name} postgresql root')
|
||||||
defaults = {
|
defaults = {
|
||||||
'apt': {
|
'apt': {
|
||||||
'packages': {
|
'packages': {
|
||||||
'postgresql': {},
|
'postgresql': {
|
||||||
|
'needs': {
|
||||||
|
'zfs_dataset:tank/postgresql',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'backup': {
|
'backup': {
|
||||||
|
@ -54,6 +58,25 @@ def conf(metadata):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'apt/config/APT/NeverAutoRemove',
|
||||||
|
)
|
||||||
|
def apt(metadata):
|
||||||
|
return {
|
||||||
|
'apt': {
|
||||||
|
'config': {
|
||||||
|
'APT': {
|
||||||
|
'NeverAutoRemove': {
|
||||||
|
# https://github.com/credativ/postgresql-common/blob/master/pg_updateaptconfig#L17-L21
|
||||||
|
f"^postgresql.*-{metadata.get('postgresql/version')}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
@metadata_reactor.provides(
|
||||||
'zfs/datasets',
|
'zfs/datasets',
|
||||||
)
|
)
|
||||||
|
|
25
bundles/pyenv/items.py
Normal file
25
bundles/pyenv/items.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
from shlex import quote
|
||||||
|
|
||||||
|
directories = {
|
||||||
|
'/opt/pyenv': {},
|
||||||
|
'/opt/pyenv/install': {},
|
||||||
|
}
|
||||||
|
|
||||||
|
git_deploy = {
|
||||||
|
'/opt/pyenv/install': {
|
||||||
|
'repo': 'https://github.com/pyenv/pyenv.git',
|
||||||
|
'rev': 'master',
|
||||||
|
'needs': {
|
||||||
|
'directory:/opt/pyenv/install',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for version in node.metadata.get('pyenv/versions'):
|
||||||
|
actions[f'pyenv_install_{version}'] = {
|
||||||
|
'command': f'PYENV_ROOT=/opt/pyenv /opt/pyenv/install/bin/pyenv install {quote(version)}',
|
||||||
|
'unless': f'PYENV_ROOT=/opt/pyenv /opt/pyenv/install/bin/pyenv versions --bare | grep -Fxq {quote(version)}',
|
||||||
|
'needs': {
|
||||||
|
'git_deploy:/opt/pyenv/install',
|
||||||
|
},
|
||||||
|
}
|
23
bundles/pyenv/metadata.py
Normal file
23
bundles/pyenv/metadata.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
defaults = {
|
||||||
|
'apt': {
|
||||||
|
'packages': {
|
||||||
|
'build-essential': {},
|
||||||
|
'libssl-dev': {},
|
||||||
|
'zlib1g-dev': {},
|
||||||
|
'libbz2-dev': {},
|
||||||
|
'libreadline-dev': {},
|
||||||
|
'libsqlite3-dev': {},
|
||||||
|
'curl': {},
|
||||||
|
'libncurses-dev': {},
|
||||||
|
'xz-utils': {},
|
||||||
|
'tk-dev': {},
|
||||||
|
'libxml2-dev': {},
|
||||||
|
'libxmlsec1-dev': {},
|
||||||
|
'libffi-dev': {},
|
||||||
|
'liblzma-dev': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'pyenv': {
|
||||||
|
'versions': set(),
|
||||||
|
},
|
||||||
|
}
|
3
bundles/raspberrymatic-cert/README.md
Normal file
3
bundles/raspberrymatic-cert/README.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
- Homematic > Settings > Control panel > Security > SSH > active & set password
|
||||||
|
- ssh to node > `ssh-copy-id -o StrictHostKeyChecking=no root@{homematic}`
|
||||||
|
- Homematic > Settings > Control panel > Security > Automatic forwarding to HTTPS > active
|
|
@ -1,6 +1,3 @@
|
||||||
from shlex import quote
|
|
||||||
|
|
||||||
|
|
||||||
@metadata_reactor.provides(
|
@metadata_reactor.provides(
|
||||||
'letsencrypt/domains',
|
'letsencrypt/domains',
|
||||||
)
|
)
|
||||||
|
@ -20,8 +17,6 @@ def letsencrypt(metadata):
|
||||||
'systemd-timers/raspberrymatic-cert',
|
'systemd-timers/raspberrymatic-cert',
|
||||||
)
|
)
|
||||||
def systemd_timers(metadata):
|
def systemd_timers(metadata):
|
||||||
domain = metadata.get('raspberrymatic-cert/domain')
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'systemd-timers': {
|
'systemd-timers': {
|
||||||
'raspberrymatic-cert': {
|
'raspberrymatic-cert': {
|
||||||
|
|
|
@ -6,80 +6,16 @@ $config['enable_installer'] = true;
|
||||||
|
|
||||||
/* Local configuration for Roundcube Webmail */
|
/* Local configuration for Roundcube Webmail */
|
||||||
|
|
||||||
// ----------------------------------
|
|
||||||
// SQL DATABASE
|
|
||||||
// ----------------------------------
|
|
||||||
// Database connection string (DSN) for read+write operations
|
|
||||||
// Format (compatible with PEAR MDB2): db_provider://user:password@host/database
|
|
||||||
// Currently supported db_providers: mysql, pgsql, sqlite, mssql or sqlsrv
|
|
||||||
// For examples see http://pear.php.net/manual/en/package.database.mdb2.intro-dsn.php
|
|
||||||
// NOTE: for SQLite use absolute path: 'sqlite:////full/path/to/sqlite.db?mode=0646'
|
|
||||||
$config['db_dsnw'] = '${database['provider']}://${database['user']}:${database['password']}@${database['host']}/${database['name']}';
|
$config['db_dsnw'] = '${database['provider']}://${database['user']}:${database['password']}@${database['host']}/${database['name']}';
|
||||||
|
$config['imap_host'] = 'localhost';
|
||||||
// ----------------------------------
|
$config['smtp_host'] = 'tls://localhost';
|
||||||
// IMAP
|
|
||||||
// ----------------------------------
|
|
||||||
// The mail host chosen to perform the log-in.
|
|
||||||
// Leave blank to show a textbox at login, give a list of hosts
|
|
||||||
// to display a pulldown menu or set one host as string.
|
|
||||||
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
|
|
||||||
// Supported replacement variables:
|
|
||||||
// %n - hostname ($_SERVER['SERVER_NAME'])
|
|
||||||
// %t - hostname without the first part
|
|
||||||
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
|
|
||||||
// %s - domain name after the '@' from e-mail address provided at login screen
|
|
||||||
// For example %n = mail.domain.tld, %t = domain.tld
|
|
||||||
// WARNING: After hostname change update of mail_host column in users table is
|
|
||||||
// required to match old user data records with the new host.
|
|
||||||
$config['default_host'] = 'localhost';
|
|
||||||
|
|
||||||
// ----------------------------------
|
|
||||||
// SMTP
|
|
||||||
// ----------------------------------
|
|
||||||
// SMTP server host (for sending mails).
|
|
||||||
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
|
|
||||||
// If left blank, the PHP mail() function is used
|
|
||||||
// Supported replacement variables:
|
|
||||||
// %h - user's IMAP hostname
|
|
||||||
// %n - hostname ($_SERVER['SERVER_NAME'])
|
|
||||||
// %t - hostname without the first part
|
|
||||||
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
|
|
||||||
// %z - IMAP domain (IMAP hostname without the first part)
|
|
||||||
// For example %n = mail.domain.tld, %t = domain.tld
|
|
||||||
$config['smtp_server'] = 'tls://localhost';
|
|
||||||
|
|
||||||
// SMTP username (if required) if you use %u as the username Roundcube
|
|
||||||
// will use the current username for login
|
|
||||||
$config['smtp_user'] = '%u';
|
$config['smtp_user'] = '%u';
|
||||||
|
|
||||||
// SMTP password (if required) if you use %p as the password Roundcube
|
|
||||||
// will use the current user's password for login
|
|
||||||
$config['smtp_pass'] = '%p';
|
$config['smtp_pass'] = '%p';
|
||||||
|
|
||||||
// provide an URL where a user can get support for this Roundcube installation
|
|
||||||
// PLEASE DO NOT LINK TO THE ROUNDCUBE.NET WEBSITE HERE!
|
|
||||||
$config['support_url'] = '';
|
$config['support_url'] = '';
|
||||||
|
|
||||||
// this key is used to encrypt the users imap password which is stored
|
|
||||||
// in the session record (and the client cookie if remember password is enabled).
|
|
||||||
// please provide a string of exactly 24 chars.
|
|
||||||
$config['des_key'] = '${des_key}';
|
$config['des_key'] = '${des_key}';
|
||||||
|
|
||||||
// Name your service. This is displayed on the login screen and in the window title
|
|
||||||
$config['product_name'] = '${product_name}';
|
$config['product_name'] = '${product_name}';
|
||||||
|
|
||||||
// ----------------------------------
|
|
||||||
// PLUGINS
|
|
||||||
// ----------------------------------
|
|
||||||
// List of active plugins (in plugins/ directory)
|
|
||||||
$config['plugins'] = array(${', '.join(f'"{plugin}"' for plugin in plugins)});
|
$config['plugins'] = array(${', '.join(f'"{plugin}"' for plugin in plugins)});
|
||||||
|
|
||||||
// the default locale setting (leave empty for auto-detection)
|
|
||||||
// RFC1766 formatted language name like en_US, de_DE, de_CH, fr_FR, pt_BR
|
|
||||||
$config['language'] = 'de_DE';
|
$config['language'] = 'de_DE';
|
||||||
|
|
||||||
|
|
||||||
// https://serverfault.com/a/991304
|
|
||||||
$config['smtp_conn_options'] = array(
|
$config['smtp_conn_options'] = array(
|
||||||
'ssl' => array(
|
'ssl' => array(
|
||||||
'verify_peer' => false,
|
'verify_peer' => false,
|
||||||
|
|
|
@ -14,4 +14,4 @@ $config['password_dovecotpw'] = '/usr/bin/sudo /usr/bin/doveadm pw';
|
||||||
$config['password_dovecotpw_method'] = 'ARGON2ID';
|
$config['password_dovecotpw_method'] = 'ARGON2ID';
|
||||||
$config['password_dovecotpw_with_method'] = true;
|
$config['password_dovecotpw_with_method'] = true;
|
||||||
$config['password_db_dsn'] = 'pgsql://mailserver:${mailserver_db_password}@localhost/mailserver';
|
$config['password_db_dsn'] = 'pgsql://mailserver:${mailserver_db_password}@localhost/mailserver';
|
||||||
$config['password_query'] = "UPDATE users SET password=%D FROM domains WHERE domains.id = domain_id AND domains.name = %d AND users.name = %l";
|
$config['password_query'] = "UPDATE users SET password = %P FROM domains WHERE domains.id = users.domain_id AND domains.name = %d AND users.name = %l";
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
assert node.has_bundle('php')
|
assert node.has_bundle('php')
|
||||||
assert node.has_bundle('mailserver')
|
assert node.has_bundle('mailserver')
|
||||||
|
|
||||||
version = node.metadata.get('roundcube/version')
|
roundcube_version = node.metadata.get('roundcube/version')
|
||||||
|
php_version = node.metadata.get('php/version')
|
||||||
|
|
||||||
directories = {
|
directories = {
|
||||||
'/opt/roundcube': {
|
'/opt/roundcube': {
|
||||||
|
@ -22,9 +23,9 @@ directories = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
files[f'/tmp/roundcube-{version}.tar.gz'] = {
|
files[f'/tmp/roundcube-{roundcube_version}.tar.gz'] = {
|
||||||
'content_type': 'download',
|
'content_type': 'download',
|
||||||
'source': f'https://github.com/roundcube/roundcubemail/releases/download/{version}/roundcubemail-{version}-complete.tar.gz',
|
'source': f'https://github.com/roundcube/roundcubemail/releases/download/{roundcube_version}/roundcubemail-{roundcube_version}-complete.tar.gz',
|
||||||
'triggered': True,
|
'triggered': True,
|
||||||
}
|
}
|
||||||
actions['delete_roundcube'] = {
|
actions['delete_roundcube'] = {
|
||||||
|
@ -32,18 +33,18 @@ actions['delete_roundcube'] = {
|
||||||
'triggered': True,
|
'triggered': True,
|
||||||
}
|
}
|
||||||
actions['extract_roundcube'] = {
|
actions['extract_roundcube'] = {
|
||||||
'command': f'tar xfvz /tmp/roundcube-{version}.tar.gz --strip 1 -C /opt/roundcube',
|
'command': f'tar xfvz /tmp/roundcube-{roundcube_version}.tar.gz --strip 1 -C /opt/roundcube',
|
||||||
'unless': f'grep -q "Version {version}" /opt/roundcube/index.php',
|
'unless': f'grep -q "Version {roundcube_version}" /opt/roundcube/index.php',
|
||||||
'preceded_by': [
|
'preceded_by': [
|
||||||
'action:delete_roundcube',
|
'action:delete_roundcube',
|
||||||
f'file:/tmp/roundcube-{version}.tar.gz',
|
f'file:/tmp/roundcube-{roundcube_version}.tar.gz',
|
||||||
],
|
],
|
||||||
'needs': [
|
'needs': [
|
||||||
'directory:/opt/roundcube',
|
'directory:/opt/roundcube',
|
||||||
],
|
],
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'action:chown_roundcube',
|
'action:chown_roundcube',
|
||||||
'action:composer_install',
|
'action:composer_lock_reset',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
actions['chown_roundcube'] = {
|
actions['chown_roundcube'] = {
|
||||||
|
@ -64,6 +65,9 @@ files['/opt/roundcube/config/config.inc.php'] = {
|
||||||
'needs': [
|
'needs': [
|
||||||
'action:chown_roundcube',
|
'action:chown_roundcube',
|
||||||
],
|
],
|
||||||
|
'triggers': [
|
||||||
|
f'svc_systemd:php{php_version}-fpm.service:restart',
|
||||||
|
],
|
||||||
}
|
}
|
||||||
files['/opt/roundcube/plugins/password/config.inc.php'] = {
|
files['/opt/roundcube/plugins/password/config.inc.php'] = {
|
||||||
'source': 'password.config.inc.php',
|
'source': 'password.config.inc.php',
|
||||||
|
@ -75,7 +79,16 @@ files['/opt/roundcube/plugins/password/config.inc.php'] = {
|
||||||
'action:chown_roundcube',
|
'action:chown_roundcube',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
actions['composer_lock_reset'] = {
|
||||||
|
'command': 'rm /opt/roundcube/composer.lock',
|
||||||
|
'triggered': True,
|
||||||
|
'needs': [
|
||||||
|
'action:chown_roundcube',
|
||||||
|
],
|
||||||
|
'triggers': [
|
||||||
|
'action:composer_install',
|
||||||
|
],
|
||||||
|
}
|
||||||
actions['composer_install'] = {
|
actions['composer_install'] = {
|
||||||
'command': "cp /opt/roundcube/composer.json-dist /opt/roundcube/composer.json && su www-data -s /bin/bash -c '/usr/bin/composer -d /opt/roundcube install'",
|
'command': "cp /opt/roundcube/composer.json-dist /opt/roundcube/composer.json && su www-data -s /bin/bash -c '/usr/bin/composer -d /opt/roundcube install'",
|
||||||
'triggered': True,
|
'triggered': True,
|
||||||
|
|
|
@ -48,6 +48,14 @@ svc_systemd = {
|
||||||
'pkg_apt:rspamd',
|
'pkg_apt:rspamd',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
# FIXME: broken since debian 12
|
||||||
|
'clamav-clamonacc': {
|
||||||
|
'enabled': False,
|
||||||
|
'running': False,
|
||||||
|
'needs': {
|
||||||
|
'pkg_apt:clamav',
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
actions = {
|
actions = {
|
||||||
|
|
|
@ -21,3 +21,4 @@ ClientAliveInterval 30
|
||||||
ClientAliveCountMax 5
|
ClientAliveCountMax 5
|
||||||
AcceptEnv LANG
|
AcceptEnv LANG
|
||||||
Subsystem sftp /usr/lib/openssh/sftp-server
|
Subsystem sftp /usr/lib/openssh/sftp-server
|
||||||
|
HostKey /etc/ssh/ssh_host_managed_key
|
||||||
|
|
|
@ -51,14 +51,14 @@ files = {
|
||||||
],
|
],
|
||||||
'skip': dont_touch_sshd,
|
'skip': dont_touch_sshd,
|
||||||
},
|
},
|
||||||
'/etc/ssh/ssh_host_ed25519_key': {
|
'/etc/ssh/ssh_host_managed_key': {
|
||||||
'content': node.metadata.get('ssh/host_key/private') + '\n',
|
'content': node.metadata.get('ssh/host_key/private') + '\n',
|
||||||
'mode': '0600',
|
'mode': '0600',
|
||||||
'triggers': [
|
'triggers': [
|
||||||
'svc_systemd:ssh:restart'
|
'svc_systemd:ssh:restart'
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'/etc/ssh/ssh_host_ed25519_key.pub': {
|
'/etc/ssh/ssh_host_managed_key.pub': {
|
||||||
'content': node.metadata.get('ssh/host_key/public') + '\n',
|
'content': node.metadata.get('ssh/host_key/public') + '\n',
|
||||||
'mode': '0644',
|
'mode': '0644',
|
||||||
'triggers': [
|
'triggers': [
|
||||||
|
@ -66,12 +66,13 @@ files = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
'/etc/ssh/ssh_known_hosts': {
|
'/etc/ssh/ssh_known_hosts': {
|
||||||
'content': '\n'.join(
|
'content': '\n'.join(sorted(
|
||||||
repo.libs.ssh.known_hosts_entry_for(other_node)
|
line
|
||||||
for other_node in sorted(repo.nodes)
|
for other_node in repo.nodes
|
||||||
if other_node != node
|
if other_node != node
|
||||||
and other_node.has_bundle('ssh')
|
and other_node.has_bundle('ssh')
|
||||||
) + '\n',
|
for line in other_node.metadata.get('ssh/is_known_as')
|
||||||
|
)) + '\n',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ from base64 import b64decode
|
||||||
defaults = {
|
defaults = {
|
||||||
'ssh': {
|
'ssh': {
|
||||||
'multiplex_incoming': True,
|
'multiplex_incoming': True,
|
||||||
|
'is_known_as': set(), # known_hosts for other nodes
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ def host_key(metadata):
|
||||||
'ssh': {
|
'ssh': {
|
||||||
'host_key': {
|
'host_key': {
|
||||||
'private': private + '\n',
|
'private': private + '\n',
|
||||||
'public': public + f' root@{node.name}',
|
'public': f'{public} {node.name}',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -47,7 +48,7 @@ def host_key(metadata):
|
||||||
def hostnames(metadata):
|
def hostnames(metadata):
|
||||||
ips = set()
|
ips = set()
|
||||||
|
|
||||||
for network in node.metadata.get('network').values():
|
for network in metadata.get('network').values():
|
||||||
if network.get('ipv4', None):
|
if network.get('ipv4', None):
|
||||||
ips.add(str(ip_interface(network['ipv4']).ip))
|
ips.add(str(ip_interface(network['ipv4']).ip))
|
||||||
if network.get('ipv6', None):
|
if network.get('ipv6', None):
|
||||||
|
@ -55,7 +56,7 @@ def hostnames(metadata):
|
||||||
|
|
||||||
domains = {
|
domains = {
|
||||||
domain
|
domain
|
||||||
for domain, records in node.metadata.get('dns').items()
|
for domain, records in metadata.get('dns').items()
|
||||||
for type, values in records.items()
|
for type, values in records.items()
|
||||||
if type in {'A', 'AAAA'}
|
if type in {'A', 'AAAA'}
|
||||||
and set(values) & ips
|
and set(values) & ips
|
||||||
|
@ -70,3 +71,18 @@ def hostnames(metadata):
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@metadata_reactor.provides(
|
||||||
|
'ssh/is_known_as',
|
||||||
|
)
|
||||||
|
def is_known_as(metadata):
|
||||||
|
return {
|
||||||
|
'ssh': {
|
||||||
|
'is_known_as': repo.libs.ssh.known_hosts_entry_for(
|
||||||
|
node_id=metadata.get('id'),
|
||||||
|
hostnames=tuple(sorted(metadata.get('ssh/hostnames'))),
|
||||||
|
pubkey=metadata.get('ssh/host_key/public'),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
|
@ -34,18 +34,19 @@ defaults = {
|
||||||
)
|
)
|
||||||
def systemd_timer(metadata):
|
def systemd_timer(metadata):
|
||||||
return {
|
return {
|
||||||
'systemd-timers': {
|
# steam python login is broken: https://github.com/ValvePython/steam/issues/442
|
||||||
f'steam-chat-logger': {
|
# 'systemd-timers': {
|
||||||
'command': '/opt/steam_chat_logger/steam_chat_logger.py',
|
# f'steam-chat-logger': {
|
||||||
'when': 'hourly',
|
# 'command': '/opt/steam_chat_logger/steam_chat_logger.py',
|
||||||
'user': 'steam_chat_logger',
|
# 'when': 'hourly',
|
||||||
'env': {
|
# 'user': 'steam_chat_logger',
|
||||||
'DB_NAME': 'steam_chat_logger',
|
# 'env': {
|
||||||
'DB_USER': 'steam_chat_logger',
|
# 'DB_NAME': 'steam_chat_logger',
|
||||||
'DB_PASSWORD': metadata.get('postgresql/roles/steam_chat_logger/password'),
|
# 'DB_USER': 'steam_chat_logger',
|
||||||
**metadata.get('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',
|
# },
|
||||||
},
|
# 'working_dir': '/var/lib/steam_chat_logger',
|
||||||
},
|
# },
|
||||||
|
# },
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
files = {
|
files = {
|
||||||
'/etc/systemd/journald.conf.d/managed.conf': {
|
'/etc/systemd/journald.conf.d/managed.conf': {
|
||||||
'content': repo.libs.systemd.generate_unitfile({
|
'content': repo.libs.systemd.generate_unitfile({
|
||||||
'Jorunal': node.metadata.get('systemd-journald'),
|
'Journal': node.metadata.get('systemd-journald'),
|
||||||
}),
|
}),
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'svc_systemd:systemd-journald:restart',
|
'svc_systemd:systemd-journald:restart',
|
||||||
|
|
|
@ -15,16 +15,14 @@ defaults = {
|
||||||
def units(metadata):
|
def units(metadata):
|
||||||
units = {}
|
units = {}
|
||||||
services = {}
|
services = {}
|
||||||
|
|
||||||
for mountpoint, conf in metadata.get('systemd-mount').items():
|
for mountpoint, conf in metadata.get('systemd-mount').items():
|
||||||
formatted_name = mountpoint[1:].replace('-', '\\x2d').replace('/', '-') + '.mount'
|
formatted_name = mountpoint[1:].replace('-', '\\x2d').replace('/', '-') + '.mount'
|
||||||
|
|
||||||
units[formatted_name] = {
|
units[formatted_name] = {
|
||||||
'Unit': {
|
'Unit': {
|
||||||
'Description': f"Mount {conf['source']} -> {mountpoint}",
|
'Description': f"Mount {conf['source']} -> {mountpoint}",
|
||||||
'DefaultDependencies': 'no',
|
'DefaultDependencies': 'no',
|
||||||
'Conflicts': 'umount.target',
|
|
||||||
'Before': 'umount.target',
|
|
||||||
},
|
},
|
||||||
'Mount': {
|
'Mount': {
|
||||||
'What': conf['source'],
|
'What': conf['source'],
|
||||||
|
@ -32,16 +30,11 @@ def units(metadata):
|
||||||
'Type': 'fuse.bindfs',
|
'Type': 'fuse.bindfs',
|
||||||
'Options': f"nonempty",
|
'Options': f"nonempty",
|
||||||
},
|
},
|
||||||
'Install': {
|
|
||||||
'WantedBy': {
|
|
||||||
'local-fs.target',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if conf.get('user'):
|
if conf.get('user'):
|
||||||
units[formatted_name]['Mount']['Options'] += f",force-user={conf.get('user')}"
|
units[formatted_name]['Mount']['Options'] += f",force-user={conf.get('user')}"
|
||||||
|
|
||||||
services[formatted_name] = {}
|
services[formatted_name] = {}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
size_mb = node.metadata.get('systemd-swap')//1_000_000
|
size = node.metadata.get('systemd-swap')
|
||||||
|
|
||||||
actions = {
|
actions = {
|
||||||
'stop_swap': {
|
'stop_swap': {
|
||||||
|
@ -15,14 +15,13 @@ actions = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'create_swapfile': {
|
'create_swapfile': {
|
||||||
'command': f'dd if=/dev/zero of=/swapfile bs=1000000 count={size_mb}',
|
'command': f'fallocate -l {size} /swapfile',
|
||||||
'unless': f'stat -c %s /swapfile | grep ^{size_mb*1_000_000}$',
|
'unless': f'stat -c %s /swapfile | grep ^{size}$',
|
||||||
'preceded_by': {
|
'preceded_by': {
|
||||||
'action:stop_swap',
|
'action:stop_swap',
|
||||||
'action:remove_swapfile',
|
'action:remove_swapfile',
|
||||||
},
|
},
|
||||||
'triggers': {
|
'triggers': {
|
||||||
'action:initialize_swapfile',
|
|
||||||
'svc_systemd:swapfile.swap:restart',
|
'svc_systemd:swapfile.swap:restart',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -38,7 +37,7 @@ actions = {
|
||||||
},
|
},
|
||||||
'initialize_swapfile': {
|
'initialize_swapfile': {
|
||||||
'command': f'mkswap /swapfile',
|
'command': f'mkswap /swapfile',
|
||||||
'triggered': True,
|
'unless': 'blkid -o value -s TYPE /swapfile | grep -q "^swap$"',
|
||||||
'needs': {
|
'needs': {
|
||||||
'action:swapfile_mode',
|
'action:swapfile_mode',
|
||||||
}
|
}
|
||||||
|
@ -47,9 +46,6 @@ actions = {
|
||||||
|
|
||||||
svc_systemd = {
|
svc_systemd = {
|
||||||
'swapfile.swap': {
|
'swapfile.swap': {
|
||||||
'preceded_by': {
|
|
||||||
'action:initialize_swapfile',
|
|
||||||
},
|
|
||||||
'needs': {
|
'needs': {
|
||||||
'action:initialize_swapfile',
|
'action:initialize_swapfile',
|
||||||
'action:systemd-reload',
|
'action:systemd-reload',
|
||||||
|
|
|
@ -6,6 +6,11 @@ defaults = {
|
||||||
'Swap': {
|
'Swap': {
|
||||||
'What': '/swapfile',
|
'What': '/swapfile',
|
||||||
},
|
},
|
||||||
|
'Install': {
|
||||||
|
'WantedBy': {
|
||||||
|
'swap.target',
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue