143 lines
4.4 KiB
Python
143 lines
4.4 KiB
Python
# import pprint
|
|
import subprocess
|
|
import sys
|
|
|
|
def _execute(command,**kwargs):
|
|
# print("Running:")
|
|
# pprint.pprint(command)
|
|
|
|
check = kwargs.get('check', True)
|
|
on_stdout_line = kwargs.get('on_stdout_line', None)
|
|
on_stderr_line = kwargs.get('on_stderr_line', None)
|
|
with subprocess.Popen(
|
|
command,
|
|
universal_newlines=True,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
) as proc:
|
|
stdout = None
|
|
if proc.stdout:
|
|
stdout = ''
|
|
for line in proc.stdout:
|
|
if on_stdout_line:
|
|
on_stdout_line(line)
|
|
stdout += line
|
|
|
|
stderr = None
|
|
if proc.stderr:
|
|
stderr = ''
|
|
for line in proc.stderr:
|
|
if on_stderr_line:
|
|
on_stderr_line(line)
|
|
stderr += line
|
|
|
|
proc.wait()
|
|
if check and proc.returncode != 0:
|
|
print("STDOUT:")
|
|
print(stdout)
|
|
print("STDERR (not interlaced properly, sorry):")
|
|
print(stderr)
|
|
|
|
raise subprocess.CalledProcessError(
|
|
command,
|
|
proc.returncode,
|
|
stdout or None,
|
|
stderr or None
|
|
)
|
|
else:
|
|
return subprocess.CompletedProcess(
|
|
command,
|
|
proc.returncode,
|
|
stdout or None,
|
|
stderr or None
|
|
)
|
|
|
|
def _docker(command, **kwargs):
|
|
return _execute([
|
|
"docker",
|
|
"compose",
|
|
"exec", '-T',
|
|
"site",
|
|
] + command,
|
|
**kwargs)
|
|
|
|
def _start():
|
|
print("Starting containers in operation mode . . .")
|
|
print(" If this takes a while, it's probably building the container.")
|
|
command = [
|
|
'docker',
|
|
'compose',
|
|
'-f', 'docker-compose.yml',
|
|
'-f', 'docker-compose-operation.yml',
|
|
'up',
|
|
'--build',
|
|
'-d',
|
|
]
|
|
result = _execute(command)
|
|
|
|
# alright this seems sketchy, bear with me
|
|
|
|
# previous versions of this code used the '--wait' command-line flag
|
|
# the problem with --wait is that it waits for the container to be healthy and working
|
|
# "but wait, isn't that what we want?"
|
|
# ah, but see, if the container will *never* be healthy and working - say, if there's a flaw causing it to fail on startup - it just waits forever
|
|
# so that's not actually useful
|
|
|
|
# previous versions of this code also had a check to see if the containers started up properly
|
|
# but this is surprisingly annoying to do if we don't know the containers' names
|
|
# docker compose *can* do it, but you either have to use very new features that aren't supported on Ubuntu 22.04, or you have to go through a bunch of parsing pain
|
|
# and it kind of doesn't seem necessary
|
|
|
|
# see, docker compose in this form *will* wait until it's *attempted* to start each container.
|
|
# so at this point in execution, either the containers are running, or they're crashed
|
|
# if they're running, hey, problem solved, we're good
|
|
# if they're crashed, y'know what, problem still solved! because our next command will fail
|
|
|
|
# maybe there's still a race condition? I dunno! Keep an eye on this.
|
|
# If there is a race condition then you're stuck doing something gnarly with `docker compose ps`. Good luck!
|
|
|
|
print(" Containers started!")
|
|
|
|
return result
|
|
|
|
def _stop():
|
|
# use "stop" instead of "down" to avoid killing all stored data
|
|
command = ['docker', 'compose', 'stop']
|
|
print("Stopping containers . . .")
|
|
result = _execute(command)
|
|
return result
|
|
|
|
def _operation(name, commands):
|
|
# restart to make sure they're in the right mode
|
|
_stop()
|
|
|
|
_start()
|
|
|
|
# prepend our upgrade, since right now we're always using it
|
|
commands = [[
|
|
"python3",
|
|
"-m", "flask",
|
|
"db", "upgrade"
|
|
]] + commands
|
|
|
|
# run operations in docker container
|
|
print(f"Running {name} . . .")
|
|
for command in commands:
|
|
result = _docker(
|
|
command,
|
|
on_stdout_line=lambda line: print(line, end=''),
|
|
on_stderr=lambda line: print(line, end=''),
|
|
)
|
|
|
|
_stop()
|
|
|
|
return result
|
|
|
|
def run_help():
|
|
print("Available commands: (test|migrate|help)")
|
|
print("Usage: './manage.py <command> [options]'")
|
|
exit(0)
|
|
|
|
def error(message,code=1):
|
|
print(message,file=sys.stderr)
|
|
exit(code)
|