From 8ac82369f5c4e56e276ccd1aa326b70467a89f13 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 18 Sep 2025 11:45:51 +0200 Subject: [PATCH] read and write with readis --- Dockerfile | 9 ++++++ config/inventory.yml | 8 +++++ src/database.py | 30 ++++++++++++++++++ src/main.py | 74 +++++++++++++++++++++++++++++++++++++++++--- src/utils.py | 9 ++++++ 5 files changed, 126 insertions(+), 4 deletions(-) create mode 100644 Dockerfile create mode 100644 config/inventory.yml create mode 100644 src/database.py create mode 100644 src/utils.py diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..15be366 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,9 @@ +FROM python:latest + +WORKDIR /usr/local/bin +COPY requirements.txt requirements.txt +RUN pip install -r requirements.txt + +COPY src/start.py . + +CMD ["src/start.py"] \ No newline at end of file diff --git a/config/inventory.yml b/config/inventory.yml new file mode 100644 index 0000000..6433930 --- /dev/null +++ b/config/inventory.yml @@ -0,0 +1,8 @@ +- 1: + hostname: '172.16.57.2' + username: 'admin' + password: 'Netapp12' +- 2: + hostname: '172.16.56.2' + username: 'admin' + password: 'Netapp12' diff --git a/src/database.py b/src/database.py new file mode 100644 index 0000000..17d53c5 --- /dev/null +++ b/src/database.py @@ -0,0 +1,30 @@ +import json +import logging +from redis import Redis, ConnectionError + + +def setup_db_conn(redishost, redisport: str): + ''' Setup Redis connection and return it open''' + log = logging.getLogger('uvicorn') + try: + redisclient = Redis(host=redishost, port=redisport, decode_responses=True) + log.info(f"Connected to Redis DB {redishost} on port {redisport}") + return redisclient + except ConnectionError as e: + print(f"FATAL: Redis DB {redishost} is unreachable on port {redisport}. Err: {e}") + return None + except Exception as e: + print(f"FATAL: {e}") + return None + +def get_inventory_from_redis(redisclient: Redis): + ''' Read inventory from Redis ''' + cluster_inv = redisclient.hgetall('cluster_inventory') + if 'inventory' in cluster_inv: + return json.loads(cluster_inv['inventory']) + return {} + +def read_config_from_db(redisclient: Redis): + ''' Load inventory to global vars''' + global_inventory = get_inventory_from_redis(redisclient) + return global_inventory \ No newline at end of file diff --git a/src/main.py b/src/main.py index cecafa1..294f7e2 100644 --- a/src/main.py +++ b/src/main.py @@ -1,5 +1,71 @@ -def main() -> None: - print("Hello, World!") +import os +import json +import logging +import yaml -if __name__ == "__main__": - main() +from pathlib import Path +from dotenv import load_dotenv +from redis import Redis +from contextlib import asynccontextmanager + +from pydantic import BaseModel, ValidationError, SecretStr, AnyHttpUrl +from typing import Optional, Literal, List, Union +from fastapi import FastAPI + + +from database import setup_db_conn, get_inventory_from_redis, read_config_from_db +from utils import setup_logging + + +def initialize_config(): + load_dotenv() + ENV_INVENTORYPATH = os.getenv('cluster_inventory_path') + ENV_REDISHOST = os.getenv('redis_host') + ENV_REDISPORT = os.getenv('redis_port') + + log.info(f"Fount Cluster Inventory file at: {ENV_INVENTORYPATH}") + if not ENV_INVENTORYPATH or not Path(ENV_INVENTORYPATH).is_file(): + print(f"FATAL: Inventory file {ENV_INVENTORYPATH} is missing or not a file.") + return False + try: + with open(ENV_INVENTORYPATH, 'r') as f: + inv = yaml.safe_load(f) + inventory = json.dumps(inv) + except Exception as e: + print(f"FATAL: Cannot read inventory file {ENV_INVENTORYPATH}. Err: {e}") + return False + + print(f'[INFO] Importing configuration to DB...') + try: + redis_conn = setup_db_conn(ENV_REDISHOST, ENV_REDISPORT) + redis_conn.hset('cluster_inventory', mapping={'inventory': inventory}) + redis_conn.close() + + log.info("Configuration has been loaded.") + return True + + except Exception as e: + print(f"FATAL: Redis DB error: {e}") + return False + +@asynccontextmanager +async def lifespan(app: FastAPI): + ''' make loading it async''' + log = logging.getLogger('uvicorn') + cfg_init_result = initialize_config() + + inv_check = read_config_from_db(setup_db_conn(os.getenv('redis_host'), os.getenv('redis_port'))) + log.info(f"Data validity check (DEVELOPER MODE): {inv_check}") + if not cfg_init_result: + log.error("Configuration initialization failed. Exiting...") + exit(1) + + yield + log.info("Shutting down FastAPI app...") + + +setup_logging() +log = logging.getLogger('uvicorn') + +log.info("Starting FastAPI app...") +app = FastAPI(lifespan=lifespan) diff --git a/src/utils.py b/src/utils.py new file mode 100644 index 0000000..2351eff --- /dev/null +++ b/src/utils.py @@ -0,0 +1,9 @@ +import logging + +def setup_logging() -> None: + """Configure logging for the application""" + logging.basicConfig( + level=logging.DEBUG, + format="[%(asctime)s] [%(levelname)5s] %(message)s" + ) + print(f"Logger is initialized.") \ No newline at end of file