first step to refactor

This commit is contained in:
Joachim Lusiardi 2016-04-10 12:36:43 +02:00
parent 0a39d8c8b1
commit c3664b34d3
2 changed files with 74 additions and 48 deletions

View File

@ -9,21 +9,24 @@ import os
from socket import getaddrinfo from socket import getaddrinfo
import logging import logging
def get_if_available(dict, key, defValue): def get_if_available(dict, key, defValue):
if key in dict: if key in dict:
return dict[key] return dict[key]
else: else:
return defValue return defValue
def analyse_proxy_data(data): def analyse_proxy_data(data):
"""Extracts the data for the proxy configuration (envrionment variable """Extracts the data for the proxy configuration (envrionment variable
'PROXY_DATA' and converts it to a dictionary.""" 'PROXY_DATA' and converts it to a dictionary."""
proxy_data = {} proxy_data = {}
for proxy_var in data['PROXY_DATA'].split(','): for proxy_var in data['PROXY_DATA'].split(','):
t = proxy_var.split(":",1) t = proxy_var.split(":", 1)
proxy_data[t[0]] = t[1] proxy_data[t[0]] = t[1]
return proxy_data return proxy_data
def analyse_env_vars(inspect_data): def analyse_env_vars(inspect_data):
"""Extracts the environment variables from the given result of an 'inspect """Extracts the environment variables from the given result of an 'inspect
container' call.""" container' call."""
@ -35,6 +38,7 @@ def analyse_env_vars(inspect_data):
env_data[t[0]] = t[1] env_data[t[0]] = t[1]
return env_data return env_data
def handle_container(docker_client, id): def handle_container(docker_client, id):
"""This function take a container's id and collects all data required """This function take a container's id and collects all data required
to create a proper proxy configuration. The configuration is then to create a proper proxy configuration. The configuration is then
@ -47,6 +51,7 @@ def handle_container(docker_client, id):
return names return names
return [] return []
def get_resolving_domains_from_containers(docker_client): def get_resolving_domains_from_containers(docker_client):
container_ids = docker_client.containers(quiet=True) container_ids = docker_client.containers(quiet=True)
@ -70,8 +75,8 @@ def get_resolving_domains_from_containers(docker_client):
return resolved_domains return resolved_domains
if __name__ == '__main__':
if __name__ == '__main__':
client = Client(base_url='unix://var/run/docker.sock', version='1.15') client = Client(base_url='unix://var/run/docker.sock', version='1.15')
resolved_domains = get_resolving_domains_from_containers(client) resolved_domains = get_resolving_domains_from_containers(client)

113
start.py
View File

@ -12,34 +12,37 @@ import threading
import list_domains import list_domains
from docker import Client from docker import Client
cert_path='/data/haproxy' cert_path = '/data/haproxy'
cert_file='/data/haproxy/cert.pem' cert_file = '/data/haproxy/cert.pem'
pid_file='/haproxy.pid' pid_file = '/haproxy.pid'
delay = 10
def hash_cert_file(): def hash_cert_file():
"""Creates the sha256 hash of the certifcate file for haproxy. If the file """Creates the sha256 hash of the certificate file for haproxy. If the file
does not exist, an empty string is returned. does not exist, an empty string is returned.
""" """
if not os.path.isfile(cert_file): if not os.path.isfile(cert_file):
return '' return ''
aFile = open(cert_file, 'rb') file_obj = open(cert_file, 'rb')
hasher = hashlib.sha256() hash_generator = hashlib.sha256()
buf = aFile.read(65536) buf = file_obj.read(65536)
while len(buf) > 0: while len(buf) > 0:
hasher.update(buf) hash_generator.update(buf)
buf = aFile.read(65536) buf = file_obj.read(65536)
return hasher.digest() return hash_generator.digest()
def setup_logging(): def setup_logging():
"""Sets up logging with a nice format""" """Sets up logging with a nice format"""
logging.basicConfig(format='%(asctime)s [%(levelname)s]: %(message)s', level=logging.INFO) logging.basicConfig(format='%(asctime)s [%(levelname)s]: %(message)s', level=logging.INFO)
def get_pid(): def get_pid():
"""This function reads the process id from the given file and returns as int.""" """This function reads the process id from the given file and returns as int."""
with open(pid_file, 'r') as file: with open(pid_file, 'r') as file:
return int(file.read()) return int(file.read())
def kill_haproxy(): def kill_haproxy():
"""Stops the currently running instance of haproxy by issueing a kill signal to its pid.""" """Stops the currently running instance of haproxy by issueing a kill signal to its pid."""
logging.info('killing haproxy') logging.info('killing haproxy')
@ -48,16 +51,19 @@ def kill_haproxy():
except OSError: except OSError:
pass pass
def start_haproxy_ssl(): def start_haproxy_ssl():
logging.info('starting haproxy SSL') logging.info('starting haproxy SSL')
os.system('/usr/sbin/haproxy -f /haproxy_ssl.conf -p /haproxy.pid') os.system('/usr/sbin/haproxy -f /haproxy_ssl.conf -p ' + pid_file)
return is_haproxy_running() return is_haproxy_running()
def start_haproxy(): def start_haproxy():
logging.info('starting haproxy NON SSL') logging.info('starting haproxy NON SSL')
os.system('/usr/sbin/haproxy -f /haproxy.conf -p /haproxy.pid') os.system('/usr/sbin/haproxy -f /haproxy.conf -p ' + pid_file)
return False return False
def is_haproxy_running(): def is_haproxy_running():
try: try:
os.kill(get_pid(), 0) os.kill(get_pid(), 0)
@ -65,6 +71,7 @@ def is_haproxy_running():
except OSError: except OSError:
return False return False
def ssl_possible(): def ssl_possible():
"""Check if a certificate is available.""" """Check if a certificate is available."""
@ -73,67 +80,81 @@ def ssl_possible():
else: else:
return True return True
def create_haproxy_cert(): def create_haproxy_cert():
"""Combines the freshly created fullchain.pem and privkey.pem into /data/haproxy/cert.pem""" """Combines the freshly created fullchain.pem and privkey.pem into /data/haproxy/cert.pem"""
logging.info('updating %s', cert_file) logging.info('updating %s', cert_file)
os.system('DIR=`ls -td /data/config/live/*/ | head -1`; echo ${DIR}; mkdir -p /data/haproxy; cat ${DIR}/fullchain.pem ${DIR}/privkey.pem > /data/haproxy/cert.pem') if not os.path.exists(cert_path):
logging.info('creating cert_path path: %s', cert_path)
os.mkdir(cert_path)
os.system(
'DIR=`ls -td /data/config/live/*/ | head -1`; echo ${DIR}; cat ${DIR}/fullchain.pem ${DIR}/privkey.pem > ' + cert_file)
def create_cert_data_standalone(domains): def create_cert_data_standalone(domains):
domains = " -d ".join(domains) domains = " -d ".join(domains)
os.system('/letsencrypt/letsencrypt-auto --config letencrypt.conf certonly --expand --force-renewal --duplicate --allow-subset-of-names --standalone-supported-challenges http-01 --http-01-port 54321 -d ' + domains) os.system(
'/letsencrypt/letsencrypt-auto --config letencrypt.conf certonly --expand --force-renewal --duplicate --allow-subset-of-names --standalone-supported-challenges http-01 --http-01-port 54321 -d ' + domains)
def cert_watcher(): def cert_watcher():
SSL_RUNNING=True ssl_active = ssl_possible() and is_haproxy_running()
cert_file_hash = hash_cert_file() cert_file_hash = hash_cert_file()
while True: while True:
logging.info('ping') logging.info('ping')
time.sleep(60) time.sleep(delay)
if ssl_possible() and not SSL_RUNNING:
kill_haproxy() if not ssl_active:
start_haproxy_ssl() if ssl_possible():
if is_haproxy_running(): # we should be able to start with SSL, but ...
cert_file_hash = hash_cert_file() kill_haproxy()
logging.info('NON SSL -> SSL') start_haproxy_ssl()
SSL_RUNNING=True if is_haproxy_running():
# running with SSL succeeded
cert_file_hash = hash_cert_file()
logging.info('NON SSL -> SSL')
ssl_active = True
else:
# something went wrong (maybe broken certificate) but without SSL we can run it
start_haproxy()
logging.info('NON SSL -> NON SSL')
else: else:
start_haproxy() # currently not running with SSL but also no cert, so we do not attempt to start with SSL
SSL_RUNNING=False pass
if SSL_RUNNING and cert_file_hash != hash_cert_file(): else:
logging.info('cert has changed') if cert_file_hash != hash_cert_file():
kill_haproxy() # we are running with SSL and the certificate has changed so we need to restart haproxy
start_haproxy_ssl() logging.info('cert has changed')
if is_haproxy_running(): kill_haproxy()
start_haproxy_ssl()
if is_haproxy_running():
# restart with SSL succeeded, update hash
logging.info('SSL -> SSL')
else:
# restart with SSL failed, so we start without SSL again
start_haproxy()
logging.info('SSL -> NON SSL')
ssl_active = False
cert_file_hash = hash_cert_file() cert_file_hash = hash_cert_file()
logging.info('SSL -> SSL')
SSL_RUNNING=True
else:
start_haproxy()
logging.info('SSL -> NON SSL')
SSL_RUNNING=False
if __name__ == '__main__': if __name__ == '__main__':
setup_logging() setup_logging()
logging.info('starting') logging.info('starting ssl endpoint')
if not os.path.exists(cert_path):
logging.info('creating cert_path path: %s', cert_path)
os.mkdir(cert_path)
client = Client(base_url='unix://var/run/docker.sock', version='1.15') client = Client(base_url='unix://var/run/docker.sock', version='1.15')
cert_file_hash = hash_cert_file()
# try to start in SSL mode, no problem if that fails # try to start in SSL mode, no problem if that fails
logging.info('try in SSL mode') logging.info('try in SSL mode')
SSL_RUNNING = start_haproxy_ssl() if not start_haproxy_ssl():
if not SSL_RUNNING:
logging.info('SSL mode failed') logging.info('SSL mode failed')
if not is_haproxy_running(): if not is_haproxy_running():
# tried to start haproxy and this failed, so we need to create a certificate and try again: # tried to start haproxy and this failed, so we need to create a certificate and try again:
# - start non ssl haproxy to be able to get a valid cert # - start non ssl haproxy to be able to get a valid cert
logging.info('try in NON SSL mode') logging.info('try in NON SSL mode')
SSL_RUNNING = start_haproxy() start_haproxy()
# - get all domains # - get all domains
resolved_domains = list_domains.get_resolving_domains_from_containers(client) resolved_domains = list_domains.get_resolving_domains_from_containers(client)
# - create cert # - create cert