# ============================================================ # Система: Единая библиотека, Центр ИИ НИУ ВШЭ # Модуль: Управления базовыми объектами Kubernetes # Авторы: Полежаев В.А., Хританков А.С. # Дата создания: 2024 г. # ============================================================ """ RBAC basic resources module. Implements reusable RBAC-related functions. """ import kopf from kubernetes.client import RbacAuthorizationV1Api, ApiException, CoreV1Api, ApiClient _DEFAULT_SA_NAME = 'default' def update_default_sa(api_client, namespace, manifest, logger): """ Обновляет сервисный аккаунт (ServiceAccount) 'default'. Функция является идемпотентной. Если сервисный аккаунт отсутствует, то обработчик выбрасывает исключение kopf.TemporaryError, что приводит к повторному вызову метода спустия заданную задержку. Если сервисный аккаунт существует, то его спецификация замещается переданной в параметре `manifest`. :api_client: Kubernetes API клиент :param namespace: Пространство имен :param manifest: Спецификация сервисного аккаунта :param logger: kopf logger :return: None. """ core_v1_api = CoreV1Api(api_client) try: core_v1_api.read_namespaced_service_account(_DEFAULT_SA_NAME, namespace) except ApiException as exc: if exc.status == 404: # SA с именем 'default' всегда существует и создается Kubernetes, # если отсутствует - нужно подождать logger.info(f'SA {_DEFAULT_SA_NAME} does not exists.') raise kopf.TemporaryError(f"Waiting for SA {_DEFAULT_SA_NAME} " f"to be created by Kubernetes system...", delay=10) raise exc logger.info(f"SA {_DEFAULT_SA_NAME} exists, trying to replace...") core_v1_api.replace_namespaced_service_account(name=_DEFAULT_SA_NAME, namespace=namespace, body=manifest) def delete_sa_if_exists(api_client: ApiClient, name, namespace, logger): core_v1_api = CoreV1Api(api_client) try: # не имеет смысла для default SA - будет пересоздан Kubernetes # оставлено для общего соответствия и на случай изменения имени SA core_v1_api.delete_namespaced_service_account(name=name, namespace=namespace) except ApiException as exc: if exc.status == 404: logger.warn(f"SA {name} doesnt exist, do nothing") return raise exc logger.info(f"SA {name} is deleted") def create_role(api_client, name, namespace, manifest): """ Создает роль (Role). Функция является идемпотентной. Если роль существует, то она будет обновлена. :param api_client: Kubernetes API клиент :param name: Имя роли :param namespace: Пространство имен :param manifest: Спецификация роли :return: None. """ rbac_v1_api = RbacAuthorizationV1Api(api_client) rbac_v1_api.replace_namespaced_role(name=name, namespace=namespace, body=manifest) def delete_role_if_exists(api_client, name, namespace, logger): """ Удаляет роль (Role), если она существует. Функция является идемпотентной. Если роль существует, то она будет удалена. Если роль не существует, то ничего не произойдет. :param api_client: Kuberentes API клиент :param name: Имя роли :param namespace: Пространство имен :param logger: kopf logger :return: None """ rbac_v1_api = RbacAuthorizationV1Api(api_client) try: rbac_v1_api.delete_namespaced_role(name=name, namespace=namespace) except ApiException as exc: if exc.status == 404: logger.warn(f"Role {name} doesnt exist, do nothing") return raise exc logger.info(f"Role {name} is deleted") def create_rb(api_client, name, namespace, manifest): """ Создает привязку роли (RoleBinding). Функция является идемпотентной. Если привязка роли существует, то она будет обновлена. :param api_client: Kubernetes API клиент :param name: Имя привязки роли :param namespace: Пространство имен :param manifest: Спецификация привязки роли :return: None. """ rbac_v1_api = RbacAuthorizationV1Api(api_client) rbac_v1_api.replace_namespaced_role_binding(name=name, namespace=namespace, body=manifest) def delete_rb_if_exists(api_client, name, namespace, logger): """ Удаляет привязку роли (RoleBinding), если она существует. Функция является идемпотентной. Если привязка роли существует, то она будет удалена. Если привязка роли не существует, то ничего не произойдет. :param api_client: Kuberentes API клиент :param name: Имя привязки роли :param namespace: Пространство имен :param logger: kopf logger :return: None """ rbac_v1_api = RbacAuthorizationV1Api(api_client) try: rbac_v1_api.delete_namespaced_role_binding(name=name, namespace=namespace) except ApiException as exc: if exc.status == 404: logger.warn(f"RoleBinding {name} doesnt exist, do nothing") return raise exc logger.info(f"RoleBinding {name} is deleted")