├── .gitignore ├── .project ├── .pydevproject ├── .travis.yml ├── LICENSE ├── README.md ├── coding102-REST-python-dcloud ├── build-topology.py ├── create-ticket.py ├── get-network-devices.py ├── get-network-hosts.py ├── manage-users.py ├── readme.txt ├── report-topology.py └── spark.py ├── coding102-REST-python-ga ├── build-topology-webserver.py ├── build-topology.py ├── create-ticket.py ├── get-network-devices.py ├── get-network-hosts.py ├── manage-users.py └── templates │ └── topology.html ├── coding103-python-json ├── Examples │ ├── example1.py │ ├── example2.py │ └── example3.py └── reqirements.txt ├── coding201-parsing-xml ├── get-ap-xml-1.py ├── get-ap-xml-2.py ├── get-ap-xml-3.py ├── get-ap-xml-4.py ├── get-tenants-xml-1.py ├── get-tenants-xml-2.py ├── get-tenants-xml-3.py └── get-tenants-xml-4.py ├── coding202-parsing-json ├── activity-debug-1.py ├── activity-parse-1.py ├── activity-parse-2.py ├── activity-parse-3.py ├── activity-parse-4.py ├── call-functions.py ├── data-type-values.py ├── get-ap-json-1.py ├── get-ap-json-2.py ├── get-ap-json-3.py ├── get-cmx-json.py ├── get-tenant-json-1.py ├── get-tenant-json-2.py ├── get-tenant-json-3.py ├── hello.py ├── helloworld.py ├── json_parse-1.py ├── json_parse-2.py └── parse.py ├── coding203-getting-input └── get-input.py ├── coding204-reading-a-file ├── my-file.txt ├── my-json.json ├── read-file-loop.py ├── read-file-one-line.py ├── read-file-with.py ├── read-file.py └── read-json-from-file.py ├── coding205-writing-file-ga ├── list-of-devices.txt ├── write-file-append.py ├── write-file-using-with.py ├── write-file.py └── write-json-to-file.py ├── coding206-logging ├── logging-step3.py ├── logging-step4.py ├── mylog.log └── super-simple-logging.py ├── coding207-putting-it-together-ga ├── crap.txt └── create-device-list.py ├── coding210-parsing-json-c++ ├── CMakeLists.txt ├── README.md ├── activity-1.cmake ├── activity-2.cmake ├── activity-3.cmake ├── activity-4.cmake ├── activity-5.cmake ├── hello.cpp ├── hello.cs ├── main-annotated.cpp ├── main-http.cpp ├── main-json-lib.cpp ├── main-json.cpp └── main.cpp ├── content-serve ├── content-server.py └── data │ ├── complex-array.json │ ├── complex.json │ └── index.html └── contributing.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | 59 | # Jetbrains IDE files 60 | .idea 61 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | coding-skills-sample-code 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | 15 | org.python.pydev.pythonNature 16 | 17 | 18 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /${PROJECT_DIR_NAME} 5 | 6 | python 3.0 7 | Default 8 | 9 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | branches: 5 | only: 6 | - clus-updates 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Cisco DevNet Learning Labs Sample Code for Coding Skills 2 | 3 | These code examples provide Python scripts to perform coding tasks. 4 | 5 | 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). 6 | 7 | Contributions are welcome, and we are glad to review changes through pull requests. See [contributing.md](contributing.md) for details. 8 | 9 | The goal of these learning labs is to ensure a 'hands-on' learning approach rather than just theory or instructions. 10 | 11 | ## Contributing 12 | 13 | These samples are for public consumption, so you must ensure that you have the rights to any code that you contribute. 14 | 15 | ## Getting Involved 16 | 17 | * If you'd like to contribute examples for an existing lab, refer to [contributing.md](contributing.md). 18 | * If you're interested in creating a new Cisco DevNet Learning Lab or code example, please contact a DevNet administrator for guidance. 19 | 20 | -------------------------------------------------------------------------------- /coding102-REST-python-dcloud/build-topology.py: -------------------------------------------------------------------------------- 1 | # Example of building topology via REST API calls from Python 2 | 3 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 4 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 5 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 6 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 7 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 8 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 9 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 10 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 11 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 12 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 13 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 14 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 15 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 16 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 17 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 18 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 19 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 20 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 21 | 22 | 23 | # import requests library 24 | import requests 25 | 26 | #import json library 27 | import json 28 | 29 | # Disable warnings 30 | requests.packages.urllib3.disable_warnings() 31 | 32 | controller='198.18.129.100' 33 | 34 | 35 | def getTicket(): 36 | # put the ip address or dns of your apic-em controller in this url 37 | url = "https://" + controller + "/api/v1/ticket" 38 | 39 | #the username and password to access the APIC-EM Controller 40 | payload = {"username":"admin","password":"C1sco12345"} 41 | 42 | #Content type must be included in the header 43 | header = {"content-type": "application/json"} 44 | 45 | #Performs a POST on the specified url to get the service ticket 46 | response= requests.post(url,data=json.dumps(payload), headers=header, verify=False) 47 | 48 | print (response) 49 | 50 | #convert response to json format 51 | r_json=response.json() 52 | 53 | #parse the json to get the service ticket 54 | ticket = r_json["response"]["serviceTicket"] 55 | 56 | return ticket 57 | 58 | 59 | 60 | def getTopology(ticket): 61 | # URL for topology REST API call to get list of existing devices on the network, and build topology 62 | url = "https://" + controller + "/api/v1/topology/physical-topology" 63 | 64 | #Content type as well as the ticket must be included in the header 65 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 66 | 67 | # this statement performs a GET on the specified network device url 68 | response = requests.get(url, headers=header, verify=False) 69 | 70 | # json.dumps serializes the json into a string and allows us to 71 | # print the response in a 'pretty' format with indentation etc. 72 | print ("Topology = ") 73 | print (json.dumps(response.json(), indent=4, separators=(',', ': '))) 74 | 75 | #convert data to json format. 76 | r_json=response.json() 77 | 78 | #Iterate through network device data and list the nodes, their interfaces, status and to what they connect 79 | for n in r_json["response"]["nodes"]: 80 | if "platformId" in n: 81 | print() 82 | print() 83 | print('{:30}'.format("Node") + '{:25}'.format("Family") + '{:20}'.format("Label")+ "Management IP") 84 | print('{:30}'.format(n["platformId"]) + '{:25}'.format(n["family"]) + '{:20}'.format(n["label"]) + n["ip"]) 85 | found=0 #print header flag 86 | printed=0 #formatting flag 87 | for i in r_json["response"]["links"]: 88 | if "startPortName" in i: 89 | #check that the source device id for the interface matches the node id. Means interface originated from this device. 90 | if i["source"] == n["id"]: 91 | if found==0: 92 | print('{:>20}'.format("Source Interface") + '{:>15}'.format("Target") +'{:>28}'.format("Target Interface") + '{:>15}'.format("Status") ) 93 | found=1 94 | printed=1 95 | for n1 in r_json["response"]["nodes"]: 96 | #find name of node to which this one connects 97 | if i["target"] == n1["id"]: 98 | print(" " + '{:<25}'.format(i["startPortName"]) + '{:<18}'.format(n1["platformId"]) + '{:<25}'.format(i["endPortName"]) + '{:<9}'.format(i["linkStatus"]) ) 99 | break; 100 | found=0 101 | 102 | for i in r_json["response"]["links"]: 103 | if "startPortName" in i: 104 | #Find interfaces that link to this one which means this node is the target. 105 | if i["target"] == n["id"]: 106 | if found==0: 107 | if printed==1: 108 | print() 109 | print('{:>10}'.format("Source") + '{:>30}'.format("Source Interface") + '{:>25}'.format("Target Interface") + '{:>13}'.format("Status")) 110 | found=1 111 | for n1 in r_json["response"]["nodes"]: 112 | #find name of node to that connects to this one 113 | if i["source"] == n1["id"]: 114 | print(" " + '{:<20}'.format(n1["platformId"]) + '{:<25}'.format(i["startPortName"]) + '{:<23}'.format(i["endPortName"]) + '{:<8}'.format(i["linkStatus"])) 115 | break; 116 | 117 | theTicket=getTicket() 118 | getTopology(theTicket) 119 | -------------------------------------------------------------------------------- /coding102-REST-python-dcloud/create-ticket.py: -------------------------------------------------------------------------------- 1 | # import requests library 2 | import requests 3 | 4 | #import json library 5 | import json 6 | 7 | # put the ip address or dns of your apic-em controller in this url 8 | url = 'https://198.18.129.100/api/v1/ticket' 9 | 10 | 11 | 12 | #the username and password to access the APIC-EM Controller 13 | payload = {"username":"admin","password":"C1sco12345"} 14 | 15 | 16 | #Content type must be included in the header 17 | header = {"content-type": "application/json"} 18 | 19 | #Performs a POST on the specified url. 20 | response= requests.post(url,data=json.dumps(payload), headers=header, verify=False) 21 | 22 | # print the json that is returned 23 | print(response.text) -------------------------------------------------------------------------------- /coding102-REST-python-dcloud/get-network-devices.py: -------------------------------------------------------------------------------- 1 | # Example of getting network-devices via REST API calls from Python 2 | 3 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 4 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 5 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 6 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 7 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 8 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 9 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 10 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 11 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 12 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 13 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 14 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 15 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 16 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 17 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 18 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 19 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 20 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 21 | 22 | 23 | # import requests library 24 | import requests 25 | 26 | #import json library 27 | import json 28 | 29 | controller='198.18.129.100' 30 | 31 | def getTicket(): 32 | # put the ip address or dns of your apic-em controller in this url 33 | url = "https://" + controller + "/api/v1/ticket" 34 | 35 | #the username and password to access the APIC-EM Controller 36 | payload = {"username":"admin","password":"C1sco12345"} 37 | 38 | #Content type must be included in the header 39 | header = {"content-type": "application/json"} 40 | 41 | #Performs a POST on the specified url to get the service ticket 42 | response= requests.post(url,data=json.dumps(payload), headers=header, verify=False) 43 | 44 | print (response) 45 | 46 | #convert response to json format 47 | r_json=response.json() 48 | 49 | #parse the json to get the service ticket 50 | ticket = r_json["response"]["serviceTicket"] 51 | 52 | return ticket 53 | 54 | 55 | def getNetworkDevices(ticket): 56 | # URL for network-device REST API call to get list of exisiting devices on the network. 57 | url = "https://" + controller + "/api/v1/network-device" 58 | 59 | #Content type as well as the ticket must be included in the header 60 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 61 | 62 | # this statement performs a GET on the specified network device url 63 | response = requests.get(url, headers=header, verify=False) 64 | 65 | # json.dumps serializes the json into a string and allows us to 66 | # print the response in a 'pretty' format with indentation etc. 67 | print ("Network Devices = ") 68 | print (json.dumps(response.json(), indent=4, separators=(',', ': '))) 69 | 70 | #convert data to json format. 71 | r_json=response.json() 72 | 73 | #Iterate through network device data and print the id and series name of each device 74 | for i in r_json["response"]: 75 | print(i["id"] + " " + '{:53}'.format(i["series"]) + " " + i["reachabilityStatus"]) 76 | 77 | 78 | 79 | theTicket=getTicket() 80 | getNetworkDevices(theTicket) 81 | -------------------------------------------------------------------------------- /coding102-REST-python-dcloud/get-network-hosts.py: -------------------------------------------------------------------------------- 1 | # Simple Example of calling REST API from Python 2 | # This is all that is required to call a REST API from python 3 | 4 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 5 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 6 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 7 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 8 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 9 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 10 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 11 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 12 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 13 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 14 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 15 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 16 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 17 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 18 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 19 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 20 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 21 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 22 | 23 | 24 | # import requests library 25 | import requests 26 | 27 | #import json library 28 | import json 29 | 30 | controller='198.18.129.100' 31 | 32 | 33 | # put the ip address or dns of your apic-em controller in this url 34 | url = "https://" + controller + "/api/v1/ticket" 35 | 36 | #the username and password to access the APIC-EM Controller 37 | payload = {"username":"admin","password":"C1sco12345"} 38 | 39 | #Content type must be included in the header 40 | header = {"content-type": "application/json"} 41 | 42 | #Performs a POST on the specified url to get the service ticket 43 | response= requests.post(url,data=json.dumps(payload), headers=header, verify=False) 44 | 45 | #convert response to json format 46 | r_json=response.json() 47 | 48 | print(r_json) 49 | #parse the json to get the service ticket 50 | ticket = r_json["response"]["serviceTicket"] 51 | 52 | # URL for Host REST API call to get list of exisitng hosts on the network. 53 | url = "https://" + controller + "/api/v1/host?limit=1&offset=1" 54 | 55 | #Content type must be included in the header as well as the ticket 56 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 57 | 58 | # this statement performs a GET on the specified host url 59 | response = requests.get(url, headers=header, verify=False) 60 | 61 | # json.dumps serializes the json into a string and allows us to 62 | # print the response in a 'pretty' format with indentation etc. 63 | print ("Hosts = ") 64 | print (json.dumps(response.json(), indent=4, separators=(',', ': '))) -------------------------------------------------------------------------------- /coding102-REST-python-dcloud/manage-users.py: -------------------------------------------------------------------------------- 1 | # Example of calling REST API from Python to manage APIC-EM users/roles using APIC-EM APIs. 2 | 3 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 4 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 5 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 6 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 7 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 8 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 9 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 10 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 11 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 12 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 13 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 14 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 15 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 16 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 17 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 18 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 19 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 20 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 21 | 22 | 23 | # import requests library 24 | import requests 25 | 26 | #import json library 27 | import json 28 | 29 | 30 | # Disable warnings 31 | requests.packages.urllib3.disable_warnings() 32 | 33 | controller='198.18.129.100' 34 | 35 | 36 | #creates and returns a service ticket. 37 | def getTicket(): 38 | print("\nCreating ticket") 39 | # put the ip address or dns of your apic-em controller in this url 40 | url = "https://" + controller + "/api/v1/ticket" 41 | 42 | #the username and password to access the APIC-EM Controller 43 | payload = {"username":"admin","password":"C1sco12345"} 44 | 45 | #Content type must be included in the header 46 | header = {"content-type": "application/json"} 47 | 48 | #Performs a POST on the specified url to get the service ticket 49 | response= requests.post(url,data=json.dumps(payload), headers=header, verify=False) 50 | 51 | print(response.text) 52 | 53 | #convert response to json format 54 | r_json=response.json() 55 | 56 | #parse the json to get the service ticket 57 | ticket = r_json["response"]["serviceTicket"] 58 | 59 | return ticket 60 | 61 | #Get and display the APIC-EM Users 62 | def getUsers(ticket): 63 | print("\nGetting list of existing users") 64 | # URL for user REST API call to get list of APIC-EM users. 65 | url = "https://" + controller + "/api/v1/user" 66 | 67 | #Content type as well as the ticket must be included in the header 68 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 69 | 70 | # this statement performs a GET on the specified host url 71 | response = requests.get(url, headers=header, verify=False) 72 | 73 | # json.dumps serializes the json into a string and allows us to 74 | # print the response in a 'pretty' format with indentation etc. 75 | print ("Users = ") 76 | print (json.dumps(response.json(), indent=4, separators=(',', ': '))) 77 | 78 | 79 | #Adds a APIC-EM User 80 | def addUser(ticket): 81 | print("\nAdding new user") 82 | # URL for user REST API call to get list of existing users in the network. 83 | url = "https://" + controller + "/api/v1/user" 84 | 85 | #Content type as well as the ticket must be included in the header 86 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 87 | 88 | username="brett" 89 | #Data for new user 90 | payload={"password":"Brett123!","username":username,"authorization":[{"scope":"ALL","role":"ROLE_OBSERVER"}]} 91 | 92 | # this statement performs a Post on the specified user url 93 | response = requests.post(url, data=json.dumps(payload), headers=header, verify=False) 94 | print ("Response after post: " + response.text) 95 | 96 | return (username) 97 | 98 | 99 | #Delete the user that corresponds to the passed in username parameter 100 | def deleteUser(username, ticket): 101 | print("\nRemoving user: " + username) 102 | # URL for a specified user REST API call. 103 | url = "https://" + controller + "/api/v1/user/" + username 104 | 105 | #Content type as well as the ticket must be included in the header 106 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 107 | 108 | # this statement performs a Delete on the specified user url 109 | response = requests.delete(url, headers=header, verify=False) 110 | print (response.text) 111 | 112 | 113 | #Show the User that corresponds to the passed in username parameter 114 | def showUser(username, ticket): 115 | print("\nDisplaying user: " + username) 116 | # URL for user REST API call to get APIC-EM user with corresponding name. 117 | url = "https://" + controller + "/api/v1/user/" + username 118 | 119 | #Content type as well as the ticket must be included in the header 120 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 121 | 122 | # this statement performs a GET on the specified user url 123 | response = requests.get(url, headers=header, verify=False) 124 | 125 | # json.dumps serializes the json into a string and allows us to 126 | # print the response in a 'pretty' format with indentation etc. 127 | print ("User found = ") 128 | print (json.dumps(response.json(), indent=4, separators=(',', ': '))) 129 | 130 | 131 | 132 | theTicket=getTicket() 133 | getUsers(theTicket) 134 | name=addUser(theTicket) 135 | showUser(name,theTicket) 136 | getUsers(theTicket) 137 | deleteUser(name,theTicket) 138 | getUsers(theTicket) -------------------------------------------------------------------------------- /coding102-REST-python-dcloud/readme.txt: -------------------------------------------------------------------------------- 1 | Before you begin 2 | 3 | These code samples are intended to be used with the Cisco DevNet Learning Labs. The Learning Labs will 4 | walk you through the code step by step. 5 | 6 | You can find the learning labs here: 7 | https://developer.cisco.com/learning/lab/coding-101-rest-basics-ga/step/1 8 | https://developer.cisco.com/learning/lab/coding-102-rest-python-ga/step/1 9 | 10 | You will need to download and setup a few items before you can begin coding along with us. 11 | 12 | Download the Coding 101 sample code and slides 13 | Your favorite text editor (text wrangler, notepad ++, sublime text etc.) 14 | Postman Rest Client for Chrome 15 | Python 16 | Python is normally pre-installed on Mac OS and most Linux distributions. 17 | You can also install Python on Windows. 18 | First, check see if you have Python installed on your system. 19 | Go to your command prompt and type “python”. 20 | If you get an error, follow the installations to install python for your system type from this page - http://learnpythonthehardway.org/book/ex0.html 21 | You will also need to install the Requests Library for Python. 22 | This is a library that makes it very easy to call REST APIs. 23 | Follow the instructions to install it here - http://docs.python-requests.org/en/latest/user/install/#install 24 | 25 | 26 | This download contains the following python examples: 27 | 28 | * create-ticket.py – First REST call to create a service ticket which is later used for authentication and role management 29 | * get-network-hosts.py – First application to parse the service ticket response and show list of hosts by doing a pretty print of the JSON data 30 | * get-network-devices.py – Retrieves network device list and parses JSON to display networkDeviceId values 31 | * manage-users.py – Shows how to manage controller access by retrieving, adding and deleting users 32 | -------------------------------------------------------------------------------- /coding102-REST-python-dcloud/report-topology.py: -------------------------------------------------------------------------------- 1 | # Example of building and reporting topology via REST API calls from Python 2 | 3 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 4 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 5 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 6 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 7 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 8 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 9 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 10 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 11 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 12 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 13 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 14 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 15 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 16 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 17 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 18 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 19 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 20 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 21 | 22 | from spark import * 23 | 24 | # import requests library 25 | import requests 26 | 27 | #import json library 28 | import json 29 | 30 | # Disable warnings 31 | requests.packages.urllib3.disable_warnings() 32 | 33 | controller='198.18.129.100' 34 | 35 | def getTicket(): 36 | # put the ip address or dns of your apic-em controller in this url 37 | url = "https://" + controller + "/api/v1/ticket" 38 | 39 | #the username and password to access the APIC-EM Controller 40 | #payload = {"username":"devnetuser","password":"Cisco123!"} 41 | payload = {"username":"admin","password":"C1sco12345"} 42 | 43 | #Content type must be included in the header 44 | header = {"content-type": "application/json"} 45 | 46 | #Performs a POST on the specified url to get the service ticket 47 | response= requests.post(url,data=json.dumps(payload), headers=header, verify=False) 48 | 49 | print (response) 50 | 51 | #convert response to json format 52 | r_json=response.json() 53 | 54 | #parse the json to get the service ticket 55 | ticket = r_json["response"]["serviceTicket"] 56 | 57 | return ticket 58 | 59 | 60 | 61 | def getTopology(ticket): 62 | # URL for topology REST API call to get list of existing devices on the network, and build topology 63 | url = "https://" + controller + "/api/v1/topology/physical-topology" 64 | 65 | #Content type as well as the ticket must be included in the header 66 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 67 | 68 | # this statement performs a GET on the specified network device url 69 | response = requests.get(url, headers=header, verify=False) 70 | 71 | # json.dumps serializes the json into a string and allows us to 72 | # print the response in a 'pretty' format with indentation etc. 73 | print ("Topology = ") 74 | print (json.dumps(response.json(), indent=4, separators=(',', ': '))) 75 | 76 | #convert data to json format. 77 | r_json=response.json() 78 | 79 | net_nodes=[] 80 | #Iterate through network device data and list the nodes, their interfaces, status and to what they connect 81 | for n in r_json["response"]["nodes"]: 82 | if "platformId" in n: 83 | print() 84 | print() 85 | print('{:30}'.format("Node") + '{:25}'.format("Family") + '{:20}'.format("Label")+ "Management IP") 86 | print('{:30}'.format(n["platformId"]) + '{:25}'.format(n["family"]) + '{:20}'.format(n["label"]) + n["ip"]) 87 | net_nodes.append(n["label"]) 88 | 89 | found=0 #print header flag 90 | for i in r_json["response"]["links"]: 91 | if "startPortName" in i: 92 | #check that the source device id for the interface matches the node id. Means interface originated from this device. 93 | if i["source"] == n["id"]: 94 | if found==0: 95 | print('{:>20}'.format("Source Interface") + '{:>15}'.format("Target") +'{:>28}'.format("Target Interface") + '{:>15}'.format("Status") ) 96 | found=1 97 | for n1 in r_json["response"]["nodes"]: 98 | #find name of node to which this one connects 99 | if i["target"] == n1["id"]: 100 | print(" " + '{:<25}'.format(i["startPortName"]) + '{:<18}'.format(n1["platformId"]) + '{:<25}'.format(i["endPortName"]) + '{:<9}'.format(i["linkStatus"]) ) 101 | break 102 | 103 | return net_nodes 104 | 105 | 106 | theTicket=getTicket() 107 | theNodes=getTopology(theTicket) 108 | nodestr="" 109 | for node in theNodes: 110 | nodestr=nodestr + node + " " 111 | setHeaders() 112 | room_id=createRoom("Brett's Room") 113 | addMembers(room_id) # Passing roomId to members function here to Post Message. 114 | postMsg(room_id,"Network nodes are " + nodestr) # Passing roomId to message function here to Post Message. 115 | -------------------------------------------------------------------------------- /coding102-REST-python-dcloud/spark.py: -------------------------------------------------------------------------------- 1 | import json 2 | import requests 3 | 4 | accessToken = "" #set your access token here 5 | 6 | 7 | def setHeaders(): 8 | global spark_header 9 | accessToken_hdr = 'Bearer ' + accessToken 10 | spark_header = {'Authorization': accessToken_hdr, 'Content-Type': 'application/json; charset=utf-8'} 11 | 12 | 13 | def createRoom(room_name): 14 | roomInfo = '{"title" :"' + room_name + '"}' 15 | uri = 'https://api.ciscospark.com/v1/rooms' 16 | resp = requests.post(uri, data=roomInfo, headers=spark_header) 17 | print("SparkAPI: ",resp) 18 | print(resp.json()) 19 | print("Newly Created RoomId: ", resp.json()['id']) # You will need this roomId to post Messages to it 20 | return resp.json()['id'] 21 | 22 | 23 | def addMembers(roomId): 24 | message = '{"roomId":"' + roomId + '","personEmail": "test@test.com", "isModerator": false}' 25 | uri = 'https://api.ciscospark.com/v1/memberships' 26 | resp = requests.post(uri, data=message, headers=spark_header) 27 | print("SparkAPI: ", resp.json()) 28 | 29 | 30 | def postMsg(roomId,message): 31 | message = '{"roomId":"' + roomId + '","text":"'+message+'"}' 32 | uri = 'https://api.ciscospark.com/v1/messages' 33 | resp = requests.post(uri, data=message, headers=spark_header) 34 | print("SparkAPI: ", resp.json()) 35 | 36 | 37 | if __name__ == '__main__': 38 | setHeaders() 39 | room_id=createRoom("Brett's Room") 40 | addMembers(room_id) # Passing roomId to members function here to Post Message. 41 | postMsg(room_id,"What's up World?") # Passing roomId to message function here to Post Message. 42 | 43 | -------------------------------------------------------------------------------- /coding102-REST-python-ga/build-topology-webserver.py: -------------------------------------------------------------------------------- 1 | # Example of render a topology via a web server. This include : 2 | # - building a web server via Flask (http://flask.pocoo.org/) 3 | # - render topology graphic via NeXt UI toolkit (https://wiki.opendaylight.org/view/NeXt:Main) 4 | # - get topology data from APIC-EM via REST API calls from Python 5 | 6 | # Before start please install flask by `pip install flask` 7 | # Then use python run this script via: python build-topology-webserver.py 8 | # Use Chrome or Safari browser. In the url field enter this link: `http://127.0.0.1:5000/` 9 | 10 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 11 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 12 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 13 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 14 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 15 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 16 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 17 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 18 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 19 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 20 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 21 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 22 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 23 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 24 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 25 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 26 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 27 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 28 | 29 | 30 | # import requests library 31 | import requests 32 | 33 | # import json library 34 | import json 35 | 36 | # import flask web framewoork 37 | from flask import Flask 38 | 39 | # from flask import render_template function 40 | from flask import render_template, jsonify 41 | 42 | # controller='sandboxapic.cisco.com' 43 | controller = 'devnetapi.cisco.com/sandbox/apic_em' 44 | 45 | 46 | def getTicket(): 47 | # put the ip address or dns of your apic-em controller in this url 48 | url = "https://" + controller + "/api/v1/ticket" 49 | 50 | # the username and password to access the APIC-EM Controller 51 | payload = {"username": "devnetuser", "password": "Cisco123!"} 52 | 53 | # Content type must be included in the header 54 | header = {"content-type": "application/json"} 55 | 56 | # Performs a POST on the specified url to get the service ticket 57 | response = requests.post(url, data=json.dumps(payload), headers=header, verify=False) 58 | 59 | print(response) 60 | 61 | # convert response to json format 62 | r_json = response.json() 63 | 64 | # parse the json to get the service ticket 65 | ticket = r_json["response"]["serviceTicket"] 66 | 67 | return ticket 68 | 69 | 70 | def getTopology(ticket): 71 | # URL for network-device REST API call to get list of exisiting devices on the network. 72 | url = "https://" + controller + "/api/v1/topology/physical-topology" 73 | 74 | # Content type as well as the ticket must be included in the header 75 | header = {"content-type": "application/json", "X-Auth-Token": ticket} 76 | 77 | # this statement performs a GET on the specified network device url 78 | response = requests.get(url, headers=header, verify=False) 79 | 80 | # convert data to json format. 81 | r_json = response.json() 82 | 83 | # return json object 84 | return r_json["response"] 85 | 86 | 87 | # intialize a web app 88 | app = Flask(__name__) 89 | 90 | # define index route to return topology.html 91 | @app.route("/") 92 | def index(): 93 | # when called '/' which is the default index page, render the template 'topology.html' 94 | return render_template("topology.html") 95 | 96 | 97 | # define an reset api to get topology data 98 | @app.route("/api/topology") 99 | def topology(): 100 | # get ticket 101 | theTicket = getTicket() 102 | 103 | # get topology data and return `jsonify` string to request 104 | return jsonify(getTopology(theTicket)) 105 | 106 | 107 | 108 | if __name__ == "__main__": 109 | app.run() 110 | -------------------------------------------------------------------------------- /coding102-REST-python-ga/build-topology.py: -------------------------------------------------------------------------------- 1 | # Example of building topology via REST API calls from Python 2 | 3 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 4 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 5 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 6 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 7 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 8 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 9 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 10 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 11 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 12 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 13 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 14 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 15 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 16 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 17 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 18 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 19 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 20 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 21 | 22 | 23 | # import requests library 24 | import requests 25 | 26 | #import json library 27 | import json 28 | 29 | # Disable warnings 30 | requests.packages.urllib3.disable_warnings() 31 | 32 | #controller='sandboxapic.cisco.com' 33 | controller='devnetapi.cisco.com/sandbox/apic_em' 34 | 35 | 36 | def getTicket(): 37 | # put the ip address or dns of your apic-em controller in this url 38 | url = "https://" + controller + "/api/v1/ticket" 39 | 40 | #the username and password to access the APIC-EM Controller 41 | payload = {"username":"devnetuser","password":"Cisco123!"} 42 | 43 | #Content type must be included in the header 44 | header = {"content-type": "application/json"} 45 | 46 | #Performs a POST on the specified url to get the service ticket 47 | response= requests.post(url,data=json.dumps(payload), headers=header, verify=False) 48 | 49 | print (response) 50 | 51 | #convert response to json format 52 | r_json=response.json() 53 | 54 | #parse the json to get the service ticket 55 | ticket = r_json["response"]["serviceTicket"] 56 | 57 | return ticket 58 | 59 | 60 | 61 | def getTopology(ticket): 62 | # URL for topology REST API call to get list of existing devices on the network, and build topology 63 | url = "https://" + controller + "/api/v1/topology/physical-topology" 64 | 65 | #Content type as well as the ticket must be included in the header 66 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 67 | 68 | # this statement performs a GET on the specified network device url 69 | response = requests.get(url, headers=header, verify=False) 70 | 71 | # json.dumps serializes the json into a string and allows us to 72 | # print the response in a 'pretty' format with indentation etc. 73 | print ("Topology = ") 74 | print (json.dumps(response.json(), indent=4, separators=(',', ': '))) 75 | 76 | #convert data to json format. 77 | r_json=response.json() 78 | 79 | #Iterate through network device data and list the nodes, their interfaces, status and to what they connect 80 | for n in r_json["response"]["nodes"]: 81 | print() 82 | print() 83 | print('{:30}'.format("Node") + '{:25}'.format("Family") + '{:20}'.format("Label")+ "Management IP") 84 | if "platformId" in n: 85 | print('{:30}'.format(n["platformId"]) + '{:25}'.format(n["family"]) + '{:20.14}'.format(n["label"]) + n["ip"]) 86 | else: 87 | print('{:30}'.format(n["role"]) + '{:25}'.format(n["family"]) + '{:20.14}'.format(n["label"]) + n["ip"]) 88 | found=0 #print header flag 89 | printed=0 #formatting flag 90 | for i in r_json["response"]["links"]: 91 | #check that the source device id for the interface matches the node id. Means interface originated from this device. 92 | if i["source"] == n["id"]: 93 | if found==0: 94 | print('{:>20}'.format("Source Interface") + '{:>15}'.format("Target") +'{:>28}'.format("Target Interface") + '{:>15}'.format("Status") ) 95 | found=1 96 | printed=1 97 | for n1 in r_json["response"]["nodes"]: 98 | #find name of node to which this one connects 99 | if i["target"] == n1["id"]: 100 | if "startPortName" in i: 101 | print(" " + '{:<25}'.format(i["startPortName"]) + '{:<18.14}'.format(n1["label"]) + '{:<25}'.format(i["endPortName"]) + '{:<9}'.format(i["linkStatus"]) ) 102 | else: 103 | print(" " + '{:<25}'.format("unknown") + '{:<18.14}'.format(n1["label"]) + '{:<25}'.format("unknown") + '{:<9}'.format(i["linkStatus"]) ) 104 | break; 105 | found=0 106 | for i in r_json["response"]["links"]: 107 | #Find interfaces that link to this one which means this node is the target. 108 | if i["target"] == n["id"]: 109 | if found==0: 110 | if printed==1: 111 | print() 112 | print('{:>10}'.format("Source") + '{:>30}'.format("Source Interface") + '{:>25}'.format("Target Interface") + '{:>13}'.format("Status")) 113 | found=1 114 | for n1 in r_json["response"]["nodes"]: 115 | #find name of node to that connects to this one 116 | if i["source"] == n1["id"]: 117 | if "startPortName" in i: 118 | print(" " + '{:<20}'.format(n1["label"]) + '{:<25}'.format(i["startPortName"]) + '{:<23}'.format(i["endPortName"]) + '{:<8}'.format(i["linkStatus"])) 119 | else: 120 | print(" " + '{:<20}'.format(n1["label"]) + '{:<25}'.format("unknown") + '{:<23}'.format("unknown") + '{:<8}'.format(i["linkStatus"])) 121 | break; 122 | 123 | theTicket=getTicket() 124 | getTopology(theTicket) 125 | -------------------------------------------------------------------------------- /coding102-REST-python-ga/create-ticket.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3.5 2 | 3 | # import requests library 4 | import requests 5 | 6 | #import json library 7 | import json 8 | 9 | # put the ip address or dns of your apic-em controller in this url 10 | #url = 'https://sandboxapic.cisco.com/api/v1/ticket' 11 | url='https://devnetapi.cisco.com/sandbox/apic_em/api/v1/ticket' 12 | 13 | 14 | 15 | #the username and password to access the APIC-EM Controller 16 | payload = {"username":"devnetuser","password":"Cisco123!"} 17 | 18 | 19 | #Content type must be included in the header 20 | header = {"content-type": "application/json"} 21 | 22 | #Performs a POST on the specified url. 23 | response= requests.post(url,data=json.dumps(payload), headers=header, verify=False) 24 | 25 | # print the json that is returned 26 | print(response.text) 27 | -------------------------------------------------------------------------------- /coding102-REST-python-ga/get-network-devices.py: -------------------------------------------------------------------------------- 1 | # Example of getting network-devices via REST API calls from Python 2 | 3 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 4 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 5 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 6 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 7 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 8 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 9 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 10 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 11 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 12 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 13 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 14 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 15 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 16 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 17 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 18 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 19 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 20 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 21 | 22 | 23 | # import requests library 24 | import requests 25 | 26 | #import json library 27 | import json 28 | 29 | #controller='sandboxapic.cisco.com' 30 | controller='devnetapi.cisco.com/sandbox/apic_em' 31 | 32 | def getTicket(): 33 | # put the ip address or dns of your apic-em controller in this url 34 | url = "https://" + controller + "/api/v1/ticket" 35 | 36 | #the username and password to access the APIC-EM Controller 37 | payload = {"username":"devnetuser","password":"Cisco123!"} 38 | 39 | #Content type must be included in the header 40 | header = {"content-type": "application/json"} 41 | 42 | #Performs a POST on the specified url to get the service ticket 43 | response= requests.post(url,data=json.dumps(payload), headers=header, verify=False) 44 | 45 | print (response) 46 | 47 | #convert response to json format 48 | r_json=response.json() 49 | 50 | #parse the json to get the service ticket 51 | ticket = r_json["response"]["serviceTicket"] 52 | 53 | return ticket 54 | 55 | 56 | def getNetworkDevices(ticket): 57 | # URL for network-device REST API call to get list of exisiting devices on the network. 58 | url = "https://" + controller + "/api/v1/network-device" 59 | 60 | #Content type as well as the ticket must be included in the header 61 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 62 | 63 | # this statement performs a GET on the specified network device url 64 | response = requests.get(url, headers=header, verify=False) 65 | 66 | # json.dumps serializes the json into a string and allows us to 67 | # print the response in a 'pretty' format with indentation etc. 68 | print ("Network Devices = ") 69 | print (json.dumps(response.json(), indent=4, separators=(',', ': '))) 70 | 71 | #convert data to json format. 72 | r_json=response.json() 73 | 74 | #Iterate through network device data and print the id and series name of each device 75 | for i in r_json["response"]: 76 | print(i["id"] + " " + '{:53}'.format(i["series"]) + " " + i["reachabilityStatus"]) 77 | 78 | 79 | 80 | theTicket=getTicket() 81 | getNetworkDevices(theTicket) 82 | -------------------------------------------------------------------------------- /coding102-REST-python-ga/get-network-hosts.py: -------------------------------------------------------------------------------- 1 | # Simple Example of calling REST API from Python 2 | # This is all that is required to call a REST API from python 3 | 4 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 5 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 6 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 7 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 8 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 9 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 10 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 11 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 12 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 13 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 14 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 15 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 16 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 17 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 18 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 19 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 20 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 21 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 22 | 23 | 24 | # import requests library 25 | import requests 26 | 27 | #import json library 28 | import json 29 | 30 | #controller='sandboxapic.cisco.com' 31 | controller='devnetapi.cisco.com/sandbox/apic_em' 32 | 33 | 34 | # put the ip address or dns of your apic-em controller in this url 35 | url = "https://" + controller + "/api/v1/ticket" 36 | 37 | #the username and password to access the APIC-EM Controller 38 | payload = {"username":"devnetuser","password":"Cisco123!"} 39 | 40 | #Content type must be included in the header 41 | header = {"content-type": "application/json"} 42 | 43 | #Performs a POST on the specified url to get the service ticket 44 | response= requests.post(url,data=json.dumps(payload), headers=header, verify=False) 45 | 46 | #convert response to json format 47 | r_json=response.json() 48 | 49 | print(r_json) 50 | #parse the json to get the service ticket 51 | ticket = r_json["response"]["serviceTicket"] 52 | 53 | # URL for Host REST API call to get list of exisitng hosts on the network. 54 | url = "https://" + controller + "/api/v1/host?limit=1&offset=1" 55 | 56 | #Content type must be included in the header as well as the ticket 57 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 58 | 59 | # this statement performs a GET on the specified host url 60 | response = requests.get(url, headers=header, verify=False) 61 | 62 | # json.dumps serializes the json into a string and allows us to 63 | # print the response in a 'pretty' format with indentation etc. 64 | print ("Hosts = ") 65 | print (json.dumps(response.json(), indent=4, separators=(',', ': '))) 66 | 67 | r_resp=response.json() 68 | 69 | print(r_resp["response"][0]["hostIp"]) -------------------------------------------------------------------------------- /coding102-REST-python-ga/manage-users.py: -------------------------------------------------------------------------------- 1 | # Example of calling REST API from Python to manage APIC-EM users/roles using APIC-EM APIs. 2 | 3 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 4 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 5 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 6 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 7 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 8 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 9 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 10 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 11 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 12 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 13 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 14 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 15 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 16 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 17 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 18 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 19 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 20 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 21 | 22 | 23 | # import requests library 24 | import requests 25 | 26 | #import json library 27 | import json 28 | 29 | 30 | # Disable warnings 31 | requests.packages.urllib3.disable_warnings() 32 | 33 | 34 | #controller='sandboxapic.cisco.com' 35 | controller='devnetapi.cisco.com/sandbox/apic_em' 36 | 37 | 38 | #creates and returns a service ticket. 39 | def getTicket(): 40 | print("\nCreating ticket") 41 | # put the ip address or dns of your apic-em controller in this url 42 | url = "https://" + controller + "/api/v1/ticket" 43 | 44 | #the username and password to access the APIC-EM Controller 45 | payload = {"username":"devnetuser","password":"Cisco123!"} 46 | 47 | #Content type must be included in the header 48 | header = {"content-type": "application/json"} 49 | 50 | #Performs a POST on the specified url to get the service ticket 51 | response= requests.post(url,data=json.dumps(payload), headers=header, verify=False) 52 | 53 | print(response.text) 54 | 55 | #convert response to json format 56 | r_json=response.json() 57 | 58 | #parse the json to get the service ticket 59 | ticket = r_json["response"]["serviceTicket"] 60 | 61 | return ticket 62 | 63 | #Get and display the APIC-EM Users 64 | def getUsers(ticket): 65 | print("\nGetting list of existing users") 66 | # URL for user REST API call to get list of APIC-EM users. 67 | url = "https://" + controller + "/api/v1/user" 68 | 69 | #Content type as well as the ticket must be included in the header 70 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 71 | 72 | # this statement performs a GET on the specified host url 73 | response = requests.get(url, headers=header, verify=False) 74 | 75 | # json.dumps serializes the json into a string and allows us to 76 | # print the response in a 'pretty' format with indentation etc. 77 | print ("Users = ") 78 | print (json.dumps(response.json(), indent=4, separators=(',', ': '))) 79 | 80 | 81 | #Adds a APIC-EM User 82 | def addUser(ticket): 83 | print("\nAdding new user") 84 | # URL for user REST API call to get list of existing users in the network. 85 | url = "https://" + controller + "/api/v1/user" 86 | 87 | #Content type as well as the ticket must be included in the header 88 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 89 | 90 | username="brett" 91 | #Data for new user 92 | payload={"password":"Brett123!","username":username,"authorization":[{"scope":"ALL","role":"ROLE_OBSERVER"}]} 93 | 94 | # this statement performs a Post on the specified user url 95 | response = requests.post(url, data=json.dumps(payload), headers=header, verify=False) 96 | print ("Response after post: " + response.text) 97 | 98 | return (username) 99 | 100 | 101 | #Delete the user that corresponds to the passed in username parameter 102 | def deleteUser(username, ticket): 103 | print("\nRemoving user: " + username) 104 | # URL for a specified user REST API call. 105 | url = "https://" + controller + "/api/v1/user/" + username 106 | 107 | #Content type as well as the ticket must be included in the header 108 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 109 | 110 | # this statement performs a Delete on the specified user url 111 | response = requests.delete(url, headers=header, verify=False) 112 | print (response.text) 113 | 114 | 115 | #Show the User that corresponds to the passed in username parameter 116 | def showUser(username, ticket): 117 | print("\nDisplaying user: " + username) 118 | # URL for user REST API call to get APIC-EM user with corresponding name. 119 | url = "https://" + controller + "/api/v1/user/" + username 120 | 121 | #Content type as well as the ticket must be included in the header 122 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 123 | 124 | # this statement performs a GET on the specified user url 125 | response = requests.get(url, headers=header, verify=False) 126 | 127 | # json.dumps serializes the json into a string and allows us to 128 | # print the response in a 'pretty' format with indentation etc. 129 | print ("User found = ") 130 | print (json.dumps(response.json(), indent=4, separators=(',', ': '))) 131 | 132 | 133 | 134 | theTicket=getTicket() 135 | getUsers(theTicket) 136 | name=addUser(theTicket) 137 | showUser(name,theTicket) 138 | getUsers(theTicket) 139 | deleteUser(name,theTicket) 140 | getUsers(theTicket) -------------------------------------------------------------------------------- /coding102-REST-python-ga/templates/topology.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | APIC-EM Topology 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /coding103-python-json/Examples/example1.py: -------------------------------------------------------------------------------- 1 | # Import Statements 2 | import json 3 | 4 | #This is our JSON sample 5 | string = """ 6 | { 7 | "first_name": "Jacob", 8 | "last_name": "Adams" 9 | } 10 | 11 | """ 12 | 13 | # Print out the JSON sample 14 | print("This is just a string \n " + string) 15 | 16 | # Load the data into a JSON object 17 | json_data = json.loads(string) 18 | 19 | # Extract first name from the object and assign it to a variable 20 | name = json_data["first_name"] 21 | 22 | # Print the extracted data to the terminal, to show us it worked. 23 | print("My first name is: " + name) -------------------------------------------------------------------------------- /coding103-python-json/Examples/example2.py: -------------------------------------------------------------------------------- 1 | # Import Statements 2 | import json 3 | 4 | # Sample json as a string 5 | string = """ 6 | { 7 | "prop_1001": { 8 | "type": "apartment", 9 | "residents": [{ 10 | "resident": "Jacob", 11 | "phone": "555-1234" 12 | }, 13 | { 14 | "resident": "Emily", 15 | "phone": "555-1235" 16 | } 17 | ] 18 | }, 19 | 20 | "prop_1002": { 21 | "type": "condo", 22 | "residents": [{ 23 | "resident": "Jock", 24 | "phone": "555-1236" 25 | }, 26 | { 27 | "resident": "Kelley", 28 | "phone": "555-1237" 29 | } 30 | ] 31 | } 32 | } 33 | 34 | """ 35 | 36 | json_string = json.loads(string) 37 | 38 | # print out type for 1001 39 | rental_type = str(json_string['prop_1001']['type']) 40 | 41 | print("the rental type is: " + rental_type) 42 | 43 | # print out the residents on prop_1002 44 | #count = 0 45 | #for i in json_string['prop_1002']["residents"]: 46 | # print("Resident number %s is %s!" % (str(count), str(i["resident"]))) 47 | # count += 1 48 | """ 49 | for i, data in enumerate(json_string['prop_1002']["residents"]): 50 | print("Resident number %s is %s!" % (str(i), str(data["resident"]))) 51 | """ 52 | 53 | -------------------------------------------------------------------------------- /coding103-python-json/Examples/example3.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import json 3 | 4 | 5 | # Request the x-auth-token 6 | url = "https://sandboxapic.cisco.com/api/v1/ticket" 7 | # Request Body 8 | payload = """{ 9 | "username":"devnetuser", 10 | "password":"Cisco123!" 11 | }""" 12 | 13 | # HTTP Headers 14 | headers = { 15 | 'content-type': "application/json" 16 | } 17 | 18 | # Execute request 19 | response = requests.request("POST", url, data=payload, headers=headers, verify=False) 20 | 21 | # Print request 22 | print(response.text) 23 | 24 | # Load the response into a JSON object 25 | json_response = json.loads(response.text) 26 | 27 | # Parse the service ticket out of the JSON 28 | service_ticket = json_response['response']['serviceTicket'] 29 | 30 | # Print the service ticket 31 | print(service_ticket) 32 | 33 | # Request the x-auth-token 34 | url = "https://sandboxapic.cisco.com/api/v1/host" 35 | 36 | # HTTP Headers 37 | headers = { 38 | 'content-type': "application/json", 39 | 'x-auth-token': service_ticket 40 | } 41 | 42 | # Execute request to get hosts, set equal to host_response 43 | host_response = requests.request("GET", url, data=payload, headers=headers, verify=False) 44 | 45 | #Print the reponse data 46 | print(host_response.text) 47 | 48 | #Load the response into a json object 49 | host_response = json.loads(host_response.text) 50 | 51 | # loop through the response, return the host IP and connection type 52 | for i, body in enumerate(host_response["response"]): 53 | host = body['hostIp'] 54 | connection = body['hostType'] 55 | message = "Host %i's ip is %s and uses a %s connection!\n" % (i + 1, host, connection) 56 | print(message) -------------------------------------------------------------------------------- /coding103-python-json/reqirements.txt: -------------------------------------------------------------------------------- 1 | requests -------------------------------------------------------------------------------- /coding201-parsing-xml/get-ap-xml-1.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | req = Request('https://msesandbox.cisco.com/api/contextaware/v1/maps/info/DevNetCampus/DevNetBuilding/DevNetZone') 3 | req.add_header('Authorization', 'Basic bGVhcm5pbmc6bGVhcm5pbmc==') 4 | response = urlopen(req) 5 | responseString = response.read().decode("utf-8") 6 | print(responseString) 7 | response.close() -------------------------------------------------------------------------------- /coding201-parsing-xml/get-ap-xml-2.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | import xml.dom.minidom 3 | req = Request('https://msesandbox.cisco.com/api/contextaware/v1/maps/info/DevNetCampus/DevNetBuilding/DevNetZone') 4 | req.add_header('Authorization', 'Basic bGVhcm5pbmc6bGVhcm5pbmc==') 5 | response = urlopen(req) 6 | responseString = response.read().decode("utf-8") 7 | dom = xml.dom.minidom.parseString(responseString) 8 | xml = dom.toprettyxml() 9 | print(xml) 10 | response.close() -------------------------------------------------------------------------------- /coding201-parsing-xml/get-ap-xml-3.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | import xml.dom.minidom 3 | req = Request('https://msesandbox.cisco.com/api/contextaware/v1/maps/info/DevNetCampus/DevNetBuilding/DevNetZone') 4 | req.add_header('Authorization', 'Basic bGVhcm5pbmc6bGVhcm5pbmc==') 5 | response = urlopen(req) 6 | responseString = response.read().decode("utf-8") 7 | dom = xml.dom.minidom.parseString(responseString) 8 | xml = dom.toprettyxml() 9 | print(xml) 10 | floor_element = dom.firstChild 11 | if floor_element.hasChildNodes : 12 | child = floor_element.firstChild 13 | while child is not None: 14 | if child.tagName == 'AccessPoint' : 15 | output = child.tagName + ": " + child.getAttribute('name') + '\t eth: ' + child.getAttribute('ethMacAddress') 16 | print(output) 17 | child = child.nextSibling 18 | response.close() -------------------------------------------------------------------------------- /coding201-parsing-xml/get-ap-xml-4.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | import xml.dom.minidom 3 | req = Request('https://msesandbox.cisco.com/api/contextaware/v1/maps/info/DevNetCampus/DevNetBuilding/DevNetZone') 4 | req.add_header('Authorization', 'Basic bGVhcm5pbmc6bGVhcm5pbmc==') 5 | response = urlopen(req) 6 | responseString = response.read().decode("utf-8") 7 | dom = xml.dom.minidom.parseString(responseString) 8 | xml = dom.toprettyxml() 9 | print(xml) 10 | access_points = dom.getElementsByTagName('AccessPoint') 11 | for access_point in access_points: 12 | ap_name = access_point.getAttribute('name') 13 | ap_eth_addr = access_point.getAttribute('ethMacAddress') 14 | ap_ip_addr = access_point.getAttribute('ipAddress') 15 | print(access_point.tagName + ": " + ap_name + '\t eth: ' + ap_eth_addr + '\t ip: ' + ap_ip_addr) 16 | response.close() -------------------------------------------------------------------------------- /coding201-parsing-xml/get-tenants-xml-1.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import xml.dom.minidom 3 | # We need to import the JSON library just to handle our request to the APIC for login 4 | import json 5 | 6 | 7 | # We need to log in to the APIC and gather a token, before we can access any data 8 | # Let's construct a request with a body 9 | 10 | # We'll need to disable certificate warnings 11 | requests.packages.urllib3.disable_warnings() 12 | 13 | # We need to have a body of data consisting of a username and password to gather a cookie from APIC 14 | encoded_body = json.dumps({ 15 | "aaaUser": { 16 | "attributes": { 17 | "name": "admin", 18 | "pwd": "ciscopsdt" 19 | } 20 | } 21 | }) 22 | 23 | # Now lets make the request and store the data 24 | resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) 25 | 26 | # This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls 27 | header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} 28 | 29 | # Now we make a call towards the tenant class on the ACI fabric with the proper header value set. 30 | # We leverage the .xml ending to receive the data back as XML 31 | tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.xml?rsp-subtree-include=health,faults", headers=header, verify=False) 32 | 33 | # Requests stores the text of the response in the .text attribute. Lets print it to see raw XML 34 | print(tenants.text) -------------------------------------------------------------------------------- /coding201-parsing-xml/get-tenants-xml-2.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import xml.dom.minidom 3 | # We need to import the JSON library just to handle our request to the APIC for login 4 | import json 5 | 6 | 7 | # We need to log in to the APIC and gather a token, before we can access any data 8 | # Let's construct a request with a body 9 | 10 | # We'll need to disable certificate warnings 11 | requests.packages.urllib3.disable_warnings() 12 | 13 | # We need to have a body of data consisting of a username and password to gather a cookie from APIC 14 | encoded_body = json.dumps({ 15 | "aaaUser": { 16 | "attributes": { 17 | "name": "admin", 18 | "pwd": "ciscopsdt" 19 | } 20 | } 21 | }) 22 | 23 | # Now lets make the request and store the data 24 | resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) 25 | 26 | # This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls 27 | header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} 28 | 29 | # Now we make a call towards the tenant class on the ACI fabric with the proper header value set. 30 | # We leverage the .xml ending to receive the data back as XML 31 | tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.xml?rsp-subtree-include=health,faults", headers=header, verify=False) 32 | 33 | # Now lets use DOM to clean up the XML from its completely raw format 34 | dom = xml.dom.minidom.parseString(tenants.text) 35 | xml = dom.toprettyxml() 36 | print(xml) -------------------------------------------------------------------------------- /coding201-parsing-xml/get-tenants-xml-3.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import xml.dom.minidom 3 | # We need to import the JSON library just to handle our request to the APIC for login 4 | import json 5 | 6 | 7 | # We need to log in to the APIC and gather a token, before we can access any data 8 | # Let's construct a request with a body 9 | 10 | # We'll need to disable certificate warnings 11 | requests.packages.urllib3.disable_warnings() 12 | 13 | # We need to have a body of data consisting of a username and password to gather a cookie from APIC 14 | encoded_body = json.dumps({ 15 | "aaaUser": { 16 | "attributes": { 17 | "name": "admin", 18 | "pwd": "ciscopsdt" 19 | } 20 | } 21 | }) 22 | 23 | # Now lets make the request and store the data 24 | resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) 25 | 26 | # This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls 27 | header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} 28 | 29 | # Now we make a call towards the tenant class on the ACI fabric with the proper header value set. 30 | # We leverage the .xml ending to receive the data back as XML 31 | tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.xml?rsp-subtree-include=health,faults", headers=header, verify=False) 32 | 33 | # Now lets use DOM to clean up the XML from its completely raw format 34 | dom = xml.dom.minidom.parseString(tenants.text) 35 | xml = dom.toprettyxml() 36 | print(xml) 37 | 38 | # 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 39 | tenant_objects = dom.firstChild 40 | if tenant_objects.hasChildNodes: 41 | tenant_element = tenant_objects.firstChild 42 | while tenant_element is not None: 43 | if tenant_element.tagName == 'fvTenant': 44 | health_element = tenant_element.firstChild 45 | output = "Tenant: " + tenant_element.getAttribute('name') + '\t Health Score: ' + health_element.getAttribute('cur') 46 | print(output.expandtabs(40)) 47 | tenant_element = tenant_element.nextSibling -------------------------------------------------------------------------------- /coding201-parsing-xml/get-tenants-xml-4.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import xml.dom.minidom 3 | # We need to import the JSON library just to handle our request to the APIC for login 4 | import json 5 | 6 | 7 | # We need to log in to the APIC and gather a token, before we can access any data 8 | # Let's construct a request with a body 9 | 10 | # We'll need to disable certificate warnings 11 | requests.packages.urllib3.disable_warnings() 12 | 13 | # We need to have a body of data consisting of a username and password to gather a cookie from APIC 14 | encoded_body = json.dumps({ 15 | "aaaUser": { 16 | "attributes": { 17 | "name": "admin", 18 | "pwd": "ciscopsdt" 19 | } 20 | } 21 | }) 22 | 23 | # Now lets make the request and store the data 24 | resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) 25 | 26 | # This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls 27 | header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} 28 | 29 | # Now we make a call towards the tenant class on the ACI fabric with the proper header value set. 30 | # We leverage the .xml ending to receive the data back as XML 31 | tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.xml?rsp-subtree-include=health,faults", headers=header, verify=False) 32 | 33 | # Now lets use DOM to clean up the XML from its completely raw format 34 | dom = xml.dom.minidom.parseString(tenants.text) 35 | xml = dom.toprettyxml() 36 | print(xml) 37 | 38 | # Now we'll do something similar, but done using a direct access method of the data, rather than interation and loops 39 | tenant_list = dom.getElementsByTagName('fvTenant') 40 | for tenants in tenant_list: 41 | tenant_name = tenants.getAttribute('name') 42 | tenant_dn = tenants.getAttribute('dn') 43 | health_score = tenants.firstChild.getAttribute('cur') 44 | output = "Tenant: " + tenant_name + "\t Health Score: " + health_score + "\n DN: " + tenant_dn 45 | print(output.expandtabs(40)) -------------------------------------------------------------------------------- /coding202-parsing-json/activity-debug-1.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | import json 3 | 4 | uri = 'https://devnetapi.cisco.com/sandbox/mse/api/config/v1/maps/info/DevNetCampus' 5 | 6 | 7 | def get_content(uri): 8 | req = Request(uri) 9 | req.add_header('Authorization', 'Basic bGVhcm5pbmc6bGVhcm5pbmc=') 10 | req.add_header('Accept', 'application/json') 11 | response = urlopen(req) 12 | response_string = response.read().decode("utf-8") 13 | response.close() 14 | return response_string 15 | 16 | 17 | json_object = json.loads(get_content(uri)) 18 | 19 | building_names = [] 20 | 21 | buildings = json_object["buildingList"] 22 | for building in buildings: 23 | building_names.append(building["name"]) 24 | 25 | # Print out the building names found - this is a Python list 26 | print(building_names) 27 | 28 | # Get the content for each of the buildings found by iterating through the building list 29 | for building_name in building_names: 30 | building_uri = uri + "/" + building_name 31 | print(building_uri) 32 | print(get_content(building_uri)) 33 | -------------------------------------------------------------------------------- /coding202-parsing-json/activity-parse-1.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | import json 3 | 4 | req = Request('http://jsonplaceholder.typicode.com/users', headers={'User-Agent': 'Mozilla/5.0'}) 5 | # req = Request('http://127.0.0.1:8000/object') 6 | # req = Request('http://127.0.0.1:8000/array') 7 | # req = Request('http://127.0.0.1:8000/random') 8 | # req = Request('http://127.0.0.1:8000/random/array') 9 | # req = Request('http://127.0.0.1:8000/complex') 10 | # req = Request('http://127.0.0.1:8000/complex/array') 11 | 12 | response = urlopen(req) 13 | response_string = response.read().decode("utf-8") 14 | 15 | json_object = json.loads(response_string) 16 | 17 | print(json_object) 18 | #print(json.dumps(json_object, sort_keys=True, indent=4)) 19 | #print(json_object[4]) 20 | #print(json.dumps(json_object[4], sort_keys=True, indent=4)) 21 | #print(json_object[4]["name"]) 22 | #print(json_object[4]["address"]["geo"]) 23 | #print(json_object[4]["address"]["geo"]["lat"]) 24 | #print(json_object[4]["address"]["geo"]["lng"]) 25 | 26 | response.close() 27 | -------------------------------------------------------------------------------- /coding202-parsing-json/activity-parse-2.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | import json 3 | 4 | req = Request('https://devnetapi.cisco.com/sandbox/mse/api/config/v1/maps') 5 | req.add_header('Authorization', 'Basic bGVhcm5pbmc6bGVhcm5pbmc=') 6 | response = urlopen(req) 7 | response_string = response.read().decode('utf-8') 8 | 9 | json_object = json.loads(response_string) 10 | 11 | print(json_object['campuses']) 12 | 13 | # campuses = json_object['campuses'] 14 | # for campus in campuses: 15 | # print(campus['name']) 16 | # # for building in campus['buildingList']: 17 | # # print('\t' + building['name']) 18 | 19 | response.close() 20 | -------------------------------------------------------------------------------- /coding202-parsing-json/activity-parse-3.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | import json 3 | 4 | req = Request('https://devnetapi.cisco.com/sandbox/mse/api/config/v1/maps/info/DevNetCampus/DevNetBuilding') 5 | req.add_header('Authorization', 'Basic bGVhcm5pbmc6bGVhcm5pbmc=') 6 | response = urlopen(req) 7 | response_string = response.read().decode('utf-8') 8 | 9 | json_object = json.loads(response_string) 10 | 11 | print(json_object['floorList']) 12 | 13 | # Parse out the floors from the result set 14 | # floors = json_object["floorList"] 15 | # for floor in floors: 16 | # print(floor['name'] + ' Floor Number: ' + str(floor['floorNumber'])) 17 | # # Parse out the access points from the returned floors 18 | # # aps = floor["accessPoints"] 19 | # # for ap in aps: 20 | # # print('\t' + ap['name'] + '/' + ap['radioMacAddress']) 21 | 22 | response.close() -------------------------------------------------------------------------------- /coding202-parsing-json/activity-parse-4.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | import json 3 | 4 | uri_cmx = 'https://devnetapi.cisco.com/sandbox/mse/api/config/v1/maps/info/CiscoCampus' 5 | 6 | 7 | # Let's wrap our common get functionality in a function definition 8 | def get_content(uri): 9 | req = Request(uri) 10 | req.add_header('Authorization', 'Basic bGVhcm5pbmc6bGVhcm5pbmc=') 11 | # req.add_header('Accept', 'application/json') 12 | response = urlopen(req) 13 | response_string = response.read().decode("utf-8") 14 | response.close() 15 | return response_string 16 | 17 | 18 | json_object = json.loads(get_content(uri_cmx)) 19 | 20 | building_names = [] 21 | 22 | buildings = json_object["buildingList"] 23 | for building in buildings: 24 | building_names.append(building["name"]) 25 | 26 | print(building_names) 27 | print(type(building_names)) 28 | 29 | # for building_name in building_names: 30 | # building_uri = uri_cmx + "/" + building_name 31 | # print(building_uri) 32 | # print(get_content(building_uri)) 33 | -------------------------------------------------------------------------------- /coding202-parsing-json/call-functions.py: -------------------------------------------------------------------------------- 1 | print ("I'm not a function") 2 | 3 | def my_function(): 4 | print("Hey I'm a function!") 5 | 6 | 7 | def brett(val): 8 | for i in range(val): 9 | print("I'm a function with args!") 10 | 11 | 12 | 13 | my_function() 14 | brett(5) -------------------------------------------------------------------------------- /coding202-parsing-json/data-type-values.py: -------------------------------------------------------------------------------- 1 | my_list=[5,'joe'] 2 | print (my_list[1]) 3 | 4 | my_tuple=('brett','Cisco',9) 5 | print (my_tuple[1]) 6 | 7 | 8 | my_dict={"red":1,"green":2} 9 | print(my_dict["green"]) -------------------------------------------------------------------------------- /coding202-parsing-json/get-ap-json-1.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | 3 | req = Request('https://devnetapi.cisco.com/sandbox/mse/api/config/v1/maps/info/DevNetCampus/DevNetBuilding/DevNetZone') 4 | req.add_header('Authorization', 'Basic bGVhcm5pbmc6bGVhcm5pbmc=') 5 | response = urlopen(req) 6 | response_string = response.read().decode('utf-8') 7 | print(response_string) 8 | response.close() 9 | -------------------------------------------------------------------------------- /coding202-parsing-json/get-ap-json-2.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | import json 3 | 4 | req = Request('https://devnetapi.cisco.com/sandbox/mse/api/config/v1/maps/info/DevNetCampus/DevNetBuilding/DevNetZone') 5 | req.add_header('Authorization', 'Basic bGVhcm5pbmc6bGVhcm5pbmc=') 6 | req.add_header('Accept', 'application/json') 7 | response = urlopen(req) 8 | response_string = response.read().decode('utf-8') 9 | # print(response_string) 10 | json_object = json.loads(response_string) 11 | print(json.dumps(json_object, sort_keys=True, indent=4)) 12 | response.close() 13 | -------------------------------------------------------------------------------- /coding202-parsing-json/get-ap-json-3.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | import json 3 | 4 | req = Request('https://devnetapi.cisco.com/sandbox/mse/api/config/v1/maps/info/DevNetCampus/DevNetBuilding/DevNetZone') 5 | req.add_header('Authorization', 'Basic bGVhcm5pbmc6bGVhcm5pbmc=') 6 | req.add_header('Accept', 'application/json') 7 | response = urlopen(req) 8 | response_string = response.read().decode("utf-8") 9 | # print(responseString) 10 | json_object = json.loads(response_string) 11 | print(json_object) 12 | print(json.dumps(json_object, sort_keys=True, indent=4)) 13 | access_points = json_object['accessPoints'] 14 | for ap in access_points: 15 | print('Access Point: ' + ap['name'] + '\t mac: ' + ap['radioMacAddress']) 16 | 17 | response.close() 18 | -------------------------------------------------------------------------------- /coding202-parsing-json/get-cmx-json.py: -------------------------------------------------------------------------------- 1 | from urllib.request import Request, urlopen 2 | import json 3 | 4 | req = Request('https://devnetapi.cisco.com/sandbox/mse/api/config/v1/maps') 5 | req.add_header('Authorization', 'Basic bGVhcm5pbmc6bGVhcm5pbmc=') 6 | req.add_header('Accept', 'application/json') 7 | 8 | response = urlopen(req) 9 | responseString = response.read().decode("utf-8") 10 | 11 | jsonObject = json.loads(responseString) 12 | 13 | print(json.dumps(jsonObject, sort_keys=True, indent=4)) 14 | 15 | response.close() 16 | -------------------------------------------------------------------------------- /coding202-parsing-json/get-tenant-json-1.py: -------------------------------------------------------------------------------- 1 | import requests 2 | # We need to import the JSON library just to handle our request to the APIC for login 3 | import json 4 | 5 | 6 | # We need to log in to the APIC and gather a token, before we can access any data 7 | # Let's construct a request with a body 8 | 9 | # We'll need to disable certificate warnings 10 | requests.packages.urllib3.disable_warnings() 11 | 12 | # We need to have a body of data consisting of a username and password to gather a cookie from APIC 13 | encoded_body = json.dumps({ 14 | "aaaUser": { 15 | "attributes": { 16 | "name": "admin", 17 | "pwd": "ciscopsdt" 18 | } 19 | } 20 | }) 21 | 22 | # Now lets make the request and store the data 23 | resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) 24 | 25 | # This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls 26 | header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} 27 | 28 | # Now we make a call towards the tenant class on the ACI fabric with the proper header value set. 29 | # 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 30 | tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.json?rsp-subtree-include=health,faults", headers=header, verify=False) 31 | 32 | # Requests stores the text of the response in the .text attribute. Lets print it to see raw JSON 33 | print(tenants.text) -------------------------------------------------------------------------------- /coding202-parsing-json/get-tenant-json-2.py: -------------------------------------------------------------------------------- 1 | import requests 2 | # We need to import the JSON library just to handle our request to the APIC for login 3 | import json 4 | 5 | 6 | # We need to log in to the APIC and gather a token, before we can access any data 7 | # Let's construct a request with a body 8 | 9 | # We'll need to disable certificate warnings 10 | requests.packages.urllib3.disable_warnings() 11 | 12 | # We need to have a body of data consisting of a username and password to gather a cookie from APIC 13 | encoded_body = json.dumps({ 14 | "aaaUser": { 15 | "attributes": { 16 | "name": "admin", 17 | "pwd": "ciscopsdt" 18 | } 19 | } 20 | }) 21 | 22 | # Now lets make the request and store the data 23 | resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) 24 | 25 | # This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls 26 | header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} 27 | 28 | # Now we make a call towards the tenant class on the ACI fabric with the proper header value set. 29 | # 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 30 | tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.json?rsp-subtree-include=health,faults", headers=header, verify=False) 31 | 32 | # Requests stores the text of the response in the .text attribute. Lets print it to see raw JSON 33 | #print(tenants.text) 34 | 35 | # Lets make this response a bit prettier, by converting it to a JSON object and using the dumps method to provide indentation 36 | json_response = json.loads(tenants.text) 37 | print(json.dumps(json_response, sort_keys=True, indent=4)) -------------------------------------------------------------------------------- /coding202-parsing-json/get-tenant-json-3.py: -------------------------------------------------------------------------------- 1 | import requests 2 | # We need to import the JSON library just to handle our request to the APIC for login 3 | import json 4 | 5 | 6 | # We need to log in to the APIC and gather a token, before we can access any data 7 | # Let's construct a request with a body 8 | 9 | # We'll need to disable certificate warnings 10 | requests.packages.urllib3.disable_warnings() 11 | 12 | # We need to have a body of data consisting of a username and password to gather a cookie from APIC 13 | encoded_body = json.dumps({ 14 | "aaaUser": { 15 | "attributes": { 16 | "name": "admin", 17 | "pwd": "ciscopsdt" 18 | } 19 | } 20 | }) 21 | 22 | # Now lets make the request and store the data 23 | resp = requests.post("https://sandboxapicdc.cisco.com/api/aaaLogin.json", data=encoded_body, verify=False) 24 | 25 | # This stores the received APIC-cookie from the login as a value to be used in subsequent REST calls 26 | header = {"Cookie": "APIC-cookie=" + resp.cookies["APIC-cookie"]} 27 | 28 | # Now we make a call towards the tenant class on the ACI fabric with the proper header value set. 29 | # 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 30 | tenants = requests.get("https://sandboxapicdc.cisco.com/api/node/class/fvTenant.json?rsp-subtree-include=health,faults", headers=header, verify=False) 31 | 32 | # Requests stores the text of the response in the .text attribute. Lets print it to see raw XML 33 | #print(tenants.text) 34 | 35 | # Lets make this response a bit prettier, by converting it to a JSON object and using the dumps method to provide indentation 36 | json_response = json.loads(tenants.text) 37 | #print(json.dumps(json_response, sort_keys=True, indent=4)) 38 | 39 | 40 | # We've commented out the pretty-print, but now lets return only the values we want. 41 | # Everything within the returned JSON is containted within the `imdata` dictionary, so lets strip that away 42 | json_tenants = json_response['imdata'] 43 | 44 | # Now we have to loop through the resulting list (using the `for` loop) and drill into the subsequent dictionaries by name 45 | # When we get to `tenant health`, we move from `attributes` dictionary to `children` dictionary. 46 | # Inside of the `children` dictionary is a list, which will need an index value to move further. 47 | # Since there is only one child object within the `children` list, we can safely set this value to `0` 48 | # This is the result of how the original query was structured, so don't assume you can always set that value to `0` 49 | for tenant in json_tenants: 50 | tenant_name = tenant['fvTenant']['attributes']['name'] 51 | tenant_dn = tenant['fvTenant']['attributes']['dn'] 52 | tenant_health = tenant['fvTenant']['children'][0]['healthInst']['attributes']['cur'] 53 | output = "Tenant: " + tenant_name + "\t Health Score: " + tenant_health + "\n DN: " + tenant_dn 54 | print(output.expandtabs(40)) -------------------------------------------------------------------------------- /coding202-parsing-json/hello.py: -------------------------------------------------------------------------------- 1 | 2 | print ("Hello World!") 3 | 4 | print ("How are you?") -------------------------------------------------------------------------------- /coding202-parsing-json/helloworld.py: -------------------------------------------------------------------------------- 1 | print ("Helloworld!") 2 | 3 | num = 1 4 | 5 | if num < 1: 6 | print ("I'm less than 1!") 7 | print ("Goodbye Cruel World!") 8 | -------------------------------------------------------------------------------- /coding202-parsing-json/json_parse-1.py: -------------------------------------------------------------------------------- 1 | food={"vegetables":["carrots","kale","cucumber","tomato"]} 2 | 3 | cars={"sports":{"Porsche":"Volkswagen","Viper":"Dodge","Corvette":"Chevy"}} 4 | 5 | 6 | 7 | #Assignment 8 | dessert={"iceCream":["Rocky-Road","strawberry","Pistachio-Cashew","Pecan-Praline"]} 9 | 10 | 11 | superhero={"Super":("Batman","Green-Hornet", "Wonder-Woman","Superman")} 12 | 13 | 14 | soup={"soup":{"tomato":"healthy","onion":"bleh!","vegetable":"goodForYou"}} 15 | 16 | 17 | network={"Network":{"router":{"ipaddress":"192.168.1.21","mac_address":"08:56:27:6f:2b:9c"}}} 18 | 19 | 20 | -------------------------------------------------------------------------------- /coding202-parsing-json/json_parse-2.py: -------------------------------------------------------------------------------- 1 | network1={"Network":{"routers":[{"ipaddress":"192.168.1.21","mac_address":"08:56:27:6f:2b:9c"},{"ipaddress":"192.168.32.15","mac_address":"3a:24:37:4f:5b:1d"}],"switches":[{"ipaddress":"192.168.32.1","mac_address":"3a:24:37:4f:5b:1d"}]}} 2 | 3 | def read_network(network1): 4 | #get the device type name 5 | for device in network1["Network"]: 6 | print("Device is: " + device) 7 | #get the attributes for each device. Returns a dictionary for each 8 | for attrib in network1["Network"][device]: 9 | print("Device attributes are: " + str(attrib)) 10 | #parse the attributes for each device 11 | for val in attrib: 12 | print ("Device attribute values are: " + val + " " + attrib[val]) 13 | print() #add extra line for separation 14 | 15 | 16 | read_network(network1) 17 | 18 | 19 | #Assignment: 20 | network2={"Network":{"routers":[{"ipaddress":"192.168.1.21","mac_address":"08:56:27:6f:2b:9c"}],"switches":[{"ipaddress":"192.168.32.1","mac_address":"3a:24:37:4f:5b:1d"}],"hosts":[{"ipaddress":"192.168.32.5","mac_address":"3b:25:31:4a:5c:3f"},{"ipaddress":"192.168.32.8","mac_address":"4b:15:32:43:51:3c"}]}} 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /coding202-parsing-json/parse.py: -------------------------------------------------------------------------------- 1 | # 0 Type anything (Temp) 2 | 3 | # 1 Import our required libraries: Request, urlopen, json 4 | 5 | # 2 Specify our URI 6 | 7 | # 3 Setup a connection Request 8 | 9 | # 4 Add the appropriate headers to our HTTP request 10 | 11 | # 5 Do the actual request and collect the response with urlopen (Also do # 15) 12 | 13 | # 6 Store the Response string 14 | 15 | # 7 Load the JSON Object 16 | 17 | # 8 Print the JSON Object (Temp) 18 | 19 | # 9 Extract the floors from Building\Floor 20 | 21 | # 10 Loop through the Floors 22 | 23 | # 11 Print the Floor (Temp) 24 | 25 | # 12 Get the APs from the Floor 26 | 27 | # 13 Print the APs 28 | 29 | # 14 Loop through the APs printing them out 30 | 31 | # 15 Close the response 32 | -------------------------------------------------------------------------------- /coding203-getting-input/get-input.py: -------------------------------------------------------------------------------- 1 | # Simple example of how to get input from a user 2 | 3 | # amwhaley@cisco.com 4 | # twitter: @mandywhaley 5 | # http://developer.cisco.com 6 | # http://developer.cisco.com/learning 7 | # Jan 15, 2015 8 | 9 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 10 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 11 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 12 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 13 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 14 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 15 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 16 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 17 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 18 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 19 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 20 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 21 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 22 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 23 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 24 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 25 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 26 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 27 | 28 | favorite_veg = input("What's your favorite vegetable? ") 29 | print("I like " + favorite_veg + " too!") 30 | 31 | favorite_sauce = input("What is your favorite sauce? ") 32 | print("I like " + favorite_veg + " with " + favorite_sauce + " on it!") 33 | -------------------------------------------------------------------------------- /coding204-reading-a-file/my-file.txt: -------------------------------------------------------------------------------- 1 | This is the first line. Absolutely, the first line. 2 | This is the second line. Yep, this is the second line. -------------------------------------------------------------------------------- /coding204-reading-a-file/my-json.json: -------------------------------------------------------------------------------- 1 | { 2 | "response": [ 3 | { 4 | "id": "d4b33d28-04dd-4733-a6de-8877ec26c196", 5 | "tag": "campus", 6 | "networkDeviceId": "e5f93514-3ae5-4109-8b52-b9fa876e1eae", 7 | "attributeInfo": {} 8 | }, 9 | { 10 | "id": "d4b33d28-04dd-4733-a6de-8877ec26c196", 11 | "tag": "campus", 12 | "networkDeviceId": "da733ffb-e34b-4733-bd85-b615fb7e61f3", 13 | "attributeInfo": {} 14 | }, 15 | { 16 | "id": "d4b33d28-04dd-4733-a6de-8877ec26c196", 17 | "tag": "campus", 18 | "networkDeviceId": "f8c3fc68-cd26-4576-bcec-51f9b578f71e", 19 | "attributeInfo": {} 20 | } 21 | ], 22 | "version": "0.0" 23 | } -------------------------------------------------------------------------------- /coding204-reading-a-file/read-file-loop.py: -------------------------------------------------------------------------------- 1 | # Read from a file one line at a time using a loop 2 | # amwhaley@cisco.com 3 | # twitter: @mandywhaley 4 | # http://developer.cisco.com 5 | # http://developer.cisco.com/learning 6 | # Jan 15, 2015 7 | 8 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 9 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 10 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 11 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 12 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 13 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 14 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 15 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 16 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 17 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 18 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 19 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 20 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 21 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 22 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 23 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 24 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 25 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 26 | 27 | # You can also loop through the lines and read each line in a loop. 28 | print ("Loop through and read each line") 29 | my_file_object = open("my-file.txt", "r") 30 | x=1 31 | for line in my_file_object: 32 | print ("Line " + str(x) + ": " + line) 33 | x += 1 34 | 35 | my_file_object.close() -------------------------------------------------------------------------------- /coding204-reading-a-file/read-file-one-line.py: -------------------------------------------------------------------------------- 1 | # Read from a file one line at a time. 2 | # amwhaley@cisco.com 3 | # twitter: @mandywhaley 4 | # http://developer.cisco.com 5 | # http://developer.cisco.com/learning 6 | # Jan 15, 2015 7 | 8 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 9 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 10 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 11 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 12 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 13 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 14 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 15 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 16 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 17 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 18 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 19 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 20 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 21 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 22 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 23 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 24 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 25 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 26 | 27 | #.readline() reads in only 1 line of the file at a time. 28 | print ("Read only the first line of the file:") 29 | my_file_object = open("my-file.txt", "r") 30 | print (my_file_object.readline()) 31 | print ("\n") 32 | my_file_object.close() -------------------------------------------------------------------------------- /coding204-reading-a-file/read-file-with.py: -------------------------------------------------------------------------------- 1 | # Read from a file using the with statement 2 | # amwhaley@cisco.com 3 | # twitter: @mandywhaley 4 | # http://developer.cisco.com 5 | # http://developer.cisco.com/learning 6 | # Jan 15, 2015 7 | 8 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 9 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 10 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 11 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 12 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 13 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 14 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 15 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 16 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 17 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 18 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 19 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 20 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 21 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 22 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 23 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 24 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 25 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 26 | 27 | print ("Loop through and read each line using with to open the file") 28 | x=1 29 | 30 | # you can open the file using 'with'. 31 | # 'with' gives you better exception handling and when you use 'with' the file automatically be closed 32 | with open("my-file.txt") as file: 33 | for line in file: 34 | print ("Line " + str(x) + ": " + line) 35 | x += 1 -------------------------------------------------------------------------------- /coding204-reading-a-file/read-file.py: -------------------------------------------------------------------------------- 1 | # Most basic example of reading from a file 2 | 3 | # amwhaley@cisco.com 4 | # twitter: @mandywhaley 5 | # http://developer.cisco.com 6 | # http://developer.cisco.com/learning 7 | # Jan 15, 2015 8 | 9 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 10 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 11 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 12 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 13 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 14 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 15 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 16 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 17 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 18 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 19 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 20 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 21 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 22 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 23 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 24 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 25 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 26 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 27 | 28 | 29 | # Use the open method to open a file 30 | # Pass in the name of the file to open and mode. 'r' for read only 'w' if you want to write to the file 31 | my_file_object = open("my-file.txt", "r") 32 | 33 | print ("Read the whole file at once:") 34 | 35 | # read() reads in the entire file. In this line of code, we read in the contents of the file and print it to the screen. 36 | print (my_file_object.read()) 37 | print ("\n") 38 | 39 | # .close closes the file object 40 | my_file_object.close() -------------------------------------------------------------------------------- /coding204-reading-a-file/read-json-from-file.py: -------------------------------------------------------------------------------- 1 | # How to read json from a file 2 | 3 | # amwhaley@cisco.com 4 | # twitter: @mandywhaley 5 | # http://developer.cisco.com 6 | # http://developer.cisco.com/learning 7 | # Jan 15, 2015 8 | 9 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 10 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 11 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 12 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 13 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 14 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 15 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 16 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 17 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 18 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 19 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 20 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 21 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 22 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 23 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 24 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 25 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 26 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 27 | 28 | # import the json library. This library provides many handy features for formatting, displaying 29 | # and manipulating json. 30 | import json 31 | 32 | # use 'with" to open the file containing json 33 | with open('my-json.json') as file: 34 | # read the whole file 35 | data = json.loads(file.read()) 36 | 37 | # access values from the json and loop through devices and display the network device id 38 | i = 0 39 | for item in data["response"]: 40 | print ("Network Device ID: " + data["response"][i]["networkDeviceId"]) 41 | i += 1 42 | 43 | -------------------------------------------------------------------------------- /coding205-writing-file-ga/list-of-devices.txt: -------------------------------------------------------------------------------- 1 | id = 2dc30cac-072e-4d67-9720-cc302d02695a type = Cisco Catalyst 2960C-8PC-L Switch 2 | id = 17184480-2617-42c3-b267-4fade5f794a9 type = Cisco 3500I Unified Access Point 3 | id = 3ab14801-5c88-477d-bbb5-0aca5e5ba840 type = Cisco Catalyst 29xx Stack-able Ethernet Switch 4 | -------------------------------------------------------------------------------- /coding205-writing-file-ga/write-file-append.py: -------------------------------------------------------------------------------- 1 | # Simple Examples of How to write to a File using with 2 | 3 | # amwhaley@cisco.com 4 | # twitter: @mandywhaley 5 | # http://developer.cisco.com 6 | # http://developer.cisco.com/learning 7 | # Jan 15, 2015 8 | 9 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 10 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 11 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 12 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 13 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 14 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 15 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 16 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 17 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 18 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 19 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 20 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 21 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 22 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 23 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 24 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 25 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 26 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 27 | 28 | print ("Writing to file..") 29 | 30 | # you can open the file using 'with'. 31 | # 'with' gives you better exception handling and when you use 'with' the file automatically be closed 32 | with open("my-new-file2.txt", "w") as file: 33 | file.write("Cisco Developers are 1337!\n") 34 | file.write("DevNet Developers rock!\n") 35 | 36 | print ("Do some stuff outside of the with block") 37 | 38 | # open the file again and append some additional text 39 | with open("my-new-file2.txt", "w") as file: 40 | file.write("Level up!\n") 41 | file.write("Go to developer.cisco.com and do more learning labs!") -------------------------------------------------------------------------------- /coding205-writing-file-ga/write-file-using-with.py: -------------------------------------------------------------------------------- 1 | # Simple Examples of How to write to a File using with 2 | 3 | # amwhaley@cisco.com 4 | # twitter: @mandywhaley 5 | # http://developer.cisco.com 6 | # http://developer.cisco.com/learning 7 | # Jan 15, 2015 8 | 9 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 10 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 11 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 12 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 13 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 14 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 15 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 16 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 17 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 18 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 19 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 20 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 21 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 22 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 23 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 24 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 25 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 26 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 27 | 28 | print ("Writing to file..") 29 | 30 | # you can open the file using 'with'. 31 | # 'with' gives you better exception handling and when you use 'with' the file automatically be closed 32 | with open("my-new-file2.txt", "w") as file: 33 | file.write("Cisco Developers are 1337!\n") 34 | file.write("DevNet Developers rock!") -------------------------------------------------------------------------------- /coding205-writing-file-ga/write-file.py: -------------------------------------------------------------------------------- 1 | # Most basic example of writing to a file 2 | 3 | # amwhaley@cisco.com 4 | # twitter: @mandywhaley 5 | # http://developer.cisco.com 6 | # http://developer.cisco.com/learning 7 | # Jan 15, 2015 8 | 9 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 10 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 11 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 12 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 13 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 14 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 15 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 16 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 17 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 18 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 19 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 20 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 21 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 22 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 23 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 24 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 25 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 26 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 27 | 28 | # Use the open method to open a file 29 | # Pass in the name of the file to open and mode. 'r' for read only 'w' if you want to write to the file 30 | # To write to this file we will use "w" 31 | # If the file does not exist, it will be created. 32 | my_file_object = open("my-new-file.txt", "w") 33 | 34 | my_file_object.write("The grey penguin flies at noon.") 35 | 36 | my_file_object.close() -------------------------------------------------------------------------------- /coding205-writing-file-ga/write-json-to-file.py: -------------------------------------------------------------------------------- 1 | # Coding 205 Example 2 | # This example retrieves a list of network devices using the APIC-EM APIs 3 | # Then we write the network device ID and type for each device out to a file. 4 | 5 | 6 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 7 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 8 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 9 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 10 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 11 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 12 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 13 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 14 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 15 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 16 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 17 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 18 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 19 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 20 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 21 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 22 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 23 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 24 | 25 | # import the requests library so we can use it to make REST calls (http://docs.python-requests.org/en/latest/index.html) 26 | import requests 27 | 28 | # import the json library. This library gives us many handy features for formatting, displaying 29 | # and manipulating json. 30 | import json 31 | 32 | # All of our REST calls will use the url for the APIC EM Controller as the base URL 33 | # So lets define a variable for the controller IP or DNS so we don't have to keep typing it 34 | #controller_url = "https://sandboxapic.cisco.com" 35 | controller_url='https://devnetapi.cisco.com/sandbox/apic_em' 36 | 37 | 38 | #the username and password to access the APIC-EM Controller 39 | payload = {"username":"devnetuser","password":"Cisco123!"} 40 | 41 | ticket_url = controller_url + "/api/v1/ticket" 42 | 43 | #Content type must be included in the header 44 | header = {"content-type": "application/json"} 45 | 46 | #Performs a POST on the specified url to get the service ticket 47 | response= requests.post(ticket_url,data=json.dumps(payload), headers=header, verify=False) 48 | 49 | #convert response to json format 50 | r_json=response.json() 51 | 52 | #parse the json to get the service ticket 53 | ticket = r_json["response"]["serviceTicket"] 54 | 55 | # Get Devices 56 | # This function allows you to view a list of 3 of the devices in the network(routers and switches). 57 | get_devices_url = controller_url + '/api/v1/network-device/1/3' 58 | 59 | #Content type as well as the ticket must be included in the header 60 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 61 | 62 | #Perform GET on get_devices_url 63 | get_devices_response = requests.get(get_devices_url, headers=header, verify=False) 64 | 65 | # The json method of the response object returned by requests.get returns the request body in json format 66 | get_devices_json = get_devices_response.json() 67 | 68 | #Now let's read and display some specific information from the json 69 | 70 | # set our parent as the top level response object 71 | parent = get_devices_json["response"] 72 | 73 | print ("Devices = ") 74 | # you can open the file using 'with'. 75 | # 'with' gives you better exception handling and when you use 'with' the file automatically be closed 76 | with open("list-of-devices.txt", "w") as file: 77 | # for each device returned, write the networkDeviceId and type value to the file 78 | for item in parent: 79 | device="id = " + item["id"] + " type = " + item["type"] 80 | file.write (device + "\n") 81 | print(device) 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /coding206-logging/logging-step3.py: -------------------------------------------------------------------------------- 1 | # Simple example of how to log to a file 2 | 3 | # amwhaley@cisco.com 4 | # twitter: @mandywhaley 5 | # http://developer.cisco.com 6 | # http://developer.cisco.com/learning 7 | # Jan 15, 2015 8 | 9 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 10 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 11 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 12 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 13 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 14 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 15 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 16 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 17 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 18 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 19 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 20 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 21 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 22 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 23 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 24 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 25 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 26 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 27 | 28 | # import logging module 29 | import logging 30 | 31 | # specify that we want to log to a file named mylog.log and that we want to track messages at the DEBUG level 32 | logging.basicConfig(filename='mylog.log',level=logging.DEBUG) 33 | 34 | logging.debug('This is a debug message. We should see this in the file.') 35 | logging.info('This is an info message. We should see this in the file.') 36 | logging.warning('This is a warning message. We should see this in the file.') -------------------------------------------------------------------------------- /coding206-logging/logging-step4.py: -------------------------------------------------------------------------------- 1 | # Formatting the messages in the logging output 2 | 3 | # amwhaley@cisco.com 4 | # twitter: @mandywhaley 5 | # http://developer.cisco.com 6 | # http://developer.cisco.com/learning 7 | # Jan 15, 2015 8 | 9 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 10 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 11 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 12 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 13 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 14 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 15 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 16 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 17 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 18 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 19 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 20 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 21 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 22 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 23 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 24 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 25 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 26 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 27 | 28 | #import the logging module 29 | import logging 30 | 31 | # specify to log to a file, specify the format for the message and the date format and the logging level 32 | logging.basicConfig(filename='mylog.log',format='%(asctime)s %(levelname)s: %(message)s',datefmt='%m/%d/%Y %I:%M:%S %p', level=logging.DEBUG) 33 | 34 | # log some messages 35 | logging.debug('This is a debug message. We should see this in the file.') 36 | logging.info('This is an info message. We should see this in the file.') 37 | logging.warning('This is a warning message. We should see this in the file.') -------------------------------------------------------------------------------- /coding206-logging/mylog.log: -------------------------------------------------------------------------------- 1 | 08/29/2016 05:53:15 PM DEBUG: This is a debug message. We should see this in the file. 2 | 08/29/2016 05:53:15 PM INFO: This is an info message. We should see this in the file. 3 | 08/29/2016 05:53:15 PM WARNING: This is a warning message. We should see this in the file. 4 | -------------------------------------------------------------------------------- /coding206-logging/super-simple-logging.py: -------------------------------------------------------------------------------- 1 | # Simple example of how to do logging in python 2 | 3 | # amwhaley@cisco.com 4 | # twitter: @mandywhaley 5 | # http://developer.cisco.com 6 | # http://developer.cisco.com/learning 7 | # Jan 15, 2015 8 | 9 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 10 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 11 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 12 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 13 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 14 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 15 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 16 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 17 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 18 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 19 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 20 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 21 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 22 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 23 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 24 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 25 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 26 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 27 | 28 | # import the logging module 29 | import logging 30 | 31 | # uncomment the following line and you will see both messages in the console 32 | logging.basicConfig(level=logging.INFO) 33 | 34 | logging.warning('This is a warning!') # this line will print a message to the console 35 | logging.info('This is information') # this will not print anything because the default logging level is warning. -------------------------------------------------------------------------------- /coding207-putting-it-together-ga/crap.txt: -------------------------------------------------------------------------------- 1 | The list of devices of type: switch 2 | id = 7f794dae-b5fc-4cc4-8140-c088d46c7d51 type = Cisco Catalyst 3850-48U-E Switch 3 | id = 4418bd65-ce35-454c-a862-6db074f99030 type = Cisco Catalyst 6503 Switch 4 | id = 9222791a-95cf-4ae3-b498-6ac72d0074f4 type = Cisco Catalyst 6503 Switch 5 | id = 0c3aa565-233a-4843-9f5e-8a70f77e1853 type = Cisco Catalyst 4507R plus E Switch 6 | id = 19a333ba-52ee-49eb-90c2-4dc9ab05b47f type = Cisco Catalyst 4507R plus E Switch 7 | -------------------------------------------------------------------------------- /coding207-putting-it-together-ga/create-device-list.py: -------------------------------------------------------------------------------- 1 | # Coding 207 - Putting it all together example 2 | # Asks the user to choose router or switch 3 | # Retrieves list of devices using APIC-EM 4 | # Writes list of devices of selected type to a file 5 | 6 | 7 | # * THIS SAMPLE APPLICATION AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY 8 | # * OF ANY KIND BY CISCO, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED 9 | # * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY FITNESS FOR A PARTICULAR 10 | # * PURPOSE, NONINFRINGEMENT, SATISFACTORY QUALITY OR ARISING FROM A COURSE OF 11 | # * DEALING, LAW, USAGE, OR TRADE PRACTICE. CISCO TAKES NO RESPONSIBILITY 12 | # * REGARDING ITS USAGE IN AN APPLICATION, AND IT IS PRESENTED ONLY AS AN 13 | # * EXAMPLE. THE SAMPLE CODE HAS NOT BEEN THOROUGHLY TESTED AND IS PROVIDED AS AN 14 | # * EXAMPLE ONLY, THEREFORE CISCO DOES NOT GUARANTEE OR MAKE ANY REPRESENTATIONS 15 | # * REGARDING ITS RELIABILITY, SERVICEABILITY, OR FUNCTION. IN NO EVENT DOES 16 | # * CISCO WARRANT THAT THE SOFTWARE IS ERROR FREE OR THAT CUSTOMER WILL BE ABLE 17 | # * TO OPERATE THE SOFTWARE WITHOUT PROBLEMS OR INTERRUPTIONS. NOR DOES CISCO 18 | # * WARRANT THAT THE SOFTWARE OR ANY EQUIPMENT ON WHICH THE SOFTWARE IS USED WILL 19 | # * BE FREE OF VULNERABILITY TO INTRUSION OR ATTACK. THIS SAMPLE APPLICATION IS 20 | # * NOT SUPPORTED BY CISCO IN ANY MANNER. CISCO DOES NOT ASSUME ANY LIABILITY 21 | # * ARISING FROM THE USE OF THE APPLICATION. FURTHERMORE, IN NO EVENT SHALL CISCO 22 | # * OR ITS SUPPLIERS BE LIABLE FOR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, LOST 23 | # * PROFITS, OR LOST DATA, OR ANY OTHER INDIRECT DAMAGES EVEN IF CISCO OR ITS 24 | # * SUPPLIERS HAVE BEEN INFORMED OF THE POSSIBILITY THEREOF.--> 25 | 26 | # import requests library 27 | import requests 28 | 29 | #import json library 30 | import json 31 | 32 | #import logging library 33 | import logging 34 | 35 | # Disable warnings 36 | requests.packages.urllib3.disable_warnings() 37 | 38 | 39 | # All of our REST calls will use the url for the APIC EM Controller as the base URL 40 | #controller_url = "https://sandboxapic.cisco.com" 41 | controller_url='https://devnetapi.cisco.com/sandbox/apic_em' 42 | 43 | 44 | def getUserInput(): 45 | #turn on logging to the mylog.log file 46 | logging.basicConfig(filename='mylog.log',format='%(asctime)s %(levelname)s: %(message)s',datefmt='%m/%d/%Y %I:%M:%S %p', level=logging.DEBUG) 47 | 48 | logging.info("Begin") 49 | logging.info("Asking user for device type") 50 | 51 | # Ask the user what kind of list they want to create 52 | device_type = input("Do you want to create a list of [r]outers or [s]witches?") 53 | 54 | # create a variable called type to hold which kind of device to save 55 | if device_type == 'r': 56 | type = "router" 57 | else: 58 | type = "switch" 59 | 60 | logging.info("Device type is " + type) 61 | 62 | # Ask user for name of the file 63 | file_name = input("Specify the file name to use for the list:") 64 | 65 | logging.info("Will save device list to " + file_name) 66 | 67 | return(type,file_name) 68 | 69 | 70 | #creates and returns a service ticket. 71 | def getTicket(): 72 | logging.info("\nCreating ticket") 73 | # put the ip address or dns of your apic-em controller in this url 74 | url = controller_url + "/api/v1/ticket" 75 | 76 | #the username and password to access the APIC-EM Controller 77 | payload = {"username":"devnetuser","password":"Cisco123!"} 78 | 79 | #Content type must be included in the header 80 | header = {"content-type": "application/json"} 81 | 82 | #Performs a POST on the specified url to get the service ticket 83 | response= requests.post(url,data=json.dumps(payload), headers=header, verify=False) 84 | 85 | logging.info(response.text) 86 | 87 | #convert response to json format 88 | r_json=response.json() 89 | 90 | #parse the json to get the service ticket 91 | ticket = r_json["response"]["serviceTicket"] 92 | 93 | return ticket 94 | 95 | 96 | def getDeviceCount(ticket): 97 | # Specify URL for the devices count 98 | devices_count_url = controller_url + '/api/v1/network-device/count' 99 | 100 | logging.info("Calling APIC-EM API url:" + devices_count_url) 101 | 102 | #Content type as well as the ticket must be included in the header 103 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 104 | 105 | # Perform GET on devices_count_url 106 | devices_count_response = requests.get(devices_count_url, headers=header, verify=False) 107 | count = devices_count_response.json()["response"] 108 | 109 | logging.debug("API response: " + json.dumps(devices_count_response.json(), indent=4, separators=(',', ': '))) 110 | 111 | return count 112 | 113 | 114 | # Get Devices 115 | # This function allows you to view a list of all the devices in the network(routers and switches) with the maximum shown specified by the passed in count variable 116 | def getDevices(ticket,count,type,file_name): 117 | get_devices_url = controller_url + '/api/v1/network-device/1/' + str(count) 118 | 119 | logging.info("Calling APIC-EM API url:" + get_devices_url) 120 | 121 | #Content type as well as the ticket must be included in the header 122 | header = {"content-type": "application/json", "X-Auth-Token":ticket} 123 | 124 | #Perform GET on get_devices_url 125 | get_devices_response = requests.get(get_devices_url, headers=header, verify=False) 126 | 127 | # The json method of the response object returned by requests.get returns the request body in json format 128 | get_devices_json = get_devices_response.json() 129 | 130 | logging.debug("API response: " + json.dumps(get_devices_json, indent=4, separators=(',', ': '))) 131 | 132 | #Now let's parse the json and write the devices out to our file 133 | file= open(file_name, "w") 134 | logging.info("File opened:" + file_name) 135 | logging.info("Begin writing list:" + file_name) 136 | file.write ("The list of devices of type: " + type + "\n" ) 137 | 138 | # set our parent as the top level response object 139 | parent = get_devices_json["response"] 140 | 141 | # for each device returned, write the networkDeviceId and type value to the file if the type corresponds to what we're seeking. 142 | for item in parent: 143 | lowerCaseType=item["type"].lower() 144 | if lowerCaseType.find(type)!=-1: 145 | file.write ("id = " + item["id"] + " type = " + item["type"] + "\n") 146 | 147 | print ("Finished writing list ...") 148 | logging.info("End writing list:" + file_name) 149 | 150 | 151 | (theType,theFilename)=getUserInput() 152 | theTicket=getTicket() 153 | theCount=getDeviceCount(theTicket) 154 | getDevices(theTicket,theCount,theType,theFilename) 155 | -------------------------------------------------------------------------------- /coding210-parsing-json-c++/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.2) 2 | 3 | project(AllProjects) 4 | include(activity-1.cmake) 5 | include(activity-2.cmake) 6 | include(activity-3.cmake) 7 | include(activity-4.cmake) 8 | include(activity-5.cmake) -------------------------------------------------------------------------------- /coding210-parsing-json-c++/README.md: -------------------------------------------------------------------------------- 1 | # coding210-parsing-json-c++ 2 | This is sample code for the parsing JSON using C++. 3 | 4 | ## Requirements ## 5 | 6 | ### Windows ### 7 | #### Installing Cygwin #### 8 | 9 | Install Cygwin and make sure you select the following packages: gcc-g++, openssl-devel, libssh2-devel, libcurl-devel, libcurl4 10 | 11 | You may need to close and reopen your console window to pickup the changes to the Windows environment. 12 | 13 | ## Instructions ## 14 | 15 | ### Get libcurl URL library 16 | To get a local copy of the required libcurl headers, execute the following command: 17 | 18 | git clone https://github.com/bagder/curl.git 19 | 20 | 21 | ### Get RapidJSON parser/generator ### 22 | To get a local copy of the required RapidJSON headers, execute the following command: 23 | 24 | git clone https://github.com/miloyip/rapidjson.git 25 | 26 | 27 | -------------------------------------------------------------------------------- /coding210-parsing-json-c++/activity-1.cmake: -------------------------------------------------------------------------------- 1 | 2 | project(coding210_parsing_json_cpp_activity_1) 3 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 4 | 5 | 6 | 7 | # hello 8 | set(SOURCE_FILES 9 | hello.cpp) 10 | 11 | add_executable(coding210_1_hello ${SOURCE_FILES}) 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /coding210-parsing-json-c++/activity-2.cmake: -------------------------------------------------------------------------------- 1 | 2 | project(coding210_parsing_json_cpp_activity_2) 3 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 4 | 5 | 6 | 7 | # main-http 8 | set(SOURCE_FILES 9 | main-http.cpp) 10 | 11 | add_executable(coding210_2_main_http ${SOURCE_FILES}) 12 | target_link_libraries(coding210_2_main_http curl) 13 | 14 | 15 | -------------------------------------------------------------------------------- /coding210-parsing-json-c++/activity-3.cmake: -------------------------------------------------------------------------------- 1 | 2 | project(coding210_parsing_json_cpp_activity_3) 3 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 4 | 5 | 6 | 7 | # main-http 8 | set(SOURCE_FILES 9 | main-json.cpp) 10 | 11 | add_executable(coding210_3_main_json ${SOURCE_FILES}) 12 | target_link_libraries(coding210_3_main_json curl) 13 | 14 | 15 | -------------------------------------------------------------------------------- /coding210-parsing-json-c++/activity-4.cmake: -------------------------------------------------------------------------------- 1 | 2 | project(coding210_parsing_json_cpp_activity_4) 3 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 4 | 5 | include_directories("rapidjson/include") 6 | 7 | # main-http 8 | set(SOURCE_FILES 9 | main-json-lib.cpp) 10 | 11 | add_executable(coding210_4_main_json_lib ${SOURCE_FILES}) 12 | target_link_libraries(coding210_4_main_json_lib curl) 13 | 14 | 15 | -------------------------------------------------------------------------------- /coding210-parsing-json-c++/activity-5.cmake: -------------------------------------------------------------------------------- 1 | 2 | project(coding210_parsing_json_cpp_activity_5) 3 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 4 | 5 | include_directories("rapidjson/include") 6 | 7 | # main 8 | set(SOURCE_FILES 9 | main.cpp) 10 | 11 | add_executable(coding210_5_main ${SOURCE_FILES}) 12 | target_link_libraries(coding210_5_main curl) 13 | -------------------------------------------------------------------------------- /coding210-parsing-json-c++/hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() 4 | { 5 | std::cout << "Hello World!\n"; 6 | std::cout << "How are you?\n"; 7 | 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /coding210-parsing-json-c++/hello.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | public class HelloWorld 4 | { 5 | static public void Main() 6 | { 7 | Console.WriteLine("Hello World!"); 8 | Console.WriteLine("How are you?"); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /coding210-parsing-json-c++/main-annotated.cpp: -------------------------------------------------------------------------------- 1 | // Include the headers needed for the input/output, cURL, and RapidJSON functionality 2 | #include 3 | #include 4 | #include "curl/curl.h" 5 | #include "curl/easy.h" 6 | #include "rapidjson/document.h" 7 | #include "rapidjson/writer.h" 8 | #include "rapidjson/stringbuffer.h" 9 | 10 | // Declare the namespaces we intend to use 11 | using namespace std; 12 | using namespace rapidjson; 13 | 14 | // Define a structure to hold our file and string information for the callback data 15 | struct JSONDATA 16 | { 17 | fstream *file; 18 | string *str; 19 | }; 20 | 21 | // The callback function used by cURL to write our file 22 | size_t write_data(void *ptr, size_t size, size_t nmemb, JSONDATA *data) { 23 | 24 | size_t numBytes = size * nmemb; 25 | 26 | if (data->file) 27 | data->file->write((char*)ptr, numBytes); 28 | 29 | if (data->str) 30 | *(data->str) += std::string((char*)ptr, numBytes); 31 | 32 | return numBytes; 33 | } 34 | 35 | // The main function of the application 36 | int main() { 37 | 38 | CURL *curl; 39 | CURLcode res; 40 | 41 | // The URI we intend to access 42 | string uri = "https://msesandbox.cisco.com/api/contextaware/v1/maps/info/DevNetCampus/DevNetBuilding/DevNetZone"; 43 | 44 | // The Authorization header with learning:learning base64 encoded for the user:password 45 | string header_authorization = "Authorization: Basic bGVhcm5pbmc6bGVhcm5pbmc="; 46 | 47 | // The Accept header specifying we would like JSON data returned to us from the server 48 | string header_accept = "Accept: application/json"; 49 | 50 | // Add the headers to a list for cURL to use 51 | struct curl_slist *headers = NULL; 52 | headers = curl_slist_append(headers, header_authorization.c_str()); 53 | headers = curl_slist_append(headers, header_accept.c_str()); 54 | 55 | // Initialize cURL 56 | curl = curl_easy_init(); 57 | 58 | // Declare a file called content.json 59 | fstream file("content.json", ios_base::out | ios_base::ate); 60 | 61 | // A string to store our json output 62 | string json; 63 | 64 | // An instance of our JSONDATA structure 65 | JSONDATA data; 66 | data.file = &file; 67 | data.str = &json; 68 | 69 | // If we have a valid cURL instance we can proceed 70 | if (curl) { 71 | 72 | // Set the cURL options for the URI, headers, the callback function, and callback data 73 | curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); 74 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 75 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); 76 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data); 77 | 78 | // Actually have cURL perform the request 79 | res = curl_easy_perform(curl); 80 | 81 | // Check to see if we received an OK from cURL 82 | if(res != CURLE_OK) 83 | cerr << "ERROR: " << curl_easy_strerror(res) << endl; 84 | else { 85 | 86 | // Create a RapidJSON document and parse the received JSON into it 87 | Document document; 88 | document.Parse(json.c_str()); 89 | 90 | // Get the Floor\AccessPoint value from the JSON 91 | Value& accessPoint = document["Floor"]["AccessPoint"]; 92 | 93 | // Check to verify we got an array of access point values in the JSON 94 | assert(accessPoint.IsArray()); 95 | 96 | // Iterate through the Access Points, printing their name 97 | for (SizeType i = 0; i < accessPoint.Size(); i++) 98 | printf("accessPoint: %s\n", accessPoint[i]["name"].GetString()); 99 | } 100 | 101 | // Cleanup the cURL instance 102 | curl_easy_cleanup(curl); 103 | } 104 | 105 | // Return a success value from our application 106 | return 0; 107 | } -------------------------------------------------------------------------------- /coding210-parsing-json-c++/main-http.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "curl/curl.h" 3 | #include "curl/easy.h" 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | 9 | string uri = "http://www.cisco.com"; 10 | 11 | CURLcode res; 12 | CURL *curl = curl_easy_init(); 13 | if(curl) { 14 | 15 | curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); 16 | res = curl_easy_perform(curl); 17 | 18 | if(res != CURLE_OK) 19 | cerr << "ERROR: " << curl_easy_strerror(res) << endl; 20 | else { 21 | // We should have received data from the URI 22 | } 23 | 24 | curl_easy_cleanup(curl); 25 | } 26 | 27 | return 0; 28 | } -------------------------------------------------------------------------------- /coding210-parsing-json-c++/main-json-lib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "curl/curl.h" 4 | #include "curl/easy.h" 5 | #include "rapidjson/document.h" 6 | #include "rapidjson/prettywriter.h" 7 | #include "rapidjson/stringbuffer.h" 8 | 9 | using namespace std; 10 | using namespace rapidjson; 11 | 12 | struct JSONDATA 13 | { 14 | fstream *file; 15 | string *str; 16 | }; 17 | 18 | size_t write_data(void *ptr, size_t size, size_t nmemb, JSONDATA *data) { 19 | 20 | size_t numBytes = size * nmemb; 21 | 22 | if (data->file) 23 | data->file->write((char*)ptr, numBytes); 24 | 25 | if (data->str) 26 | *(data->str) += std::string((char*)ptr, numBytes); 27 | 28 | return numBytes; 29 | } 30 | 31 | int main() { 32 | 33 | CURL *curl; 34 | CURLcode res; 35 | 36 | string uri = "https://msesandbox.cisco.com/api/contextaware/v1/maps/info/DevNetCampus/DevNetBuilding/DevNetZone"; 37 | string header_authorization = "Authorization: Basic bGVhcm5pbmc6bGVhcm5pbmc="; 38 | string header_accept = "Accept: application/json"; 39 | 40 | struct curl_slist *headers = NULL; 41 | headers = curl_slist_append(headers, header_authorization.c_str()); 42 | headers = curl_slist_append(headers, header_accept.c_str()); 43 | 44 | curl = curl_easy_init(); 45 | 46 | fstream file("content.json", ios_base::out | ios_base::ate); 47 | string json; 48 | 49 | JSONDATA data; 50 | data.file = &file; 51 | data.str = &json; 52 | 53 | if(curl) { 54 | 55 | curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); 56 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 57 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); 58 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data); 59 | 60 | res = curl_easy_perform(curl); 61 | 62 | if(res != CURLE_OK) 63 | cerr << "ERROR: " << curl_easy_strerror(res) << endl; 64 | else { 65 | 66 | Document document; 67 | document.Parse(json.c_str()); 68 | 69 | StringBuffer buffer; 70 | PrettyWriter writer(buffer); 71 | document.Accept(writer); 72 | 73 | cout << buffer.GetString() << endl; 74 | } 75 | 76 | curl_easy_cleanup(curl); 77 | } 78 | 79 | return 0; 80 | } -------------------------------------------------------------------------------- /coding210-parsing-json-c++/main-json.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "curl/curl.h" 3 | #include "curl/easy.h" 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | 9 | string uri = "https://msesandbox.cisco.com/api/contextaware/v1/maps/info/DevNetCampus/DevNetBuilding/DevNetZone"; 10 | string header_authorization = "Authorization: Basic bGVhcm5pbmc6bGVhcm5pbmc="; 11 | string header_accept = "Accept: application/json"; 12 | 13 | struct curl_slist *headers = NULL; 14 | headers = curl_slist_append(headers, header_authorization.c_str()); 15 | headers = curl_slist_append(headers, header_accept.c_str()); 16 | 17 | CURLcode res; 18 | CURL *curl = curl_easy_init(); 19 | if(curl) { 20 | 21 | curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); 22 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 23 | res = curl_easy_perform(curl); 24 | 25 | if(res != CURLE_OK) 26 | cerr << "ERROR: " << curl_easy_strerror(res) << endl; 27 | else { 28 | // We should have received data from the URI 29 | } 30 | 31 | curl_easy_cleanup(curl); 32 | } 33 | 34 | return 0; 35 | } -------------------------------------------------------------------------------- /coding210-parsing-json-c++/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "curl/curl.h" 4 | #include "curl/easy.h" 5 | #include "rapidjson/document.h" 6 | #include "rapidjson/writer.h" 7 | #include "rapidjson/stringbuffer.h" 8 | 9 | using namespace std; 10 | using namespace rapidjson; 11 | 12 | struct JSONDATA 13 | { 14 | fstream *file; 15 | string *str; 16 | }; 17 | 18 | size_t write_data(void *ptr, size_t size, size_t nmemb, JSONDATA *data) { 19 | 20 | size_t numBytes = size * nmemb; 21 | 22 | if (data->file) 23 | data->file->write((char*)ptr, numBytes); 24 | 25 | if (data->str) 26 | *(data->str) += std::string((char*)ptr, numBytes); 27 | 28 | return numBytes; 29 | } 30 | 31 | int main() { 32 | 33 | CURL *curl; 34 | CURLcode res; 35 | 36 | string uri = "https://msesandbox.cisco.com/api/contextaware/v1/maps/info/DevNetCampus/DevNetBuilding/DevNetZone"; 37 | string header_authorization = "Authorization: Basic bGVhcm5pbmc6bGVhcm5pbmc="; 38 | string header_accept = "Accept: application/json"; 39 | 40 | struct curl_slist *headers = NULL; 41 | headers = curl_slist_append(headers, header_authorization.c_str()); 42 | headers = curl_slist_append(headers, header_accept.c_str()); 43 | 44 | curl = curl_easy_init(); 45 | 46 | fstream file("content.json", ios_base::out | ios_base::ate); 47 | string json; 48 | 49 | JSONDATA data; 50 | data.file = &file; 51 | data.str = &json; 52 | 53 | if(curl) { 54 | 55 | curl_easy_setopt(curl, CURLOPT_URL, uri.c_str()); 56 | curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); 57 | curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); 58 | curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data); 59 | 60 | res = curl_easy_perform(curl); 61 | 62 | if(res != CURLE_OK) 63 | cerr << "ERROR: " << curl_easy_strerror(res) << endl; 64 | else { 65 | 66 | Document document; 67 | document.Parse(json.c_str()); 68 | 69 | Value& accessPoint = document["Floor"]["AccessPoint"]; 70 | assert(accessPoint.IsArray()); 71 | 72 | // Iterate through the Access Points 73 | for (SizeType i = 0; i < accessPoint.Size(); i++) 74 | printf("accessPoint: %s\n", accessPoint[i]["name"].GetString()); 75 | } 76 | 77 | curl_easy_cleanup(curl); 78 | } 79 | 80 | return 0; 81 | } -------------------------------------------------------------------------------- /content-serve/content-server.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python 2 | 3 | import http.server 4 | import random 5 | 6 | server_ip = "127.0.0.1" 7 | server_port = 8000 8 | 9 | 10 | class CustomRequestHandler(http.server.BaseHTTPRequestHandler): 11 | def do_GET(self): 12 | 13 | route_path = self.path.rstrip("/") 14 | 15 | # print(route_path) 16 | if route_path == '/object': 17 | self.send_response(200) 18 | self.write_object() 19 | elif route_path == '/array': 20 | self.send_response(200) 21 | self.write_array() 22 | elif route_path == '/random': 23 | self.send_response(200) 24 | self.write_random() 25 | elif route_path == '/random/array': 26 | self.send_response(200) 27 | self.write_random_array() 28 | elif route_path == '/complex': 29 | self.send_response(200) 30 | self.write_complex() 31 | elif route_path == '/complex/array': 32 | self.send_response(200) 33 | self.write_complex_array() 34 | else: 35 | # Otherwise send a default response 36 | self.send_response(200) 37 | self.send_header('Content-type', 'text/html') 38 | self.end_headers() 39 | self.wfile.write(open("./data/index.html", "rb").read()) 40 | 41 | return 42 | 43 | def write_object(self): 44 | self.send_header('Content-type', 'application/json') 45 | self.end_headers() 46 | self.wfile.write(b'{ "first_name": "Mike", "last_name": "Maas" }') 47 | 48 | def write_array(self): 49 | self.send_header('Content-type', 'application/json') 50 | self.end_headers() 51 | self.wfile.write(b'[{ "first_name": "Mike", "last_name": "Maas" }, { "first_name": "Matt", "last_name": "Denapoli" }]') 52 | 53 | def write_complex(self): 54 | self.send_header('Content-type', 'application/json') 55 | self.end_headers() 56 | self.wfile.write(open("./data/complex.json", "rb").read()) 57 | 58 | def write_complex_array(self): 59 | self.send_header('Content-type', 'application/json') 60 | self.end_headers() 61 | self.wfile.write(open("./data/complex-array.json", "rb").read()) 62 | 63 | def write_random(self): 64 | self.send_header('Content-type', 'application/json') 65 | self.end_headers() 66 | result = '{"value":' + str(random.randrange(0, 100, 1)) + '}' 67 | self.wfile.write(bytes(result, "utf-8")) 68 | 69 | def write_random_array(self): 70 | self.send_header('Content-type', 'application/json') 71 | self.end_headers() 72 | 73 | # Construct a JSON array with random entries 74 | values = [] 75 | value_count = random.randint(0, 15) 76 | for element in range(0, value_count): 77 | value = '{{ "{}" : {}, "value" : {} }}'.format("id", element, str(random.randrange(0, 100, 1))) 78 | values.append(value) 79 | 80 | result = '[' + ', '.join(values) + ']' 81 | self.wfile.write(bytes(result, "utf-8")) 82 | 83 | 84 | def run(): 85 | # Set the server settings 86 | server_address = (server_ip, server_port) 87 | httpd = http.server.HTTPServer(server_address, CustomRequestHandler) 88 | print("Serving content at http://" + server_ip + ":" + str(server_port)) 89 | httpd.serve_forever() 90 | 91 | 92 | if __name__ == '__main__': 93 | run() 94 | -------------------------------------------------------------------------------- /content-serve/data/complex-array.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "order": { 4 | "placed": "2017-01-01T00:00:00+00:00", 5 | "priority" : 1, 6 | "user": { 7 | "id": 1, 8 | "first_name": "Mike", 9 | "last_name": "Maas" 10 | }, 11 | "product": { 12 | "sku": "TS007-XL-001", 13 | "location": { 14 | "container" : 9, 15 | "shelf": 4, 16 | "slot" : 6, 17 | "coordinates": [ 18 | { 19 | "x": 11 20 | }, 21 | { 22 | "y": 44 23 | }, 24 | { 25 | "z": -4 26 | } 27 | ] 28 | }, 29 | "price": 9.99, 30 | "tags": [ 31 | "t-shirt", 32 | "black" 33 | ] 34 | } 35 | } 36 | }, 37 | { 38 | "order": { 39 | "placed": "2016-01-01T00:00:00+00:00", 40 | "priority" : 3, 41 | "user": { 42 | "id": 2, 43 | "first_name": "Matt", 44 | "last_name": "Denapoli" 45 | }, 46 | "product": { 47 | "sku": "TS009-XL-003", 48 | "location": { 49 | "container" : 9, 50 | "shelf": 4, 51 | "slot" : 5, 52 | "coordinates": [ 53 | { 54 | "x": 11 55 | }, 56 | { 57 | "y": 44 58 | }, 59 | { 60 | "z": -4 61 | } 62 | ] 63 | }, 64 | "price": 8.99, 65 | "tags": [ 66 | "t-shirt", 67 | "blue" 68 | ] 69 | } 70 | } 71 | }, 72 | { 73 | "order": { 74 | "placed": "2015-01-01T00:00:00+00:00", 75 | "priority" : 2, 76 | "user": { 77 | "id": 3, 78 | "first_name": "Ashley", 79 | "last_name": "Roach" 80 | }, 81 | "product": { 82 | "sku": "TS003-L-001", 83 | "location": { 84 | "container" : 8, 85 | "shelf": 5, 86 | "slot" : 2, 87 | "coordinates": [ 88 | { 89 | "x": 9 90 | }, 91 | { 92 | "y": 34 93 | }, 94 | { 95 | "z": -5 96 | } 97 | ] 98 | }, 99 | "price": 12.99, 100 | "tags": [ 101 | "t-shirt", 102 | "salmon" 103 | ] 104 | } 105 | } 106 | } 107 | ] -------------------------------------------------------------------------------- /content-serve/data/complex.json: -------------------------------------------------------------------------------- 1 | { 2 | "order": { 3 | "placed" : "2017-01-01T00:00:00+00:00", 4 | "priority" : 1, 5 | "user": { 6 | "id": 1, 7 | "first_name": "Mike", 8 | "last_name": "Maas" 9 | }, 10 | "product": { 11 | "sku": "TS007-XL-001", 12 | "location": { 13 | "container" : 9, 14 | "shelf" : 4, 15 | "slot" : 6, 16 | "coordinates": [ 17 | { 18 | "x": 11 19 | }, 20 | { 21 | "y": 44 22 | }, 23 | { 24 | "z": -4 25 | } 26 | ] 27 | }, 28 | "price": 9.99, 29 | "tags": [ 30 | "t-shirt", 31 | "blue" 32 | ] 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /content-serve/data/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Content Server 6 | 7 | 8 | 9 |

Content Server

10 | 13 | 14 | 17 | 18 | 21 | 22 | 25 | 26 | 29 | 30 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # How to contribute to a Learning Lab 2 | 3 | For Learning Labs, there are a few primary ways to help: 4 | - Testing the Learning Lab and then reporting issues in the repo or in the common issues tracking repo 5 | - Using the Issue tracker to report issues or comment that you will work on an issue 6 | - Updating the content in the Learning Lab repo 7 | - Requesting or creating a release 8 | - Contacting DevNet to publish new or updated Learning Labs 9 | 10 | ## Using the issue tracker 11 | 12 | For Learning Labs, there are two potential places to track issues, depending on 13 | whether the repo is a public or private repo. 14 | 15 | For public repo Learning Labs, use the issue tracker in the repo. All Learning Labs repos in the CiscoDevNet organization have a topic of `learning-labs`. 16 | 17 | For private Learning Labs, use the common Issue tracker in the [CiscoDevNet/learning-labs-issues](https://github.com/CiscoDevNet/learning-labs-issues) repo. 18 | 19 | For DevNet Express events, use these Issue tracker repos based on the content track: 20 | * https://github.com/CiscoDevNet/devnet-express-dna-issues 21 | * https://github.com/CiscoDevNet/devnet-express-cc-issues 22 | * https://github.com/CiscoDevNet/devnet-express-dci-issues 23 | * https://github.com/CiscoDevNet/devnet-express-security-issues 24 | 25 | Use the issue tracker to suggest additions, report bugs, and ask questions. 26 | This is also a great way to connect with the developers of the project as well 27 | as others who are interested in this solution. 28 | 29 | Also use the issue tracker to find ways to contribute. Test a lab, find a bug, 30 | log an issue, or offer an update, comment on the issue that you will take on 31 | that effort, then follow the _Changing the Learning Lab content_ guidance below. 32 | 33 | ## Changing the Learning Lab content 34 | 35 | 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 36 | to validate that documented tasks work correctly. Additionally, the content 37 | should follow the [Learning Lab Style Guide](https://github.com/CiscoDevNet/devnet-writing-guidelines/wiki/Lab-Style-Guide). 38 | 39 | The [DevNet Writing Guidelines Wiki](https://github.com/CiscoDevNet/devnet-writing-guidelines/wiki) 40 | describes the review and publishing process in detail. Please feel free to request reviews from DevNet contributors you see in the repository and we will review submissions. 41 | --------------------------------------------------------------------------------