Skip to content

async_fmg

FMG API for humans

logger module-attribute #

logger = getLogger(__name__)

AsyncFMG #

AsyncFMG(settings: Optional[FMGSettings] = None, **kwargs)

Bases: AsyncFMGBase

FMG API for humans

Goal of this class to provide easy access to FMG features. This extends the base class capabilities with easy to use methods.

Parameters:

Name Type Description Default
settings Settings

FortiManager settings

None

Other Parameters:

Name Type Description
base_url str

Base URL to access FMG (e.g.: https://myfmg/jsonrpc)

username str

User to authenticate

password str

Password for authentication

adom str

ADOM to use for this connection

verify bool

Verify SSL certificate (REQUESTS_CA_BUNDLE can set accepted CA cert)

timeout float

Connection timeout for requests in seconds

raise_on_error bool

Raise exception on error

discard_on_close bool

Discard changes after connection close (workspace mode)

discard_on_error bool

Discard changes when exception occurs (workspace mode)

Source code in pyfortinet/fmg_api/async_fmg.py
def __init__(self, settings: Optional[FMGSettings] = None, **kwargs):
    """Initializes FMG

    Args:
        settings (Settings): FortiManager settings

    Keyword Args:
        base_url (str): Base URL to access FMG (e.g.: https://myfmg/jsonrpc)
        username (str): User to authenticate
        password (str): Password for authentication
        adom (str): ADOM to use for this connection
        verify (bool): Verify SSL certificate (REQUESTS_CA_BUNDLE can set accepted CA cert)
        timeout (float): Connection timeout for requests in seconds
        raise_on_error (bool): Raise exception on error
        discard_on_close (bool): Discard changes after connection close (workspace mode)
        discard_on_error (bool): Discard changes when exception occurs (workspace mode)
    """
    super().__init__(settings, **kwargs)

add async #

add(request: Union[dict[str, Any], FMGObject]) -> AsyncFMGResponse

Add operation

Parameters:

Name Type Description Default
request Union[dict[str, Any], FMGObject]

Add operation's data structure or object

required

Examples:

Low-level - dict#
>>> import asyncio
>>> settings = {...}
>>> address_request = {
...     "url": "/pm/config/global/obj/firewall/address",
...     "data": {
...         "name": "test-address",
...         "associated-interface": "inside",
...         "obj-type": "ip",
...         "type": "ipmask",
...         "start-ip": "10.0.0.1/24"
...     }
... }
>>> async def add_request(request: dict[str,Any]):
...     async with AsyncFMG(**settings) as fmg:
...         return await fmg.add(address_request)
>>> asyncio.run(add_request(address_request))
High-level - obj#
>>> from pyfortinet.fmg_api.firewall import Address
>>> settings = {...}
>>> address = Address(name="test-address", associated_interface="inside", obj_type="ip",
...                   type="ipmask", start_ip="10.0.0.1/24")
>>> async def add_request(addr):
...     async with AsyncFMG(**settings) as fmg:
...         return await fmg.add(addr)
>>> asyncio.run(add_request(address))

Returns:

Type Description
AsyncFMGResponse

Result of operation

Source code in pyfortinet/fmg_api/async_fmg.py
async def add(self, request: Union[dict[str, Any], FMGObject]) -> AsyncFMGResponse:
    """Add operation

    Args:
        request: Add operation's data structure or object

    Examples:
        ## Low-level - dict

        ```pycon

        >>> import asyncio
        >>> settings = {...}
        >>> address_request = {
        ...     "url": "/pm/config/global/obj/firewall/address",
        ...     "data": {
        ...         "name": "test-address",
        ...         "associated-interface": "inside",
        ...         "obj-type": "ip",
        ...         "type": "ipmask",
        ...         "start-ip": "10.0.0.1/24"
        ...     }
        ... }
        >>> async def add_request(request: dict[str,Any]):
        ...     async with AsyncFMG(**settings) as fmg:
        ...         return await fmg.add(address_request)
        >>> asyncio.run(add_request(address_request))
        ```

        ## High-level - obj

        ```pycon

        >>> from pyfortinet.fmg_api.firewall import Address
        >>> settings = {...}
        >>> address = Address(name="test-address", associated_interface="inside", obj_type="ip",
        ...                   type="ipmask", start_ip="10.0.0.1/24")
        >>> async def add_request(addr):
        ...     async with AsyncFMG(**settings) as fmg:
        ...         return await fmg.add(addr)
        >>> asyncio.run(add_request(address))
        ```

    Returns:
        (AsyncFMGResponse): Result of operation
    """
    response = AsyncFMGResponse(fmg=self)
    if isinstance(request, dict):  # dict input, low-level operation
        return await super().add(request)

    elif isinstance(request, FMGObject):  # high-level operation
        request.fmg_scope = request.fmg_scope or self._settings.adom
        api_data = request.model_dump(by_alias=True, exclude_none=True)
        return await super().add(request={"url": request.get_url, "data": api_data})
    else:
        response.data = {"error": f"Wrong type of request received: {request}"}
        response.status = 400
        logger.error(response.data["error"])
        if self._raise_on_error:
            raise FMGWrongRequestException(request)
        return response

delete async #

delete(request: Union[dict[str, str], FMGObject]) -> AsyncFMGResponse

Delete operation

Parameters:

Name Type Description Default
request Union[dict[str, str], FMGObject]

dict or object to delete

required

Examples:

Low-level - dict#
>>> import asyncio
>>> settings = {...}
>>> address_request = {
...     "url": "/pm/config/global/obj/firewall/address/test-address",
... }
>>> async def delete_address(address_request):
...     async with AsyncFMG(**settings) as fmg:
...         await fmg.delete(address_request)
>>> asyncio.run(delete_address(address_request))
High-level - obj#
>>> from pyfortinet.fmg_api.firewall import Address
>>> settings = {...}
>>> address = Address(name="test-address")
>>> async def delete_address(addr):
...     async with AsyncFMG(**settings) as fmg:
...         return await fmg.delete(addr)
>>> asyncio.run(delete_address(address))

Returns:

Type Description
AsyncFMGResponse

Result of operation

Source code in pyfortinet/fmg_api/async_fmg.py
async def delete(self, request: Union[dict[str, str], FMGObject]) -> AsyncFMGResponse:
    """Delete operation

    Args:
        request: dict or object to delete

    Examples:
        ## Low-level - dict

        ```pycon

        >>> import asyncio
        >>> settings = {...}
        >>> address_request = {
        ...     "url": "/pm/config/global/obj/firewall/address/test-address",
        ... }
        >>> async def delete_address(address_request):
        ...     async with AsyncFMG(**settings) as fmg:
        ...         await fmg.delete(address_request)
        >>> asyncio.run(delete_address(address_request))
        ```

        ## High-level - obj

        ```pycon

        >>> from pyfortinet.fmg_api.firewall import Address
        >>> settings = {...}
        >>> address = Address(name="test-address")
        >>> async def delete_address(addr):
        ...     async with AsyncFMG(**settings) as fmg:
        ...         return await fmg.delete(addr)
        >>> asyncio.run(delete_address(address))
        ```

    Returns:
        (AsyncFMGResponse): Result of operation
    """
    response = AsyncFMGResponse(fmg=self)
    if isinstance(request, dict):  # JSON input, low-level operation
        return await super().delete(request)

    elif isinstance(request, FMGObject):  # high-level operation
        request.fmg_scope = request.fmg_scope or self._settings.adom
        return await super().delete(
            {"url": f"{request.get_url}/{request.name}"}
        )  # assume URL with name for del operation
    else:
        response.data = {"error": f"Wrong type of request received: {request}"}
        response.status = 400
        logger.error(response.data["error"])
        if self._raise_on_error:
            raise FMGWrongRequestException(request)
        return response

exec async #

exec(request: Union[dict[str, Any], FMGExecObject]) -> AsyncFMGResponse

Execute on FMG

Source code in pyfortinet/fmg_api/async_fmg.py
async def exec(self, request: Union[dict[str, Any], FMGExecObject]) -> AsyncFMGResponse:
    """Execute on FMG"""
    if isinstance(request, dict):  # low-level operation
        return await super().exec(request)
    elif isinstance(request, FMGExecObject):
        logger.info("requesting exec with high-level op to %s", request.get_url)
        request.fmg_scope = request.fmg_scope or self._settings.adom
        return await super().exec({"url": request.get_url, "data": request.data})
    else:
        result = AsyncFMGResponse(
            fmg=self, data={"error": f"Wrong type of request received: {request}"}, status=400
        )
        logger.error(result.data["error"])
        return result

get async #

get(request: Union[dict[str, Any], Type[FMGObject]], filters: FILTER_TYPE = None, scope: Optional[str] = None, fields: Optional[List[str]] = None, loadsub: bool = True, options: Optional[List[GetOption]] = None) -> AsyncFMGResponse

Get info from FMG

Parameters:

Name Type Description Default
request Union[dict[str, Any], Type[FMGObject]]

Get operation's data structure

required
scope Optional[str]

Scope where the object is searched (defaults to FMG setting on connection)

None
filters FILTER_TYPE

Filter expression

None
fields Optional[List[str]]

Fields to return (default: None means all fields)

None
loadsub bool

Load sub objects

True
options Optional[List[GetOption]]

API request options

None

Examples:

Low-level - dict#
>>> import asyncio
>>> address_request = {
...    "url": "/pm/config/global/obj/firewall/address",
...    "filter": [ ["name", "==", "test-address"] ],
...    "fields": [ "name", "subnet" ]
...}
>>> settings = {...}
>>> async def get_address(request: dict[str, Any]):
...     async with AsyncFMG(**settings) as fmg:
...         return await fmg.get(address_request)
>>> asyncio.run(get_address())
High-level - obj#
>>> import asyncio
>>> from pyfortinet.fmg_api.firewall import Address
>>> from pyfortinet.fmg_api.common import F
>>> settings = {...}
>>> async def get_address():
...     async with AsyncFMG(**settings) as fmg:
...         return await fmg.get(Address, F(name__like="test-%") & F(subnet="test-subnet"))
>>> asyncio.run(get_address())

Returns:

Type Description
AsyncFMGResponse

response object with data

Source code in pyfortinet/fmg_api/async_fmg.py
@auth_required
async def get(
    self,
    request: Union[dict[str, Any], Type[FMGObject]],
    filters: FILTER_TYPE = None,
    scope: Optional[str] = None,
    fields: Optional[List[str]] = None,
    loadsub: bool = True,
    options: Optional[List[GetOption]] = None,
) -> AsyncFMGResponse:
    """Get info from FMG

    Args:
        request: Get operation's data structure
        scope: Scope where the object is searched (defaults to FMG setting on connection)
        filters: Filter expression
        fields: Fields to return (default: None means all fields)
        loadsub: Load sub objects
        options: API request options

    Examples:
        ## Low-level - dict

        ```pycon

        >>> import asyncio
        >>> address_request = {
        ...    "url": "/pm/config/global/obj/firewall/address",
        ...    "filter": [ ["name", "==", "test-address"] ],
        ...    "fields": [ "name", "subnet" ]
        ...}
        >>> settings = {...}
        >>> async def get_address(request: dict[str, Any]):
        ...     async with AsyncFMG(**settings) as fmg:
        ...         return await fmg.get(address_request)
        >>> asyncio.run(get_address())
        ```

        ## High-level - obj

        ```pycon

        >>> import asyncio
        >>> from pyfortinet.fmg_api.firewall import Address
        >>> from pyfortinet.fmg_api.common import F
        >>> settings = {...}
        >>> async def get_address():
        ...     async with AsyncFMG(**settings) as fmg:
        ...         return await fmg.get(Address, F(name__like="test-%") & F(subnet="test-subnet"))
        >>> asyncio.run(get_address())
        ```

    Returns:
        (AsyncFMGResponse): response object with data
    """
    # Call base function for base arguments
    if isinstance(request, dict):
        return await super().get(request)
    # High level arguments
    result = AsyncFMGResponse(fmg=self)
    if issubclass(request, FMGObject):
        # derive url from current scope and adom
        if not scope:  # get adom from FMG settings
            scope = "global" if self._settings.adom == "global" else f"adom/{self._settings.adom}"
        else:  # user specified
            scope = "global" if scope == "global" else f"adom/{scope}"
        url = request._url.default.replace("{scope}", scope)
        if self._settings.adom != "global":
            url = url.replace("{adom}", f"/adom/{self._settings.adom}")
        else:
            url = url.replace("{adom}", "")

        api_request = {
            "loadsub": 1 if loadsub else 0,
        }

        if filters:
            api_request["filter"] = self._get_filter_list(filters)

        if options:
            api_request["option"] = options

        body = {
            "method": "get",
            "params": [{"url": url, **api_request}],
            "verbose": 1,
            "session": self._token.get_secret_value(),
            "id": self._id,
        }
    else:
        result.data = {"error": f"Wrong type of request received: {request}"}
        result.status = 400
        logger.error(result.data["error"])
        if self._raise_on_error:
            raise FMGWrongRequestException(result)
        return result
    try:
        api_result = await self._post(request=body)
    except FMGException as err:
        api_result = {"error": str(err)}
        logger.error("Error in get request: %s", api_result["error"])
        if self._raise_on_error:
            raise
        result.data = api_result
        return result
    # No need for the following. Pydantic "alias" can be used to handle space or dash in keys!
    # converting API names to object names (replace '-' and ' ' -> _)
    # obj_model = [
    #     {key.replace("-", "_").replace(" ", "_"): value for key, value in data.items()}
    #     for data in api_result.get("data")
    # ]
    # construct object list
    objects = []
    for value in api_result.get("data"):
        objects.append(request(**value, scope=scope, fmg=self))
    result.data = objects
    result.success = True
    return result

get_adom_list async #

get_adom_list(filters: FILTER_TYPE = None) -> Optional[List[str]]

Gather adoms from FMG

Parameters:

Name Type Description Default
filters FILTER_TYPE

filter as list or F object

None

Returns:

Type Description
Optional[List[str]]

list of adom strings or None in case of error

Source code in pyfortinet/fmg_api/async_fmg.py
async def get_adom_list(self, filters: FILTER_TYPE = None) -> Optional[List[str]]:
    """Gather adoms from FMG

    Args:
        filters: filter as list or F object

    Returns:
        list of adom strings or None in case of error
    """
    request = {"url": "/dvmdb/adom", "fields": ["name"]}
    if filters:
        request["filter"] = self._get_filter_list(filters)

    response: AsyncFMGResponse = await self.get(request)
    if response.success:
        return [adom.get("name") for adom in response.data.get("data")]
    return None

get_obj #

get_obj(obj: Union[Type[FMGObject], Type[FMGExecObject], AnyFMGObject], **kwargs: Dict[str, Any]) -> AnyFMGObject

Get an object and tie it to this FMG

Parameters:

Name Type Description Default
obj Union[Type[FMGObject], Type[FMGExecObject], AnyFMGObject]

Any type or instance of FMGObject or FMGExecObject

required
kwargs Dict[str, Any]

fields for the new object initialization

{}

Returns:

Type Description
AnyFMGObject

New object, tied to this FMG

Source code in pyfortinet/fmg_api/async_fmg.py
def get_obj(
    self, obj: Union[Type[FMGObject], Type[FMGExecObject], AnyFMGObject], **kwargs: Dict[str, Any]
) -> AnyFMGObject:
    """Get an object and tie it to this FMG

    Arguments:
        obj: Any type or instance of FMGObject or FMGExecObject
        kwargs: fields for the new object initialization

    Returns:
        (AnyFMGObject): New object, tied to this FMG
    """
    if isinstance(obj, Union[FMGObject, FMGExecObject]):
        obj._fmg = self
        return obj
    elif isclass(obj) and issubclass(obj, Union[FMGObject, FMGExecObject]):
        return obj(fmg=self, **kwargs)

    raise TypeError(f"Argument {obj} is not an FMGObject or FMGExecObject type")

set async #

set(request: Union[dict[str, Any], FMGObject]) -> AsyncFMGResponse

Set operation

Parameters:

Name Type Description Default
request Union[dict[str, Any], FMGObject]

Update operation's data structure

required

Examples:

Low-level - dict#
>>> import asyncio
>>> settings = {...}
>>> address_request = {
...     "url": "/pm/config/global/obj/firewall/address",
...     "data": {
...         "name": "test-address",
...         "associated-interface": "inside",
...         "obj-type": "ip",
...         "type": "ipmask",
...         "start-ip": "10.0.0.1/24"
...     }
... }
>>> async def set_address(request):
...     async with AsyncFMG(**settings) as fmg:
...         return await fmg.set(request)
>>> asyncio.run(set_address(address_request))
High-level - obj#
>>> from pyfortinet.fmg_api.firewall import Address
>>> settings = {...}
>>> address = Address(name="test-address", associated_interface="inside", obj_type="ip",
...                   type="ipmask", start_ip="10.0.0.1/24")
>>> async def set_address(request):
...     async with AsyncFMG(**settings) as fmg:
...         return await fmg.set(request)
>>> asyncio.run(set_address(address))

Returns:

Type Description
AsyncFMGResponse

Result of operation

Source code in pyfortinet/fmg_api/async_fmg.py
async def set(self, request: Union[dict[str, Any], FMGObject]) -> AsyncFMGResponse:
    """Set operation

    Args:
        request: Update operation's data structure

    Examples:
        ## Low-level - dict

        ```pycon

        >>> import asyncio
        >>> settings = {...}
        >>> address_request = {
        ...     "url": "/pm/config/global/obj/firewall/address",
        ...     "data": {
        ...         "name": "test-address",
        ...         "associated-interface": "inside",
        ...         "obj-type": "ip",
        ...         "type": "ipmask",
        ...         "start-ip": "10.0.0.1/24"
        ...     }
        ... }
        >>> async def set_address(request):
        ...     async with AsyncFMG(**settings) as fmg:
        ...         return await fmg.set(request)
        >>> asyncio.run(set_address(address_request))
        ```

        ## High-level - obj

        ```pycon

        >>> from pyfortinet.fmg_api.firewall import Address
        >>> settings = {...}
        >>> address = Address(name="test-address", associated_interface="inside", obj_type="ip",
        ...                   type="ipmask", start_ip="10.0.0.1/24")
        >>> async def set_address(request):
        ...     async with AsyncFMG(**settings) as fmg:
        ...         return await fmg.set(request)
        >>> asyncio.run(set_address(address))
        ```

    Returns:
        (AsyncFMGResponse): Result of operation
    """
    response = AsyncFMGResponse(fmg=self)
    if isinstance(request, dict):  # JSON input, low-level operation
        return await super().set(request)
    elif isinstance(request, FMGObject):  # high-level operation
        request.fmg_scope = request.fmg_scope or self._settings.adom
        api_data = request.model_dump(by_alias=True, exclude_none=True)
        return await super().set({"url": request.get_url, "data": api_data})
    else:
        response.data = {"error": f"Wrong type of request received: {request}"}
        response.status = 400
        logger.error(response.data["error"])
        if self._raise_on_error:
            raise FMGWrongRequestException(request)
        return response

update async #

update(request: Union[dict[str, Any], FMGObject]) -> AsyncFMGResponse

Update operation

Parameters:

Name Type Description Default
request Union[dict[str, Any], FMGObject]

Update operation's data structure

required

Examples:

Low-level - dict#
>>> import asyncio
>>> settings = {...}
>>> address_request = {
...     "url": "/pm/config/global/obj/firewall/address",
...     "data": {
...         "name": "test-address",
...         "associated-interface": "inside",
...         "obj-type": "ip",
...         "type": "ipmask",
...         "start-ip": "10.0.0.1/24"
...     }
... }
>>> async def update_address(request):
...     async with AsyncFMG(**settings) as fmg:
...         return await fmg.update(request)
>>> asyncio.run(update_address(address_request))
High-level - obj#
>>> from pyfortinet.fmg_api.firewall import Address
>>> settings = {...}
>>> address = Address(name="test-address", associated_interface="inside", obj_type="ip",
...                   type="ipmask", start_ip="10.0.0.1/24")
>>> async def update_address(addr):
...     async with AsyncFMG(**settings) as fmg:
...         return await fmg.update(addr)
>>> asyncio.run(update_address(address))

Returns:

Type Description
AsyncFMGResponse

Result of operation

Source code in pyfortinet/fmg_api/async_fmg.py
async def update(self, request: Union[dict[str, Any], FMGObject]) -> AsyncFMGResponse:
    """Update operation

    Args:
        request: Update operation's data structure

    Examples:
        ## Low-level - dict

        ```pycon

        >>> import asyncio
        >>> settings = {...}
        >>> address_request = {
        ...     "url": "/pm/config/global/obj/firewall/address",
        ...     "data": {
        ...         "name": "test-address",
        ...         "associated-interface": "inside",
        ...         "obj-type": "ip",
        ...         "type": "ipmask",
        ...         "start-ip": "10.0.0.1/24"
        ...     }
        ... }
        >>> async def update_address(request):
        ...     async with AsyncFMG(**settings) as fmg:
        ...         return await fmg.update(request)
        >>> asyncio.run(update_address(address_request))
        ```

        ## High-level - obj

        ```pycon

        >>> from pyfortinet.fmg_api.firewall import Address
        >>> settings = {...}
        >>> address = Address(name="test-address", associated_interface="inside", obj_type="ip",
        ...                   type="ipmask", start_ip="10.0.0.1/24")
        >>> async def update_address(addr):
        ...     async with AsyncFMG(**settings) as fmg:
        ...         return await fmg.update(addr)
        >>> asyncio.run(update_address(address))
        ```

    Returns:
        (AsyncFMGResponse): Result of operation
    """
    response = AsyncFMGResponse(fmg=self)
    if isinstance(request, dict):  # JSON input, low-level operation
        return await super().update(request)
    elif isinstance(request, FMGObject):  # high-level operation
        request.fmg_scope = request.fmg_scope or self._settings.adom
        api_data = request.model_dump(by_alias=True, exclude_none=True)
        return await super().update({"url": request.get_url, "data": api_data})
    else:
        response.data = {"error": f"Wrong type of request received: {request}"}
        response.status = 400
        logger.error(response.data["error"])
        if self._raise_on_error:
            raise FMGWrongRequestException(request)
        return response