This is an updated version of This Post.

I will quickly run through my environment and steps I took to get the script working in my lab environment.

I run VMware Workstation 15 Pro on my home PC with 2 virtual machines, an FMCv 6.3.0 (build 83) with 4vCPU & 4GB RAM; and a Debian machine for running the scripts on. These machines both connect to a host-only network, the Debian VM also has a NAT interface so that it can reach the Internet via my home connection.

The Debian machine will need some installs before the script will work, PIP (sudo apt-get install python-pip) and the Python Requests library (sudo pip install requests). I am using Python 2.7 in this post, it will need some changes to work in Python3. Here is my installed packages and versions FYI:

[email protected]:~/python$ pip list
Package       Version
------------- ---------
asn1crypto    0.24.0
certifi       2019.9.11
chardet       3.0.4
configparser  3.5.0b2
cryptography  2.6.1
entrypoints   0.3
enum34        1.1.6
idna          2.8
ipaddress     1.0.17
keyring       17.1.1
keyrings.alt  3.1.1
pip           18.1
pycrypto      2.6.1
PyGObject     3.30.4
pyxdg         0.25
requests      2.22.0
SecretStorage 2.3.1
setuptools    40.8.0
six           1.12.0
urllib3       1.25.6
wheel         0.32.3

In my last post I was able to create both network objects AND host objects in the same script, but for some reason this doesn’t work for me anymore, I’m guessing due to working with a newer version of the FMC. It seems now you need to make 2 separate API calls, one for host objects and another for network objects.

Thankfully only 1 line in the script needs to change to differentiate between the different object types. In the script you will find the line api_path = “/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/object/hosts – notice the end, simply change hosts to networks depending on what you are creating. Or have 2 versions of the script, post_hosts.py and post_networks.py for example, with said line being different in each script.

The CSV file used should be stored in the same directory as the script, and it must be referenced when calling the script like so: python <script.py> <csvfile.csv>. Here is the CSV file I used for the hosts:

name,value,type,description
Host-1,10.0.1.10,host,Host 1
Host-2,10.0.2.10,host,Host 2

And the CSV file I used for the networks:

name,value,type,description
Network-1,10.0.1.0/29,network,Network 1
Network-2,10.0.2.0/29,network,Network 2

Note: The description field not required. Networks must be in CIDR format.

Here is the full script. It is an adapted version taken from the FMC’s provided examples to work with CSV files and produce a log. In order to get this to work in your environment, you must change the Server, Username & Password fields. You may also have to change the Domain-ID in the api_path (mine being: e276abec-e0f2-11e3-8169-6d9ed49b625f) but I’ve found the same ID used a lot so chances are it’s the same as mine. I use a dedicated account for the API as to avoid my main account being logged out of the GUI after the script has ran.

import csv
import json
import sys
import requests
import os

server = "https://192.168.45.45"
username = "api"
password = "ciscoAPI"
headers = {'Content-Type': 'application/json'}
api_auth_path = "/api/fmc_platform/v1/auth/generatetoken"
auth_url = server + api_auth_path
r = None

def yes_or_no(question):
    answer = raw_input(question + "(y/n): ").lower().strip()
    print("")
    while not(answer == "y" or answer == "yes" or \
    answer == "n" or answer == "no"):
        print("Input yes or no")
        answer = raw_input(question + "(y/n):").lower().strip()
        print("")
    if answer[0] == "y":
        return True
    else:
        return False

csvfile = open(sys.argv[1])
objects = csv.DictReader(csvfile)

print('\nThis script will attempt to create objects via an API call')
if yes_or_no('\nDo you want to continue?'):
    ()
else:
    quit()


try:
    print('\n\nAttempting connection to FMC...')
    requests.packages.urllib3.disable_warnings()
    r = requests.post(auth_url, headers=headers,
    auth=requests.auth.HTTPBasicAuth(username,password), verify=False)
    auth_headers = r.headers
    auth_token = auth_headers.get('X-auth-access-token', default=None)
    if auth_token == None:
        print("auth_token not found. Exiting...")
        sys.exit()
except Exception as err:
    print ("Error in generating auth token --> "+str(err))
    sys.exit()

headers['X-auth-access-token'] = auth_token
print('...Connected! Auth token collected successfully (' + auth_token + (')\n'))
api_path = "/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/object/hosts"
url = server + api_path
if (url[-1] == '/'):
    url = url[:-1]

for object in objects:
    post_data = {
        "name": object["name"],
        "type": object["type"],
        "value": object["value"],
        "description": object["description"],
    }
    print('\n*************************************')
    print('Creating object: ' + object["name"])

    try:
        r = requests.post(url, data=json.dumps(post_data), headers=headers, verify=False)
        status_code = r.status_code
        resp = r.text
        log = open('post_objects.log', 'a')
        print(" Status code: "+str(status_code))
        json_resp = json.loads(resp)
        log.write('\n---------------------------------------------------------------------\n')
        log.write(json.dumps(json_resp,sort_keys=True,indent=4, separators=(',', ': ')))

        if status_code == 201 or status_code == 202:
            print (" SUCCESS ")
        elif status_code == 400:
            print (" Message: ")  + resp + ('\n')
        else:
            r.raise_for_status()
            print (" Message: ")  + resp + ('\n')

    except requests.exceptions.HTTPError as err:
        print ("Error in connection --> "+str(err))
    finally:
        if r: r.close()

print('\nLog file "post_objects.log" appended\n')

And here is the script running on the Debian VM:

[email protected]:~/python$ python post_hosts.py hosts.csv

This script will attempt to create objects via an API call

Do you want to continue?(y/n): y



Attempting connection to FMC...
...Connected! Auth token collected successfully (22048d24-3db3-45cd-aba3-c1f368f14951)


*************************************
Creating object: Host-1
 Status code: 201
 SUCCESS

*************************************
Creating object: Host-2
 Status code: 201
 SUCCESS

Log file "post_objects.log" appended


[email protected]:~/python$ python post_networks.py networks.csv

This script will attempt to create objects via an API call

Do you want to continue?(y/n): y



Attempting connection to FMC...
...Connected! Auth token collected successfully (5177f016-9251-4381-ae4b-16dbdcfd65e3)


*************************************
Creating object: Network-1
 Status code: 201
 SUCCESS

*************************************
Creating object: Network-2
 Status code: 201
 SUCCESS
Log file "networks.log" appended

A log file will be created as ‘api.log’ and appended to every time the script is ran. It will contain the JSON dumps which were sent along with the API calls. Here is the log for the Host-1 Object:

 {
     "description": "Host 1",
     "id": "000C29B8-C6AF-0ed3-0000-034359739999",
     "links": {
         "parent": "https://192.168.45.45/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/object/networkaddresses",
         "self": "https://192.168.45.45/api/fmc_config/v1/domain/e276abec-e0f2-11e3-8169-6d9ed49b625f/object/hosts/000C29B8-C6AF-0ed3-0000-034359739999"
     },
     "metadata": {
         "domain": {
             "id": "e276abec-e0f2-11e3-8169-6d9ed49b625f",
             "name": "Global"
         },
         "ipType": "V_4",
         "lastUser": {
             "name": "api"
         },
         "parentType": "NetworkAddress",
         "timestamp": 0
     },
     "name": "Host-1",
     "overridable": false,
     "type": "Host",
     "value": "10.0.1.10"
 }

And finally checking in the FMC you can see the objects have been created successfully.

Please leave a comment if you have any problems using this script or have any questions.


7 Comments

Donnie Spencer · January 20, 2020 at 7:45 pm

How would one go about adding the newly created objects to a single object ground en masse?

    Tom · January 20, 2020 at 8:03 pm

    Good luck with that! I really struggled to achieve it. We have groups with 1000’s of objects and it’s been painful. Using the GUI is really bad, the already used objects still show in the available objects which is so annoying!

    I believe you need a script to GET all of the object ID’s and the ID for the group and store them, and then make another api call to PUT the objects into the group, but I’ve heard it removes the existing objects and replaces them instead of appending, not been able to find any evidence of doing this online either.

Hello · March 7, 2020 at 5:59 pm

Hi Tom, could you help me about this output ??

[email protected]:~/FMC$ python network_script.py network_2.csv

This script will attempt to create objects via an API call

Do you want to continue?(y/n): y

Attempting connection to FMC…
…Connected! Auth token collected successfully (a1359354-6589-495d-b4bc-46af2dab9ded)

Traceback (most recent call last):
File “network_script.py”, line 53, in
“name”: object[“name”],
KeyError: ‘name’
[email protected]:~/FMC$

    Tom · March 10, 2020 at 7:43 pm

    Hi there! I can only think that the issue is with the CSV file, I have just tried this script in my lab and it worked fine for me. Ensure there are no spaces before ‘name’ in the header field of the CSV file, if you are using a different header in your CSV instead of ‘name’ then ensure you update the script accordingly. Hope this helps.

    Edit — I was able to re-create this issue by adding a blank space before ‘name’ in the CSV file, hopefully you fixed it!

    [email protected]:~/python$ python post_networks.py csv/networks.csv

    This script will attempt to create objects via an API call

    Do you want to continue?(y/n): y

    Attempting connection to FMC…
    …Connected! Auth token collected successfully (4e4a6a17-5399-457f-ac22-8d97b83c0a53)

    Traceback (most recent call last):
    File “post_networks.py”, line 61, in
    “name”: object[“name”],
    KeyError: ‘name’

Uriel · May 21, 2020 at 1:08 pm

Your script is awesome, I changed it a bit for migrating service objects and it seems to work.

    Tom · July 2, 2020 at 9:05 pm

    Hey – Thanks! I’m glad you liked it.

Leave a Reply to Uriel Cancel reply

Your email address will not be published. Required fields are marked *