| 1 | from fastapi import HTTPException |
| 2 | from loguru import logger |
| 3 | from packaging.version import InvalidVersion |
| 4 | from packaging.version import Version |
| 5 | from sqlalchemy.ext.asyncio import AsyncSession |
| 6 | from sqlalchemy.future import select |
| 7 | |
| 8 | from app.connectors.graylog.services.content_packs import get_content_packs |
| 9 | from app.connectors.graylog.services.management import get_system_info |
| 10 | from app.network_connectors.models.network_connectors import CustomerNetworkConnectors |
| 11 | from app.network_connectors.models.network_connectors import ( |
| 12 | CustomerNetworkConnectorsMeta, |
| 13 | ) |
| 14 | from app.stack_provisioning.graylog.schema.provision import AvailableContentPacks |
| 15 | |
| 16 | |
| 17 | async def get_graylog_version() -> str: |
| 18 | """ |
| 19 | Get the version of the Graylog instance. |
| 20 | |
| 21 | Returns: |
| 22 | str: The version of the Graylog instance. |
| 23 | """ |
| 24 | system_info = await get_system_info() |
| 25 | return system_info.version |
| 26 | |
| 27 | |
| 28 | async def system_version_check(compatible_version: str) -> bool: |
| 29 | """ |
| 30 | Check if the Graylog version is compatible with the content pack. |
| 31 | |
| 32 | Args: |
| 33 | compatible_version (str): The version of the Graylog instance. |
| 34 | |
| 35 | Returns: |
| 36 | bool: True if the version is compatible, False if it is not. |
| 37 | """ |
| 38 | system_version = await get_graylog_version() |
| 39 | logger.info(f"Graylog System version: {system_version}") |
| 40 | |
| 41 | try: |
| 42 | system_version_parsed = Version(system_version) |
| 43 | compatible_version_parsed = Version(compatible_version) |
| 44 | except InvalidVersion as e: |
| 45 | raise HTTPException( |
| 46 | status_code=400, |
| 47 | detail=f"Invalid version format: {e}", |
| 48 | ) |
| 49 | |
| 50 | if system_version_parsed >= compatible_version_parsed: |
| 51 | return True |
| 52 | else: |
| 53 | raise HTTPException( |
| 54 | status_code=400, |
| 55 | detail=f"Graylog version {system_version} is not compatible with the content pack", |
| 56 | ) |
| 57 | |
| 58 | |
| 59 | async def is_content_pack_available(content_pack_name: str) -> bool: |
| 60 | """ |
| 61 | Check if the content pack is available for provisioning. |
| 62 | |
| 63 | Args: |
| 64 | content_pack_name (str): The name of the content pack to check. |
| 65 | |
| 66 | Returns: |
| 67 | bool: True if the content pack is available, False if it is not. |
| 68 | """ |
| 69 | available_content_packs = [pack.name for pack in AvailableContentPacks] |
| 70 | if content_pack_name in available_content_packs: |
| 71 | logger.info(f"Content pack {content_pack_name} is available") |
| 72 | return True |
| 73 | else: |
| 74 | logger.info(f"Content pack {content_pack_name} is not available") |
| 75 | raise HTTPException( |
| 76 | status_code=400, |
| 77 | detail=f"Content pack {content_pack_name} is not available", |
| 78 | ) |
| 79 | |
| 80 | |
| 81 | async def does_content_pack_exist(content_pack_name: str) -> bool: |
| 82 | """ |
| 83 | Check if the content pack exists in the list of content packs. |
| 84 | |
| 85 | Args: |
| 86 | content_pack_name (str): The name of the content pack to check. |
| 87 | |
| 88 | Returns: |
| 89 | bool: True if the content pack exists, False if it does not. |
| 90 | """ |
| 91 | content_packs = await get_content_packs() |
| 92 | for content_pack in content_packs: |
| 93 | logger.info(f"Checking content pack {content_pack.name}") |
| 94 | if content_pack.name == content_pack_name: |
| 95 | logger.info(f"Content pack {content_pack_name} exists") |
| 96 | if "PROCESSING_PIPELINE" in content_pack.name: |
| 97 | return True |
| 98 | else: |
| 99 | raise HTTPException( |
| 100 | status_code=400, |
| 101 | detail=f"Content pack {content_pack_name} already exists", |
| 102 | ) |
| 103 | logger.info(f"Content pack {content_pack_name} does not exist") |
| 104 | return False |
| 105 | |
| 106 | |
| 107 | async def insert_into_customer_network_connectors_meta_table( |
| 108 | customer_network_connectors_meta: CustomerNetworkConnectorsMeta, |
| 109 | session: AsyncSession, |
| 110 | ) -> None: |
| 111 | """ |
| 112 | Insert the customer network connectors meta into the database. |
| 113 | |
| 114 | Args: |
| 115 | customer_network_connectors_meta (CustomerNetworkConnectorsMeta): The customer network connectors meta to insert. |
| 116 | session (AsyncSession): The async session object for database operations. |
| 117 | |
| 118 | Returns: |
| 119 | None |
| 120 | """ |
| 121 | await session.add(customer_network_connectors_meta) |
| 122 | await session.commit() |
| 123 | |
| 124 | |
| 125 | async def set_deployed_flag(customer_code: str, network_connector_service_name: str, flag: bool, session: AsyncSession) -> None: |
| 126 | """ |
| 127 | Set the deployed flag to True for the specified customer code and for Fortinet. |
| 128 | |
| 129 | Args: |
| 130 | customer_code (str): The customer code. |
| 131 | network_connector_service_name (str): The network connector service name. |
| 132 | session (AsyncSession): The async session object for database operations. |
| 133 | |
| 134 | Returns: |
| 135 | None |
| 136 | """ |
| 137 | # Retrieve the customer network connectors object for the customer code and network connector service name |
| 138 | customer_network_connectors = await session.execute( |
| 139 | select(CustomerNetworkConnectors).filter_by( |
| 140 | customer_code=customer_code, |
| 141 | network_connector_service_name=network_connector_service_name, |
| 142 | ), |
| 143 | ) |
| 144 | customer_network_connectors = customer_network_connectors.scalars().first() |
| 145 | # Update the deployed flag to True |
| 146 | customer_network_connectors.deployed = flag |
| 147 | await session.commit() |
| 148 | return None |