Skip to content

FMC

wingpy.cisco.fmc.CiscoFMC

CiscoFMC(
    *,
    base_url: str | None = None,
    username: str | None = None,
    password: str | None = None,
    verify: SSLContext | bool = True,
    timeout: int = 10,
    retries: int = 3
)

Bases: RestApiBaseClass

Interact with the Cisco Secure Firewall Management Center (FMC) API.

Parameters:

Name Type Description Default
base_url str | None

Base URL of the API including https://.

Overrides the environment variable WINGPY_FMC_BASE_URL.

None
username str | None

Username for API authentication.

Overrides the environment variable WINGPY_FMC_USERNAME.

None
password str | None

Password for API authentication.

Overrides the environment variable WINGPY_FMC_PASSWORD.

None
verify SSLContext | bool

Boolean values will enable or disable the default SSL verification.

Use an ssl.SSLContext to specify custom Certificate Authority.

True
timeout int

Number of seconds to wait for HTTP responses before raising httpx.TimeoutException exception.

10
retries int

Number of failed HTTP attempts allowed before raising httpx.HTTPStatusError exception.

3

Examples:

from wingpy import CiscoFMC
fmc = CiscoFMC(
    base_url="https://fmc.example.com",
    username="admin",
    password="password",
    verify=False
)
fmc.get_all("/api/fmc_config/v1/domain/{domainUUID}/object/hosts")
Source code in src/wingpy/cisco/fmc.py
def __init__(
    self,
    *,
    base_url: str | None = None,
    username: str | None = None,
    password: str | None = None,
    verify: SSLContext | bool = True,
    timeout: int = 10,
    retries: int = 3,
):
    # Allow parameters to be passed directly or fallback to environment variables

    self.fmc_url = base_url or os.getenv("WINGPY_FMC_BASE_URL")
    """
    The base URL for the FMC API.

    Examples
    --------
    - https://fmc.example.com
    - https://192.0.2.1:8443
    """

    self.username = username or os.getenv("WINGPY_FMC_USERNAME")
    """
    The username for authentication to the FMC API.
    """

    self.password = password or os.getenv("WINGPY_FMC_PASSWORD")
    """
    The password for authentication to the FMC API.
    """

    if not self.fmc_url or not self.username or not self.password:
        raise ValueError(
            "FMC base_url, username and password must be provided either as arguments or environment variables"
        )

    super().__init__(
        base_url=self.fmc_url,
        auth_lifetime=1800,
        auth_refresh_percentage=0.9,
        verify=verify,
        rate_limit_period=60,
        rate_limit_max_requests=120,
        timeout=timeout,
        retries=retries,
        headers={
            "Content-Type": "application/json",
            "Accept": "application/json",
        },
    )

    self.version: Version | None = None
    """
    The version of the FMC API.
    """

    self._token: str | None = None
    """
    The current token for the FMC API.
    """

get

get(
    path: str,
    *,
    params: dict | None = None,
    path_params: dict | None = None,
    headers: dict | None = None,
    timeout: int | None = None
) -> httpx.Response

Send an HTTP GET request to the specified path.

Parameters:

Name Type Description Default
path str

The API endpoint path to send the request to.

required
params dict | None

URL query parameters to include in the request. will be added as ?key=value pairs in the URL.

None
path_params dict | None

Replace placeholders like {objectId} in the URL path with actual values.

Will be combined with self.path_params before sending request.

Note: {domainUUID} will be implicitly substituted with the default FMC domain.

None
headers dict | None

HTTP headers to be sent with the request.

Will be combined with self.headers before sending request.

None
timeout int | None

Override the standard timeout timer self.timeout for a single request.

None

Returns:

Type Description
Response

The httpx.Response object from the request.

Source code in src/wingpy/cisco/fmc.py
def get(
    self,
    path: str,
    *,
    params: dict | None = None,
    path_params: dict | None = None,
    headers: dict | None = None,
    timeout: int | None = None,
) -> httpx.Response:
    """
    Send an HTTP `GET` request to the specified path.

    Parameters
    ----------
    path : str
        The API endpoint path to send the request to.

    params : dict | None, default=None
        URL query parameters to include in the request. will be added as `?key=value` pairs in the URL.

    path_params : dict | None, default=None
        Replace placeholders like `{objectId}` in the URL path with actual values.

        Will be combined with [self.path_params](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.path_params) before sending request.

        Note: `{domainUUID}` will be implicitly substituted with the default FMC domain.

    headers : dict | None, default=None
        HTTP headers to be sent with the request.

        Will be combined with [self.headers](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.headers) before sending request.

    timeout : int | None, default=None
        Override the standard timeout timer [self.timeout](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.timeout) for a single request.

    Returns
    -------
    httpx.Response
        The [`httpx.Response`](https://www.python-httpx.org/api/#response) object from the request.
    """

    response = self.request(
        "GET",
        path,
        data=None,
        params=params,
        path_params=path_params,
        headers=headers,
        timeout=timeout,
        is_auth_endpoint=False,
        auth=None,
    )
    return response

get_all

get_all(
    path: str,
    *,
    params: dict | None = None,
    path_params: dict | None = None,
    headers: dict | None = None,
    timeout: int | None = None,
    expanded: bool = False,
    page_size: int = 1000
) -> list

Retrieves all pages of data from a GET endpoint using maximum concurrency.

Parameters:

Name Type Description Default
path str

The API endpoint path to send the request to.

required
params dict | None

URL query parameters to include in the request. will be added as ?key=value pairs in the URL.

None
path_params dict | None

Replace placeholders like {objectId} in the URL path with actual values.

Will be combined with self.path_params before sending request.

Note: {domainUUID} will be implicitly substituted with the default FMC domain.

None
headers dict | None

HTTP headers to be sent with the request.

Will be combined with self.headers before sending request.

None
timeout int | None

Override the standard timeout timer self.timeout for a single request.

None
expanded bool

Whether to expand the returned resources with more details. This is a common option for all paginated GET endpoints in FMC.

False
page_size int

The number of items to retrieve per page.

1000

Returns:

Type Description
list[dict]

A concatenated list of returned dictionaries from all pages.

Similar to the items key in the FMC API JSON responses.

Source code in src/wingpy/cisco/fmc.py
def get_all(
    self,
    path: str,
    *,
    params: dict | None = None,
    path_params: dict | None = None,
    headers: dict | None = None,
    timeout: int | None = None,
    expanded: bool = False,
    page_size: int = 1000,
) -> list:
    """
    Retrieves all pages of data from a `GET` endpoint using maximum concurrency.

    Parameters
    ----------
    path : str
        The API endpoint path to send the request to.

    params : dict | None, default=None
        URL query parameters to include in the request. will be added as `?key=value` pairs in the URL.

    path_params : dict | None, default=None
        Replace placeholders like `{objectId}` in the URL path with actual values.

        Will be combined with [self.path_params](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.path_params) before sending request.

        Note: `{domainUUID}` will be implicitly substituted with the default FMC domain.

    headers : dict | None, default=None
        HTTP headers to be sent with the request.

        Will be combined with [self.headers](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.headers) before sending request.

    timeout : int | None, default=None
        Override the standard timeout timer [self.timeout](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.timeout) for a single request.

    expanded : bool, default=False
        Whether to expand the returned resources with more details.
        This is a common option for all paginated GET endpoints in FMC.

    page_size : int, default=1000
        The number of items to retrieve per page.

    Returns
    -------
    list[dict]
        A concatenated list of returned dictionaries from all pages.

        Similar to the `items` key in the FMC API JSON responses.
    """

    logger.debug(f"Retrieving all pages from {path}")

    first_page = self.get_page(
        path,
        params=params,
        path_params=path_params,
        offset=0,
        limit=page_size,
        expanded=expanded,
    )

    json_response_data = first_page.json()

    result: list = json_response_data.get("items", [])

    total_count = int(json_response_data["paging"]["count"])

    logger.debug(
        f"Paging with {range(page_size, total_count, page_size) = } = {list(range(page_size, total_count, page_size))}"
    )

    # Prepare the pages to be retrieved in parallel
    for offset in range(page_size, total_count, page_size):
        self.tasks.schedule(
            self.get_page,
            path,
            params=params,
            path_params=path_params,
            headers=headers,
            timeout=timeout,
            offset=offset,
            limit=page_size,
        )

    page_responses = self.tasks.run()

    for page_response in page_responses.values():
        result += page_response.json().get("items", [])

    logger.debug(f"Received {len(result)} items from {path}")

    return result

post

post(
    path: str,
    *,
    data: dict | str,
    params: dict | None = None,
    path_params: dict | None = None,
    headers: dict | None = None,
    timeout: int | None = None,
    auth: Auth | None = None,
    is_auth_endpoint: bool = False
) -> httpx.Response

Send an HTTP POST request to the specified path.

Parameters:

Name Type Description Default
path str

The API endpoint path to send the request to.

required
data dict | str

Request payload as JSON string or Python dict.

required
params dict | None

URL query parameters to include in the request. will be added as ?key=value pairs in the URL.

None
path_params dict | None

Replace placeholders like {objectId} in the URL path with actual values.

Will be combined with self.path_params before sending request.

Note: {domainUUID} will be implicitly substituted with the default FMC domain.

None
headers dict | None

HTTP headers to be sent with the request.

Will be combined with self.headers before sending request.

None
timeout int | None

Override the standard timeout timer self.timeout for a single request.

None

Other Parameters:

Name Type Description
auth Auth | None

Override the standard Authorization header.

is_auth_endpoint bool

Disables the authentication flow for this request.

Disables retries to prevent lockouts on failed authentication.

Returns:

Type Description
Response

The httpx.Response object from the request.

Source code in src/wingpy/cisco/fmc.py
def post(
    self,
    path: str,
    *,
    data: dict | str,
    params: dict | None = None,
    path_params: dict | None = None,
    headers: dict | None = None,
    timeout: int | None = None,
    auth: httpx.Auth | None = None,
    is_auth_endpoint: bool = False,
) -> httpx.Response:
    """
    Send an HTTP `POST` request to the specified path.

    Parameters
    ----------
    path : str
        The API endpoint path to send the request to.

    data : dict | str
        Request payload as JSON string or Python dict.

    params : dict | None, default=None
        URL query parameters to include in the request. will be added as `?key=value` pairs in the URL.

    path_params : dict | None, default=None
        Replace placeholders like `{objectId}` in the URL path with actual values.

        Will be combined with [self.path_params](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.path_params) before sending request.

        Note: `{domainUUID}` will be implicitly substituted with the default FMC domain.

    headers : dict | None, default=None
        HTTP headers to be sent with the request.

        Will be combined with [self.headers](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.headers) before sending request.

    timeout : int | None, default=None
        Override the standard timeout timer [self.timeout](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.timeout) for a single request.

    Other parameters
    ----------------
    auth : httpx.Auth | None, default=None
        Override the standard Authorization header.

    is_auth_endpoint : bool, default=False
        Disables the authentication flow for this request.

        Disables retries to prevent lockouts on failed authentication.

    Returns
    -------
    httpx.Response
        The [`httpx.Response`](https://www.python-httpx.org/api/#response) object from the request.
    """

    response = self.request(
        "POST",
        path,
        data=data,
        params=params,
        path_params=path_params,
        headers=headers,
        timeout=timeout,
        auth=auth,
        is_auth_endpoint=is_auth_endpoint,
    )
    return response

put

put(
    path: str,
    *,
    data: dict | str,
    params: dict | None = None,
    path_params: dict | None = None,
    headers: dict | None = None,
    timeout: int | None = None
) -> httpx.Response

Send an HTTP PUT request to the specified path.

Parameters:

Name Type Description Default
path str

The API endpoint path to send the request to.

required
data dict | str

Request payload as JSON string or Python dict.

required
params dict | None

URL query parameters to include in the request. will be added as ?key=value pairs in the URL.

None
path_params dict | None

Replace placeholders like {objectId} in the URL path with actual values.

Will be combined with self.path_params before sending request.

Note: {domainUUID} will be implicitly substituted with the default FMC domain.

None
headers dict | None

HTTP headers to be sent with the request.

Will be combined with self.headers before sending request.

None
timeout int | None

Override the standard timeout timer self.timeout for a single request.

None

Returns:

Type Description
Response

The httpx.Response object from the request.

Source code in src/wingpy/cisco/fmc.py
def put(
    self,
    path: str,
    *,
    data: dict | str,
    params: dict | None = None,
    path_params: dict | None = None,
    headers: dict | None = None,
    timeout: int | None = None,
) -> httpx.Response:
    """
    Send an HTTP `PUT` request to the specified path.

    Parameters
    ----------
    path : str
        The API endpoint path to send the request to.

    data : dict | str
        Request payload as JSON string or Python dict.

    params : dict | None, default=None
        URL query parameters to include in the request. will be added as `?key=value` pairs in the URL.

    path_params : dict | None, default=None
        Replace placeholders like `{objectId}` in the URL path with actual values.

        Will be combined with [self.path_params](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.path_params) before sending request.

        Note: `{domainUUID}` will be implicitly substituted with the default FMC domain.

    headers : dict | None, default=None
        HTTP headers to be sent with the request.

        Will be combined with [self.headers](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.headers) before sending request.

    timeout : int | None, default=None
        Override the standard timeout timer [self.timeout](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.timeout) for a single request.

    Returns
    -------
    httpx.Response
        The [`httpx.Response`](https://www.python-httpx.org/api/#response) object from the request.
    """

    response = self.request(
        "PUT",
        path,
        data=data,
        params=params,
        path_params=path_params,
        headers=headers,
        timeout=timeout,
        auth=None,
        is_auth_endpoint=None,
    )
    return response

delete

delete(
    path: str,
    *,
    params: dict | None = None,
    path_params: dict | None = None,
    headers: dict | None = None,
    timeout: int | None = None
) -> httpx.Response

Send an HTTP DELETE request to the specified path.

Parameters:

Name Type Description Default
path str

The API endpoint path to send the request to.

required
params dict | None

URL query parameters to include in the request. will be added as ?key=value pairs in the URL.

None
path_params dict | None

Replace placeholders like {objectId} in the URL path with actual values.

Will be combined with self.path_params before sending request.

Note: {domainUUID} will be implicitly substituted with the default FMC domain.

None
headers dict | None

HTTP headers to be sent with the request.

Will be combined with self.headers before sending request.

None
timeout int | None

Override the standard timeout timer self.timeout for a single request.

None

Returns:

Type Description
Response

The httpx.Response object from the request.

Source code in src/wingpy/cisco/fmc.py
def delete(
    self,
    path: str,
    *,
    params: dict | None = None,
    path_params: dict | None = None,
    headers: dict | None = None,
    timeout: int | None = None,
) -> httpx.Response:
    """
    Send an HTTP `DELETE` request to the specified path.

    Parameters
    ----------
    path : str
        The API endpoint path to send the request to.

    params : dict | None, default=None
        URL query parameters to include in the request. will be added as `?key=value` pairs in the URL.

    path_params : dict | None, default=None
        Replace placeholders like `{objectId}` in the URL path with actual values.

        Will be combined with [self.path_params](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.path_params) before sending request.

        Note: `{domainUUID}` will be implicitly substituted with the default FMC domain.

    headers : dict | None, default=None
        HTTP headers to be sent with the request.

        Will be combined with [self.headers](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.headers) before sending request.

    timeout : int | None, default=None
        Override the standard timeout timer [self.timeout](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.timeout) for a single request.

    Returns
    -------
    httpx.Response
        The [`httpx.Response`](https://www.python-httpx.org/api/#response) object from the request.
    """

    response = self.request(
        "DELETE",
        path,
        data=None,
        params=params,
        path_params=path_params,
        headers=headers,
        timeout=timeout,
        auth=None,
        is_auth_endpoint=None,
    )
    return response

get_page

get_page(
    path: str,
    offset: int,
    limit: int,
    *,
    params: dict | None = None,
    path_params: dict | None = None,
    headers: dict | None = None,
    timeout: int | None = None,
    expanded: bool = False
) -> httpx.Response

Retrieves a specific page of data from a GET endpoint.

Parameters:

Name Type Description Default
path str

The API endpoint path to send the request to.

required
offset int

Index of first items of the page.

required
limit int

The number of items to retrieve per page.

required
params dict | None

URL query parameters to include in the request. will be added as ?key=value pairs in the URL.

None
path_params dict | None

Replace placeholders like {objectId} in the URL path with actual values.

Will be combined with self.path_params before sending request.

Note: {domainUUID} will be implicitly substituted with the default FMC domain.

None
headers dict | None

HTTP headers to be sent with the request.

Will be combined with self.headers before sending request.

None
timeout int | None

Override the standard timeout timer self.timeout for a single request.

None
expanded bool

Whether to expand the returned resources with more details. This is a common option for all paginated GET endpoints in FMC.

False

Returns:

Type Description
Response

The httpx.Response object from the request.

Source code in src/wingpy/cisco/fmc.py
def get_page(
    self,
    path: str,
    offset: int,
    limit: int,
    *,
    params: dict | None = None,
    path_params: dict | None = None,
    headers: dict | None = None,
    timeout: int | None = None,
    expanded: bool = False,
) -> httpx.Response:
    """
    Retrieves a specific page of data from a `GET` endpoint.

    Parameters
    ----------
    path : str
        The API endpoint path to send the request to.

    offset : int
        Index of first items of the page.

    limit : int
        The number of items to retrieve per page.

    params : dict | None, default=None
        URL query parameters to include in the request. will be added as `?key=value` pairs in the URL.

    path_params : dict | None, default=None
        Replace placeholders like `{objectId}` in the URL path with actual values.

        Will be combined with [self.path_params](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.path_params) before sending request.

        Note: `{domainUUID}` will be implicitly substituted with the default FMC domain.

    headers : dict | None, default=None
        HTTP headers to be sent with the request.

        Will be combined with [self.headers](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.headers) before sending request.

    timeout : int | None, default=None
        Override the standard timeout timer [self.timeout](https://wingpy.automation.wingmen.dk/api/apic/#wingpy.cisco.fmc.CiscoFMC.timeout) for a single request.

    expanded : bool, default=False
        Whether to expand the returned resources with more details.
        This is a common option for all paginated GET endpoints in FMC.

    Returns
    -------
    httx.Response
        The [`httpx.Response`](https://www.python-httpx.org/api/#response) object from the request.
    """

    if isinstance(params, dict):
        params = params.copy()
    else:
        params = {}

    # All paginated GET endpoints in FMC have an option to expand the returned resources with more details
    params["expanded"] = expanded

    # Prepare params for the first page of data
    params["offset"] = offset
    params["limit"] = limit

    rsp = self.get(
        path,
        params=params,
        path_params=path_params,
        headers=headers,
        timeout=timeout,
    )

    json_response_data = rsp.json()

    if "paging" not in json_response_data.keys():  # pragma: no cover
        # Invalid response payload
        raise KeyError(
            f'Paginated response payload is expected to have an "paging" key. Available keys: {json_response_data.keys()}'
        )

    if "count" not in json_response_data["paging"].keys():  # pragma: no cover
        # Invalid response payload
        raise KeyError(
            f'"paging" is expected to have an "count" key. Available keys: {json_response_data["paging"]}'
        )

    total_count = int(json_response_data["paging"]["count"])

    total_pages = math.ceil(total_count / limit)

    page = offset // (limit + 1) + 1

    logger.debug(f"Successfully retrieved page {page} of {total_pages} from {path}")

    return rsp

authenticate

authenticate() -> None

Executes the API-specific authentication process and records timestamps for session tracking.

Notes

Authentication will automatically be carried out just-in-time.

Only call this method directly if you need to authenticate proactively, outside of normal request flow.

Source code in src/wingpy/base.py
def authenticate(self) -> None:
    """
    Executes the API-specific authentication process and records timestamps
    for session tracking.

    Notes
    ----
    Authentication will automatically be carried out just-in-time.

    Only call this method directly if you need to authenticate proactively,
    outside of normal request flow.
    """

    # Authenticate
    logger.debug("Authenticating and recording token lifetime.")
    auth_response = self._authenticate()

    # Record the time of authentication
    self.auth_timestamp = arrow.utcnow()

    self._after_auth(auth_response=auth_response)

tasks instance-attribute

tasks: TaskRunner = TaskRunner(max_workers=max_workers)

Manages concurrent requests to the API server.

The number of concurrent requests is limited by the MAX_CONNECTIONS property:

  • 1 connection is reserved for the main thread used for authentication and synchronous requests.
  • The remaining connections are used for concurrent requests.
See Also

wingpy.scheduling.TaskRunner Schedule and run asynchronous tasks in parallel.

is_authenticated property

is_authenticated: bool

Check if the client is authenticated.

timeout instance-attribute

timeout: int = timeout

The timeout in seconds for each request to the API server.

MAX_CONNECTIONS class-attribute instance-attribute

MAX_CONNECTIONS = 10

The maximum number of concurrent connections opened to the FMC.

According to FMC documentation, a maximum of 10 concurrent connections from the same source IP address are supported.

1 connection will be used for general synchronous requests.

9 connections will be used for parallel asynchronous requests.

RETRY_RESPONSES class-attribute instance-attribute

RETRY_RESPONSES = [
    HttpResponsePattern(
        status_codes=[200],
        methods=["GET"],
        content_patterns=[compile("{}")],
    ),
    HttpResponsePattern(
        status_codes=[500],
        methods=["GET", "POST", "PUT", "DELETE"],
        content_patterns=[
            compile(
                '{"error":{"category":"OTHER","messages":\\[{}\\],"severity":"ERROR"}}'
            ),
            compile(
                '{"error":{"category":"FRAMEWORK","messages":\\[{"description":"The action type is null"}\\],"severity":"ERROR"}}'
            ),
        ],
    ),
    HttpResponsePattern(
        status_codes=[504],
        methods=["GET", "POST", "PUT", "DELETE"],
        content_patterns=[
            compile(
                '{"error":{"category":"FRAMEWORK","messages":\\[{"description":"Request Timed Out\\. Retry after sometime."}\\],"severity":"ERROR"}}'
            )
        ],
    ),
]

The standard HTTP 429 status code indicates that the user has sent too many requests in a given amount of time, and is being rate limited.

When under heavy load, Cisco FMC will in some cases send back other responses with invalid payloads, instead of the standard HTTP 429 status code.

These responses will be retried until properly rate limited or a valid response is received.

headers instance-attribute

headers: dict = headers or {}

A dictionary of HTTP headers to be sent with each request. These headers will be merged with any headers dict passed to an individual request.

path_params instance-attribute

path_params: dict = {}

A dictionary of path parameters to be used in the API path of each request.

These parameters will be merged with any path_params dict passed to the request.