"""Информер для обновления кэша ресурсов NodePool""" import asyncio import sys from config import CHUNK_SIZE, DEFAULT_SCHEDULER, logger from lightkube import AsyncClient, NotReadyError from lightkube.generic_resource import create_global_resource # создаем класс для ресурса типа nodepool NodePool = create_global_resource("k8s.dpc24.ru", "v1", "NodePool", "nodepools") class NodePoolInformer: """Информер для NodePool (паттерн list-and-watch)""" def __init__(self, client: AsyncClient): # клиент для k8s self.client = client # внутренний кэш (# nodepool_name -> scheduler_name) self._cache = dict() # блокировка self._lock = asyncio.Lock() async def fill(self): """Начальное наполнение кэша информера""" # предварительная очистка self._cache.clear() # запуск заполнения словаря async for nodepool in self.client.list(NodePool, chunk_size=CHUNK_SIZE): # имя nodepool nodepool_name: str = nodepool.metadata.name # имя планировщика scheduler_name: str = nodepool.spec.get("schedulerName", DEFAULT_SCHEDULER) # ставим блокировку async with self._lock: # заносим объект в кэш self._cache[nodepool_name] = scheduler_name async def get(self): """Получить данные из кэша""" # блокировка, чтобы не испортить данные async with self._lock: # данные из кэша data = self._cache return data async def watch(self): """Обновление кэша""" # запускаем watch while True: try: async for event, nodepool in self.client.watch(NodePool): try: # имя nodepool nodepool_name: str = nodepool.metadata.name # имя планировщика scheduler_name: str = nodepool.spec.get( "schedulerName", DEFAULT_SCHEDULER ) # реакция на основе событий match event: case "ADDED" | "MODIFIED": async with self._lock: self._cache[nodepool_name] = scheduler_name logger.debug( f"Nodepool added: {nodepool_name} -> {scheduler_name}" ) case "DELETED": async with self._lock: self._cache.pop(nodepool_name, None) logger.debug(f"Nodepool deleted: : {nodepool_name}") case _: pass except (KeyError, NotReadyError): # пустой watch, отсутствие ресурса в кэше и пропуск события pass except Exception as error: logger.error(f"Error in watch_nodepool_crs: {error}") sys.exit(1) except Exception as error: logger.error( f"Watch error for Nodepool: {error}. Reconnecting in 5s..." ) await asyncio.sleep(5) logger.debug(f"Nodepool cache: {self._cache}")