mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-24 15:36:27 +00:00

Up until now I didn't see the point of using spaces for indentation. However, the previous commit (a18bec3) was quite eye opening. Given that python is an indentation aware language, the amount of mistakes that went unnoticed because tabs and spaces were used at the same time (tabs for indentation and spaces for alignment) were unacceptable. E101,W191 have been re-enable in the tox flake8 checker and the documentation has been modified accordingly. The following files have been left as-is: * bootstrapvz/common/assets/extlinux/extlinux.conf * bootstrapvz/common/assets/init.d/expand-root * bootstrapvz/common/assets/init.d/generate-ssh-hostkeys * bootstrapvz/common/assets/init.d/squeeze/generate-ssh-hostkeys * bootstrapvz/plugins/docker_daemon/assets/init.d/docker * bootstrapvz/providers/ec2/assets/bin/growpart * bootstrapvz/providers/ec2/assets/grub.d/40_custom * bootstrapvz/providers/ec2/assets/init.d/ec2-get-credentials * bootstrapvz/providers/ec2/assets/init.d/ec2-run-user-data * docs/_static/taskoverview.coffee * docs/_static/taskoverview.less * tests/unit/subprocess.sh
130 lines
4.3 KiB
Python
130 lines
4.3 KiB
Python
import Pyro4
|
|
import logging
|
|
|
|
Pyro4.config.REQUIRE_EXPOSE = True
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
def main():
|
|
opts = getopts()
|
|
from . import register_deserialization_handlers
|
|
register_deserialization_handlers()
|
|
log_forwarder = setup_logging()
|
|
server = Server(opts['--listen'], log_forwarder)
|
|
server.start()
|
|
|
|
|
|
def setup_logging():
|
|
root = logging.getLogger()
|
|
root.setLevel(logging.NOTSET)
|
|
|
|
from log import LogForwarder
|
|
log_forwarder = LogForwarder()
|
|
root.addHandler(log_forwarder)
|
|
|
|
from datetime import datetime
|
|
import os.path
|
|
from bootstrapvz.base.log import get_file_handler
|
|
timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
|
|
filename = '{timestamp}_remote.log'.format(timestamp=timestamp)
|
|
logfile_path = os.path.join('/var/log/bootstrap-vz', filename)
|
|
file_handler = get_file_handler(logfile_path, True)
|
|
root.addHandler(file_handler)
|
|
|
|
return log_forwarder
|
|
|
|
|
|
def getopts():
|
|
from docopt import docopt
|
|
usage = """bootstrap-vz-server
|
|
|
|
Usage: bootstrap-vz-server [options]
|
|
|
|
Options:
|
|
--listen <port> Serve on specified port [default: 46675]
|
|
-h, --help show this help
|
|
"""
|
|
return docopt(usage)
|
|
|
|
|
|
class Server(object):
|
|
|
|
def __init__(self, listen_port, log_forwarder):
|
|
self.stop_serving = False
|
|
self.log_forwarder = log_forwarder
|
|
self.listen_port = listen_port
|
|
|
|
def start(self):
|
|
Pyro4.config.COMMTIMEOUT = 0.5
|
|
daemon = Pyro4.Daemon('localhost', port=int(self.listen_port), unixsocket=None)
|
|
daemon.register(self, 'server')
|
|
|
|
daemon.requestLoop(loopCondition=lambda: not self.stop_serving)
|
|
|
|
@Pyro4.expose
|
|
def set_callback_server(self, server):
|
|
log.debug('Forwarding logs to the callback server')
|
|
self.log_forwarder.set_server(server)
|
|
|
|
@Pyro4.expose
|
|
def ping(self):
|
|
if hasattr(self, 'connection_timeout'):
|
|
self.connection_timeout.cancel()
|
|
del self.connection_timeout
|
|
return 'pong'
|
|
|
|
@Pyro4.expose
|
|
def stop(self):
|
|
if hasattr(self, 'bootstrap_process'):
|
|
log.warn('Sending SIGINT to bootstrapping process')
|
|
import os
|
|
import signal
|
|
os.killpg(self.bootstrap_process.pid, signal.SIGINT)
|
|
self.bootstrap_process.join()
|
|
|
|
# We can't send a SIGINT to the server,
|
|
# for some reason the Pyro4 shutdowns are rather unclean,
|
|
# throwing exceptions and such.
|
|
self.stop_serving = True
|
|
|
|
@Pyro4.expose
|
|
def run(self, manifest, debug=False, dry_run=False):
|
|
|
|
def bootstrap(queue):
|
|
# setsid() creates a new session, making this process the group leader.
|
|
# We do that, so when the server calls killpg (kill process group)
|
|
# on us, it won't kill itself (this process was spawned from a
|
|
# thread under the server, meaning it's part of the same group).
|
|
# The process hierarchy looks like this:
|
|
# Pyro server (process - listening on a port)
|
|
# +- pool thread
|
|
# +- pool thread
|
|
# +- pool thread
|
|
# +- started thread (the one that got the "run()" call)
|
|
# L bootstrap() process (us)
|
|
# Calling setsid() also fixes another problem:
|
|
# SIGINTs sent to this process seem to be redirected
|
|
# to the process leader. Since there is a thread between
|
|
# us and the process leader, the signal will not be propagated
|
|
# (signals are not propagated to threads), this means that any
|
|
# subprocess we start (i.e. debootstrap) will not get a SIGINT.
|
|
import os
|
|
os.setsid()
|
|
from bootstrapvz.base.main import run
|
|
try:
|
|
bootstrap_info = run(manifest, debug=debug, dry_run=dry_run)
|
|
queue.put(bootstrap_info)
|
|
except (Exception, KeyboardInterrupt) as e:
|
|
queue.put(e)
|
|
|
|
from multiprocessing import Queue
|
|
from multiprocessing import Process
|
|
queue = Queue()
|
|
self.bootstrap_process = Process(target=bootstrap, args=(queue,))
|
|
self.bootstrap_process.start()
|
|
self.bootstrap_process.join()
|
|
del self.bootstrap_process
|
|
result = queue.get()
|
|
if isinstance(result, Exception):
|
|
raise result
|
|
return result
|