diff --git a/README.md b/README.md index b497b5e..7a01e98 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ ## Cisco DevNet Learning Labs Sample Code for Coding Skills -These code examples provide Python scripts to perform network automation tasks such as creating a ticket or getting a list of network hosts or devices. +These code examples provide Python scripts to perform coding tasks. -The step-by-step tutorials that work with this code are Learning Labs, displayed within the [Cisco DevNet Learning Labs system](https://learninglabs.cisco.com). +The step-by-step tutorials that work with this code are Learning Labs, displayed within the [Cisco DevNet Learning Labs system](https://developer.cisco.com/learning). Contributions are welcome, and we are glad to review changes through pull requests. See [contributing.md](contributing.md) for details. diff --git a/coding102-REST-python-dcloud/readme.txt b/coding102-REST-python-dcloud/readme.txt index e4eb4ba..df1d9e5 100644 --- a/coding102-REST-python-dcloud/readme.txt +++ b/coding102-REST-python-dcloud/readme.txt @@ -4,8 +4,8 @@ These code samples are intended to be used with the Cisco DevNet Learning Labs. walk you through the code step by step. You can find the learning labs here: -https://learninglabs.cisco.com/lab/coding-101-rest-basics-ga/step/1 -https://learninglabs.cisco.com/lab/coding-102-rest-python-ga/step/1 +https://developer.cisco.com/learning/lab/coding-101-rest-basics-ga/step/1 +https://developer.cisco.com/learning/lab/coding-102-rest-python-ga/step/1 You will need to download and setup a few items before you can begin coding along with us. diff --git a/coding201-parsing-xml/get-tenants-xml-1.py b/coding201-parsing-xml/get-tenants-xml-1.py new file mode 100644 index 0000000..514f26a --- /dev/null +++ b/coding201-parsing-xml/get-tenants-xml-1.py @@ -0,0 +1,34 @@ +import requests +import xml.dom.minidom +# We need to import the JSON library just to handle our request to the APIC for login +import json + + +# We need to log in to the APIC and gather a token, before we can access any data +# Let's construct a request with a body + +# We'll need to disable certificate warnings +requests.packages.urllib3.disable_warnings() + +# We need to have a body of data consisting of a username and password to gather a cookie from APIC +encoded_body = json.dumps({ + "aaaUser": { + "attributes": { + "name": "admin", + "pwd": "ciscopsdt" + } + } +}) + +# Now lets make the request and store the data +resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) + +# This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls +header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} + +# Now we make a call towards the tenant class on the ACI fabric with the proper header value set. +# We leverage the .xml ending to receive the data back as XML +tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.xml?rsp-subtree-include=health,faults", headers=header, verify=False) + +# Requests stores the text of the response in the .text attribute. Lets print it to see raw XML +print(tenants.text) \ No newline at end of file diff --git a/coding201-parsing-xml/get-tenants-xml-2.py b/coding201-parsing-xml/get-tenants-xml-2.py new file mode 100644 index 0000000..c59ea12 --- /dev/null +++ b/coding201-parsing-xml/get-tenants-xml-2.py @@ -0,0 +1,36 @@ +import requests +import xml.dom.minidom +# We need to import the JSON library just to handle our request to the APIC for login +import json + + +# We need to log in to the APIC and gather a token, before we can access any data +# Let's construct a request with a body + +# We'll need to disable certificate warnings +requests.packages.urllib3.disable_warnings() + +# We need to have a body of data consisting of a username and password to gather a cookie from APIC +encoded_body = json.dumps({ + "aaaUser": { + "attributes": { + "name": "admin", + "pwd": "ciscopsdt" + } + } +}) + +# Now lets make the request and store the data +resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) + +# This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls +header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} + +# Now we make a call towards the tenant class on the ACI fabric with the proper header value set. +# We leverage the .xml ending to receive the data back as XML +tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.xml?rsp-subtree-include=health,faults", headers=header, verify=False) + +# Now lets use DOM to clean up the XML from its completely raw format +dom = xml.dom.minidom.parseString(tenants.text) +xml = dom.toprettyxml() +print(xml) \ No newline at end of file diff --git a/coding201-parsing-xml/get-tenants-xml-3.py b/coding201-parsing-xml/get-tenants-xml-3.py new file mode 100644 index 0000000..93b1cfd --- /dev/null +++ b/coding201-parsing-xml/get-tenants-xml-3.py @@ -0,0 +1,47 @@ +import requests +import xml.dom.minidom +# We need to import the JSON library just to handle our request to the APIC for login +import json + + +# We need to log in to the APIC and gather a token, before we can access any data +# Let's construct a request with a body + +# We'll need to disable certificate warnings +requests.packages.urllib3.disable_warnings() + +# We need to have a body of data consisting of a username and password to gather a cookie from APIC +encoded_body = json.dumps({ + "aaaUser": { + "attributes": { + "name": "admin", + "pwd": "ciscopsdt" + } + } +}) + +# Now lets make the request and store the data +resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) + +# This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls +header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} + +# Now we make a call towards the tenant class on the ACI fabric with the proper header value set. +# We leverage the .xml ending to receive the data back as XML +tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.xml?rsp-subtree-include=health,faults", headers=header, verify=False) + +# Now lets use DOM to clean up the XML from its completely raw format +dom = xml.dom.minidom.parseString(tenants.text) +xml = dom.toprettyxml() +print(xml) + +# Now we want to parse the resulting XML and print only the tenant name and its current health score. We'll do this through iteration over the elements in the XML +tenant_objects = dom.firstChild +if tenant_objects.hasChildNodes: + tenant_element = tenant_objects.firstChild + while tenant_element is not None: + if tenant_element.tagName == 'fvTenant': + health_element = tenant_element.firstChild + output = "Tenant: " + tenant_element.getAttribute('name') + '\t Health Score: ' + health_element.getAttribute('cur') + print(output.expandtabs(40)) + tenant_element = tenant_element.nextSibling \ No newline at end of file diff --git a/coding201-parsing-xml/get-tenants-xml-4.py b/coding201-parsing-xml/get-tenants-xml-4.py new file mode 100644 index 0000000..419ac85 --- /dev/null +++ b/coding201-parsing-xml/get-tenants-xml-4.py @@ -0,0 +1,45 @@ +import requests +import xml.dom.minidom +# We need to import the JSON library just to handle our request to the APIC for login +import json + + +# We need to log in to the APIC and gather a token, before we can access any data +# Let's construct a request with a body + +# We'll need to disable certificate warnings +requests.packages.urllib3.disable_warnings() + +# We need to have a body of data consisting of a username and password to gather a cookie from APIC +encoded_body = json.dumps({ + "aaaUser": { + "attributes": { + "name": "admin", + "pwd": "ciscopsdt" + } + } +}) + +# Now lets make the request and store the data +resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) + +# This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls +header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} + +# Now we make a call towards the tenant class on the ACI fabric with the proper header value set. +# We leverage the .xml ending to receive the data back as XML +tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.xml?rsp-subtree-include=health,faults", headers=header, verify=False) + +# Now lets use DOM to clean up the XML from its completely raw format +dom = xml.dom.minidom.parseString(tenants.text) +xml = dom.toprettyxml() +print(xml) + +# Now we'll do something similar, but done using a direct access method of the data, rather than interation and loops +tenant_list = dom.getElementsByTagName('fvTenant') +for tenants in tenant_list: + tenant_name = tenants.getAttribute('name') + tenant_dn = tenants.getAttribute('dn') + health_score = tenants.firstChild.getAttribute('cur') + output = "Tenant: " + tenant_name + "\t Health Score: " + health_score + "\n DN: " + tenant_dn + print(output.expandtabs(40)) \ No newline at end of file diff --git a/coding202-parsing-json/get-tenant-json-1.py b/coding202-parsing-json/get-tenant-json-1.py new file mode 100644 index 0000000..a5b55e4 --- /dev/null +++ b/coding202-parsing-json/get-tenant-json-1.py @@ -0,0 +1,33 @@ +import requests +# We need to import the JSON library just to handle our request to the APIC for login +import json + + +# We need to log in to the APIC and gather a token, before we can access any data +# Let's construct a request with a body + +# We'll need to disable certificate warnings +requests.packages.urllib3.disable_warnings() + +# We need to have a body of data consisting of a username and password to gather a cookie from APIC +encoded_body = json.dumps({ + "aaaUser": { + "attributes": { + "name": "admin", + "pwd": "ciscopsdt" + } + } +}) + +# Now lets make the request and store the data +resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) + +# This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls +header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} + +# Now we make a call towards the tenant class on the ACI fabric with the proper header value set. +# We leverage the .xml ending to receive the data back as XML. We're adding health and faults to the printout to ensure that we get levels of data back from the APIC +tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.json?rsp-subtree-include=health,faults", headers=header, verify=False) + +# Requests stores the text of the response in the .text attribute. Lets print it to see raw JSON +print(tenants.text) \ No newline at end of file diff --git a/coding202-parsing-json/get-tenant-json-2.py b/coding202-parsing-json/get-tenant-json-2.py new file mode 100644 index 0000000..df4f238 --- /dev/null +++ b/coding202-parsing-json/get-tenant-json-2.py @@ -0,0 +1,37 @@ +import requests +# We need to import the JSON library just to handle our request to the APIC for login +import json + + +# We need to log in to the APIC and gather a token, before we can access any data +# Let's construct a request with a body + +# We'll need to disable certificate warnings +requests.packages.urllib3.disable_warnings() + +# We need to have a body of data consisting of a username and password to gather a cookie from APIC +encoded_body = json.dumps({ + "aaaUser": { + "attributes": { + "name": "admin", + "pwd": "ciscopsdt" + } + } +}) + +# Now lets make the request and store the data +resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) + +# This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls +header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} + +# Now we make a call towards the tenant class on the ACI fabric with the proper header value set. +# We leverage the .xml ending to receive the data back as XML. We're adding health and faults to the printout to ensure that we get levels of data back from the APIC +tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.json?rsp-subtree-include=health,faults", headers=header, verify=False) + +# Requests stores the text of the response in the .text attribute. Lets print it to see raw JSON +#print(tenants.text) + +# Lets make this response a bit prettier, by converting it to a JSON object and using the dumps method to provide indentation +json_response = json.loads(tenants.text) +print(json.dumps(json_response, sort_keys=True, indent=4)) \ No newline at end of file diff --git a/coding202-parsing-json/get-tenant-json-3.py b/coding202-parsing-json/get-tenant-json-3.py new file mode 100644 index 0000000..b14c51e --- /dev/null +++ b/coding202-parsing-json/get-tenant-json-3.py @@ -0,0 +1,54 @@ +import requests +# We need to import the JSON library just to handle our request to the APIC for login +import json + + +# We need to log in to the APIC and gather a token, before we can access any data +# Let's construct a request with a body + +# We'll need to disable certificate warnings +requests.packages.urllib3.disable_warnings() + +# We need to have a body of data consisting of a username and password to gather a cookie from APIC +encoded_body = json.dumps({ + "aaaUser": { + "attributes": { + "name": "admin", + "pwd": "ciscopsdt" + } + } +}) + +# Now lets make the request and store the data +resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) + +# This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls +header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} + +# Now we make a call towards the tenant class on the ACI fabric with the proper header value set. +# We leverage the .xml ending to receive the data back as XML. We're adding health and faults to the printout to ensure that we get levels of data back from the APIC +tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.json?rsp-subtree-include=health,faults", headers=header, verify=False) + +# Requests stores the text of the response in the .text attribute. Lets print it to see raw XML +#print(tenants.text) + +# Lets make this response a bit prettier, by converting it to a JSON object and using the dumps method to provide indentation +json_response = json.loads(tenants.text) +#print(json.dumps(json_response, sort_keys=True, indent=4)) + + +# We've commented out the pretty-print, but now lets return only the values we want. +# Everything within the returned JSON is containted within the `imdata` dictionary, so lets strip that away +json_tenants = json_response['imdata'] + +# Now we have to loop through the resulting list (using the `for` loop) and drill into the subsequent dictionaries by name +# When we get to `tenant health`, we move from `attributes` dictionary to `children` dictionary. +# Inside of the `children` dictionary is a list, which will need an index value to move further. +# Since there is only one child object within the `children` list, we can safely set this value to `0` +# This is the result of how the original query was structured, so don't assume you can always set that value to `0` +for tenant in json_tenants: + tenant_name = tenant['fvTenant']['attributes']['name'] + tenant_dn = tenant['fvTenant']['attributes']['dn'] + tenant_health = tenant['fvTenant']['children'][0]['healthInst']['attributes']['cur'] + output = "Tenant: " + tenant_name + "\t Health Score: " + tenant_health + "\n DN: " + tenant_dn + print(output.expandtabs(40)) \ No newline at end of file diff --git a/coding203-getting-input/get-input.py b/coding203-getting-input/get-input.py index e166bae..a5fa07d 100644 --- a/coding203-getting-input/get-input.py +++ b/coding203-getting-input/get-input.py @@ -3,7 +3,7 @@ # amwhaley@cisco.com # twitter: @mandywhaley # http://developer.cisco.com -# http://learninglabs.cisco.com +# http://developer.cisco.com/learning # Jan 15, 2015 # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY diff --git a/coding204-reading-a-file/read-file-loop.py b/coding204-reading-a-file/read-file-loop.py index fa5befd..5f49a9b 100644 --- a/coding204-reading-a-file/read-file-loop.py +++ b/coding204-reading-a-file/read-file-loop.py @@ -2,7 +2,7 @@ # amwhaley@cisco.com # twitter: @mandywhaley # http://developer.cisco.com -# http://learninglabs.cisco.com +# http://developer.cisco.com/learning # Jan 15, 2015 # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY diff --git a/coding204-reading-a-file/read-file-one-line.py b/coding204-reading-a-file/read-file-one-line.py index d8e8108..8a37390 100644 --- a/coding204-reading-a-file/read-file-one-line.py +++ b/coding204-reading-a-file/read-file-one-line.py @@ -2,7 +2,7 @@ # amwhaley@cisco.com # twitter: @mandywhaley # http://developer.cisco.com -# http://learninglabs.cisco.com +# http://developer.cisco.com/learning # Jan 15, 2015 # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY diff --git a/coding204-reading-a-file/read-file-with.py b/coding204-reading-a-file/read-file-with.py index a722ada..9c4ec5b 100644 --- a/coding204-reading-a-file/read-file-with.py +++ b/coding204-reading-a-file/read-file-with.py @@ -2,7 +2,7 @@ # amwhaley@cisco.com # twitter: @mandywhaley # http://developer.cisco.com -# http://learninglabs.cisco.com +# http://developer.cisco.com/learning # Jan 15, 2015 # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY diff --git a/coding204-reading-a-file/read-file.py b/coding204-reading-a-file/read-file.py index f56b27b..02625f1 100644 --- a/coding204-reading-a-file/read-file.py +++ b/coding204-reading-a-file/read-file.py @@ -3,7 +3,7 @@ # amwhaley@cisco.com # twitter: @mandywhaley # http://developer.cisco.com -# http://learninglabs.cisco.com +# http://developer.cisco.com/learning # Jan 15, 2015 # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY diff --git a/coding204-reading-a-file/read-json-from-file.py b/coding204-reading-a-file/read-json-from-file.py index dde254b..cbb7d95 100644 --- a/coding204-reading-a-file/read-json-from-file.py +++ b/coding204-reading-a-file/read-json-from-file.py @@ -3,7 +3,7 @@ # amwhaley@cisco.com # twitter: @mandywhaley # http://developer.cisco.com -# http://learninglabs.cisco.com +# http://developer.cisco.com/learning # Jan 15, 2015 # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY diff --git a/coding205-writing-file-ga/write-file-append.py b/coding205-writing-file-ga/write-file-append.py index fddcbae..716ea31 100644 --- a/coding205-writing-file-ga/write-file-append.py +++ b/coding205-writing-file-ga/write-file-append.py @@ -3,7 +3,7 @@ # amwhaley@cisco.com # twitter: @mandywhaley # http://developer.cisco.com -# http://learninglabs.cisco.com +# http://developer.cisco.com/learning # Jan 15, 2015 # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY diff --git a/coding205-writing-file-ga/write-file-using-with.py b/coding205-writing-file-ga/write-file-using-with.py index cac1d92..05cb29c 100644 --- a/coding205-writing-file-ga/write-file-using-with.py +++ b/coding205-writing-file-ga/write-file-using-with.py @@ -3,7 +3,7 @@ # amwhaley@cisco.com # twitter: @mandywhaley # http://developer.cisco.com -# http://learninglabs.cisco.com +# http://developer.cisco.com/learning # Jan 15, 2015 # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY diff --git a/coding205-writing-file-ga/write-file.py b/coding205-writing-file-ga/write-file.py index da7e7cc..9844698 100644 --- a/coding205-writing-file-ga/write-file.py +++ b/coding205-writing-file-ga/write-file.py @@ -3,7 +3,7 @@ # amwhaley@cisco.com # twitter: @mandywhaley # http://developer.cisco.com -# http://learninglabs.cisco.com +# http://developer.cisco.com/learning # Jan 15, 2015 # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY diff --git a/coding206-logging/logging-step3.py b/coding206-logging/logging-step3.py index ff58159..79e9e15 100644 --- a/coding206-logging/logging-step3.py +++ b/coding206-logging/logging-step3.py @@ -3,7 +3,7 @@ # amwhaley@cisco.com # twitter: @mandywhaley # http://developer.cisco.com -# http://learninglabs.cisco.com +# http://developer.cisco.com/learning # Jan 15, 2015 # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY diff --git a/coding206-logging/logging-step4.py b/coding206-logging/logging-step4.py index 3cd07ae..8582041 100644 --- a/coding206-logging/logging-step4.py +++ b/coding206-logging/logging-step4.py @@ -3,7 +3,7 @@ # amwhaley@cisco.com # twitter: @mandywhaley # http://developer.cisco.com -# http://learninglabs.cisco.com +# http://developer.cisco.com/learning # Jan 15, 2015 # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY diff --git a/coding206-logging/super-simple-logging.py b/coding206-logging/super-simple-logging.py index 1e97236..c3bc93c 100644 --- a/coding206-logging/super-simple-logging.py +++ b/coding206-logging/super-simple-logging.py @@ -3,7 +3,7 @@ # amwhaley@cisco.com # twitter: @mandywhaley # http://developer.cisco.com -# http://learninglabs.cisco.com +# http://developer.cisco.com/learning # Jan 15, 2015 # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY diff --git a/contributing.md b/contributing.md index e14e1fb..55913d9 100644 --- a/contributing.md +++ b/contributing.md @@ -16,10 +16,11 @@ For public repo Learning Labs, use the issue tracker in the repo. All Learning L For private Learning Labs, use the common Issue tracker in the [CiscoDevNet/learning-labs-issues](https://github.com/CiscoDevNet/learning-labs-issues) repo. -For DevNet Express events, use these three Issue tracker repos based on the content track: +For DevNet Express events, use these Issue tracker repos based on the content track: * https://github.com/CiscoDevNet/devnet-express-dna-issues * https://github.com/CiscoDevNet/devnet-express-cc-issues * https://github.com/CiscoDevNet/devnet-express-dci-issues +* https://github.com/CiscoDevNet/devnet-express-security-issues Use the issue tracker to suggest additions, report bugs, and ask questions. This is also a great way to connect with the developers of the project as well @@ -31,8 +32,7 @@ that effort, then follow the _Changing the Learning Lab content_ guidance below. ## Changing the Learning Lab content -Generally speaking, you should fork the Learning Lab repository, make changes in -your fork, and then submit a pull request (PR). All new content should be tested +Generally speaking, you should clone the Learning Lab repository, make changes locally, and then submit a pull request (PR). All new content should be tested to validate that documented tasks work correctly. Additionally, the content should follow the [Learning Lab Style Guide](https://github.com/CiscoDevNet/devnet-writing-guidelines/wiki/Lab-Style-Guide).