Lab 12 - Pynautobot Basics¶
Lab Overview¶
In this lab we will use the pynautobot python package to interact with the Nautobot ReST API.
Table of Contents¶
Task 1 - Prepare the environment¶
Step 1-1 - Login via ssh to your pod¶
Connect via ssh to your Nautobot pod as the ntc user. Use the password provided by the instructor.
ssh ntc@{{ your pod }}
Verify you are logged in as the ntc user.
Step 1-2 - Create and activate a virtual environment¶
A virtual environment will isolate any packages we install and can easily be activated, deactivated or deleted.
Create the virtual environment
Activate the virtual environment
Step 1-3 - Install pynautobot¶
Collecting pynautobot
Downloading pynautobot-1.5.0-py3-none-any.whl (33 kB)
Collecting urllib3<1.27,>=1.21.1
Downloading urllib3-1.26.16-py2.py3-none-any.whl (143 kB)
|████████████████████████████████| 143 kB 51.7 MB/s
Collecting requests<3.0.0,>=2.30.0
Downloading requests-2.31.0-py3-none-any.whl (62 kB)
|████████████████████████████████| 62 kB 816 kB/s
Collecting charset-normalizer<4,>=2
Downloading charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (199 kB)
|████████████████████████████████| 199 kB 61.3 MB/s
Collecting idna<4,>=2.5
Downloading idna-3.4-py3-none-any.whl (61 kB)
|████████████████████████████████| 61 kB 78 kB/s
Collecting certifi>=2017.4.17
Downloading certifi-2023.7.22-py3-none-any.whl (158 kB)
|████████████████████████████████| 158 kB 78.9 MB/s
Installing collected packages: urllib3, charset-normalizer, idna, certifi, requests, pynautobot
Successfully installed certifi-2023.7.22 charset-normalizer-3.2.0 idna-3.4 pynautobot-1.5.0 requests-2.31.0 urllib3-1
After pynautobot has successfully installed, enter the python shell.
Python 3.8.10 (default, May 26 2023, 14:05:08)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
urlib3 to disable warnings about request security. This is not a requirement for using pynautobot, but in our lab environment disabling the warnings will prevent unnecessary message noise while we interact with pynautobot.
Task 2 - Pynautobot basics¶
Step 2-1 - Create a client¶
Import pynautobot so we can use it!
By providing domain and authentication details to a pynautobot client, we can run commands against the API without having to re-enter this information every time. The function arguments have been broken out into variables for increased readability, but if you want everything can be put into a single call to the api method.
You will need a Token for the client, this can be found in the Admin section of Nautobot as discussed in a previous lab. Don't forget to put the url and token values into a string by using quotes.
>>> url = "https://{{ your pod }}/"
>>> token = "1234123412341234123412341234123412341234"
>>> nautobot = pynautobot.api(url=url, token=token)
Next we need to disable SSL verification so pynautobot will work in our lab.
Step 2-2 - Get Nautobot data using pynautobot¶
Use the client to assign all the Sites to a variable
Print the contents ofsites
[<pynautobot.core.response.Record ('AMS01') at 0x7fa1bc6ac0d0>, <pynautobot.core.response.Record ('ANG01') at 0x7fa1bc69f580>, <pynautobot.core.response.Record ('ATL01') at 0x7fa1bc69fac0>, <pynautobot.core.response.Record ('ATL02') at 0x7fa1bc6a8a60>, <pynautobot.core.response.Record ('AUS01') at 0x7fa1bc69f5e0>, <pynautobot.core.response.Record ('AZD01') at 0x7fa1bc405460>, <pynautobot.core.response.Record ('BKK01') at 0x7fa1bc4055b0>, <pynautobot.core.response.Record ('BRE01') at 0x7fa1bc405700>, <pynautobot.core.response.Record ('CAN01') at 0x7fa1bc405850>, <pynautobot.core.response.Record ('CDG01') at 0x7fa1bc4059a0>, <pynautobot.core.response.Record ('CDG02') at 0x7fa1bc405af0>, <pynautobot.core.response.Record ('DEL01') at 0x7fa1bc405c40>, <pynautobot.core.response.Record ('DEN01') at 0x7fa1bc405d90>, <pynautobot.core.response.Record ('DFW01') at 0x7fa1bc405ee0>, <pynautobot.core.response.Record ('DFW02') at 0x7fa1bc405fd0>, <pynautobot.core.response.Record ('DXB01') at 0x7fa1bc405370>, <pynautobot.core.response.Record ('DXB02') at 0x7fa1bc391310>, <pynautobot.core.response.Record ('FRA01') at 0x7fa1bc391460>, <pynautobot.core.response.Record ('HKG01') at 0x7fa1bc3915b0>, <pynautobot.core.response.Record ('HND01') at 0x7fa1bc391700>, <pynautobot.core.response.Record ('HND02') at 0x7fa1bc391850>, <pynautobot.core.response.Record ('HOU01') at 0x7fa1bc3919a0>, <pynautobot.core.response.Record ('ICN01') at 0x7fa1bc391af0>, <pynautobot.core.response.Record ('JFK01') at 0x7fa1bc391c40>, <pynautobot.core.response.Record ('Jersey City') at 0x7fa1bc391d90>, <pynautobot.core.response.Record ('KOL01') at 0x7fa1bc391ee0>, <pynautobot.core.response.Record ('LAX01') at 0x7fa1bc391fd0>, <pynautobot.core.response.Record ('LAX02') at 0x7fa1bc3911c0>, <pynautobot.core.response.Record ('LAX03') at 0x7fa1bc325310>, <pynautobot.core.response.Record ('LHR01') at 0x7fa1bc325460>, <pynautobot.core.response.Record ('LHR02') at 0x7fa1bc3255b0>, <pynautobot.core.response.Record ('LON01') at 0x7fa1bc325700>, <pynautobot.core.response.Record ('MAD01') at 0x7fa1bc325850>, <pynautobot.core.response.Record ('NYM01') at 0x7fa1bc3259a0>, <pynautobot.core.response.Record ('New York City') at 0x7fa1bc325af0>, <pynautobot.core.response.Record ('ORD01') at 0x7fa1bc325c40>, <pynautobot.core.response.Record ('ORD02') at 0x7fa1bc325d90>, <pynautobot.core.response.Record ('PEK01') at 0x7fa1bc325ee0>, <pynautobot.core.response.Record ('PEK02') at 0x7fa1bc325fd0>, <pynautobot.core.response.Record ('PVG01') at 0x7fa1bc3251c0>, <pynautobot.core.response.Record ('PVG02') at 0x7fa1bc334310>, <pynautobot.core.response.Record ('SIN01') at 0x7fa1bc334460>, <pynautobot.core.response.Record ('SLC01') at 0x7fa1bc3345b0>, <pynautobot.core.response.Record ('SMF01') at 0x7fa1bc334700>, <pynautobot.core.response.Record ('Weehawken') at 0x7fa1bc334850>]
>>> for site in sites:
... print(f"Site Name: {site.name}")
... print(f"Site Status: {site.status}")
Site Name: AMS01
Site Status: Active
Site Name: ANG01
Site Status: Active
Site Name: ATL01
Site Status: Active
Site Name: ATL02
Site Status: Active
Site Name: AUS01
Site Status: Active
Site Name: AZD01
Site Status: Active
Site Name: BKK01
Site Status: Active
Site Name: BRE01
Site Status: Active
Site Name: CAN01
Site Status: Active
...
>>> for site in us_sites:
... print(f"Site Name: {site.name}")
... print(f"Site Status: {site.status}")
print(f"Site Region: {site.region}")
Site Name: ANG01
Site Status: Active
Site Region: United States
Site Name: ATL01
Site Status: Active
Site Region: United States
Site Name: ATL02
Site Status: Active
Site Region: United States
Site Name: AZD01
Site Status: Active
Site Region: United States
Site Name: BRE01
Site Status: Active
Site Region: United States
Site Name: DEN01
Site Status: Active
Site Region: United States
Site Name: DFW01
Site Status: Active
Site Region: United States
Site Name: DFW02
Site Status: Active
Site Region: United States
Site Name: HOU01
Site Status: Active
Site Region: Texas
...
Step 2-3 - Update Nautobot data using pynautobot¶
In a previous step we assigned the HOU01 site to a variable. Let's check the status.
Active, Update it to Planned.
Check the Site Status.
That didn't work! Why? We haven't actually saved the changes we made to the Nautobot database, we have only modified the variable in memory.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute 'value'
HOU01 doesn't meet the requirement. We could update the name and slug here, or disable the regex rule.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/ntc/pynautobot_venv/lib/python3.8/site-packages/pynautobot/core/response.py", line 392, in save
if req.patch({i: serialized[i] for i in diff}):
File "/home/ntc/pynautobot_venv/lib/python3.8/site-packages/pynautobot/core/query.py", line 400, in patch
return self._make_call(verb="patch", data=data)
File "/home/ntc/pynautobot_venv/lib/python3.8/site-packages/pynautobot/core/query.py", line 276, in _make_call
raise RequestError(req)
pynautobot.core.query.RequestError: The request failed with code 400 Bad Request: {'name': ['Site names must be in the format AAA000 or AAA0000. The name must begin with exactly 3 upper case letters followed by 3 or 4 numbers between 0 and 9.']}
True means the save was successful.
Get the data from the database again to update the variable with the new data. I'm also creating a new variable so the variable name matches the Site name.
Print out the updated Site data. You can also verify this data in the Nautobot GUI.
Step 2-4 - Send a GraphQL query with pynautobot¶
To make the response more readable, import json.
Create the query. Note the triple quotes which are used for multi-line strings in python.
Send the request. Print the json data.{
"data": {
"devices": [
{
"name": "ams01-dist-01"
},
{
"name": "ams01-edge-01"
},
{
"name": "ams01-edge-02"
},
{
"name": "ams01-leaf-01"
},
{
"name": "ams01-leaf-02"
},
{
"name": "ams01-leaf-03"
},
{
"name": "ams01-leaf-04"
},
{
"name": "ams01-leaf-05"
},
{
"name": "ams01-leaf-06"
},
{
"name": "ams01-leaf-07"
},
{
"name": "ams01-leaf-08"
},
{
"name": "ang01-dist-01"
},
{
"name": "ang01-edge-01"
},
{
"name": "ang01-edge-02"
},
...