#!/usr/bin/python3 # Copyright (C) 2017-2018 Lars Wirzenius # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import logging import logging.handlers import os import sys import apifw import slog import yaml import ick2 transactions = slog.Counter() def counter(): return 'HTTP transaction {}'.format(transactions.increment()) def dict_logger(log, stack_info=None): ick2.log.log(exc_info=stack_info, **log) default_config = { 'token-public-key': None, 'token-audience': None, 'token-issuer': None, 'log': [], 'statedir': None, 'artifact-store': None, 'auth-url': None, 'notify-url': None, 'apt-server': None, } def load_config(filename, defconf): conf = yaml.safe_load(open(filename, 'r')) actual_config = dict(defconf) actual_config.update(conf) return actual_config def check_config(config, musthave): for key in config: if key not in musthave: raise Exception('Config %s is not known' % key) for key in musthave: if config.get(key) is None: raise Exception('Config %s must not be None' % key) def main(): logger = logging.getLogger() logger.setLevel(logging.DEBUG) handler = logging.StreamHandler(sys.stderr) logger.addHandler(handler) logging.info('Starting ick controller main program') try: config_filename = os.environ.get('ICK_CONTROLLER_CONFIG') logging.info('config filename %r', config_filename) if not config_filename: logging.error('no ICK_CONTROLLER_CONFIG in environment') raise Exception('No ICK_CONTROLLER_CONFIG defined in environment') logging.info('reading config from %r', config_filename) config = load_config(config_filename, default_config) logging.info('config is %r', config) ick2.setup_logging(config) check_config(config, default_config) ick2.log.log('info', msg_text='Ick2 controller starts', config=config) state = ick2.FilePersistentState() state.set_directory(config['statedir']) api = ick2.ControllerAPI(state) api.set_apt_server(config['apt-server']) api.set_artifact_store_url(config['artifact-store']) api.set_auth_url(config['auth-url']) api.set_notify_url(config['notify-url']) ick2.log.log( 'info', msg_text='created ControllerAPI', artifact_store=config['artifact-store']) application = apifw.create_bottle_application( api, counter, dict_logger, config) ick2.log.log('info', msg_text='called apifw.create_bottle_application') return application except SystemExit: raise except BaseException as e: logging.error(str(e)) ick2.log.log( 'error', msg_text='Uncaught exception', exception=str(e), exc_info=True) sys.exit(1) app = main() # If we are running this program directly with Python, and not via # gunicorn, we can use the Bottle built-in debug server, which can # make some things easier to debug. if __name__ == '__main__': print('running in debug mode') app.run(host='127.0.0.1', port=12765)