cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
3304
Views
0
Helpful
13
Replies
Highlighted
Beginner

How to post an xml file via APIC CLI ?

Hello,

to set up the initial network configuration of an ACI fabric with all the needed tenants and their associated definitions (AP, EPG, BD, VRF, Contracts, ...), we create 1 xml file per tenant to be defined (via a script), but then, we manually post each of these tenant xml files via APIC GUI, one by one, which can be a bit long according to the number of tenants and DCs to deploy.

Question :

Is there some CLI MO or NXOS command on APIC that would allow to import them (via a post or equivalent), supposing we have uploaded all these xml tenant files via SCP on the APIC disk drive ?

thanks in advance

3 ACCEPTED SOLUTIONS

Accepted Solutions
Highlighted
Participant

Hi

Hi

You can post local XML files to the APIC with icurl using HTTP on port 7777 (assuming your files are named "tenantConfig1.xml", "tenantConfig2.xml" etc.):

icurl -X POST http://localhost:7777/api/mo.xml -d @tenantConfig1.xml
icurl -X POST http://localhost:7777/api/mo.xml -d @tenantConfig2.xml
etc.

However I would suggest to post your config files with the help of of a script - there are a lot of modules out there for every language. My favourite to communicate with the APIC is python and the requests module (http://docs.python-requests.org/en/master/user/quickstart/)

HTH

Marcel

View solution in original post

Highlighted
Cisco Employee

Hello

Hello

You can try using POSTMan (google chrome extension)

That is what i use in the lab. Remember you need to login and then do your regular POST or GET

View solution in original post

Highlighted
Participant

No, thats not possible you

No, thats not possible you can only post one MO (with its childs) per POST. There is only one dn allowed per post.

Have a look at the infra-configuration, you'll see the main object (infraInfra with dn="uni/infra") and the attached childs. This will help you to build the correct XML for your POST:

https://<APIC>/api/mo/uni/infra.xml?rsp-subtree=full&rsp-prop-include=config-only

Or using icurl:

icurl -X GET 'http://localhost:7777/api/mo/uni/infra.xml?rsp-subtree=full&rsp-prop-include=config-only'

Marcel

View solution in original post

13 REPLIES 13
Highlighted
Participant

Hi

Hi

You can post local XML files to the APIC with icurl using HTTP on port 7777 (assuming your files are named "tenantConfig1.xml", "tenantConfig2.xml" etc.):

icurl -X POST http://localhost:7777/api/mo.xml -d @tenantConfig1.xml
icurl -X POST http://localhost:7777/api/mo.xml -d @tenantConfig2.xml
etc.

However I would suggest to post your config files with the help of of a script - there are a lot of modules out there for every language. My favourite to communicate with the APIC is python and the requests module (http://docs.python-requests.org/en/master/user/quickstart/)

HTH

Marcel

View solution in original post

Highlighted
Beginner

thanks a lot for your reply

thanks a lot for your reply

I knew a bit about Postman, yes, but I wanted something that can be easily scripted since I already create all my XML via a script (which is Python, btw).

so, the method with icurl seems good for this approach since I can also generate those icurl commands via the same script that generates the XML files.

I did not know about this "Requests" Python package, I just installed via pip

I will test that for sure

thanks again !

Highlighted
Beginner

Hi Marcel,

Hi Marcel,

we used icurl to post tenants those last days and it is really simple and useful

similar question :

is it possible to save an existing tenant in xml format via icurl ?

thanks

Highlighted
Participant

Hi

Hi

Sure:

This will print the config

icurl -X GET http://localhost:7777/api/mo/uni/tn-<TN-NAME>.xml?rsp-subtree=full&rsp-prop-include=config-only

You can also save it to a file:

icurl -o <FILENAME>.xml -X GET http://localhost:7777/api/mo/uni/tn-<TN-NAME>.xml?rsp-subtree=full&rsp-prop-include=config-only

BTW: Did you check the requests Python module? It's easier to get the configuration direct from a python script instead of using icurl on the apic and copy the configuration somewhere using scp.

Regards

Marcel

Highlighted
Beginner

Hi Marcel,

Hi Marcel,

thanks for these infos

under native APIC, I got an error because the question mark is not taken into account :

DC1_APIC1# icurl -o /tmp/xml/tn-DC1_TENANT1.xml -X GET http://localhost:7777/api/mo/uni/tn-TENANT1.xml?
DC1_APIC1# icurl -o /tmp/xml/tn-DC1_TENANT1.xml -X GET http://localhost:7777/api/mo/uni/tn-TENANT1.xmlrsp-subtree=full&rsp-prop-include=config-only 
% Total % Received % Xferd Average Speed Time Time Time Current 
Dload Upload Total Spent Left Speed 
139 139 139 139 0 0 62556 0 --:--:-- --:--:-- --:--:-- 135k 
Error: Invalid argument 'rsp-prop-include=config-only '. Please check syntax in command reference guide 
DC1_APIC1#

under bash mode, I got an error on option "rsp-prop-include=config-only" :

admin@DC1_APIC1:xml> icurl -o /tmp/xml/tn-DC1_TENANT1.xml -X GET http://localhost:7777/api/mo/uni/tn-TENANT1.xml?rsp-subtree=full&rsp-prop-include=config-only
[1] 18000
bash: rsp-prop-include=config-only: command not found
admin@DC1_APIC1:xml>   % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 59177  100 59177    0     0  1225k      0 --:--:-- --:--:-- --:--:-- 1256k


[1]+  Done                    icurl -o /tmp/xml/tn-DC1_TENANT1.xml -X GET http://localhost:7777/api/mo/uni/tn-TENANT1.xml?rsp-subtree=full

Any idea ?

thanks

Highlighted
Participant

Try using quotes:

Try using quotes:

icurl -o /tmp/xml/tn-DC1_TENANT1.xml -X GET 'http://localhost:7777/api/mo/uni/tn-TENANT1.xml?rsp-subtree=full&rsp-prop-include=config-only'

Marcel

Highlighted
Beginner

great, it works !

great, it works !

thanks again, Marcel.

About the Python Request module, I would like to use it, for sure,

but, as I am still a a bit a beginner on this part, I can't find the right syntax that will allow me to do, via this Request module, the initial login to APIC and get the associated cookie/token that I must use for the next Post or Get requests to APIC ;

I have created the following apic1_login.xml :

<?xml version="1.0" encoding="UTF-8"?>
<imdata totalCount="1">
<aaaUser name="admin" pwd="abcdefgh"/>
</imdata>

then via interactive python, just for a test, I tried this :

>>> import requests
>>> login_apic = requests.post('http://10.1.1.1/api/apic1_login.xml')
>>>

so, it is not rejected, but after that, how to collect the cookie, and do the POST or GET ...?

do you have some an example to do POST or GET via Request module ?

I would like to get all tenants xml files via such GET operations, and possibly all Fabric Access Policies xml files;

well, a snaphot allows to get all Fabric xml in a single commande I know, but there are 2 drawbacks with the snapshot :

a) the resulting snapshot tgz file, when stored locally on the APIC cannot be found : no way to find where it is stored and CISCO doc does not tell it, so, you need to store it in a remote location (that can be 1 of the other APICs)

b) all the xml files stored in this resulting tgz are named with generic names so, you cannot find easily a specific tenant xml file for example

thanks in advance

by the way, I had read and tried a bit to install the different package alternatives mentionned in CISCO doc (ACIToolkit, ARYA, Cobra APIC Python SDK) but was not so successful;

Highlighted
Participant

You can create a requests

You can create a requests session, this will store the login cookie after you login to the fabric:

import requests
requests.packages.urllib3.disable_warnings()

if __name__ == '__main__':
# variables
apic_ip = '10.10.1.1'
apic_user = 'admin'
apic_pw = 'xyz'
apic_apic_url = 'https://' + apic_ip + '/api/'

# login data
login_data = '''<?xml version="1.0" encoding="UTF-8"?>
<imdata totalCount="1">
<aaaUser name="''' + apic_user + '''" pwd="''' + apic_pw + '''"/>
</imdata>'''

# create requests session
session = requests.session()

# login to apic (store cookie in requests session)
result = session.post(apic_apic_url + 'aaaLogin.xml', data=login_data, verify=False)

# get all tenants
allTenants = session.get(apic_apic_url + 'class/fvTenant.xml?rsp-subtree=full&rsp-prop-include=config-only')
print allTenants.text


# get specificTenant
tenant = 'XYZ'
specTenant = session.get(apic_apic_url + 'mo/uni/tn-' + tenant + '.xml?rsp-subtree=full&rsp-prop-include=config-only')
print specTenant.text

This is just for you to get started - you will also need a python xml module to pretty-print and manipulate the results in an easy way.

If you go with python I would recommend to use json to communicate with the API: json-response can be mapped 1:1 to a python-dictionary, so it's much easier to work with json in- and output in python compared to XML.

Marcel

Highlighted
Beginner

thanks Marcel

thanks Marcel

about your useful sample, 2 things :

1) I don't see anything about the cookie ...  or did I miss something ?  I tried to use result.cookies['APIC-Cookie'] without success ?

2) I guess the "+ 'aaaLogin.xml'" must be removed in the "result = ..." line since all is defined now inline ... : right ?

thanks again

Highlighted
Participant

1) The cookie is in the

1) The cookie is in the result.text. Just do a print result.text, you should see something like <aaaLogin token="yourTokenCode">. Now because we created a session

session = requests.session()

the requests module will automatically send the token-code to the apic for any following GETs or POSTs:

xyz = session.get(apic_apic_url + 'xyz')

In the above example the token which we received with the initial login is stored in the session and will be used to authenticate the get request.

2) No, this POST call will initialise the token and stores it to your session (it's the python/requests way to login to your fabric):

    result = session.post(apic_apic_url + 'aaaLogin.xml', data=login_data, verify=False)

This is necessary in order to login to the fabric (you actually don't need to assign the result to an variable, I just did this out of habit).

So to summarise the above - basically the requests-session with APIC works like this

# CREATE A SESSION 
my_session = request.session()
# LOGIN TO APIC, RECEIVE TOKE AND STORE IT TO THE SESSION
loginData = '''<XML with username and password>'''
my_session.post('https://APIC-IP/api/aaaLogin.xml', data=loginData)
# with the above post we sent the username and password to the apic login URI. We receive the token and attach it to our session (we just logged in to the APIC)
# NOW WE ARE AUTHENTICATED/LOGGED-IN and can POST and GET without taking care of the auth-token (for example get all tenants)
allTenants = my_session.get('https://APIC-IP/api/class/fvTenant.xml')
print allTenants.text

HTH

Highlighted
Beginner

hello Marcel,

hello Marcel,

it work now, thanks a lot

(I was a bit surprised by the aaalogin.xml, so, initially, I had removed i; now, it is OK now)

last question (at least for today) :

I want to kind of copy/paste the full set of Fabric Access Policies (referred as FAP below) from an already configured DC (DC1) to a new one (DC2) since it is a dual fabric environnement and so, those FAP are supposed to be identical on both  DCs

so, I  collected all those FAP via GET operations from DC1 : 1 GET per Policy Type, and I got 11 XML files : 1 grouping all VLAN Pools, 1 for all Phys Domains, 1 for all PGs, ...

and now, I want to POST all these 11 XMLs "as is" (apart from the Switch Policy VPC Default) to the new DC2 ;

unfortunately, when using the same kind of syntax I used to POST 1 tenant (still via icurl, with the format you initially provided in this post), I got an error when POSTing those XML that include more than 1 object :

a) 1st test with same POST syntax as for 1 tenant : for 1 XML including all VLAN Pools :

admin@DC2_APIC1:~> icurl -X POST http://localhost:7777/api/mo.xml -d @/tmp/POST_DC2_FAP/all_VLAN_POOL.xml

response ==>

<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="122" text="class fvnsVlanInstP not found"/></imdata>

b) 2nd test by using the same POST syntax as the GET that allowed to obtain the xml to be POSTed :

admin@DC2_APIC1:~> icurl -X 'POST http://localhost:7777/api/class/fvnsVlanInstP.xml' -d @/tmp/POST_DC2_FAP/all_VLAN_POOL.xml  

response ==>

<?xml version="1.0" encoding="UTF-8"?><imdata totalCount="1"><error code="400" text="Updates are allowed only for objects"/></imdata>

any idea ?

Is it possible to POST 1 xml file with more than 1 object inside ?

thanks

Highlighted
Participant

No, thats not possible you

No, thats not possible you can only post one MO (with its childs) per POST. There is only one dn allowed per post.

Have a look at the infra-configuration, you'll see the main object (infraInfra with dn="uni/infra") and the attached childs. This will help you to build the correct XML for your POST:

https://<APIC>/api/mo/uni/infra.xml?rsp-subtree=full&rsp-prop-include=config-only

Or using icurl:

icurl -X GET 'http://localhost:7777/api/mo/uni/infra.xml?rsp-subtree=full&rsp-prop-include=config-only'

Marcel

View solution in original post

Highlighted
Cisco Employee

Hello

Hello

You can try using POSTMan (google chrome extension)

That is what i use in the lab. Remember you need to login and then do your regular POST or GET

View solution in original post