Better starttup/shutdown notification

This commit is contained in:
Lauri Võsandi 2017-07-11 18:57:19 +00:00
parent d44b6035c2
commit 03b9778170
6 changed files with 39 additions and 30 deletions

View File

@ -1284,15 +1284,14 @@ def certidude_cron():
@click.command("serve", help="Run server")
@click.option("-e", "--exit-handler", default=False, is_flag=True, help="Install /api/exit/ handler")
@click.option("-p", "--port", default=8080, help="Listen port")
@click.option("-l", "--listen", default="127.0.1.1", help="Listen address")
@click.option("-f", "--fork", default=False, is_flag=True, help="Fork to background")
def certidude_serve(port, listen, fork, exit_handler):
def certidude_serve(port, listen, fork):
import pwd
from setproctitle import setproctitle
from certidude.signer import SignServer
from certidude import authority, const
from certidude import authority, const, push
if port == 80:
click.echo("WARNING: Please run Certidude behind nginx, remote address is assumed to be forwarded by nginx!")
@ -1332,7 +1331,8 @@ def certidude_serve(port, listen, fork, exit_handler):
if os.path.exists(const.SIGNER_SOCKET_PATH):
os.unlink(const.SIGNER_SOCKET_PATH)
if not os.fork():
signer_pid = os.fork()
if not signer_pid:
click.echo("Signer process spawned with PID %d at %s" % (os.getpid(), const.SIGNER_SOCKET_PATH))
setproctitle("[signer]")
@ -1421,29 +1421,23 @@ def certidude_serve(port, listen, fork, exit_handler):
with open(const.SERVER_PID_PATH, "w") as pidfile:
pidfile.write("%d\n" % pid)
def exit_handler():
def cleanup_handler(*args):
push.publish("server-stopped")
logger.debug(u"Shutting down Certidude")
import atexit
atexit.register(exit_handler)
assert authority.signer_exec("exit") == "ok"
sys.exit(0) # TODO: use another code, needs test refactor
import signal
signal.signal(signal.SIGTERM, cleanup_handler) # Handle SIGTERM from systemd
push.publish("server-started")
logger.debug(u"Started Certidude at %s", const.FQDN)
drop_privileges()
class ExitResource():
"""
Provide way to gracefully shutdown server
"""
def on_get(self, req, resp):
assert httpd._BaseServer__shutdown_request == False
httpd._BaseServer__shutdown_request = True
if exit_handler:
app.add_route("/api/exit/", ExitResource())
httpd.serve_forever()
# Shut down signer as well
assert authority.signer_exec("exit") == "ok"
try:
httpd.serve_forever()
except KeyboardInterrupt:
cleanup_handler() # FIXME
@click.command("yubikey", help="Set up Yubikey as client authentication token")

View File

@ -7,12 +7,11 @@ from datetime import datetime
from certidude import config
def publish(event_type, event_data):
def publish(event_type, event_data=''):
"""
Publish event on nchan EventSource publisher
"""
assert event_type, "No event type specified"
assert event_data, "No event data specified"
if not isinstance(event_data, basestring):
from certidude.decorators import MyEncoder

View File

@ -22,6 +22,9 @@
<li id="section-log" data-section="log" style="display:none;">Log</li>
</ul>
</nav>
<div id="under_maintenance" class="container" style="display:none;">
Server under maintenance...
</div>
<div id="container" class="container">
Loading certificate authority...
</div>

View File

@ -199,6 +199,18 @@ function onAttributeUpdated(e) {
})
}
function onServerStarted() {
console.info("Server started");
location.reload();
}
function onServerStopped() {
$("#container").hide();
$("#under_maintenance").show();
console.info("Server stopped");
}
$(document).ready(function() {
console.info("Loading CA, to debug: curl " + window.location.href + " --negotiate -u : -H 'Accept: application/json'");
$.ajax({
@ -247,6 +259,8 @@ $(document).ready(function() {
source.addEventListener("certificate-revoked", onCertificateRevoked);
source.addEventListener("tag-update", onTagUpdated);
source.addEventListener("attribute-update", onAttributeUpdated);
source.addEventListener("server-started", onServerStarted);
source.addEventListener("server-stopped", onServerStopped);
console.info("Swtiching to requests section");
$("section").hide();

View File

@ -5,7 +5,6 @@ After=network.target
[Service]
Environment=PYTHON_EGG_CACHE=/tmp/.cache
PIDFile=/run/certidude/server.pid
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
ExecStart={{ certidude_path }} serve

View File

@ -270,7 +270,7 @@ def test_cli_setup_authority():
server_pid = os.fork()
if not server_pid:
# Fork to prevent umask, setuid, setgid side effects
result = runner.invoke(cli, ['serve', '-p', '8080', '-l', '127.0.1.1', '-e'])
result = runner.invoke(cli, ['serve'])
assert not result.exception, result.output
return
@ -988,7 +988,7 @@ def test_cli_setup_authority():
####################################
# Shut down current instance
requests.get("http://ca.example.lan/api/exit")
os.kill(server_pid, 15)
requests.get("http://ca.example.lan/api/")
os.waitpid(server_pid, 0)
@ -1051,7 +1051,7 @@ def test_cli_setup_authority():
assert "admin;adminbot;Admin;Bot;adminbot@example.lan" in result.output
assert "admin;Administrator;Administrator;;Administrator@example.lan" in result.output
result = runner.invoke(cli, ['serve', '-p', '8080', '-l', '127.0.1.1', '-e'])
result = runner.invoke(cli, ['serve'])
assert not result.exception, result.output
return
@ -1179,7 +1179,7 @@ def test_cli_setup_authority():
# Shut down server
assert os.path.exists("/proc/%d" % server_pid)
requests.get("http://ca.example.lan/api/exit")
os.kill(server_pid, 15)
os.waitpid(server_pid, 0)
# Note: STORAGE_PATH was mangled above, hence it's /tmp not /var/lib/certidude