bootstrap-vz/bootstrapvz/remote/server.py
Anders Ingemann f62c8ade99 Convert indentation from tabs to spaces (4)
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
2016-06-04 11:38:16 +02:00

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