From: Guillaume Abrioux Date: Fri, 16 Jun 2023 09:13:56 +0000 (+0200) Subject: node-proxy: create entrypoint main() X-Git-Tag: v18.2.4~314^2~87 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=481e75ee0181c91a21bc337e0b72391497d4c6de;p=ceph.git node-proxy: create entrypoint main() This creates a `main()` function in server.py that will be the entrypoint of node-proxy. This also implement arg parsing and add a `--config` parameter to specify the configuration file. Finally, this introduce a small refactor of class `Config` and class `Logger` in util.py because there was a circular dependency between them. Signed-off-by: Guillaume Abrioux (cherry picked from commit f2f87f4259bbfe1014f5a2309a82f5b08a8d78d3) --- diff --git a/src/cephadm/node-proxy/server-v2.py b/src/cephadm/node-proxy/server-v2.py index f4afba4daa11e..4eef854bea550 100644 --- a/src/cephadm/node-proxy/server-v2.py +++ b/src/cephadm/node-proxy/server-v2.py @@ -5,6 +5,7 @@ from util import Config, Logger from typing import Dict from basesystem import BaseSystem import sys +import argparse # for devel purposes import os @@ -33,133 +34,179 @@ for env_var in DEVEL_ENV_VARS: print(f"{env_var} environment variable must be set.") sys.exit(1) -config = Config(default_config=DEFAULT_CONFIG) - -log = Logger(__name__, level=config.logging['level']) -# must be passed as arguments -host = os.environ.get('REDFISH_HOST') -username = os.environ.get('REDFISH_USERNAME') -password = os.environ.get('REDFISH_PASSWORD') - -# create the redfish system and the obsever -log.logger.info("Server initialization...") -system = RedfishDell(host=host, - username=username, - password=password, - system_endpoint='/Systems/System.Embedded.1', - config=config) -reporter_agent = Reporter(system, "http://127.0.0.1:8000") - class Memory: exposed = True + def __init__(self, backend: BaseSystem) -> None: + self.backend = backend + @cherrypy.tools.json_out() def GET(self) -> Dict[str, Dict[str, Dict]]: - return {'memory': system.get_memory()} + return {'memory': self.backend.get_memory()} class Network: exposed = True + def __init__(self, backend: BaseSystem) -> None: + self.backend = backend + @cherrypy.tools.json_out() def GET(self) -> Dict[str, Dict[str, Dict]]: - return {'network': system.get_network()} + return {'network': self.backend.get_network()} class Processors: exposed = True + def __init__(self, backend: BaseSystem) -> None: + self.backend = backend + @cherrypy.tools.json_out() def GET(self) -> Dict[str, Dict[str, Dict]]: - return {'processors': system.get_processors()} + return {'processors': self.backend.get_processors()} class Storage: exposed = True + def __init__(self, backend: BaseSystem) -> None: + self.backend = backend + @cherrypy.tools.json_out() def GET(self) -> Dict[str, Dict[str, Dict]]: - return {'storage': system.get_storage()} + return {'storage': self.backend.get_storage()} class Status: exposed = True + def __init__(self, backend: BaseSystem) -> None: + self.backend = backend + @cherrypy.tools.json_out() def GET(self) -> Dict[str, Dict[str, Dict]]: - return {'status': system.get_status()} + return {'status': self.backend.get_status()} class System: exposed = True - memory = Memory() - network = Network() - processors = Processors() - storage = Storage() - status = Status() - # actions = Actions() - # control = Control() + + def __init__(self, backend: BaseSystem) -> None: + self.memory = Memory(backend) + self.network = Network(backend) + self.processors = Processors(backend) + self.storage = Storage(backend) + self.status = Status(backend) + # actions = Actions() + # control = Control() class Shutdown: exposed = True + def __init__(self, backend: BaseSystem, reporter: Reporter) -> None: + self.backend = backend + self.reporter = reporter + def POST(self) -> str: - _stop() + _stop(self.backend, self.reporter) cherrypy.engine.exit() return 'Server shutdown...' -def _stop() -> None: - system.stop_update_loop() - system.client.logout() - reporter_agent.stop() +def _stop(backend: BaseSystem, reporter: Reporter) -> None: + backend.stop_update_loop() + backend.client.logout() + reporter.stop() class Start: exposed = True + def __init__(self, backend: BaseSystem, reporter: Reporter) -> None: + self.backend = backend + self.reporter = reporter + def POST(self) -> str: - system.start_client() - system.start_update_loop() - reporter_agent.run() + self.backend.start_client() + self.backend.start_update_loop() + self.reporter.run() return 'node-proxy daemon started' class Stop: exposed = True + def __init__(self, backend: BaseSystem, reporter: Reporter) -> None: + self.backend = backend + self.reporter = reporter + def POST(self) -> str: - _stop() + _stop(self.backend, self.reporter) return 'node-proxy daemon stopped' class ConfigReload: exposed = True - def __init__(self, config: cherrypy.config) -> None: + def __init__(self, config: Config) -> None: self.config = config def POST(self) -> str: - self.config['node_proxy'].reload() + self.config.reload() return 'node-proxy config reloaded' class API: exposed = True - system = System() - shutdown = Shutdown() - start = Start() - stop = Stop() - config_reload = ConfigReload(cherrypy.config) + def __init__(self, + backend: BaseSystem, + reporter: Reporter, + config: Config) -> None: + + self.system = System(backend) + self.shutdown = Shutdown(backend, reporter) + self.start = Start(backend, reporter) + self.stop = Stop(backend, reporter) + self.config_reload = ConfigReload(config) def GET(self) -> str: return 'use /system' -if __name__ == '__main__': +def main() -> None: + + parser = argparse.ArgumentParser( + prog='node-proxy', + ) + parser.add_argument( + '--config', + dest='config', + type=str, + required=False, + default='/etc/ceph/node-proxy.yml' + ) + + args = parser.parse_args() + config = Config(args.config, default_config=DEFAULT_CONFIG) + + log = Logger(__name__, level=config.logging['level']) + # must be passed as arguments + host = os.environ.get('REDFISH_HOST') + username = os.environ.get('REDFISH_USERNAME') + password = os.environ.get('REDFISH_PASSWORD') + + # create the redfish system and the obsever + log.logger.info("Server initialization...") + system = RedfishDell(host=host, + username=username, + password=password, + system_endpoint='/Systems/System.Embedded.1', + config=config) + reporter_agent = Reporter(system, "http://127.0.0.1:8000") cherrypy.config.update({ 'node_proxy': config, 'server.socket_port': config.__dict__['server']['port'] @@ -170,4 +217,8 @@ if __name__ == '__main__': }} system.start_update_loop() reporter_agent.run() - cherrypy.quickstart(API(), config=c) + cherrypy.quickstart(API(system, reporter_agent, config), config=c) + + +if __name__ == '__main__': + main() diff --git a/src/cephadm/node-proxy/util.py b/src/cephadm/node-proxy/util.py index 6420e904876f2..112652f7bd769 100644 --- a/src/cephadm/node-proxy/util.py +++ b/src/cephadm/node-proxy/util.py @@ -5,14 +5,26 @@ import time from typing import Dict, List, Callable, Any -def normalize_dict(test_dict: Dict) -> Dict: - res = dict() - for key in test_dict.keys(): - if isinstance(test_dict[key], dict): - res[key.lower()] = normalize_dict(test_dict[key]) - else: - res[key.lower()] = test_dict[key] - return res +class Logger: + _Logger: List['Logger'] = [] + + def __init__(self, name: str, level: int = logging.INFO): + self.name = name + self.level = level + + Logger._Logger.append(self) + self.logger = self.get_logger() + + def get_logger(self) -> logging.Logger: + logger = logging.getLogger(self.name) + logger.setLevel(self.level) + handler = logging.StreamHandler() + handler.setLevel(self.level) + fmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') + handler.setFormatter(fmt) + logger.addHandler(handler) + + return logger class Config: @@ -50,26 +62,17 @@ class Config: self.load_config() -class Logger: - _Logger: List['Logger'] = [] - - def __init__(self, name: str, level: int = logging.INFO): - self.name = name - self.level = level +log = Logger(__name__) - Logger._Logger.append(self) - self.logger = self.get_logger() - def get_logger(self) -> logging.Logger: - logger = logging.getLogger(self.name) - logger.setLevel(self.level) - handler = logging.StreamHandler() - handler.setLevel(self.level) - fmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') - handler.setFormatter(fmt) - logger.addHandler(handler) - - return logger +def normalize_dict(test_dict: Dict) -> Dict: + res = dict() + for key in test_dict.keys(): + if isinstance(test_dict[key], dict): + res[key.lower()] = normalize_dict(test_dict[key]) + else: + res[key.lower()] = test_dict[key] + return res def retry(exceptions: Any = Exception, retries: int = 20, delay: int = 1) -> Callable: @@ -78,12 +81,12 @@ def retry(exceptions: Any = Exception, retries: int = 20, delay: int = 1) -> Cal _tries = retries while _tries > 1: try: - print("{}".format(_tries)) + log.logger.debug("{} {} attempt(s) left.".format(f, _tries - 1)) return f(*args, **kwargs) except exceptions: time.sleep(delay) _tries -= 1 - print("{} has failed after {} tries".format(f, retries)) + log.logger.warn("{} has failed after {} tries".format(f, retries)) return f(*args, **kwargs) return _retry return decorator