Code Monkey home page Code Monkey logo

firerest's Introduction

python3 pypi license status published

FireREST

FireREST is a python library to interface with Cisco Firepower Management Center REST API. The goal of FireREST is to provide a simple SDK to programmatically interact with FMC.

Features

  • Authentication and automatic session refresh / re-authentication
  • Rate-limit detection and automatic backoff and retry behavior
  • Automatic squashing of paginated api payloads
  • Sanitization of api payloads for create and update operations (automatically remove unsupported elements like links, metadata from payload)
  • Detailed logging of api requests and responses
  • API specific error handling using various custom exceptions for typical errors (e.g. ResourceAlreadyExists, UnprocessAbleEntityError, ...)
  • Support for resource lookup by name instead of uuid for all CRUD operations

Requirements

  • Python >= 3.7

Quickstart

Installation

> pip install fireREST

Import api client

from fireREST import FMC

Authentication

FireREST uses basic authentication. In case your authentication token times out, the api client will automatically refresh the session and retry a failed operation. If all 3 refresh tokens have been used up the connection object will try to re-authenticate again automatically.

fmc = FMC(hostname='fmc.example.com', username='firerest', password='Cisco123', domain='Global')

NOTE: By default domain is set to Global

CRUD Operations

Objects

Create network object
net_obj = {
    'name': 'NetObjViaAPI',
    'value': '198.18.1.0/24',
}

response = fmc.object.network.create(data=net_obj)

NOTE: in case a resource supports the bulk option FireREST will automatically perform a bulk operation if the data provided is of type list

Get all network objects
net_objects = fmc.object.network.get()
Get specific network object
net_objects = fmc.object.network.get(name='NetObjViaAPI')

NOTE: You can access a resource either by name or uuid. If the resource supports a filtering by name FireREST will utilize the filter option, in case a Resource does not support filter params it will iterate through all resources to find a match

Update network object
net_obj = fmc.object.network.get(name='NetObjViaAPI')
net_obj['name'] = 'RenamedNetObjViaAPI'
response = fmc.object.network.update(data=net_obj)

NOTE: FireREST automatically extracts the id field of the provided data dict to update the correct resource.

Delete network object
response = fmc.object.network.delete(name='NetObjViaAPI')

Supported operations

Since FireREST does not try to provide a python object model nearly all api calls up to version 6.7.0 are available which includes but is not limited to the following CRUD operations:

├── assignment
│   └── policyassignment
├── audit
│   └── auditrecord
├── deployment
│   ├── deployabledevice
│   │   ├── deployment
│   │   └── pendingchanges
│   ├── deploymentrequest
│   ├── jobhistory
│   └── rollbackrequest
├── device
│   └── devicerecord
│       ├── bridgegroupinterface
│       ├── etherchannelinterface
│       ├── fpinterfacestatistics
│       ├── fplogicalinterface
│       ├── fpphysicalinterface
│       ├── inlineset
│       ├── interfaceevent
│       ├── operational
│       │   ├── command
│       │   └── metric
│       ├── physicalinterface
│       ├── redundantinterface
│       ├── routing
│       │   ├── bgp
│       │   ├── bgpgeneralsettings
│       │   ├── ipv4staticroute
│       │   ├── ipv6staticroute
│       │   ├── ospfinterface
│       │   ├── ospfv2route
│       │   ├── ospfv3interface
│       │   ├── staticroute
│       │   └── virtualrouter
│       ├── subinterface
│       ├── virtualswitch
│       ├── virtualtunnelinterface
│       └── vlaninterface
├── devicecluster
│   └── ftddevicecluster
├── devicegroup
│   └── devicegrouprecord
├── devicehapair
│   └── ftddevicehapair
│       ├── failoverinterfacemacaddressconfig
│       └── monitoredinterface
├── health
│   ├── alert
│   └── metric
├── integration
│   ├── cloudeventsconfig
│   ├── cloudregion
│   ├── externallookup
│   └── externalstorage
├── intelligence
│   ├── taxiiconfig
│   │   ├── collection
│   │   └── discoveryinfo
│   └── tid
│       ├── element
│       ├── incident
│       ├── indicator
│       ├── observable
│       ├── setting
│       └── source
├── job
│   └── taskstatus
├── object
│   ├── anyprotocolportobject
│   ├── application
│   ├── applicationcategory
│   ├── applicationfilter
│   ├── applicationproductivities
│   ├── applicationrisk
│   ├── applicationtag
│   ├── applicationtype
│   ├── aspathlist
│   ├── certenrollment
│   ├── communitylist
│   ├── continent
│   ├── country
│   ├── dnsservergroup
│   ├── endpointdevicetype
│   ├── expandedcommunitylist
│   ├── extendedaccesslist
│   ├── fqdn
│   │   └── override
│   ├── geolocation
│   ├── globaltimezone
│   ├── host
│   │   └── override
│   ├── icmpv4object
│   │   └── override
│   ├── icmpv6object
│   │   └── override
│   ├── ikev1ipsecproposal
│   ├── ikev1policy
│   ├── ikev2ipsecproposal
│   ├── ikev2policy
│   ├── interface
│   ├── interfacegroup
│   ├── ipv4prefixlist
│   ├── ipv6prefixlist
│   ├── isesecuritygrouptag
│   ├── keychain
│   │   └── override
│   ├── network
│   │   └── override
│   ├── networkaddress
│   ├── networkgroup
│   │   └── override
│   ├── policylist
│   ├── port
│   ├── portobjectgroup
│   │   └── override
│   ├── protocolportobject
│   │   └── override
│   ├── range
│   │   └── override
│   ├── realmuser
│   ├── realmusergroup
│   ├── routemap
│   ├── securitygrouptag
│   ├── securityzone
│   ├── siurlfeed
│   ├── siurllist
│   ├── slamonitor
│   ├── standardaccesslist
│   ├── standardcommunitylist
│   ├── timerange
│   ├── timezone
│   │   └── override
│   ├── tunneltag
│   ├── url
│   │   └── override
│   ├── urlcategory
│   ├── urlgroup
│   │   └── override
│   ├── variableset
│   ├── vlangrouptag
│   │   └── override
│   └── vlantag
│       └── override
├── policy
│   ├── accesspolicy
│   │   ├── accessrule
│   │   ├── category
│   │   ├── defaultaction
│   │   ├── inheritancesettings
│   │   ├── loggingsettings
│   │   └── operational
│   │       └── hitcounts
│   ├── filepolicy
│   ├── ftdnatpolicy
│   │   ├── autonatrule
│   │   ├── manualnatrule
│   │   └── natrule
│   ├── ftds2svpn
│   │   ├── advancedsettings
│   │   ├── endpoint
│   │   ├── ikesettings
│   │   └── ipsecsettings
│   ├── intrusionpolicy
│   │   └── intrusionrule
│   ├── prefilterpolicy
│   │   ├── defaultaction
│   │   ├── operational
│   │   │   └── hitcounts
│   │   └── prefilterrule
│   ├── snmpalert
│   └── syslogalert
├── system
│   └── info
│       ├── domain
│       └── serverversion
├── update
│   └── upgradepackage
│       └── applicabledevice
└── user
    ├── authrole
    └── ssoconfig

Troubleshooting

UnprocessableEntityError

You might see an UnprocessableEntityError exception when you try to execute CREATEor UPDATE operations. Depending on the API endpoint the error message from FMC might not contain enough information to pinpoint what is causing the issue. In this case I would recommend using pigtail on FMC to get more detailed information.

Example

In this example we are trying to create an object override, but the field value is invalid. The subnet mask chosen is not correct, which will cause the FMC API to respond with an UnprocessAbleEntity error.

data = {
    "overrides": {
        "parent": {
            "id": "00505699-76B7-0ed3-0000-077309525737"
        },
        "target": {
            "id": "0ff8161e-096e-11eb-8ec0-cb721f246e60",
            "type": "Device"
        }
    },
    "value": "198.18.201.0/241",
    "name": "NetObjWithOverrides",
    "id": "00505699-76B7-0ed3-0000-077309525737"
}
fmc.object.network.update(data=data)

On FMC we can use the pigtail utility to tail the logfile on the Tomcat webserver hosting the REST API. Using this method we can monitor the APIs response and get some additional information on the error

> expert
admin@fmc:/Volume/home/admin# sudo su -
root@fmc:/Volume/home/admin# pigtail TCAT

Here we see that a Java exception has been thrown, indicating that the request failed due an invalid ip address being passed

TCAT: 02-02 15:36:33 INFO: 172.21.100.145	-	-	443	PUT	/api/fmc_config/v1/domain/b76ff587-9224-65c7-d2af-000000000000/object/networks/00505699-76B7-0ed3-0000-077309525737	-	400	-	301	169	https://fmc.example.com	FireREST/1.0.0	-
TCAT: 02-02 15:34:33 [ajp-nio-127.0.0.1-9009-exec-1] ERROR com.cisco.api.external.rest.common.resource.ContainerServerResource - **Invalid IP Address**
TCAT: 02-02 15:34:33 APIException:Invalid IP Address

Authors

Oliver Kaiser ([email protected])

License

GNU General Public License v3.0 or later.

See LICENSE for the full text.

firerest's People

Contributors

jwendling avatar kaisero avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

firerest's Issues

Issue with Get_audit_records

Hi there. First, thanks for your time and this helpful tool. Next, I have an issue when I use the get_audit_records method.

FMC 6.5
Python 3.8.3

Source:

from fireREST import Client
client = Client(hostname='fmc ip', username='user', password='pass')
client.get_audit_records()

Debug from ipython:

In [18]:  client.get_audit_records()
---------------------------------------------------------------------------
HTTPError                                 Traceback (most recent call last)
~/github/devnet/firepower/fmc_audit/venv/lib/python3.8/site-packages/fireREST/utils.py in wrapper(*args, **kwargs)
    151             response = f(*args, **kwargs)
--> 152             response.raise_for_status()
    153         except HTTPError:

~/github/devnet/firepower/fmc_audit/venv/lib/python3.8/site-packages/requests/models.py in raise_for_status(self)
    940         if http_error_msg:
--> 941             raise HTTPError(http_error_msg, response=self)
    942

HTTPError: 404 Client Error: Not Found for url: https://192.168.10.195/api/fmc_platform/v1/audit/auditrecords?limit=1000&expanded=True

During handling of the above exception, another exception occurred:

HTTPError                                 Traceback (most recent call last)
<ipython-input-18-80541365c4d5> in <module>
----> 1 client.get_audit_records()

~/github/devnet/firepower/fmc_audit/venv/lib/python3.8/site-packages/fireREST/utils.py in wrapper(*args, **kwargs)
    109                     f'{f.__name__} requires fmc software version {minimum_version}. Installed version: {installed_version}',
    110                 )
--> 111             return f(*args, **kwargs)
    112
    113         return wrapper

~/github/devnet/firepower/fmc_audit/venv/lib/python3.8/site-packages/fireREST/__init__.py in get_audit_records(self)
    390     def get_audit_records(self):
    391         url = self._url('platform', '/audit/auditrecords')
--> 392         return self._get(url)
    393
    394     @utils.minimum_version_required('6.1.0')

~/github/devnet/firepower/fmc_audit/venv/lib/python3.8/site-packages/fireREST/__init__.py in _get(self, url, params, items)
    124             params['expanded'] = defaults.API_EXPANSION_MODE
    125
--> 126         response = self._request('get', url, params)
    127         payload = response.json()
    128

~/github/devnet/firepower/fmc_audit/venv/lib/python3.8/site-packages/fireREST/utils.py in wrapper(*args, **kwargs)
    156                 client._refresh()
    157             else:
--> 158                 raise_for_status(response)
    159         return response
    160

~/github/devnet/firepower/fmc_audit/venv/lib/python3.8/site-packages/fireREST/utils.py in raise_for_status(response)
    186             if error['msg'] in response.text:
    187                 raise error['exception']
--> 188     raise exceptions.get(status_code, HTTPError)

HTTPError:

Thanks!

the get_policy method errors out when passing "params"

It doesn't seem as if the "expanded" flag is permitted for the get_policy method in api 6.2.3. I have been using the following code block instead:

#def get_policy(self, policy_id, policy_type, expanded=False):
def get_policy(self, policy_id, policy_type):
        request = '/policy/{0}/{1}'.format(policy_type, policy_id)
#        params = {
#          'expanded': expanded
#       }
        url = self._url('config', request)
        return self._get(url)
#        return self._get(url, params)

Unable to perform GET on full list of continent objects

Trying to do an fmc.object.continent.get() to get the full list of continents however it fails because the PATH in the Continent object is incorrect. The URL has continent as plural.

fireREST code

from fireREST.fmc import Resource


class Continent(Resource):
    PATH = '/object/continent/{uuid}'
    MINIMUM_VERSION_REQUIRED_GET = '6.1.0'

Corrected code

from fireREST.fmc import Resource


class Continent(Resource):
    PATH = '/object/continents/{uuid}'
    MINIMUM_VERSION_REQUIRED_GET = '6.1.0'

I tested this change and it pulled the continents fine.

use examples

do you have any examples of how to utilize the API wrapper. bit of a newbie looking for some prior work to get ideas off of. thank you in advance.

Getting Error 500 Internal error with get_deployabledevices

Hello,
Thanks for your very nice job here.
I'm stuck on deployement of my policy.
I have the feeling it's an issue on the FMC but I post here in case i'm doing something wrong ...

 response = client.update_accesspolicy_rule(policy_id,rule_id,rule)
{"error":{"category":"OTHER","messages":[{"description":"JsonNull"}],"severity":"ERROR"}}

i'm getting the same kind of error with the api/explorer embedded in the FMC.
In fact the /var/log/mojo.log it's seems that the response is prepared & ready but maybe after has been reached a timer elapsed.
I didn't find any timer on the FMC settings regarding the API...

Any clues ?

Oh, and BTW the deployement seems way more touchy :
we need to send that kind of data :

{
  "metadata": {
    "lastUser": {
      "name": "a175552",
      "links": {
        "parent": "string",
        "self": "string"
      },
      "id": "string",
      "type": "string"
    },
    "task": {
      "taskType": "DEVICE_REGISTRATION",
      "subTasks": [
        {
          "message": "string",
          "target": {
            "metadata": {
              "lastUser": {
                "name": "string",
                "links": {
                  "parent": "string",
                  "self": "string"
                },
                "id": "string",
                "type": "string"
              },
              "domain": {
                "name": "string",
                "links": {
                  "parent": "string",
                  "self": "string"
                },
                "id": "string",
                "type": "string"
              },
              "readOnly": {
                "reason": "RBAC",
                "state": true
              },
              "timestamp": 0
            },
            "name": "string",
            "description": "string",
            "links": {
              "parent": "string",
              "self": "string"
            },
            "id": "string",
            "type": "string",
            "version": "string"
          },
          "status": "string"
        }
      ],
      "name": "string",
      "description": "string",
      "links": {
        "parent": "string",
        "self": "string"
      },
      "id": "string",
      "type": "string",
      "message": "string",
      "status": "string"
    },
    "domain": {
      "name": "string",
      "links": {
        "parent": "string",
        "self": "string"
      },
      "id": "string",
      "type": "string"
    },
    "readOnly": {
      "reason": "RBAC",
      "state": true
    },
    "timestamp": 0
  },
  "forceDeploy": true,
  "name": "string",
  "deviceList": [
    "string"
  ],
  "ignoreWarning": true,
  "description": "string",
  "links": {
    "parent": "string",
    "self": "string"
  },
  "id": "string",
  "type": "string",
  "version": "string"
}

The API endpoint for `auditrecords` is incorrect

The api call for getting all audit records is

/api/fmc_platform/v1/domain/{domainUUID}/audit/auditrecords

But when I implement this using this library, I get a 404 error. When I dig into the error, I see the API endpoint the library querying is

/api/fmc_config/v1/domain/{domainUUID}/audit/auditrecords

The source code I used to produce this problem

import fireREST as fr
from ..config import HOSTNAME, USERNAME, PASSWORD, DOMAIN

# Try establishing a connection and exit out if the credentials
# are not correct
try:
    fmc = fr.FMC(hostname=HOSTNAME, username=USERNAME, password=PASSWORD, domain=DOMAIN)
except fr.exceptions.AuthError:
    print('Auth error, check your credentials')
    exit(0)

all_audits =  fmc.audit.auditrecords.get()

Traceback

Traceback (most recent call last):
  File "C:\Users\User\Python\Python310\lib\site-packages\fireREST\utils.py", line 190, in wrapper
    response.raise_for_status()
  File "C:\Users\User\Python\Python310\lib\site-packages\requests\models.py", line 960, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 404 Client Error: 404 for url: https://10.106.38.119/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/audit/auditrecords?limit=1000&expanded=True

Missing reference to Physical Interface in Device Record

PhysicalInterface class import missing in devicerecord:

diff --git a/fireREST/fmc/device/devicerecord/__init__.py b/fireREST/fmc/device/devicerecord/__init__.py
index dd45828..12b6f56 100644
--- a/fireREST/fmc/device/devicerecord/__init__.py
+++ b/fireREST/fmc/device/devicerecord/__init__.py
@@ -7,6 +7,7 @@ from fireREST.fmc.device.devicerecord.fpphysicalinterface import FpPhysicalInter
 from fireREST.fmc.device.devicerecord.inlineset import InlineSet
 from fireREST.fmc.device.devicerecord.interfaceevent import InterfaceEvent
 from fireREST.fmc.device.devicerecord.operational import Operational
+from fireREST.fmc.device.devicerecord.physicalinterface import PhysicalInterface
 from fireREST.fmc.device.devicerecord.redundantinterface import RedundantInterface
 from fireREST.fmc.device.devicerecord.routing import Routing
 from fireREST.fmc.device.devicerecord.subinterface import SubInterface
@@ -34,6 +35,7 @@ class DeviceRecord(Resource):
         self.inlineset = InlineSet(conn)
         self.interfaceevent = InterfaceEvent(conn)
         self.operational = Operational(conn)
+        self.physicalinterface = PhysicalInterface(conn)
         self.redundantinterface = RedundantInterface(conn)
         self.routing = Routing(conn)
         self.subinterface = SubInterface(conn)

Issue with token refresh

Firstly, great library! Really saves me a heap of time compared to access the FMC API directly.

I'm trying to run through ruleset sequentially to move lots of access rules into categories, however I think this could be triggered on also everything that relies on resolve_by_name.

Mostly working but hit a issue that I have not been expecting. I'm really not parsing responses for invalid token because from my understanding the wrapper @utils.handle_errors on Connection _request should be handling token refresh and retry.

That reasoning seems to be okay but I also happened to be using resolve_by_name and that doesnt seem to be protected by handle_errors.

Can the wrapper in resolve_by_name also be sent through handle_errors?

In the meantime, I will update my code to not be as lazy and only utilise the resolve_by_name on the first call to get the UUID for future calls.

I happened to be running it in a debugging session in FMC and also had pigtail running.

VSCode Stack Trace

Traceback (most recent call last):
  File "C:\Program Files\Python39\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Program Files\Python39\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "c:\Users\ictcg\.vscode\extensions\ms-python.python-2021.9.1246542782\pythonFiles\lib\python\debugpy\__main__.py", line 45, in <module>
    cli.main()
  File "c:\Users\ictcg\.vscode\extensions\ms-python.python-2021.9.1246542782\pythonFiles\lib\python\debugpy/..\debugpy\server\cli.py", line 444, in main
    run()
  File "c:\Users\ictcg\.vscode\extensions\ms-python.python-2021.9.1246542782\pythonFiles\lib\python\debugpy/..\debugpy\server\cli.py", line 285, in run_file
    runpy.run_path(target_as_str, run_name=compat.force_str("__main__"))
  File "C:\Program Files\Python39\lib\runpy.py", line 268, in run_path
    return _run_module_code(code, init_globals, run_name,
  File "C:\Program Files\Python39\lib\runpy.py", line 97, in _run_module_code
    _run_code(code, mod_globals, init_globals,
  File "C:\Program Files\Python39\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "Z:\Documents\Code\cisco-FMC-client/update_access_policy_categories.py", line 92, in <module>
    update_access_policy_categories(fmc,POLICY_NAME)
  File "Z:\Documents\Code\cisco-FMC-client/update_access_policy_categories.py", line 22, in update_access_policy_categories
    category = fmc.policy.accesspolicy.category.get(
  File "z:\Documents\Code\cisco-FMC-client\venv\lib\site-packages\fireREST\utils.py", line 109, in wrapper
    if item['name'] == container_name:
TypeError: string indices must be integers

Pigtail stack trace

TCAT: 09-26 05:45:17 INFO: __REDACTED__     -       -       443     POST    /api/fmc_config/v1/domain/__REDACTED__    /policy/accesspolicies/__REDACTED__    /accessrules    category=__REDACTED__    201     -       1100    3308    https://__REDACTED__    FireREST/1.0.8  -
TCAT: 09-26 05:45:17 [ajp-nio-127.0.0.1-9009-exec-6] ERROR com.cisco.api.external.rest.common.utils.TokenValidationUtils - Access Token has expired. Please get renewed access token.
TCAT: 09-26 05:45:17 [ajp-nio-127.0.0.1-9009-exec-6] ERROR com.cisco.api.external.rest.common.filters.AuthenticationFilter - Access Token invalid.
TCAT: 09-26 05:45:17 [ajp-nio-127.0.0.1-9009-exec-6] ERROR com.cisco.api.external.rest.common.filters.AuthenticationFilter - Access token invalid.
TCAT: 09-26 05:45:17 APIException:Access token invalid.
TCAT: 09-26 05:45:17    at com.cisco.api.external.rest.common.filters.AuthenticationFilter.authenticateAccessToken(AuthenticationFilter.java:307)
TCAT: 09-26 05:45:17    at com.cisco.api.external.rest.common.filters.AuthenticationFilter.beforeHandle(AuthenticationFilter.java:151)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:195)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.doHandle(Filter.java:150)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:197)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.doHandle(Filter.java:150)
TCAT: 09-26 05:45:17    at com.cisco.api.external.rest.common.filter.AuditFilter.doHandle(AuditFilter.java:133)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:197)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.doHandle(Filter.java:150)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:197)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.doHandle(Filter.java:150)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:197)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.doHandle(Filter.java:150)
TCAT: 09-26 05:45:17    at org.restlet.engine.application.StatusFilter.doHandle(StatusFilter.java:140)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:197)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.doHandle(Filter.java:150)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:197)
TCAT: 09-26 05:45:17    at org.restlet.engine.CompositeHelper.handle(CompositeHelper.java:202)
TCAT: 09-26 05:45:17    at org.restlet.engine.application.ApplicationHelper.handle(ApplicationHelper.java:75)
TCAT: 09-26 05:45:17    at org.restlet.Application.handle(Application.java:385)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.doHandle(Filter.java:150)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:197)
TCAT: 09-26 05:45:17    at org.restlet.routing.Router.doHandle(Router.java:422)
TCAT: 09-26 05:45:17    at org.restlet.routing.Router.handle(Router.java:639)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.doHandle(Filter.java:150)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:197)
TCAT: 09-26 05:45:17    at org.restlet.routing.Router.doHandle(Router.java:422)
TCAT: 09-26 05:45:17    at org.restlet.routing.Router.handle(Router.java:639)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.doHandle(Filter.java:150)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:197)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.doHandle(Filter.java:150)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:197)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.doHandle(Filter.java:150)
TCAT: 09-26 05:45:17    at org.restlet.engine.application.StatusFilter.doHandle(StatusFilter.java:140)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:197)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.doHandle(Filter.java:150)
TCAT: 09-26 05:45:17    at org.restlet.routing.Filter.handle(Filter.java:197)
TCAT: 09-26 05:45:17    at org.restlet.engine.CompositeHelper.handle(CompositeHelper.java:202)
TCAT: 09-26 05:45:17    at org.restlet.Component.handle(Component.java:408)
TCAT: 09-26 05:45:17    at com.cisco.api.external.rest.common.APIComponent.handle(APIComponent.java:294)
TCAT: 09-26 05:45:17    at org.restlet.Server.handle(Server.java:507)
TCAT: 09-26 05:45:17    at org.restlet.engine.connector.ServerHelper.handle(ServerHelper.java:63)
TCAT: 09-26 05:45:17    at org.restlet.engine.adapter.HttpServerHelper.handle(HttpServerHelper.java:143)
TCAT: 09-26 05:45:17    at org.restlet.ext.servlet.ServerServlet.service(ServerServlet.java:1117)
TCAT: 09-26 05:45:17    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
TCAT: 09-26 05:45:17    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
TCAT: 09-26 05:45:17    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
TCAT: 09-26 05:45:17    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
TCAT: 09-26 05:45:17    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
TCAT: 09-26 05:45:17    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
TCAT: 09-26 05:45:17    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
TCAT: 09-26 05:45:17    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
TCAT: 09-26 05:45:17    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)
TCAT: 09-26 05:45:17    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
TCAT: 09-26 05:45:17    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
TCAT: 09-26 05:45:17    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
TCAT: 09-26 05:45:17    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
TCAT: 09-26 05:45:17    at org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:394)
TCAT: 09-26 05:45:17    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
TCAT: 09-26 05:45:17    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853)
TCAT: 09-26 05:45:17    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
TCAT: 09-26 05:45:17    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
TCAT: 09-26 05:45:17    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
TCAT: 09-26 05:45:17    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
TCAT: 09-26 05:45:17    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
TCAT: 09-26 05:45:17    at java.base/java.lang.Thread.run(Unknown Source)

TypeError: inner_function() takes 1 positional argument but 2 were given

Good day,

Working on interfacing with our firewall and receiving the following error on some requests:

TypeError: inner_function() takes 1 positional argument but 2 were given

An example is:

...
>>> api.get_device_id_by_name('TESTFW')  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: inner_function() takes 1 positional argument but 2 were given

As well as:

>>> api.get_accesspolicy_id_by_name('test-policy')   
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: inner_function() takes 1 positional argument but 2 were given

Info

Python: 3.7.3
FMC: 6.6.0.1
fireREST: 0.1.4

Add custom exception for connection errors

Currently if Connection is refused by FMC (e.g. not reachable) ConnectionError is thrown.

ConnectionError: HTTPSConnectionPool(host='fmc.example.com', port=443): Max 
retries exceeded with url: /api/fmc_platform/v1/auth/generatetoken (Caused by 
NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x10dc3f490>: 
Failed to establish a new connection: [Errno 61] Connection refused'))

This should be replaced with a more user friendly custom exception

Add support for FMC 7.1.0 APIs

Direct Internet Access

  • New APIs were added to enable you to create, view, edit, and delete your Policy Based Routing configuration
  • New parameters added to existing APIs for Extended Access Control Lists to define applications
  • New parameters added to existing APIs for device interfaces to define interface priority

Chassis Management

  • New Chassis Management APIs for managed chassis, chassis interfaces, network modules, and breakout interfaces

Deployment

  • New job history API

Device Clusters

  • New APIs to perform readiness checks and modify clustering

Devices

  • Get FTD interface
  • Packet Tracer
  • Routing
  • Virtual LAN

Health Monitoring

  • Added tunnel APIs

Objects

Various enhancements / new APIs for...

  • Autonomous Service Paths
  • Expanded Community Lists
  • Extended Community Lists
  • Extended Access Lists
  • IPv4 Prefix Lists
  • IPv6 Prefix Lists
  • Policy Lists
  • Route Maps
  • Standard Access Lists
  • Standard Community Lists

Policies

  • New APIs to modify automatic and manual NAT rules

Users

  • New APIs to retrieve and modify Duo configurations

Troubleshooting

  • New Packet Tracer PCAP functionality

Updates

  • New API to revert upgrades

Network Map

  • New APIs for hosts and vulnerabilities

Unable to pull application category by id

I'm trying to extract the applications from a access rule and if you have a rule that references an app category, the information returned by the API is not helpful unless you make a second call to pull the app category by the ID returned by the first API call. When I use the fmc.object.applicationcategory(uuid={'some_id'}) call, it fails with an HTTP 400 client error. I'll provide the trace below.

For example, I have an inline application filter of type 'categories' in a rule. The rule really references the 'database' category, but the API returns:

{'id': '32', 'name': 'category', 'type': 'ApplicationCategory'}

If I use the API explorer to pull this, it works perfectly. The API explorer uses this as the URL:

https://x.x.x.x/api/fmc_config/v1/domain/{fmc_uuid}/object/applicationcategories/32

When I go to use fireREST, I get this traceback:

fmc.object.applicationcategory.get(uuid='32')
Traceback (most recent call last):
  File "C:\Python39\lib\site-packages\fireREST\utils.py", line 188, in wrapper
    response.raise_for_status()
  File "C:\Users\xxx\AppData\Roaming\Python\Python39\site-packages\requests\models.py", line 953, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: 400 for url: https://x.x.x.x/api/fmc_config/v1/domain/{fmc_uuid}/object/applicationcategories/32?limit=1000&expanded=True

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python39\lib\site-packages\fireREST\utils.py", line 138, in wrapper
    return f(*args, **kwargs)
  File "C:\Python39\lib\site-packages\fireREST\utils.py", line 81, in wrapper
    return f(*args, **kwargs)
  File "C:\Python39\lib\site-packages\fireREST\fmc\__init__.py", line 372, in get
    return self.conn.get(url, params)
  File "C:\Python39\lib\site-packages\fireREST\fmc\__init__.py", line 165, in get
    response = self._request('get', url, params=params)
  File "C:\Python39\lib\site-packages\decorator.py", line 232, in fun
    return caller(func, *(extras + args), **kw)
  File "C:\Python39\lib\site-packages\retry\api.py", line 73, in retry_decorator
    return __retry_internal(partial(f, *args, **kwargs), exceptions, tries, delay, max_delay, backoff, jitter,
  File "C:\Python39\lib\site-packages\retry\api.py", line 33, in __retry_internal
    return f()
  File "C:\Python39\lib\site-packages\fireREST\utils.py", line 198, in wrapper
    raise_for_status(response)
  File "C:\Python39\lib\site-packages\fireREST\utils.py", line 246, in raise_for_status
    raise exceptions.get(status_code, exc.GenericApiError)(
fireREST.exceptions.GenericApiError: Invalid query parameter for the GETBYID operation.

Almost seems like it doesn't like the limit=1000&expanded=True part of the URL.

This was run on 6.7.0 code.

Overrides support

Do you have any overrides support? I did a repo search for "overrid" and found nothing so I am guessing there is no support for it. Can you confirm if you do or do not?

TIA.

Naming incosistency: ftddevicehapair vs ftdhapair

In the fireREST.fmc.devicehapair constructor the method is named "ftdhapair" while in the directory tree and docs is named "ftddevicehapair".

from fireREST.fmc import Connection
from fireREST.fmc.devicehapair.ftddevicehapair import FtdHAPair

class DeviceHAPair:
def init(self, conn: Connection):
self.ftdhapair = FtdHAPair(conn)

Crash if applicabledevices return 404

requests.exceptions.HTTPError: 404 Client Error: 404 for url: https://fmc.lab.local/api/fmc_platform/v1/updates/upgradepackages/82db7c60-850c-11eb-995a-bdf00d291159/applicabledevices?limit=1000&expanded=True

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "fmc_patching.py", line 69, in
response = fmc.conn.get(applicabledevicesURL)
File "\Python39\site-packages\fireREST\fmc_init_.py", line 159, in get
response = self._request('get', url, params=params)
File "", line 2, in wrapper
File "\Python39\site-packages\retry\api.py", line 73, in retry_decorator
return __retry_internal(partial(f, *args, **kwargs), exceptions, tries, delay, max_delay, backoff, jitter,
File "\Python39\site-packages\retry\api.py", line 33, in __retry_internal
return f()
File "\Python39\site-packages\fireREST\utils.py", line 197, in wrapper
raise_for_status(response)
File "\Python39\site-packages\fireREST\utils.py", line 245, in raise_for_status
raise exceptions.get(status_code, exc.GenericApiError)(
fireREST.exceptions.ResourceNotFoundError: No resource found

client.create_object gives TypeError: 'dict' object is not callable

Python 3.7 on CentOS Linux release 7.7.1908 (Core)

(venv-fmc-obj-maker) [root@devbox firepower-obj-maker]# pip freeze
certifi==2020.4.5.1
chardet==3.0.4
decorator==4.4.2
fireREST==0.1.1
idna==2.9
packaging==20.4
py==1.8.1
pyparsing==2.4.7
requests==2.23.0
retry==0.9.2
six==1.15.0
urllib3==1.25.9

Source:

from fireREST import Client

fmc_hostname = '<ip>'
fmc_username = 'admin'
fmc_password = 'admin'

fmc_client = Client(hostname=fmc_hostname, username=fmc_username, password=fmc_password)

net_obj = {
 'name': 'NetObjViaAPI',
 'value': '198.18.1.0/24'
}

response = fmc_client.create_object('network', net_obj)

Error:
Traceback (most recent call last):
File "", line 1, in
File "/etc/samba/devbox/firepower-obj-maker/venv-fmc-obj-maker/lib/python3.7/site-packages/fireREST/utils.py", line 137, in wrapper
return f(*args, **kwargs)
File "/etc/samba/devbox/firepower-obj-maker/venv-fmc-obj-maker/lib/python3.7/site-packages/fireREST/utils.py", line 111, in wrapper
return f(*args, **kwargs)
File "/etc/samba/devbox/firepower-obj-maker/venv-fmc-obj-maker/lib/python3.7/site-packages/fireREST/init.py", line 408, in create_object
return self._create(url, data)
File "/etc/samba/devbox/firepower-obj-maker/venv-fmc-obj-maker/lib/python3.7/site-packages/fireREST/init.py", line 185, in _create
return self._request('post', url, params, data)
File "/etc/samba/devbox/firepower-obj-maker/venv-fmc-obj-maker/lib/python3.7/site-packages/fireREST/utils.py", line 151, in wrapper
response = f(*args, **kwargs)
File "/etc/samba/devbox/firepower-obj-maker/venv-fmc-obj-maker/lib/python3.7/site-packages/fireREST/init.py", line 103, in _request
verify=self.verify_cert,
File "/etc/samba/devbox/firepower-obj-maker/venv-fmc-obj-maker/lib/python3.7/site-packages/requests/sessions.py", line 516, in request
prep = self.prepare_request(req)
File "/etc/samba/devbox/firepower-obj-maker/venv-fmc-obj-maker/lib/python3.7/site-packages/requests/sessions.py", line 459, in prepare_request
hooks=merge_hooks(request.hooks, self.hooks),
File "/etc/samba/devbox/firepower-obj-maker/venv-fmc-obj-maker/lib/python3.7/site-packages/requests/models.py", line 318, in prepare
self.prepare_auth(auth, url)
File "/etc/samba/devbox/firepower-obj-maker/venv-fmc-obj-maker/lib/python3.7/site-packages/requests/models.py", line 550, in prepare_auth
r = auth(self)
TypeError: 'dict' object is not callable

Update:
I also get the same behavior running the code in a docker python:3.7.7-buster & python:3.8.3-buster image with packaging & urllib3 downgraded to match what I see in your pipfile document.

422 Client Error on FMC 6.2.2

I'm trying to use this on an older FMC to pull data from to build a new FMC on 6.7 code. When I try to create the FMC object, I get a 422 client error, but I can connect to the new FMC just fine. I'm thinking it is an issue with the older FMC version and the API it presents. I did confirm the REST API is enabled on the old server.

Here is the error I get:

Traceback (most recent call last):
  File "C:\Python39\lib\site-packages\fireREST\utils.py", line 188, in wrapper
    response.raise_for_status()
  File "C:\Users\xxx\AppData\Roaming\Python\Python39\site-packages\requests\models.py", line 953, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 422 Client Error: Unprocessable Entity for url: https://10.90.192.38/api/fmc_platform/v1/auth/generatetoken

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python39\lib\site-packages\fireREST\__init__.py", line 43, in __init__
    self.conn = Connection(hostname, username, password, protocol, verify_cert, domain, timeout, dry_run)
  File "C:\Python39\lib\site-packages\fireREST\fmc\__init__.py", line 74, in __init__
    self.login()
  File "C:\Python39\lib\site-packages\fireREST\fmc\__init__.py", line 232, in login
    response = self._request('post', url, auth=self.cred)
  File "C:\Python39\lib\site-packages\decorator.py", line 232, in fun
    return caller(func, *(extras + args), **kw)
  File "C:\Python39\lib\site-packages\retry\api.py", line 73, in retry_decorator
    return __retry_internal(partial(f, *args, **kwargs), exceptions, tries, delay, max_delay, backoff, jitter,
  File "C:\Python39\lib\site-packages\retry\api.py", line 33, in __retry_internal
    return f()
  File "C:\Python39\lib\site-packages\fireREST\utils.py", line 198, in wrapper
    raise_for_status(response)
  File "C:\Python39\lib\site-packages\fireREST\utils.py", line 246, in raise_for_status
    raise exceptions.get(status_code, exc.GenericApiError)(
fireREST.exceptions.UnprocessableEntityError: The Payload size is above:0 Bytes

Can't pass limit to get_objects

Great module - thanks.

I've been using it in my script, but when calling "get_objects" I am unable to pass an increased limit beyond the 100. Obviously I could just call "_url" directly, so you may not consider this an issue, but would be good to use the abstraction of "get_objects" and increase the limit as otherwise it takes ages for something like "applications" which has thousands of objects.

I'm not a massive python expert, but don't think I've missed a way to do this using your code (apologies if I have). For now I've just created a child class in my script and overwritten the value that way.

Devices in Expand mode

Hi,

to get detail over device status, we need the "expanded" parameter. So I would prefer this way:

def get_devices(self, expanded = False):
    request = '/devices/devicerecords'
    params = {
        'expanded': expanded
    }
    url = self._url('config', request)
    return self._get(url, params)

best regards,
Lars

Add testing for internals

There are not enough tests in FireREST to make sure new builds do not break the library. Integration tests should be added for all core functionalities

Job>taskstatus is not included in the FMC class

FMC version 6.6

As title, the job.taskstatus is not declared in the FMC class. Please add it to the FMC class.

Also, this taskstatus API endpoint on FMC doesn't like the query parameters at the back. I realise the code adds "?limit=1000&expanded=True" at the end by default. Please update the resource to not adding any query parameters for taskstatus.

My workaround for this API endpoint at the moment:
taskStatusURL = "https://"+hostname+"/api/fmc_config/v1/domain/"+fmc.domain['id']+"/job/taskstatuses/"+taskId
response = fmc.conn.get(taskStatusURL,None,1)

It might not be perfect, but it works.

API Limit/Offset

Hi Kaisero,
Great work, this helped me out in a time of need!
I needed to update 8000 AC Rules to include Syslog after a migration from ASA.
The current "limit" is set to 50 in fireREST.py on line 70.
The FirePower API Token is only valid for 30 minutes, and the script took a while to get through all 8000 Rules, so i had to increase the "limit" to 1000 (which is the API limit itself). This meant that the script collected the data much quicker.
It may be worth increasing this limit in the production code to prevent this issue occurring going forwards.
Also, it might be worth investigating whether there is a way to utilise the X-authentication-refresh-token if the script runs over 30 minutes.
I have a couple of API scripts myself which ill do a bit of testing with around this and report back if i find anything.

How to Deploy

Are there any code examples available for best practice on how to check if changes made to FMC and deployable and to trigger a deployment?

Invalid Refresh Token - Browser Timeout Set to 10 minutes

FMC version: 7.0.4
Exception has occurred: GenericApiError
Invalid refresh token

Is there anyway to handle if there is a browser timeout since it looks like the browser timeout also kills off the refresh token along with the access token. Our timeout was required to be set to 10 minutes per our security needs. I have a job that I am pulling all of our ACLs and their related objects and it crashes on this error.
Let me know if any other details are needed.

404 when using fmc.policy.ftdnatpolicy.manualnatrule.create with container_name

FMC version 6.7.0
fireREST version 1.0.4

My goal is to create a manual nat rule by specifying the nat policy for the rule by name, and the translated/original sources for the rule by as host or network objects by name. It appears that I'm only able to use uuids.

I get a ResourceNotFoundError/404 when attempting to create a manual nat rule using container_name:

from fireREST import FMC
fmc = FMC(hostname='fmchost', username='user', password='pass')
data = {'translatedSource':{'type':'Host', 'id':'guid-of-host-object'}, 'originalSource':{'type': 'Host', 'id': 'guid-of-another-host-object'}, 'dns': True, 'natType':'STATIC'}
fmc.policy.ftdnatpolicy.manualnatrule.create(container_name='Test NAT', section='before_auto', data=data)

returns:

Traceback (most recent call last):
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/utils.py", line 191, in wrapper
    response.raise_for_status()
  File "/path/to/venv/lib/python3.8/site-packages/requests/models.py", line 943, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 404 Client Error: 404 for url: https://fmchost/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/policy/ftdnatpolicies/None/manualnatrules?section=before_auto

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/utils.py", line 169, in wrapper
    return f(*args, **kwargs)
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/fmc/policy/ftdnatpolicy/manualnatrule/__init__.py", line 30, in create
    return super().create(data=data, container_uuid=container_uuid, container_name=container_name, params=params)
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/utils.py", line 78, in wrapper
    return f(*args, **kwargs)
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/fmc/__init__.py", line 426, in create
    return self.conn.post(url, data, params, self.IGNORE_FOR_CREATE)
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/fmc/__init__.py", line 196, in post
    return self._request('post', url, params=params, data=data)
  File "<decorator-gen-2>", line 2, in wrapper
  File "/path/to/venv/lib/python3.8/site-packages/retry/api.py", line 73, in retry_decorator
    return __retry_internal(partial(f, *args, **kwargs), exceptions, tries, delay, max_delay, backoff, jitter,
  File "/path/to/venv/lib/python3.8/site-packages/retry/api.py", line 33, in __retry_internal
    return f()
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/utils.py", line 197, in wrapper
    raise_for_status(response)
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/utils.py", line 241, in raise_for_status
    raise exceptions.get(status_code,
fireREST.exceptions.ResourceNotFoundError: No data found for: /None

The above works if i use container_uuid instead of container_name.

Also, I'm not able to reference translatedSource or originalSource by name:

data={'translatedSource': {'type': 'Host', 'name': 'host1'}, 'originalSource': {'type': 'Host', 'name': 'host2'}, 'dns': True, 'natType': 'STATIC'}
fmc.policy.ftdnatpolicy.manualnatrule.create(container_uuid='uuid-of-nat-policy', section='before_auto', data=data)
Traceback (most recent call last):
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/utils.py", line 191, in wrapper
    response.raise_for_status()
  File "/path/to/venv/lib/python3.8/site-packages/requests/models.py", line 943, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: 400 for url: https://fmchost/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/policy/ftdnatpolicies/005056B9-24B2-0ed3-0000-008589936073/manualnatrules?section=before_auto

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/utils.py", line 169, in wrapper
    return f(*args, **kwargs)
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/fmc/policy/ftdnatpolicy/manualnatrule/__init__.py", line 30, in create
    return super().create(data=data, container_uuid=container_uuid, container_name=container_name, params=params)
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/utils.py", line 78, in wrapper
    return f(*args, **kwargs)
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/fmc/__init__.py", line 426, in create
    return self.conn.post(url, data, params, self.IGNORE_FOR_CREATE)
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/fmc/__init__.py", line 196, in post
    return self._request('post', url, params=params, data=data)
  File "<decorator-gen-2>", line 2, in wrapper
  File "/path/to/venv/lib/python3.8/site-packages/retry/api.py", line 73, in retry_decorator
    return __retry_internal(partial(f, *args, **kwargs), exceptions, tries, delay, max_delay, backoff, jitter,
  File "/path/to/venv/lib/python3.8/site-packages/retry/api.py", line 33, in __retry_internal
    return f()
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/utils.py", line 197, in wrapper
    raise_for_status(response)
  File "/path/to/venv/lib/python3.8/site-packages/fireREST/utils.py", line 241, in raise_for_status
    raise exceptions.get(status_code,
fireREST.exceptions.GenericApiError: <html> The original source cannot be empty. Select a Network Object or a<br>Network Object Group<br><br> Empty original source is not allowed<br><br></html>

policy.ftdnatpolicy.natrule.get passes expanded parameter when it shouldn't, or I'm doing it wrong.

I have a NAT policy with 2 rules. I'm able to return a list of both rules with:

fmc.policy.ftdnatpolicy.natrule.get(container_name='Test Threat Defense NAT', data={})

or

fmc.policy.ftdnatpolicy.natrule.get(container_name='Test Threat Defense NAT', data=None)

What I'm not able to do is get a specific rule by id. I've tried:

fmc.policy.ftdnatpolicy.natrule.get(container_name='Test Threat Defense NAT', uuid='005056B9-24B2-0ed3-0000-008589936189', data={})

and

fmc.policy.ftdnatpolicy.natrule.get(container_name='Test Threat Defense NAT', uuid='005056B9-24B2-0ed3-0000-008589936189', data=None)

and the following error is returned:

Traceback (most recent call last):
  File "/path/to/.pyenv/versions/venv/lib/python3.7/site-packages/fireREST/utils.py", line 190, in wrapper
    response.raise_for_status()
  File "/path/to/.pyenv/versions/venv/lib/python3.7/site-packages/requests/models.py", line 941, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 400 Client Error: 400 for url: https://fmc/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/policy/ftdnatpolicies/005056B9-24B2-0ed3-0000-008589936073/natrules/005056B9-24B2-0ed3-0000-008589936189?limit=1000&expanded=True

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/path/to/.pyenv/versions/venv/lib/python3.7/site-packages/fireREST/utils.py", line 170, in wrapper
    return f(*args, **kwargs)
  File "/path/to/.pyenv/versions/venv/lib/python3.7/site-packages/fireREST/fmc/policy/ftdnatpolicy/natrule/__init__.py", line 50, in get
    container_uuid=container_uuid, container_name=container_name, name=name, uuid=uuid, params=params
  File "/path/to/.pyenv/versions/venv/lib/python3.7/site-packages/fireREST/utils.py", line 136, in wrapper
    return f(*args, **kwargs)
  File "/path/to/.pyenv/versions/venv/lib/python3.7/site-packages/fireREST/utils.py", line 78, in wrapper
    return f(*args, **kwargs)
  File "/path/to/.pyenv/versions/venv/lib/python3.7/site-packages/fireREST/fmc/__init__.py", line 430, in get
    return self.conn.get(url, params)
  File "/path/to/.pyenv/versions/venv/lib/python3.7/site-packages/fireREST/fmc/__init__.py", line 140, in get
    response = self._request('get', url, params=params)
  File "<decorator-gen-2>", line 2, in wrapper
  File "/path/to/.pyenv/versions/venv/lib/python3.7/site-packages/retry/api.py", line 74, in retry_decorator
    logger)
  File "/path/to/.pyenv/versions/venv/lib/python3.7/site-packages/retry/api.py", line 33, in __retry_internal
    return f()
  File "/path/to/.pyenv/versions/venv/lib/python3.7/site-packages/fireREST/utils.py", line 196, in wrapper
    raise_for_status(response)
  File "/path/to/.pyenv/versions/venv/lib/python3.7/site-packages/fireREST/utils.py", line 239, in raise_for_status
    raise exceptions.get(status_code, HTTPError)(msg=response.json()['error']['messages'][0]['description'])
fireREST.exceptions.GenericApiError: Invalid query parameter for the GETBYID operation.

I'm able to get it with a filter:

fmc.policy.ftdnatpolicy.natrule.get(container_name='Test Threat Defense NAT', translated_source='10.117.108.194-32', data=None)
[{'metadata': {'section': 'BEFORE_AUTO', 'index': 1, 'parentType': 'FTDNatRule', 'timestamp': 1612906807140, 'domain': {'name': 'Global', 'id': 'e276abec-e0f2-11e3-8169-6d9ed49b625f', 'type': 'Domain'}}, 'links': {'self': 'https://fmc/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/policy/ftdnatpolicies/005056B9-24B2-0ed3-0000-008589936073/manualnatrules/005056B9-24B2-0ed3-0000-008589936189', 'parent': 'https://fmc/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/policy/ftdnatpolicies/005056B9-24B2-0ed3-0000-008589936073/natrules'}, 'enabled': True, 'unidirectional': False, 'translatedSource': {'type': 'Host', 'overridable': False, 'id': '005056B9-24B2-0ed3-0000-008589936145', 'name': '10.117.108.194-32'}, 'originalSource': {'type': 'Host', 'overridable': False, 'id': '005056B9-24B2-0ed3-0000-008589936145', 'name': '10.117.108.194-32'}, 'interfaceInOriginalDestination': False, 'interfaceInTranslatedSource': False, 'type': 'FTDManualNatRule', 'fallThrough': False, 'dns': True, 'routeLookup': False, 'noProxyArp': False, 'netToNet': False, 'natType': 'STATIC', 'interfaceIpv6': False, 'id': '005056B9-24B2-0ed3-0000-008589936189'}]

2 questions:

  • How would I query for a specific NAT rule by ID?
  • Why is data marked as a required parameter? The GET methods for /api/fmc_config/v1/domain/{domainUUID}/policy/ftdnatpolicies/{containerUUID}/natrules and /api/fmc_config/v1/domain/{domainUUID}/policy/ftdnatpolicies/{containerUUID}/natrules/{objectId} don't support passing a body.

Enhance logging capabilities

API calls are currently poorly logged with not enough details. The implementation should be changed to include a built-in default logger with an additional loglevel (TRACE) to also include exceptions into logs.

log_request should automatically include the action type and all passed params which are being stitched to the url within the respective api calls

Remove redundant get/create operations

The current FireREST implementation exposes different functions for some create and get operations that should be merged into a single function which takes a param to indicate if the user wants to receive a specific result or all resources

Is there a way to connect to CDO?

By the description, I would need to connect to a cdFMC instance but seems that the authentication in this package is not supported, or is it?

Add result caching to get operations

Currently result caching is achieved using functools lru_cache without cache invalidation for get_id_by_name operations only. The goal is to enable caching by default and add memoization with integrated cache invalidation upon changes performed via create/update procedures.

Bulk updates fail for UPDATE operations

Bulk operations fail due to incorrect url formatting. Update operations require a uuid at the moment, but this is not neccessary for bulk operations where a list of items is passed directly to the api endpoint without specifying the specific uuid of the resource to change

Thanks to Gyorgy Acs for discovering this issue

simplejson.errors.JSONDecodeError after FMC initialization

Hello! Any help is greatly appreciated with this issue.

During initialization I'm receiving this error:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/lib/python3.8/dist-packages/fireREST/__init__.py", line 42, in __init__
    self.conn = Connection(hostname, username, password, protocol, verify_cert, domain, timeout)
  File "/usr/local/lib/python3.8/dist-packages/fireREST/fmc/__init__.py", line 69, in __init__
    self.login()
  File "/usr/local/lib/python3.8/dist-packages/fireREST/fmc/__init__.py", line 203, in login
    response = self._request('post', url, auth=self.cred)
  File "<decorator-gen-2>", line 2, in wrapper
  File "/usr/local/lib/python3.8/dist-packages/retry/api.py", line 73, in retry_decorator
    return __retry_internal(partial(f, *args, **kwargs), exceptions, tries, delay, max_delay, backoff, jitter,
  File "/usr/local/lib/python3.8/dist-packages/retry/api.py", line 33, in __retry_internal
    return f()
  File "/usr/local/lib/python3.8/dist-packages/fireREST/utils.py", line 189, in wrapper
    response = f(*args, **kwargs)
  File "/usr/local/lib/python3.8/dist-packages/fireREST/fmc/__init__.py", line 112, in _request
    logger.debug('\n"response": %s', json.dumps(response.json(), sort_keys=True, indent=4))
  File "/usr/local/lib/python3.8/dist-packages/requests/models.py", line 900, in json
    return complexjson.loads(self.text, **kwargs)
  File "/usr/lib/python3/dist-packages/simplejson/__init__.py", line 518, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3/dist-packages/simplejson/decoder.py", line 370, in decode
    obj, end = self.raw_decode(s)
  File "/usr/lib/python3/dist-packages/simplejson/decoder.py", line 400, in raw_decode
    return self.scan_once(s, idx=_w(s, idx).end())
simplejson.errors.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

Step to reproduce:

  1. Run the command
fmc = FMC(hostname=FMC_HOST, username=FMC_USER, password=FMC_PASS, domain='Global')

Environment:

  • 20.04.1 LTS (Focal Fossa)
  • python 3.8.5
  • Cisco Firepower Management Center for KVM, Software Version 6.4.0.6 (build 28)

Additional information:

  • As I see the authentication was successful (my session in web browser was closed after I ran the command).
  • No errors in Cisco Firepower logs.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.