Compare commits

...

4 Commits

Author SHA1 Message Date
root
0b30d5ea83 restructure 2025-09-18 12:04:10 +02:00
root
8ac82369f5 read and write with readis 2025-09-18 11:45:51 +02:00
root
1eac2e75ae req file extended 2025-09-18 09:39:36 +02:00
root
847579419b basic creds schema 2025-09-18 09:04:08 +02:00
9 changed files with 148 additions and 5 deletions

9
Dockerfile Normal file
View File

@@ -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"]

8
config/inventory.yml Normal file
View File

@@ -0,0 +1,8 @@
- 1:
hostname: '172.16.57.2'
username: 'admin'
password: 'Netapp12'
- 2:
hostname: '172.16.56.2'
username: 'admin'
password: 'Netapp12'

0
initialize.py Normal file
View File

View File

@@ -1,3 +1,6 @@
fastapi[standard]>=0.116.2 fastapi[standard]>=0.116.2
httpx>=0.28.1 httpx>=0.28.1
redis>=6.4.0 redis>=6.4.0
pydantic
redis[hiredis]
dotenv

30
src/database.py Normal file
View File

@@ -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

View File

@@ -4,3 +4,11 @@ from pydantic import BaseModel
class ExampleSchema(BaseModel): class ExampleSchema(BaseModel):
example_field: str example_field: str
another_field: int another_field: int
class ClusterCreds(BaseModel):
"""A structure to hold basic auth cluster credentials for a cluster"""
username: str
password: str
hostname: str = None
cert_filepath: Path = None
key_filepath: Path = None

40
src/initialize.py Normal file
View File

@@ -0,0 +1,40 @@
import os
import json
import logging
import yaml
from pathlib import Path
from dotenv import load_dotenv
from database import setup_db_conn
def initialize_config():
load_dotenv()
log = logging.getLogger('uvicorn')
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

View File

@@ -1,5 +1,41 @@
def main() -> None: import os
print("Hello, World!") import json
import logging
import yaml
if __name__ == "__main__": from pathlib import Path
main() 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 initialize import initialize_config
from utils import setup_logging
@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)

9
src/utils.py Normal file
View File

@@ -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.")