build cystal
This commit is contained in:
parent
7ad5f62022
commit
6cceae2458
26 changed files with 701 additions and 12 deletions
2
.envrc
2
.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
|
||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
.secrets.cfg*
|
||||
.venv
|
||||
.cache
|
||||
|
|
|
@ -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
|
||||
|
|
0
bundles/build-agent/items.py
Normal file
0
bundles/build-agent/items.py
Normal file
38
bundles/build-agent/metadata.py
Normal file
38
bundles/build-agent/metadata.py
Normal file
|
@ -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
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
2
bundles/build-server/README.md
Normal file
2
bundles/build-server/README.md
Normal file
|
@ -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
|
169
bundles/build-server/example.json
Normal file
169
bundles/build-server/example.json
Normal file
|
@ -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": ""
|
||||
}
|
||||
}
|
31
bundles/build-server/files/crystal
Normal file
31
bundles/build-server/files/crystal
Normal file
|
@ -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
|
24
bundles/build-server/items.py
Normal file
24
bundles/build-server/items.py
Normal file
|
@ -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'),
|
||||
},
|
||||
},
|
||||
}
|
59
bundles/build-server/metadata.py
Normal file
59
bundles/build-server/metadata.py
Normal file
|
@ -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',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
6
bundles/download-server/items.py
Normal file
6
bundles/download-server/items.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
# directories = {
|
||||
# '/var/lib/downloads': {
|
||||
# 'owner': 'downloads',
|
||||
# 'group': 'www-data',
|
||||
# }
|
||||
# }
|
66
bundles/download-server/metadata.py
Normal file
66
bundles/download-server/metadata.py
Normal file
|
@ -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')
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
54
bundles/flask/README.md
Normal file
54
bundles/flask/README.md
Normal file
|
@ -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`.
|
10
bundles/flask/files/flask.cfg
Normal file
10
bundles/flask/files/flask.cfg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<%
|
||||
from json import dumps
|
||||
from bundlewrap.metadata import MetadataJSONEncoder
|
||||
%>
|
||||
${dumps(
|
||||
json_config,
|
||||
cls=MetadataJSONEncoder,
|
||||
indent=4,
|
||||
sort_keys=True,
|
||||
)}
|
14
bundles/flask/files/flask.service
Normal file
14
bundles/flask/files/flask.service
Normal file
|
@ -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
|
119
bundles/flask/items.py
Normal file
119
bundles/flask/items.py
Normal file
|
@ -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',
|
||||
],
|
||||
}
|
61
bundles/flask/metadata.py
Normal file
61
bundles/flask/metadata.py
Normal file
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,6 +24,6 @@ defaults = {
|
|||
},
|
||||
},
|
||||
'sudoers': {
|
||||
'telegraf': ['/usr/local/share/icinga/plugins/smartctl'],
|
||||
'telegraf': {'/usr/local/share/icinga/plugins/smartctl'},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
11
data/nginx/directory_listing.conf
Normal file
11
data/nginx/directory_listing.conf
Normal file
|
@ -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;
|
||||
}
|
|
@ -9,8 +9,4 @@ server {
|
|||
location / {
|
||||
proxy_pass ${target};
|
||||
}
|
||||
|
||||
location /.well-known/acme-challenge/ {
|
||||
alias /var/lib/dehydrated/acme-challenges/;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,4 +7,5 @@ server {
|
|||
ssl_certificate_key /var/lib/dehydrated/certs/${server_name}/privkey.pem;
|
||||
|
||||
return 302 ${target};
|
||||
autoindex_exact_size off;
|
||||
}
|
||||
|
|
6
groups/applications/build-server.py
Normal file
6
groups/applications/build-server.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
'bundles': {
|
||||
'build-server',
|
||||
'flask',
|
||||
},
|
||||
}
|
|
@ -8,10 +8,11 @@
|
|||
'webserver',
|
||||
],
|
||||
'bundles': [
|
||||
'zfs',
|
||||
'openhab',
|
||||
'build-agent',
|
||||
'java',
|
||||
'openhab',
|
||||
'systemd-swap',
|
||||
'zfs',
|
||||
],
|
||||
'metadata': {
|
||||
'FIXME_dont_touch_sshd': True,
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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': {},
|
||||
|
|
Loading…
Reference in a new issue