def update(args, config={}): if config == {}: config = load_config(args)[0] previous_version = parse_version( import_module("cherrydoor.__version__").__version__) if step_enabled("pip", args): pip_update() current_version = parse_version( import_module("cherrydoor.__version__").__version__) database_enabled = step_enabled("database", args) if database_enabled: from pymongo import MongoClient db = MongoClient( f"mongodb://{config.get('mongo', {}).get('url', 'localhost:27017')}/{config.get('mongo', {}).get('name', 'cherrydoor')}" )[config.get("mongo", {}).get("name", "cherrydoor")] database_version = db.settings.find_one({"setting": "version"}) if database_version == None: database_version = previous_version config_enabled = step_enabled("config", args) if config_enabled: config_version = parse_version(str(config.get("version", ""))) path = find_spec( "cherrydoor.cli.update_scripts").submodule_search_locations[0] for script_name in iglob(f"{path}/[a-zA-Z0-9]*.*py"): update_script = import_module( f"cherrydoor.cli.update_scripts.{basename(script_name)[:-3]}") script_version = parse_version(update_script.__version__) if script_version > previous_version: try: update_script.update() except AttributeError: pass if database_enabled and script_version > database_version: try: update_script.update_database(db) except AttributeError: pass if config_enabled and script_version > config_version: try: update_script.update_config(config) except AttributeError: pass
def cherrydoor(): parser = argparse.ArgumentParser(prog="cherrydoor", description="Cherrydoor management") parser.add_argument( "-v", "--version", help="Print Cherrydoor version and exit", action="version", version=f"Cherrydoor {__version__}", ) subparsers = parser.add_subparsers(dest="subcommand") install_parser = subparsers.add_parser( "install", help="Install some possible requirements") install_parser.set_defaults(install_steps_excluded=[], install_steps=[], fail=False) install_parser.add_argument( "--exit-on-fail", help="If any step fails, stop the installer", dest="fail", action="store_true", ) install_steps_group = install_parser.add_argument_group( "steps", "installation steps you want to run (if none are selected all will be run)", ) install_steps = { "dependencies": "install all dependencies that weren't installed with pip", "service": "set up a systemd unit file", "config": "create a config file", "database": "set up MongoDB user, collections, etc.", "user": "******", } for (step, description) in install_steps.items(): install_steps_group.add_argument( f"--{step}", dest="install_steps", action="append_const", const=step, help=description, ) install_steps_group.add_argument( f"--no-{step}", dest="install_steps_excluded", action="append_const", const=step, help=f"don't {description}", ) update_parser = subparsers.add_parser( "update", help="update Cherrydoor to the newest version") update_parser.set_defaults(update_steps_excluded=[], update_steps=[], fail=False) update_parser.add_argument( "-d", "--dev", help="Install latest development version", dest="dev", action="store_true", ) update_parser.add_argument( "-v", "--verison", help="Install specific version", dest="version", action="store", ) update_parser.add_argument( "--exit-on-fail", help="If any step fails, stop the updater", dest="fail", action="store_true", ) update_steps_group = update_parser.add_argument_group( "steps", "update steps you want to run (if none are selected all will be run)", ) update_steps = { "pip": "install the newest version of Cherrydoor via pip", "config": "update your config file", "database": "Update database schema and settings", } for (step, description) in update_steps.items(): update_steps_group.add_argument( f"--{step}", dest="update_steps", action="append_const", const=step, help=description, ) update_steps_group.add_argument( f"--no-{step}", dest="update_steps_excluded", action="append_const", const=step, help=f"don't {description}", ) start_parser = subparsers.add_parser( "start", help= "Explicitly start the server (this action is preformed if no other argument is passed too)", ) add_args(parser) add_args(start_parser) args = parser.parse_args() config, _ = load_config(args) log_level = getattr(logging, config.get("log_level", "WARN").upper()) if not isinstance(log_level, int): log_level = logging.WARN logging.warn( "Invalid log level %s - defaulting to WARN", config.get("log_level", "WARN").upper(), ) logging.basicConfig( level=log_level, format="%(asctime)s:%(name)s:%(levelname)s: %(message)s", ) if args.subcommand == "install": from cherrydoor.cli.install import install install(args) if args.subcommand == "update": from cherrydoor.cli.update import update update(args) # if start argument was passed or no arguments were used, start the server if args.subcommand in ["start", None]: from cherrydoor.app import setup_app from cherrydoor.interface.serial import Serial try: import uvloop uvloop.install() except ModuleNotFoundError: pass loop = asyncio.get_event_loop() app = setup_app(loop, config) interface = Serial(app["db"], loop) app["serial"] = interface app.on_startup.append(interface.aiohttp_startup) app.on_cleanup.append(interface.cleanup) web.run_app( app, host=config.get("host", "127.0.0.1"), port=config.get("port", 5000), path=config.get("path", None), )
def setup_app(loop=asyncio.get_event_loop(), config=load_config()[0]): if config.get("sentry_dsn", None): sentry_sdk.init( dsn=config["sentry_dsn"], integrations=[AioHttpIntegration()], release=f"cherrydoor@{__version__}", ) # create app app = web.Application(loop=loop) # make config accessible through the app app["config"] = config # setup database and add it to the app db = init_db(config, loop) app["db"] = db # create a token generator/validator and add make it accessible through the app api_tokens = ApiTokens(app, config.get("secret_key", "")) app["api_tokens"] = api_tokens app.on_startup.append(setup_db) # set up aiohttp-session with aiohttp-session-mongo for storage setup_session( app, MongoStorage( db["sessions"], max_age=None, cookie_name="session_id", ), ) # set up aiohttp-security setup_security( app, SessionIdentityPolicy("uid", config.get("max_session_age", 31536000)), AuthorizationPolicy(app), ) # set up secure.py secure_setup(app) app.middlewares.append(set_secure_headers) csrf_policy = aiohttp_csrf.policy.FormAndHeaderPolicy( CSRF_HEADER_NAME, CSRF_FIELD_NAME ) csrf_storage = aiohttp_csrf.storage.SessionStorage(CSRF_SESSION_NAME) aiohttp_csrf.setup(app, policy=csrf_policy, storage=csrf_storage) # app.middlewares.append(aiohttp_csrf.csrf_middleware) load_and_connect_all_endpoints_from_folder( path=f"{os.path.dirname(os.path.realpath(__file__))}/api", app=app, version_prefix="api/v1", ) redoc_url = "/api/v1/docs" setup_redoc( app, redoc_url=redoc_url, description=openapi_description, title="Cherrydoor API", page_title="Cherrydocs", openapi_info=get_openapi_documentation(overrides=openapi_overrides), redoc_options=redoc_options, contact=openapi_contact, ) app["redoc_url"] = redoc_url app.router.add_routes(redoc_routes) setup_static_routes(app) jinja2_loader = PackageLoader("cherrydoor", "templates") setup_jinja2(app, loader=jinja2_loader, auto_reload=True) get_env(app).globals["sri"] = sri_for get_env(app).globals["csrf_field_name"] = CSRF_FIELD_NAME get_env(app).filters["vue"] = vue setup_routes(app) sio.attach(app) app.on_startup.append(setup_socket_tasks) return app
def get_config(): from cherrydoor.config import load_config config, _ = load_config() return config
def get_config(): """Load AttrDict with configuration.""" from cherrydoor.config import load_config # pylint: disable=import-outside-toplevel config, _ = load_config() return config