From 6cceae2458a6655757662635e12212d5ffe5ddbb Mon Sep 17 00:00:00 2001 From: mwiegand Date: Wed, 17 Nov 2021 01:13:01 +0100 Subject: [PATCH] build cystal --- .envrc | 2 +- .gitignore | 1 + README.md | 1 - bundles/build-agent/items.py | 0 bundles/build-agent/metadata.py | 38 +++++++ bundles/build-server/README.md | 2 + bundles/build-server/example.json | 169 ++++++++++++++++++++++++++++ bundles/build-server/files/crystal | 31 +++++ bundles/build-server/items.py | 24 ++++ bundles/build-server/metadata.py | 59 ++++++++++ bundles/download-server/items.py | 6 + bundles/download-server/metadata.py | 66 +++++++++++ bundles/flask/README.md | 54 +++++++++ bundles/flask/files/flask.cfg | 10 ++ bundles/flask/files/flask.service | 14 +++ bundles/flask/items.py | 119 ++++++++++++++++++++ bundles/flask/metadata.py | 61 ++++++++++ bundles/smartctl/metadata.py | 2 +- bundles/users/items.py | 7 +- data/nginx/directory_listing.conf | 11 ++ data/nginx/proxy_pass.conf | 4 - data/nginx/redirect.conf | 1 + groups/applications/build-server.py | 6 + nodes/home.openhab.py | 5 +- nodes/home.server.py | 16 +++ nodes/netcup.mails.py | 4 + 26 files changed, 701 insertions(+), 12 deletions(-) create mode 100644 bundles/build-agent/items.py create mode 100644 bundles/build-agent/metadata.py create mode 100644 bundles/build-server/README.md create mode 100644 bundles/build-server/example.json create mode 100644 bundles/build-server/files/crystal create mode 100644 bundles/build-server/items.py create mode 100644 bundles/build-server/metadata.py create mode 100644 bundles/download-server/items.py create mode 100644 bundles/download-server/metadata.py create mode 100644 bundles/flask/README.md create mode 100644 bundles/flask/files/flask.cfg create mode 100644 bundles/flask/files/flask.service create mode 100644 bundles/flask/items.py create mode 100644 bundles/flask/metadata.py create mode 100644 data/nginx/directory_listing.conf create mode 100644 groups/applications/build-server.py diff --git a/.envrc b/.envrc index 6894359..e85f2cd 100644 --- a/.envrc +++ b/.envrc @@ -3,6 +3,6 @@ python3 -m venv .venv source ./.venv/bin/activate -export BW_GIT_DEPLOY_CACHE="$(realpath ~)/.cache/bw/git_deploy" +export BW_GIT_DEPLOY_CACHE=.cache/bw/git_deploy mkdir -p "$BW_GIT_DEPLOY_CACHE" unset PS1 diff --git a/.gitignore b/.gitignore index 1e6d0ea..fbef28c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .secrets.cfg* .venv +.cache diff --git a/README.md b/README.md index aadf803..730b100 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # TODO -- raspberry cpu frequency /sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_cur_freq - gollum wiki - blog? - fix dkim not working sometimes diff --git a/bundles/build-agent/items.py b/bundles/build-agent/items.py new file mode 100644 index 0000000..e69de29 diff --git a/bundles/build-agent/metadata.py b/bundles/build-agent/metadata.py new file mode 100644 index 0000000..7738f04 --- /dev/null +++ b/bundles/build-agent/metadata.py @@ -0,0 +1,38 @@ +defaults = { + 'apt': { + 'packages': { + 'build-essential': {}, + # crystal + 'clang': {}, + 'libssl-dev': {}, + 'libpcre3-dev': {}, + 'libgc-dev': {}, + 'libevent-dev': {}, + 'zlib1g-dev': {}, + }, + }, + 'users': { + 'build-agent': { + 'home': '/var/lib/build-agent', + }, + }, +} + + +@metadata_reactor.provides( + 'users/build-agent/authorized_users', +) +def ssh_keys(metadata): + return { + 'users': { + 'build-agent': { + 'authorized_users': { + f'build-server@{other_node.name}' + for other_node in repo.nodes + if other_node.has_bundle('build-server') + for architecture in other_node.metadata.get('build-server/architectures').values() + if architecture['node'] == node.name + }, + }, + }, + } diff --git a/bundles/build-server/README.md b/bundles/build-server/README.md new file mode 100644 index 0000000..f2a3ee3 --- /dev/null +++ b/bundles/build-server/README.md @@ -0,0 +1,2 @@ +JSON=$(cat bundles/build-server/example.json) +curl -X POST 'https://build.sublimity.de/crystal?file=procio.cr' -H "Content-Type: application/json" --data-binary @- <<< $JSON diff --git a/bundles/build-server/example.json b/bundles/build-server/example.json new file mode 100644 index 0000000..e9053be --- /dev/null +++ b/bundles/build-server/example.json @@ -0,0 +1,169 @@ +{ + "after": "122d7843c7814079e8df4919b0208c95ec7c75e3", + "before": "7a358255247926363ef0ef34111f0bc786a8c6f4", + "commits": [ + { + "added": [], + "author": { + "email": "mwiegand@seibert-media.net", + "name": "mwiegand", + "username": "" + }, + "committer": { + "email": "mwiegand@seibert-media.net", + "name": "mwiegand", + "username": "" + }, + "id": "122d7843c7814079e8df4919b0208c95ec7c75e3", + "message": "wip\n", + "modified": [ + "README.md" + ], + "removed": [], + "timestamp": "2021-11-16T22:10:05+01:00", + "url": "https://git.sublimity.de/cronekorkn/telegraf-procio/commit/122d7843c7814079e8df4919b0208c95ec7c75e3", + "verification": null + } + ], + "compare_url": "https://git.sublimity.de/cronekorkn/telegraf-procio/compare/7a358255247926363ef0ef34111f0bc786a8c6f4...122d7843c7814079e8df4919b0208c95ec7c75e3", + "head_commit": { + "added": [], + "author": { + "email": "mwiegand@seibert-media.net", + "name": "mwiegand", + "username": "" + }, + "committer": { + "email": "mwiegand@seibert-media.net", + "name": "mwiegand", + "username": "" + }, + "id": "122d7843c7814079e8df4919b0208c95ec7c75e3", + "message": "wip\n", + "modified": [ + "README.md" + ], + "removed": [], + "timestamp": "2021-11-16T22:10:05+01:00", + "url": "https://git.sublimity.de/cronekorkn/telegraf-procio/commit/122d7843c7814079e8df4919b0208c95ec7c75e3", + "verification": null + }, + "pusher": { + "active": false, + "avatar_url": "https://git.sublimity.de/user/avatar/cronekorkn/-1", + "created": "2021-06-13T19:19:25+02:00", + "description": "", + "email": "i@ckn.li", + "followers_count": 0, + "following_count": 0, + "full_name": "", + "id": 1, + "is_admin": false, + "language": "", + "last_login": "0001-01-01T00:00:00Z", + "location": "", + "login": "cronekorkn", + "prohibit_login": false, + "restricted": false, + "starred_repos_count": 0, + "username": "cronekorkn", + "visibility": "public", + "website": "" + }, + "ref": "refs/heads/master", + "repository": { + "allow_merge_commits": true, + "allow_rebase": true, + "allow_rebase_explicit": true, + "allow_squash_merge": true, + "archived": false, + "avatar_url": "", + "clone_url": "https://git.sublimity.de/cronekorkn/telegraf-procio.git", + "created_at": "2021-11-05T18:46:04+01:00", + "default_branch": "master", + "default_merge_style": "merge", + "description": "", + "empty": false, + "fork": false, + "forks_count": 0, + "full_name": "cronekorkn/telegraf-procio", + "has_issues": true, + "has_projects": true, + "has_pull_requests": true, + "has_wiki": true, + "html_url": "https://git.sublimity.de/cronekorkn/telegraf-procio", + "id": 5, + "ignore_whitespace_conflicts": false, + "internal": false, + "internal_tracker": { + "allow_only_contributors_to_track_time": true, + "enable_issue_dependencies": true, + "enable_time_tracker": true + }, + "mirror": false, + "mirror_interval": "", + "name": "telegraf-procio", + "open_issues_count": 0, + "open_pr_counter": 0, + "original_url": "", + "owner": { + "active": false, + "avatar_url": "https://git.sublimity.de/user/avatar/cronekorkn/-1", + "created": "2021-06-13T19:19:25+02:00", + "description": "", + "email": "i@ckn.li", + "followers_count": 0, + "following_count": 0, + "full_name": "", + "id": 1, + "is_admin": false, + "language": "", + "last_login": "0001-01-01T00:00:00Z", + "location": "", + "login": "cronekorkn", + "prohibit_login": false, + "restricted": false, + "starred_repos_count": 0, + "username": "cronekorkn", + "visibility": "public", + "website": "" + }, + "parent": null, + "permissions": { + "admin": true, + "pull": true, + "push": true + }, + "private": false, + "release_counter": 0, + "size": 28, + "ssh_url": "git@git.sublimity.de:cronekorkn/telegraf-procio.git", + "stars_count": 0, + "template": false, + "updated_at": "2021-11-16T21:41:40+01:00", + "watchers_count": 1, + "website": "" + }, + "sender": { + "active": false, + "avatar_url": "https://git.sublimity.de/user/avatar/cronekorkn/-1", + "created": "2021-06-13T19:19:25+02:00", + "description": "", + "email": "i@ckn.li", + "followers_count": 0, + "following_count": 0, + "full_name": "", + "id": 1, + "is_admin": false, + "language": "", + "last_login": "0001-01-01T00:00:00Z", + "location": "", + "login": "cronekorkn", + "prohibit_login": false, + "restricted": false, + "starred_repos_count": 0, + "username": "cronekorkn", + "visibility": "public", + "website": "" + } +} diff --git a/bundles/build-server/files/crystal b/bundles/build-server/files/crystal new file mode 100644 index 0000000..117d9ee --- /dev/null +++ b/bundles/build-server/files/crystal @@ -0,0 +1,31 @@ +#!/bin/bash + +set -exu + +DOWNLOAD_SERVER="${download_server}" +CONFIG=$(cat ${config_path}) +JSON="$1" +ARGS="$2" +REPO_NAME=$(jq -r .repository.name <<< $JSON) +CLONE_URL=$(jq -r .repository.clone_url <<< $JSON) +BUILD_FILE=$(jq -r .file <<< $ARGS) +DATE=$(date --utc +%s) + +cd ~ +rm -rf "$REPO_NAME" +git clone "$CLONE_URL" +cd "$REPO_NAME" + +for ARCH in $(jq -r '.architectures | keys[]' <<< $CONFIG) +do + TARGET=$(jq -r .architectures.$ARCH.target <<< $CONFIG) + IP=$(jq -r .architectures.$ARCH.ip <<< $CONFIG) + BUILD_CMD=$(crystal build "$BUILD_FILE" --cross-compile --target="$TARGET" --release -o "$REPO_NAME") + + scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$REPO_NAME.o" "build-agent@$IP:~" + ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "build-agent@$IP" $BUILD_CMD + scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "build-agent@$IP:~/$REPO_NAME" . + ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "downloads@$DOWNLOAD_SERVER" mkdir -p "~/$REPO_NAME" + scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$REPO_NAME" "downloads@$DOWNLOAD_SERVER:~/$REPO_NAME/$REPO_NAME-$ARCH-$DATE" + ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "downloads@$DOWNLOAD_SERVER" ln -sf "$REPO_NAME-$ARCH-$DATE" "~/$REPO_NAME/$REPO_NAME-$ARCH-latest" +done diff --git a/bundles/build-server/items.py b/bundles/build-server/items.py new file mode 100644 index 0000000..d09d7bd --- /dev/null +++ b/bundles/build-server/items.py @@ -0,0 +1,24 @@ +import json +from bundlewrap.metadata import MetadataJSONEncoder + +directories = { + '/opt/build-server/strategies': { + 'owner': 'build-server', + }, +} + +files = { + '/etc/build-server.json': { + 'owner': 'build-server', + 'content': json.dumps(node.metadata.get('build-server'), indent=4, cls=MetadataJSONEncoder) + }, + '/opt/build-server/strategies/crystal': { + 'content_type': 'mako', + 'owner': 'build-server', + 'mode': '0777', # FIXME + 'context': { + 'config_path': '/etc/build-server.json', + 'download_server': node.metadata.get('build-server/download_server_ip'), + }, + }, +} diff --git a/bundles/build-server/metadata.py b/bundles/build-server/metadata.py new file mode 100644 index 0000000..f742198 --- /dev/null +++ b/bundles/build-server/metadata.py @@ -0,0 +1,59 @@ +from ipaddress import ip_interface + +defaults = { + 'flask': { + 'build-server' : { + 'git_url': "https://git.sublimity.de/cronekorkn/build-server.git", + 'port': 4000, + 'app_module': 'build_server', + 'user': 'build-server', + 'group': 'build-server', + 'timeout': 900, + 'env': { + 'CONFIG': '/etc/build-server.json', + 'STRATEGIES_DIR': '/opt/build-server/strategies', + }, + }, + }, + 'users': { + 'build-server': { + 'home': '/var/lib/build-server', + }, + }, +} + + +@metadata_reactor.provides( + 'build-server', +) +def agent_conf(metadata): + download_server = repo.get_node(metadata.get('build-server/download_server')) + return { + 'build-server': { + 'architectures': { + architecture: { + 'ip': str(ip_interface(repo.get_node(conf['node']).metadata.get('network/internal/ipv4')).ip), + } + for architecture, conf in metadata.get('build-server/architectures').items() + }, + 'download_server_ip': str(ip_interface(download_server.metadata.get('network/internal/ipv4')).ip), + }, + } + + +@metadata_reactor.provides( + 'nginx/vhosts', +) +def nginx(metadata): + return { + 'nginx': { + 'vhosts': { + metadata.get('build-server/hostname'): { + 'content': 'nginx/proxy_pass.conf', + 'context': { + 'target': 'http://127.0.0.1:4000', + }, + }, + }, + }, + } diff --git a/bundles/download-server/items.py b/bundles/download-server/items.py new file mode 100644 index 0000000..3f74add --- /dev/null +++ b/bundles/download-server/items.py @@ -0,0 +1,6 @@ +# directories = { +# '/var/lib/downloads': { +# 'owner': 'downloads', +# 'group': 'www-data', +# } +# } diff --git a/bundles/download-server/metadata.py b/bundles/download-server/metadata.py new file mode 100644 index 0000000..4fea1cc --- /dev/null +++ b/bundles/download-server/metadata.py @@ -0,0 +1,66 @@ +defaults = { + 'users': { + 'downloads': { + 'home': '/var/lib/downloads', + 'needs': { + 'zfs_dataset:tank/downloads' + }, + }, + }, + 'zfs': { + 'datasets': { + 'tank/downloads': { + 'mountpoint': '/var/lib/downloads', + }, + }, + }, +} + + +@metadata_reactor.provides( + 'systemd-mount' +) +def mount_certs(metadata): + return { + 'systemd-mount': { + '/var/lib/downloads_nginx': { + 'source': '/var/lib/downloads', + 'user': 'www-data', + }, + }, + } + + +@metadata_reactor.provides( + 'nginx/vhosts', +) +def nginx(metadata): + return { + 'nginx': { + 'vhosts': { + metadata.get('download-server/hostname'): { + 'content': 'nginx/directory_listing.conf', + 'context': { + 'directory': '/var/lib/downloads_nginx', + }, + }, + }, + }, + } + + +@metadata_reactor.provides( + 'users/downloads/authorized_users', +) +def ssh_keys(metadata): + return { + 'users': { + 'downloads': { + 'authorized_users': { + f'build-server@{other_node.name}' + for other_node in repo.nodes + if other_node.has_bundle('build-server') + }, + }, + }, + } diff --git a/bundles/flask/README.md b/bundles/flask/README.md new file mode 100644 index 0000000..1a5864d --- /dev/null +++ b/bundles/flask/README.md @@ -0,0 +1,54 @@ +# Flask + +This bundle can deploy one or more Flask applications per node. + +```python + 'flask': { + 'myapp': { + 'app_module': "myapp", + 'apt_dependencies': [ + "libffi-dev", + "libssl-dev", + ], + 'env': { + 'APP_SECRETS': "/opt/client_secrets.json", + }, + 'json_config': { + 'this json': 'is_visible', + 'inside': 'your template.cfg', + }, + 'git_url': "ssh://git@bitbucket.apps.seibert-media.net:7999/smedia/myapp.git", + 'git_branch': "master", + 'deployment_triggers': ["action:do-a-thing"], + }, + }, +``` + +The git repo containing the application has to obey some conventions: + +* requirements-frozen.txt (preferred) or requirements.txt +* minimal setup.py to allow for installation with pip + +The `app` instance has to exists in the module defined by `app_module`. + +It is also very advisable to enable logging in your app (otherwise HTTP 500s won't be logged): + +```python +import logging + +if not app.debug: + stream_handler = logging.StreamHandler() + stream_handler.setLevel(logging.INFO) + app.logger.addHandler(stream_handler) +``` + +If you specify `json_config`, then `/opt/${app}/config.json` will be +created. The environment variable `$APP_CONFIG` will point to the exact +name. You can use it in your app to load your config: + +```python +app.config.from_json(environ['APP_CONFIG']) +``` + +If `json_config` is *not* specified, you *can* put a static file in +`data/flask/files/cfg/$app_name`. diff --git a/bundles/flask/files/flask.cfg b/bundles/flask/files/flask.cfg new file mode 100644 index 0000000..e6c7980 --- /dev/null +++ b/bundles/flask/files/flask.cfg @@ -0,0 +1,10 @@ +<% +from json import dumps +from bundlewrap.metadata import MetadataJSONEncoder +%> +${dumps( + json_config, + cls=MetadataJSONEncoder, + indent=4, + sort_keys=True, +)} diff --git a/bundles/flask/files/flask.service b/bundles/flask/files/flask.service new file mode 100644 index 0000000..9cf1077 --- /dev/null +++ b/bundles/flask/files/flask.service @@ -0,0 +1,14 @@ +[Unit] +Description=flask application ${name} +After=network.target + +[Service] +% for key, value in env.items(): +Environment=${key}=${value} +% endfor +User=${user} +Group=${group} +ExecStart=/opt/${name}/venv/bin/gunicorn -w ${workers} -b ${host}:${port} ${app_module}:app + +[Install] +WantedBy=multi-user.target diff --git a/bundles/flask/items.py b/bundles/flask/items.py new file mode 100644 index 0000000..39c1fb8 --- /dev/null +++ b/bundles/flask/items.py @@ -0,0 +1,119 @@ +for name, conf in node.metadata.get('flask').items(): + for dep in conf.get('apt_dependencies', []): + pkg_apt[dep] = { + 'needed_by': { + f'svc_systemd:{name}', + }, + } + + directories[f'/opt/{name}'] = { + 'owner': conf['user'], + 'group': conf['group'], + } + directories[f'/opt/{name}/src'] = {} + + git_deploy[f'/opt/{name}/src'] = { + 'repo': conf['git_url'], + 'rev': conf.get('git_branch', 'master'), + 'triggers': [ + f'action:flask_{name}_pip_install_deps', + *conf.get('deployment_triggers', []), + ], + } + + # CONFIG + + env = conf.get('env', {}) + + if conf.get('json_config', {}): + env['APP_CONFIG'] = f'/opt/{name}/config.json' + files[env['APP_CONFIG']] = { + 'source': 'flask.cfg', + 'context': { + 'json_config': conf.get('json_config', {}), + }, + } + + if 'APP_CONFIG' in env: + files[env['APP_CONFIG']].update({ + 'content_type': 'mako', + 'group': 'www-data', + 'needed_by': [ + f'svc_systemd:{name}', + ], + 'triggers': [ + f'svc_systemd:{name}:restart', + ], + }) + + # secrets + + if 'secrets.json' in conf: + env['APP_SECRETS'] = f'/opt/{name}/secrets.json' + files[env['APP_SECRETS']] = { + 'content': conf['secrets.json'], + 'mode': '0600', + 'owner': conf.get('user', 'www-data'), + 'group': conf.get('group', 'www-data'), + 'needed_by': [ + f'svc_systemd:{name}', + ], + } + + # VENV + + actions[f'flask_{name}_create_virtualenv'] = { + 'cascade_skip': False, + 'command': f'python3 -m venv /opt/{name}/venv', + 'unless': f'test -d /opt/{name}/venv', + 'needs': [ + f'directory:/opt/{name}', + 'pkg_apt:python3-venv', + ], + 'triggers': [ + f'action:flask_{name}_pip_install_deps', + ], + } + + actions[f'flask_{name}_pip_install_deps'] = { + 'cascade_skip': False, + 'command': f'/opt/{name}/venv/bin/pip3 install -r /opt/{name}/src/requirements-frozen.txt || /opt/{name}/venv/bin/pip3 install -r /opt/{name}/src/requirements.txt', + 'triggered': True, # TODO: https://stackoverflow.com/questions/16294819/check-if-my-python-has-all-required-packages + 'needs': [ + f'git_deploy:/opt/{name}/src', + 'pkg_apt:python3-pip', + ], + 'triggers': [ + f'action:flask_{name}_pip_install_gunicorn', + ], + } + + actions[f'flask_{name}_pip_install_gunicorn'] = { + 'command': f'/opt/{name}/venv/bin/pip3 install -U gunicorn', + 'triggered': True, + 'cascade_skip': False, + 'needs': [ + f'action:flask_{name}_create_virtualenv', + ], + 'triggers': [ + f'action:flask_{name}_pip_install', + ], + } + + actions[f'flask_{name}_pip_install'] = { + 'command': f'/opt/{name}/venv/bin/pip3 install -e /opt/{name}/src', + 'triggered': True, + 'cascade_skip': False, + 'triggers': [ + f'svc_systemd:{name}:restart', + ], + } + + # UNIT + + svc_systemd[name] = { + 'needs': [ + f'action:flask_{name}_pip_install', + f'file:/etc/systemd/system/{name}.service', + ], + } diff --git a/bundles/flask/metadata.py b/bundles/flask/metadata.py new file mode 100644 index 0000000..ca333b8 --- /dev/null +++ b/bundles/flask/metadata.py @@ -0,0 +1,61 @@ +defaults = { + 'apt': { + 'packages': { + 'python3-pip': {}, + 'python3-dev': {}, + 'python3-venv': {}, + }, + }, + 'flask': {}, +} + + +@metadata_reactor.provides( + 'flask', +) +def app_defaults(metadata): + return { + 'flask': { + name: { + 'user': 'root', + 'group': 'root', + 'workers': 8, + 'timeout': 30, + **conf, + } + for name, conf in metadata.get('flask').items() + } + } + + +@metadata_reactor.provides( + 'systemd/units', +) +def units(metadata): + return { + 'systemd': { + 'units': { + f'{name}.service': { + 'Unit': { + 'Description': name, + 'After': 'network.target', + }, + 'Service': { + 'Environment': { + f'{k}={v}' + for k, v in conf.get('env', {}).items() + }, + 'User': conf['user'], + 'Group': conf['group'], + 'ExecStart': f"/opt/{name}/venv/bin/gunicorn -w {conf['workers']} -b 127.0.0.1:{conf['port']} --timeout {conf['timeout']} {conf['app_module']}:app" + }, + 'Install': { + 'WantedBy': { + 'multi-user.target' + } + }, + } + for name, conf in metadata.get('flask').items() + } + } + } diff --git a/bundles/smartctl/metadata.py b/bundles/smartctl/metadata.py index 18726ca..8da7ad9 100644 --- a/bundles/smartctl/metadata.py +++ b/bundles/smartctl/metadata.py @@ -24,6 +24,6 @@ defaults = { }, }, 'sudoers': { - 'telegraf': ['/usr/local/share/icinga/plugins/smartctl'], + 'telegraf': {'/usr/local/share/icinga/plugins/smartctl'}, }, } diff --git a/bundles/users/items.py b/bundles/users/items.py index 730c8db..33dbd0a 100644 --- a/bundles/users/items.py +++ b/bundles/users/items.py @@ -3,8 +3,9 @@ for group, config in node.metadata.get('groups', {}).items(): for name, config in node.metadata.get('users').items(): directories[config['home']] = { - 'owner': name, - 'mode': '700', + 'owner': config.get('home_owner', name), + 'group': config.get('home_group', name), + 'mode': config.get('home_mode', '700'), } files[f"{config['home']}/.ssh/id_{config['keytype']}"] = { @@ -33,5 +34,5 @@ for name, config in node.metadata.get('users').items(): } users[name] = config - for option in ['authorized_keys', 'authorized_users', 'privkey', 'pubkey', 'keytype']: + for option in ['authorized_keys', 'authorized_users', 'privkey', 'pubkey', 'keytype', 'home_owner', 'home_group', 'home_mode']: users[name].pop(option, None) diff --git a/data/nginx/directory_listing.conf b/data/nginx/directory_listing.conf new file mode 100644 index 0000000..af232d0 --- /dev/null +++ b/data/nginx/directory_listing.conf @@ -0,0 +1,11 @@ +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name ${server_name}; + + ssl_certificate /var/lib/dehydrated/certs/${server_name}/fullchain.pem; + ssl_certificate_key /var/lib/dehydrated/certs/${server_name}/privkey.pem; + + root ${directory}; + autoindex on; +} diff --git a/data/nginx/proxy_pass.conf b/data/nginx/proxy_pass.conf index 906ad0c..0955d6c 100644 --- a/data/nginx/proxy_pass.conf +++ b/data/nginx/proxy_pass.conf @@ -9,8 +9,4 @@ server { location / { proxy_pass ${target}; } - - location /.well-known/acme-challenge/ { - alias /var/lib/dehydrated/acme-challenges/; - } } diff --git a/data/nginx/redirect.conf b/data/nginx/redirect.conf index 56bdffa..6b0a63e 100644 --- a/data/nginx/redirect.conf +++ b/data/nginx/redirect.conf @@ -7,4 +7,5 @@ server { ssl_certificate_key /var/lib/dehydrated/certs/${server_name}/privkey.pem; return 302 ${target}; + autoindex_exact_size off; } diff --git a/groups/applications/build-server.py b/groups/applications/build-server.py new file mode 100644 index 0000000..eb332d3 --- /dev/null +++ b/groups/applications/build-server.py @@ -0,0 +1,6 @@ +{ + 'bundles': { + 'build-server', + 'flask', + }, +} diff --git a/nodes/home.openhab.py b/nodes/home.openhab.py index e21774d..62985c5 100644 --- a/nodes/home.openhab.py +++ b/nodes/home.openhab.py @@ -8,10 +8,11 @@ 'webserver', ], 'bundles': [ - 'zfs', - 'openhab', + 'build-agent', 'java', + 'openhab', 'systemd-swap', + 'zfs', ], 'metadata': { 'FIXME_dont_touch_sshd': True, diff --git a/nodes/home.server.py b/nodes/home.server.py index 2d627c3..c6cbf46 100644 --- a/nodes/home.server.py +++ b/nodes/home.server.py @@ -7,8 +7,10 @@ 'monitored', 'webserver', 'hardware', + 'build-server', ], 'bundles': [ + 'build-agent', 'gitea', 'gollum', 'grafana', @@ -31,6 +33,20 @@ 'gateway4': '10.0.0.1', }, }, + 'build-server': { + 'hostname': 'build.sublimity.de', + 'architectures': { + 'amd64': { + 'node': 'home.server', + 'target': 'x86_64-unknown-linux-gnu', + }, + 'arm64': { + 'node': 'home.openhab', + 'target': 'aarch64-unknown-linux-gnu', + }, + }, + 'download_server': 'netcup.mails', + }, 'gitea': { 'version': '1.15.5', 'sha256': 'c3f190848c271bf250d385b80c1a98a7e2c9b23d092891cf1f7e4ce18c736484', diff --git a/nodes/netcup.mails.py b/nodes/netcup.mails.py index 468254b..4506b3c 100644 --- a/nodes/netcup.mails.py +++ b/nodes/netcup.mails.py @@ -10,6 +10,7 @@ ], 'bundles': [ 'bind-acme', + 'download-server', 'islamicstate.eu', 'wireguard', 'zfs', @@ -60,6 +61,9 @@ 'AAAA': ['2a01:4f8:1c1c:4121::2'], }, }, + 'download-server': { + 'hostname': 'dl.sublimity.de', + }, 'letsencrypt': { 'domains': { 'ckn.li': {},