Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f74e99eee | |||
| d98edb63a5 | |||
| 01c6283ced |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
__pycache__/
|
|
||||||
36
Readme.md
36
Readme.md
@ -1,38 +1,4 @@
|
|||||||
# Usage
|
# Usage
|
||||||
|
|
||||||
## autodiscover
|
|
||||||
|
|
||||||
usage: `python3 discover.py [-a <action>] [-l] service_dir [service_dir …]`
|
|
||||||
|
|
||||||
add label "de.wie-ei.autostart=true" to any service in a docker-compose-file
|
|
||||||
|
|
||||||
!! This label is discovered as string, not by parsing Yaml. Commenting will not work!
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
|
|
||||||
* start services (up -d) `python3 discover.py /srv/services/ /opt/docker/testing/`
|
|
||||||
* which services are configured for autostart? `python3 discover.py -l /srv/services/ /opt/docker/testing/`
|
|
||||||
* check status `python3 discover.py -a ps /opt/docker/testing/`
|
|
||||||
* stop services `python3 discover.py -a "down -v /srv/testing/`
|
|
||||||
|
|
||||||
### pre/post exec
|
|
||||||
|
|
||||||
e.g. `python3 discover.py ./sample/ -a ps --pre 'echo {path} {step}' --post './sample/notify_telegram.sh <telegram_bot_key> <telegram_room> {path} {cmd} {returncode} \n {stdout}'`
|
|
||||||
|
|
||||||
## manual config
|
|
||||||
|
|
||||||
### json config
|
|
||||||
* create config.json from sample.json
|
* create config.json from sample.json
|
||||||
* add `python3 /opt/docker-autostart/start.py /path/to/your/config.json -t json` to `/etc/rc.local`
|
* add `python3 /opt/docker-autostart/start.py /path/to/your/config.json` to `/etc/rc.local`
|
||||||
|
|
||||||
### raw config
|
|
||||||
* create config.lst from sample.lst
|
|
||||||
* add `python3 /opt/docker-autostart/start.py /path/to/your/config.lst` to `/etc/rc.local`
|
|
||||||
|
|
||||||
### other actions
|
|
||||||
* default action: up -d
|
|
||||||
* add argument -a "<compose action>"
|
|
||||||
|
|
||||||
### pre/post exec
|
|
||||||
|
|
||||||
e.g. `python3 start.py test.lst -a ps --pre 'echo {path} {step}' --post './sample/notify_telegram.sh <telegram_bot_key> <telegram_room> {path} {cmd} {returncode} \n {stdout}'`
|
|
||||||
|
|||||||
17
config.json
Normal file
17
config.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"/opt/docker/": [
|
||||||
|
"frontend"
|
||||||
|
],
|
||||||
|
"/opt/docker/services/": [
|
||||||
|
"ldap",
|
||||||
|
"keycloak",
|
||||||
|
"cloud",
|
||||||
|
"cms",
|
||||||
|
"ics_merger",
|
||||||
|
"keycloak_account_selector",
|
||||||
|
"antragsgruen",
|
||||||
|
"zitate"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
73
discover.py
73
discover.py
@ -1,73 +0,0 @@
|
|||||||
import os
|
|
||||||
import logging
|
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
from start import base_args, change_service
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
COMPOSE_FILE = "docker-compose.yml"
|
|
||||||
CONFIG_CMD = "docker-compose -f {path} config "
|
|
||||||
AUTOSTART_KEY = "{prefix}.autostart=true"
|
|
||||||
PRIORITY_KEY = "{prefix}.autostart.priority="
|
|
||||||
PREFIX = "de.wie-ei"
|
|
||||||
|
|
||||||
Service = namedtuple("Service", ("path", "prio"))
|
|
||||||
|
|
||||||
def complete_compose(entry):
|
|
||||||
path = entry.path
|
|
||||||
if not path.endswith(COMPOSE_FILE):
|
|
||||||
return os.path.join(path, COMPOSE_FILE)
|
|
||||||
return path
|
|
||||||
|
|
||||||
def has_compose(path):
|
|
||||||
return os.path.exists(path)
|
|
||||||
|
|
||||||
def find_services(dirs):
|
|
||||||
entries = [entry for base in dirs for entry in os.scandir(base) if entry.is_dir()]
|
|
||||||
return filter(has_compose, map(complete_compose, entries))
|
|
||||||
|
|
||||||
def should_autostart(service):
|
|
||||||
with open(service) as src:
|
|
||||||
service_definitions = src.read()
|
|
||||||
key = AUTOSTART_KEY.format(prefix=PREFIX)
|
|
||||||
if not key in service_definitions:
|
|
||||||
return False
|
|
||||||
prio_key = PRIORITY_KEY.format(prefix=PREFIX)
|
|
||||||
pos = service_definitions.find(prio_key)
|
|
||||||
if pos >= 0:
|
|
||||||
start = pos + len(prio_key)
|
|
||||||
end = pos + service_definitions[pos:].find('"\n')
|
|
||||||
prio = service_definitions[start:end]
|
|
||||||
return int(prio)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def find_autostart_services(services):
|
|
||||||
start_services = []
|
|
||||||
for service in services:
|
|
||||||
prio = should_autostart(service)
|
|
||||||
if prio:
|
|
||||||
start_services.append(Service(path=service, prio=prio))
|
|
||||||
return [x.path for x in sorted(start_services, key=lambda x:x.prio, reverse=True)]
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
logging.basicConfig(format="%(message)s (status %(returncode)s)", level=logging.INFO)
|
|
||||||
parser = base_args("Docker-compose Autostart discovery")
|
|
||||||
parser.add_argument("service_dir", nargs="+", help="One or more directories containing docker-compose services, only direct subdirectories are scanned")
|
|
||||||
parser.add_argument("--list", "-l", action="store_true", help="list autostart services only, no action")
|
|
||||||
parser.add_argument("--key", "-k", help=f"alternative label prefix, default: '{PREFIX}'")
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if args.key:
|
|
||||||
PREFIX = args.key
|
|
||||||
services = find_services(args.service_dir)
|
|
||||||
autostarts = find_autostart_services(services)
|
|
||||||
if args.list:
|
|
||||||
if autostarts:
|
|
||||||
print("\n".join(autostarts))
|
|
||||||
else:
|
|
||||||
import start
|
|
||||||
for service in autostarts:
|
|
||||||
start.change_service(service, args.action, pre_cmd=args.pre, post_cmd=args.post)
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
#!/sbin/openrc-run
|
|
||||||
|
|
||||||
command="python3"
|
|
||||||
command_args="/opt/docker/docker-autostart/discover.py /opt/docker/ /opt/docker/services/"
|
|
||||||
|
|
||||||
depend(){
|
|
||||||
need docker
|
|
||||||
after sshd
|
|
||||||
}
|
|
||||||
|
|
||||||
start(){
|
|
||||||
#python3 /opt/docker/docker-autostart/discover.py /opt/docker/ /opt/docker/services/
|
|
||||||
$command $command_args
|
|
||||||
}
|
|
||||||
|
|
||||||
stop(){
|
|
||||||
#python3 -a down /opt/docker/docker-autostart/discover.py /opt/docker/ /opt/docker/services/
|
|
||||||
$command $command_args -a down
|
|
||||||
}
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
version: "3"
|
|
||||||
|
|
||||||
services:
|
|
||||||
http:
|
|
||||||
image: httpd:alpine
|
|
||||||
ports:
|
|
||||||
- "8080:80"
|
|
||||||
labels:
|
|
||||||
- "de.wie-ei.autostart=true"
|
|
||||||
- "de.wie-ei.autostart.priority=100"
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
version: "3"
|
|
||||||
|
|
||||||
services:
|
|
||||||
http:
|
|
||||||
image: httpd:alpine
|
|
||||||
ports:
|
|
||||||
- "8080:80"
|
|
||||||
labels:
|
|
||||||
- "de.wie-ei.autostart=true"
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
key="$1"
|
|
||||||
room="$2"
|
|
||||||
shift 2
|
|
||||||
url="https://api.telegram.org/bot${key}/sendMessage"
|
|
||||||
json='{"chat_id":'${room}', "text":"'"$@"'"}'
|
|
||||||
curl "$url" --data "$json" -X POST -H 'Content-Type: application/json'
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
/srv/services/gitea
|
|
||||||
/srv/services/http
|
|
||||||
/srv/services/icinga/
|
|
||||||
/srv/services/rz_measurements/docker-compose.yml
|
|
||||||
/srv/services/traefik
|
|
||||||
/home/clemens/hg/biodiv2go/games/web
|
|
||||||
76
start.py
76
start.py
@ -2,71 +2,23 @@ import argparse
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import logging
|
|
||||||
import sys
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
def start(config):
|
||||||
|
with open(config, "r") as src:
|
||||||
|
|
||||||
def change_service(path, action, pre_cmd=None, post_cmd=None):
|
|
||||||
cmd = ["docker-compose"] + action.split()
|
|
||||||
if path.endswith("/docker-compose.yml"):
|
|
||||||
path = path[:-len("/docker-compose.yml")]
|
|
||||||
args = {
|
|
||||||
"args": cmd,
|
|
||||||
"cwd": path,
|
|
||||||
}
|
|
||||||
if post_cmd:
|
|
||||||
args["capture_output"] = True
|
|
||||||
args["text"] = True
|
|
||||||
if pre_cmd:
|
|
||||||
subprocess.run(pre_cmd.format(path=path, cmd=cmd, step="pre").split())
|
|
||||||
r = subprocess.run(**args)
|
|
||||||
log.info(f"processed {path}", extra={"path": path, "cmd": cmd, "returncode": r.returncode})
|
|
||||||
if post_cmd:
|
|
||||||
if r.stdout: print(r.stdout)
|
|
||||||
if r.stderr: print(r.stderr, file=sys.stderr)
|
|
||||||
subprocess.run(post_cmd.format(path=path, cmd=cmd, step="post", returncode=r.returncode, stdout=r.stdout, stderr=r.stderr).split())
|
|
||||||
print()
|
|
||||||
|
|
||||||
|
|
||||||
def load_json(config_file):
|
|
||||||
with open(config_file, "r") as src:
|
|
||||||
data = json.load(src)
|
data = json.load(src)
|
||||||
return [os.path.join(base, service) for base in data for service in data[base]]
|
if data:
|
||||||
|
for base in data:
|
||||||
|
for service in data[base]:
|
||||||
|
path = os.path.join(base, service)
|
||||||
|
print(path)
|
||||||
|
r = subprocess.run(["docker-compose", "up", "-d"], cwd=path)
|
||||||
|
print(r)
|
||||||
|
|
||||||
def load_raw(config_file):
|
|
||||||
with open(config_file) as src:
|
|
||||||
return [line.strip() for line in src]
|
|
||||||
|
|
||||||
def load_stdin(_):
|
|
||||||
for line in sys.stdin:
|
|
||||||
yield line.strip()
|
|
||||||
|
|
||||||
def get_loader(config_file):
|
|
||||||
if config_file.endswith(".json"):
|
|
||||||
return load_json
|
|
||||||
if "-" == config_file:
|
|
||||||
return load_stdin
|
|
||||||
return load_raw
|
|
||||||
|
|
||||||
def apply(config_file, action, pre=None, post=None):
|
|
||||||
load = get_loader(config_file)
|
|
||||||
for path in load(config_file):
|
|
||||||
change_service(path, action, pre_cmd=pre, post_cmd=post)
|
|
||||||
|
|
||||||
def base_args(desc):
|
|
||||||
parser = argparse.ArgumentParser(description=desc)
|
|
||||||
parser.add_argument("--action", "-a", default="up -d", help="docker-compose action to apply, default: up -d")
|
|
||||||
parser.add_argument("--pre", "-s", help="pre-exec: command to run before each action")
|
|
||||||
parser.add_argument("--post", "-e", help="post-exec: command to run after each action")
|
|
||||||
return parser
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
logging.basicConfig(format="%(message)s (status %(returncode)s)", level=logging.INFO)
|
parser = argparse.ArgumentParser(description="Docker-compose Autostart")
|
||||||
parser = base_args("Docker-compose Autostart")
|
parser.add_argument("config_file")
|
||||||
parser.add_argument("config_file", default="-", help="json file, plain text list or - for stdin")
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
apply(args.config_file, args.action, pre=args.pre, post=args.post)
|
start(args.config_file)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user