├── .gitignore ├── Dockerfile ├── LICENSE ├── NOTICE ├── README.md ├── Vagrantfile ├── acitoolkit ├── __about__.py ├── __init__.py ├── aciConcreteLib.py ├── aciFaults.py ├── aciHealthScore.py ├── aciSearch.py ├── aciTable.py ├── acibaseobject.py ├── acicounters.py ├── acifakeapic.py ├── aciphysobject.py ├── acisession.py ├── acitoolkit.py └── acitoolkitlib.py ├── applications ├── aci-diagram │ ├── README.md │ └── diagram.py ├── cableplan │ ├── .coverage │ ├── aciCableplan_test.py │ ├── cableplan.py │ └── docs │ │ └── cable.rst ├── cli │ ├── acitoolkitcli.py │ ├── clicommands.txt │ └── test_cli.txt ├── configpush │ ├── apic_rest_server.py │ ├── apic_tool.py │ ├── apicservice.py │ ├── apicservice_test.py │ ├── configpush_test1_policies.json.gz │ ├── configpush_test1_policies_tenant_golden.json.gz │ ├── configpush_test1_policies_with_useipEpgs_tenant_golden.json.gz │ ├── configpush_test2_policies.json.gz │ ├── configpush_test2_policies_tenant_golden.json.gz │ ├── configpush_test2_policies_with_useipEpgs_tenant_golden.json.gz │ ├── configpush_test3_policies.json.gz │ ├── configpush_test3_policies_tenant_golden.json.gz │ ├── configpush_test3_policies_with_useipEpgs_tenant_golden.json.gz │ ├── configpush_test4_policies.json.gz │ ├── configpush_test4_policies_tenant_golden.json.gz │ ├── configpush_test4_policies_with_useipEpgs_tenant_golden.json.gz │ └── json_schema.json ├── connection_search │ ├── Forms.py │ ├── aciConSearch.py │ ├── aciConSearchGui.py │ ├── aciConSearchGui_test.py │ ├── aciConSearch_test.py │ ├── static │ │ ├── connSearchResult.js │ │ ├── connectionSearch.css │ │ ├── connectionSearch.js │ │ ├── layout.css │ │ └── spin.js │ └── templates │ │ ├── about.html │ │ ├── admin │ │ └── index.html │ │ ├── credentials.html │ │ ├── feedback.html │ │ ├── layout.html │ │ ├── loading.html │ │ └── search_result.html ├── endpointtracker │ ├── README.md │ ├── aci-endpoint-tracker-gui.py │ ├── aci-endpoint-tracker.py │ ├── daemon.py │ └── templates │ │ └── main.html ├── eventfeeds │ ├── .gitignore │ ├── eventfeeds.py │ ├── static │ │ └── pure-min.css │ └── templates │ │ ├── config.html │ │ └── feeds.html ├── inheritance │ ├── inheritance.py │ ├── inheritance_apic_credentials.ini │ ├── inheritance_rest_server.py │ ├── inheritance_test.py │ └── schema.json ├── intraepg │ ├── intraepg.py │ └── intraepg_templates.py ├── lint │ ├── README.md │ └── acilint.py ├── multisite │ ├── README.md │ ├── aci_multisite_config_test.py │ ├── intersite.py │ ├── intersite_automator.py │ ├── intersite_rest_server.py │ └── intersite_test.py ├── object_browser │ ├── object_browser.py │ ├── static │ │ └── style.css │ └── templates │ │ ├── layout.html │ │ ├── show_class.html │ │ └── show_mo.html ├── reports │ ├── Forms.py │ ├── aci-report-logical.py │ ├── aci-report-security-audit.py │ ├── aci-report-switch.py │ ├── aciReportDB.py │ ├── aciReportGui.py │ ├── static │ │ ├── d3-tablesort.css │ │ └── d3-tablesort.js │ └── templates │ │ ├── about.html │ │ ├── admin │ │ └── index.html │ │ ├── credentials.html │ │ ├── feedback.html │ │ ├── layout.html │ │ └── select_switch.html ├── search │ ├── Forms.py │ ├── aciSearchDb.py │ ├── aciSearchGui.py │ ├── aciSearch_test.py │ ├── aciSearch_update_local_database_test.py │ ├── static │ │ ├── autocomplete.css │ │ ├── autocomplete.js │ │ ├── d3-searchresult.js │ │ ├── d3-tablesort.css │ │ ├── d3-tablesort.js │ │ ├── layout.css │ │ ├── show_object.js │ │ └── spin.js │ └── templates │ │ ├── about.html │ │ ├── admin │ │ └── index.html │ │ ├── credentials.html │ │ ├── feedback.html │ │ ├── layout.html │ │ └── search_result.html ├── snapback │ ├── aciconfigdb.py │ ├── aciconfigdb_test.py │ ├── snapback.py │ ├── snapback_test.py │ ├── static │ │ ├── data.csv │ │ └── layout.css │ └── templates │ │ ├── about.html │ │ ├── admin │ │ └── index.html │ │ ├── credentials.html │ │ ├── diffview.html │ │ ├── feedback.html │ │ ├── fileview.html │ │ ├── layout.html │ │ ├── list.html │ │ ├── rollback.html │ │ ├── snapshot.html │ │ └── stackedbardiffs.html ├── testharness │ ├── apic_test_harness.py │ └── sample_apic_test_harness_config.ini └── visualizations │ ├── README.md │ ├── acitoolkit-visualizations.py │ ├── acitoolkitvisualizationslib.py │ ├── epg-bubbles.py │ ├── static │ ├── acitoolkit.css │ ├── endpoint_hierarchical_data.json │ └── graph.json │ └── templates │ ├── bubble-tooltips.html │ ├── endpoint-force.html │ ├── endpoint-hierarchical-edge-bundling.html │ ├── endpoint-radial.html │ ├── endpoint-sunburst.html │ ├── endpoint-tracker-pie.html │ ├── endpoint-tree.html │ └── index.html ├── contributors.txt ├── docs ├── Makefile └── source │ ├── Connection_Search-welcome.png │ ├── aci.png │ ├── acilint.rst │ ├── acitoolkit.aciFaults.rst │ ├── acitoolkit.acibaseobject.rst │ ├── acitoolkit.aciphysobject.rst │ ├── acitoolkit.acisession.rst │ ├── acitoolkit.acitoolkit.rst │ ├── acitoolkit.acitoolkitlib.rst │ ├── acitoolkit.rst │ ├── applications.rst │ ├── apptopo.png │ ├── cableplan.rst │ ├── conf.py │ ├── connection-search-example1.png │ ├── connection-search-example2.png │ ├── connection-search-example3.png │ ├── connection_search-credentials-set.png │ ├── connection_search-credentials.png │ ├── connection_search-search-start.png │ ├── connectionsearch.rst │ ├── credentials.png │ ├── endpointtracker.rst │ ├── eventfeeds.png │ ├── eventfeeds.rst │ ├── eventfeeds_config.png │ ├── fakeapic.rst │ ├── index.rst │ ├── interfacemodel.png │ ├── intersite.rst │ ├── introduction.rst │ ├── modules.rst │ ├── monitor_policy.rst │ ├── monitorpolicyhier.png │ ├── objectModelController.png │ ├── objectModelSwitch.png │ ├── objectModelTop.png │ ├── objectmodel.rst │ ├── reports-gui.rst │ ├── reports-logical.rst │ ├── reports-security.rst │ ├── reports-switch.rst │ ├── reports.rst │ ├── reportview-main.png │ ├── saved-credentials.png │ ├── snapback-credentials-set.png │ ├── snapback-credentials.png │ ├── snapback-schedule-snapshot-set.png │ ├── snapback-schedule-snapshot.png │ ├── snapback-snapshots-diffview1.png │ ├── snapback-snapshots-diffview2.png │ ├── snapback-snapshots-view.png │ ├── snapback-snapshots.png │ ├── snapback-versiondiffs.png │ ├── snapback-welcome.png │ ├── snapback.rst │ ├── stats.rst │ ├── stats │ ├── egrBytes.rst │ ├── egrDropPkts.rst │ ├── egrPkts.rst │ ├── egrTotal │ ├── egrTotal.rst │ ├── ingrBytes.rst │ ├── ingrDropPkts.rst │ ├── ingrPkts.rst │ ├── ingrStorm.rst │ ├── ingrTotal.rst │ ├── ingrUnkBytes.rst │ └── ingrUnkPkts.rst │ ├── statsbody.rst │ ├── statsdetail.rst │ ├── subscriptions.rst │ ├── switch-reports.png │ ├── tenant-reports.png │ ├── testharness.rst │ ├── tutorial.rst │ ├── tutorialpackages.rst │ ├── tutorialsetup.rst │ ├── tutorialsimpleconfig.rst │ ├── userabc.crt.png │ └── visualizations.rst ├── pylintrc ├── requirements.txt ├── samples ├── README.md ├── aci-add-static-binding-leaves.py ├── aci-add-tags.py ├── aci-attach-epg-to-interface.py ├── aci-attach-epgs-with-contract.py ├── aci-check-cluster.py ├── aci-copy-tenant-config.py ├── aci-create-bd.py ├── aci-create-bgp-peer.py ├── aci-create-epg.py ├── aci-create-microepg.py ├── aci-create-ospf-external.py ├── aci-create-phys-domain.py ├── aci-create-static-endpoint.py ├── aci-create-tenant.py ├── aci-create-vmw-domain.py ├── aci-delete-epgs-tag.py ├── aci-delete-tenants-tag.py ├── aci-delete-tenants.py ├── aci-demo-contract-interface.py ├── aci-demo-contract.py ├── aci-demo-portchannel.py ├── aci-demo-script.py ├── aci-endpoint-stats-tracker.py ├── aci-epg-reports-in-yaml.py ├── aci-find-ip.py ├── aci-get-interface-stats-from-nodes.py ├── aci-get-tenantObject-from-json.py ├── aci-raw-class-query.py ├── aci-show-all-filter-entries.py ├── aci-show-cdp.py ├── aci-show-contexts.py ├── aci-show-contracts.py ├── aci-show-domains.py ├── aci-show-endpoints.py ├── aci-show-epgs-tags.py ├── aci-show-epgs.py ├── aci-show-external-networks.py ├── aci-show-faults-by-domain.py ├── aci-show-filter-entries.py ├── aci-show-imported-contracts.py ├── aci-show-interface-stats.py ├── aci-show-interfaces.py ├── aci-show-ip-endpoints.py ├── aci-show-ip-int-brief.py ├── aci-show-lldp.py ├── aci-show-monitor-policy.py ├── aci-show-nodes.py ├── aci-show-phys-domains.py ├── aci-show-physical-inventory.py ├── aci-show-process.py ├── aci-show-subnets.py ├── aci-show-tenant-detail.py ├── aci-show-tenant-faults.py ├── aci-show-tenant-health.py ├── aci-show-tenants-in-multisite-orchestrator.py ├── aci-show-tenants-tags.py ├── aci-show-tenants.py ├── aci-show-vm-names.py ├── aci-spine-leaf-optics.py ├── aci-subscribe-tenants.py ├── aci-where-used.py ├── credentials.py.sample ├── switch-commands │ ├── README.md │ ├── aci-show-fex.py │ ├── aci-show-interface-description.py │ ├── aci-show-interface-fex.py │ ├── aci-show-interface.py │ ├── aci-show-port-channel-summary.py │ └── aci-show-vlan-ext.py └── tutorial.py ├── scripts └── install_dependencies ├── setup.py ├── shippable.yml └── tests ├── README.md ├── aciConcreteLib_test.py ├── aciTable_test.py ├── aci_configuration_randomizer.ini ├── aci_configuration_randomizer.py ├── aciphysobject_test.py ├── acitoolkit_fakeapic_test.py ├── acitoolkit_randomized_test.py ├── acitoolkit_test.py └── acitoolkitlib_test.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.egg-info 3 | .DS_STORE 4 | *.json 5 | *.csv 6 | .idea 7 | *.sqlite -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # VERSION 1.0 2 | FROM python:3.7.8-buster 3 | 4 | MAINTAINER Kevin Corbin, kecorbin@cisco.com, Updated by Quinn Snyder 5 | 6 | RUN apt-get update \ 7 | && apt-get -y install git graphviz-dev pkg-config python python-pip vim-tiny \ 8 | && cd /opt \ 9 | && git clone https://github.com/datacenter/acitoolkit \ 10 | && cd acitoolkit \ 11 | && python setup.py install \ 12 | && apt-get clean 13 | WORKDIR /opt/acitoolkit 14 | CMD ["/bin/bash"] 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2015 Cisco Systems, Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | acitoolkit uses the requests library. 2 | http://docs.python-requests.org/en/latest/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # acitoolkit [![Documentation Status](https://readthedocs.org/projects/acitoolkit/badge/?version=latest)](https://readthedocs.org/projects/acitoolkit/?badge=latest) [![Build Status](https://api.shippable.com/projects/54ea96315ab6cc13528d52ad/badge?branchName=master)](https://app.shippable.com/projects/54ea96315ab6cc13528d52ad/builds/latest) [![](https://img.shields.io/badge/License-Apache2-blue.svg)](https://img.shields.io/badge/License-Apache2-blue.svg) 2 | [![Join the chat at https://gitter.im/datacenter/acitoolkit](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/datacenter/acitoolkit?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 3 | 4 | 5 | # Description 6 | 7 | The ACI Toolkit is a set of python libraries that allow basic 8 | configuration of the Cisco APIC controller. It is intended to allow users to quickly begin using the REST API and accelerate the learning curve necessary to begin using the APIC. 9 | 10 | The full documentation is published at the following link: 11 | [http://datacenter.github.io/acitoolkit/](http://datacenter.github.io/acitoolkit/) 12 | 13 | 14 | # Installation 15 | 16 | ## Environment 17 | 18 | Required 19 | 20 | * Python 2.7+ 21 | * [setuptools package](https://pypi.python.org/pypi/setuptools) 22 | 23 | ## Downloading 24 | 25 | ### Option A: 26 | 27 | If you have git installed, clone the repository 28 | 29 | git clone https://github.com/datacenter/acitoolkit.git 30 | 31 | ### Option B: 32 | 33 | If you don't have git, [download a zip copy of the repository](https://github.com/datacenter/acitoolkit/archive/master.zip) and extract. 34 | 35 | ### Option C: 36 | 37 | The latest build of this project is also available as a Docker image from Docker Hub 38 | 39 | docker pull dockercisco/acitoolkit 40 | 41 | ## Installing 42 | 43 | After downloading, install using setuptools. 44 | 45 | cd acitoolkit 46 | python setup.py install 47 | 48 | If you plan on modifying the actual toolkit files, you should install the developer environment that will link the package installation to your development directory. 49 | 50 | cd acitoolkit 51 | python setup.py develop 52 | 53 | # Usage 54 | 55 | A tutorial and overview of the acitoolkit object model can be found in 56 | the Documentation section found at 57 | [http://datacenter.github.io/acitoolkit/](http://datacenter.github.io/acitoolkit/) 58 | 59 | 60 | # Using Docker Image 61 | 62 | ``` 63 | docker run -it --name acitoolkit dockercisco/acitoolkit 64 | ``` 65 | 66 | # License 67 | 68 | Copyright 2015 Cisco Systems, Inc. 69 | 70 | Licensed under the Apache License, Version 2.0 (the "License"); 71 | you may not use this file except in compliance with the License. 72 | You may obtain a copy of the License at 73 | 74 | http://www.apache.org/licenses/LICENSE-2.0 75 | 76 | Unless required by applicable law or agreed to in writing, software 77 | distributed under the License is distributed on an "AS IS" BASIS, 78 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 79 | See the License for the specific language governing permissions and 80 | limitations under the License. 81 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | Vagrant.configure(2) do |config| 9 | # The most common configuration options are documented and commented below. 10 | # For a complete reference, please see the online documentation at 11 | # https://docs.vagrantup.com. 12 | 13 | # Every Vagrant development environment requires a box. You can search for 14 | # boxes at https://atlas.hashicorp.com/search. 15 | config.vm.box = "ubuntu/trusty64" 16 | 17 | # Disable automatic box update checking. If you disable this, then 18 | # boxes will only be checked for updates when the user runs 19 | # `vagrant box outdated`. This is not recommended. 20 | # config.vm.box_check_update = false 21 | 22 | # Create a forwarded port mapping which allows access to a specific port 23 | # within the machine from a port on the host machine. In the example below, 24 | # accessing "localhost:8080" will access port 80 on the guest machine. 25 | # config.vm.network "forwarded_port", guest: 80, host: 8080 26 | 27 | # Create a private network, which allows host-only access to the machine 28 | # using a specific IP. 29 | # config.vm.network "private_network", ip: "192.168.33.10" 30 | 31 | # Create a public network, which generally matched to bridged network. 32 | # Bridged networks make the machine appear as another physical device on 33 | # your network. 34 | # config.vm.network "public_network" 35 | 36 | # Share an additional folder to the guest VM. The first argument is 37 | # the path on the host to the actual folder. The second argument is 38 | # the path on the guest to mount the folder. And the optional third 39 | # argument is a set of non-required options. 40 | # config.vm.synced_folder "../data", "/vagrant_data" 41 | 42 | # Provider-specific configuration so you can fine-tune various 43 | # backing providers for Vagrant. These expose provider-specific options. 44 | # Example for VirtualBox: 45 | # 46 | # config.vm.provider "virtualbox" do |vb| 47 | # # Display the VirtualBox GUI when booting the machine 48 | # vb.gui = true 49 | # 50 | # # Customize the amount of memory on the VM: 51 | # vb.memory = "1024" 52 | # end 53 | # 54 | # View the documentation for the provider you are using for more 55 | # information on available options. 56 | 57 | # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies 58 | # such as FTP and Heroku are also available. See the documentation at 59 | # https://docs.vagrantup.com/v2/push/atlas.html for more information. 60 | # config.push.define "atlas" do |push| 61 | # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME" 62 | # end 63 | 64 | # Enable provisioning with a shell script. Additional provisioners such as 65 | # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the 66 | # documentation for more information about their specific syntax and use. 67 | config.vm.provision "shell", inline: <<-SHELL 68 | sudo apt-get update 69 | sudo apt-get install python-pip -y 70 | sudo apt-get install git -y 71 | sudo apt-get install python-dev -y 72 | sudo apt-get install -y python-pygraphviz 73 | git clone https://github.com/datacenter/acitoolkit.git 74 | cd acitoolkit 75 | sudo python setup.py develop 76 | SHELL 77 | end 78 | -------------------------------------------------------------------------------- /acitoolkit/__about__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); 2 | # you may not use this file except in compliance with the License. 3 | # You may obtain a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | 13 | __all__ = [ 14 | "__title__", "__summary__", "__uri__", "__version__", "__author__", 15 | "__email__", "__license__", "__copyright__", 16 | ] 17 | 18 | __title__ = "acitoolkit" 19 | __summary__ = "Toolkit for Cisco ACI Fabrics" 20 | __uri__ = "http://datacenter.github.io/acitoolkit/" 21 | 22 | __version__ = "0.4" 23 | 24 | __author__ = "Cisco Systems, Inc." 25 | __email__ = "acitoolkit@external.cisco.com" 26 | 27 | __license__ = "Apache License, Version 2.0" 28 | __copyright__ = "2017 %s" % __author__ 29 | -------------------------------------------------------------------------------- /acitoolkit/__init__.py: -------------------------------------------------------------------------------- 1 | # Licensed under the Apache License, Version 2.0 (the "License"); 2 | # you may not use this file except in compliance with the License. 3 | # You may obtain a copy of the License at 4 | # 5 | # http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software 8 | # distributed under the License is distributed on an "AS IS" BASIS, 9 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | # See the License for the specific language governing permissions and 11 | # limitations under the License. 12 | """ 13 | __init__.py 14 | """ 15 | from .__about__ import ( # noqa 16 | __author__, __copyright__, __email__, __license__, __summary__, __title__, 17 | __uri__, __version__, 18 | ) 19 | 20 | _about_exports = [ 21 | "__author__", "__copyright__", "__email__", "__license__", "__summary__", 22 | "__title__", "__uri__", "__version__", 23 | ] 24 | 25 | from .acicounters import ( # noqa 26 | AtomicCounter, AtomicCountersOnGoing, AtomicNode, AtomicPath, 27 | InterfaceStats, 28 | ) 29 | from .aciHealthScore import HealthScore # noqa 30 | from .aciFaults import (Faults) # noqa 31 | from .aciSearch import AciSearch, Searchable # noqa 32 | from .acisession import EventHandler, Login, Session, Subscriber, CredentialsError # noqa 33 | from .aciTable import Table # noqa 34 | from .acibaseobject import BaseACIObject, BaseRelation 35 | from .acitoolkit import ( # noqa 36 | AnyEPG, AppProfile, AttributeCriterion, BaseContract, 37 | BGPSession, BridgeDomain, CollectionPolicy, 38 | CommonEPG, Context, Contract, ContractInterface, ContractSubject, Endpoint, 39 | EPG, EPGDomain, FexInterface, Filter, FilterEntry, IPEndpoint, InputTerminal, 40 | L2ExtDomain, L2Interface, L3ExtDomain, L3Interface, LogicalModel, MonitorPolicy, 41 | MonitorStats, MonitorTarget, NetworkPool, OSPFInterface, 42 | OSPFInterfacePolicy, OSPFRouter, OutputTerminal, OutsideEPG, 43 | OutsideL2, OutsideL2EPG, OutsideL3, OutsideNetwork, 44 | PhysDomain, PortChannel, Search, Subnet, Taboo, Tenant, TunnelInterface, 45 | VMM, VMMCredentials, VmmDomain, VMMvSwitchInfo, Tag, _interface_from_dn 46 | ) 47 | from .acitoolkitlib import Credentials, AcitoolkitGraphBuilder # noqa 48 | from .acifakeapic import FakeSession # noqa 49 | # Dependent on acitoolkit 50 | from .aciConcreteLib import ( # noqa 51 | ConcreteAccCtrlRule, ConcreteArp, ConcreteBD, ConcreteContext, ConcreteEp, 52 | ConcreteFilter, ConcreteFilterEntry, ConcreteLoopback, ConcreteOverlay, 53 | ConcretePortChannel, ConcreteSVI, ConcreteVpc, ConcreteVpcIf, 54 | ConcreteTunnel, ConcreteCdp 55 | ) 56 | # Dependent on aciconcretelib 57 | from .aciphysobject import ( # noqa 58 | Cluster, ExternalSwitch, Fabric, Fan, Fantray, Interface, Linecard, Link, 59 | Node, PhysicalModel, Pod, Powersupply, Process, Supervisorcard, 60 | Systemcontroller, WorkingData, 61 | ) 62 | 63 | import inspect as _inspect 64 | 65 | __all__ = _about_exports + sorted( 66 | name for name, obj in locals().items() 67 | if not (name.startswith('_') or _inspect.ismodule(obj)) 68 | ) 69 | -------------------------------------------------------------------------------- /applications/aci-diagram/README.md: -------------------------------------------------------------------------------- 1 | # ACI Diagram generator 2 | 3 | This is a simple tool to connect to a Cisco ACI Application Policy Infrastructure Controller using the [acitoolkit](http://github.com/datacenter/acitoolkit) library, interrogate the configuration and generate logical diagrams. 4 | 5 | ##Installation 6 | ###Requirements 7 | - GraphViz and the python wrapper PyGraphViz. 8 | 9 | On MacOS, the easiest way to install the GraphViz requirements is (assuming you have HomeBrew and pip setup): 10 | 11 | ```bash 12 | brew install graphviz 13 | pip install pygraphviz 14 | ``` 15 | 16 | Installation instructions for the acitoolkit are [here](http://github.com/datacenter/acitoolkit) 17 | 18 | 19 | ##Usage 20 | 21 | The usage is simple - the login (username), password and URL arguments are optional, but you will be prompted to enter them if they are not provided on the command line. By default the tool will include all tenants on the APIC in the diagram, but you can restrict this to a subset of tenants using the `-t` argument. 22 | 23 | 24 | ``` 25 | usage: diagram.py [-h] [-l LOGIN] [-p PASSWORD] [-u URL] -o OUTPUT 26 | [-t [TENANTS [TENANTS ...]]] [-v] 27 | 28 | Generate logical diagrams of a running Cisco ACI Application Policy 29 | Infrastructure Controller 30 | 31 | optional arguments: 32 | -h, --help show this help message and exit 33 | -l LOGIN, --login LOGIN 34 | Login for authenticating to APIC 35 | -p PASSWORD, --password PASSWORD 36 | Password for authenticating to APIC 37 | -u URL, --url URL URL for connecting to APIC 38 | -o OUTPUT, --output OUTPUT 39 | Output file for diagram - e.g. out.png, out.jpeg 40 | -t [TENANTS [TENANTS ...]], --tenants [TENANTS [TENANTS ...]] 41 | Tenants to include when generating diagrams 42 | -v, --verbose show verbose logging information 43 | ``` 44 | 45 | -------------------------------------------------------------------------------- /applications/cableplan/.coverage: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/cableplan/.coverage -------------------------------------------------------------------------------- /applications/cli/test_cli.txt: -------------------------------------------------------------------------------- 1 | show bridgedomain 2 | show tenant 3 | show app 4 | show epg 5 | show interface 6 | show context 7 | show invalid 8 | show infradomains 9 | help show 10 | ? 11 | config t 12 | interface eth 1/101/1/65 13 | speed 1G 1G 14 | speed 1000G 15 | speed 100M 16 | no speed 100M 17 | speed 10G 18 | epg 19 | epg epg1 20 | exit 21 | bridgedomain 22 | bridgedomain bd1 bd2 23 | bridgedomain bd1 24 | context 25 | context ctx1 26 | context ctx1 ctx2 27 | no context ctx1 28 | contract contract1 29 | show contract 30 | app app1 31 | tenant 32 | tenant acitoolkit acitoolkit 33 | tenant acitoolkit 34 | no tenant acitoolkit 35 | tenant acitoolkit 36 | exit 37 | switchto acitoolkit 38 | config t 39 | interface eth 1/101/1/65 40 | exit 41 | exit 42 | switchback acitoolkit 43 | switchback 44 | no switchto acitoolkit 45 | switchto 46 | switchto acitoolkit acitoolkit 47 | switchto dlfkdjflshf 48 | switchto acitoolkit 49 | conf t 50 | bridgedomain bd1 51 | ip 52 | ip address 53 | ip address address address 54 | ip address 1.2.3.4/24 55 | no ip address 1.2.3.4/24 56 | show bridgedomain 57 | show tenant 58 | show app 59 | show epg 60 | show interface 61 | show port-channel 62 | show context 63 | show contract 64 | exit 65 | no bridgedomain bd1 66 | context ctx 67 | allowall 68 | no allowall 69 | exit 70 | no context ctx 71 | contract contract1 contract2 72 | contract contract1 73 | exit 74 | no contract contract1 75 | app 76 | app app1 app2 77 | app app1 78 | epg 79 | epg epg1 epg2 80 | epg epg1 81 | bridgedomain 82 | bridgedomain bd1 bd2 83 | bridgedomain bd1 84 | no bridgedomain bd1 85 | exit 86 | no epg epg2 87 | exit 88 | interface eth 1/101/1/65 89 | epg app1/epg1 vlan 1 90 | exit 91 | app app1 92 | no epg epg1 93 | exit 94 | no app app1 95 | no tenant acitoolkit 96 | exit 97 | exit 98 | 99 | 100 | -------------------------------------------------------------------------------- /applications/configpush/apic_rest_server.py: -------------------------------------------------------------------------------- 1 | """ 2 | Application to allow the configuration push to run as a REST service 3 | """ 4 | from flask import Flask, request, abort, make_response, jsonify 5 | from apicservice import execute_tool, get_arg_parser 6 | import json 7 | import logging 8 | from flask.ext.httpauth import HTTPBasicAuth 9 | 10 | DEFAULT_PORT = '5000' 11 | DEFAULT_IPADDRESS = '127.0.0.1' 12 | DEFAULT_USERNAME = 'admin' 13 | DEFAULT_PASSWORD = 'acitoolkit' 14 | 15 | auth = HTTPBasicAuth() 16 | 17 | parser = get_arg_parser() 18 | parser.add_argument('--ip', 19 | default=DEFAULT_IPADDRESS, 20 | help='IP address to listen on.') 21 | parser.add_argument('--port', 22 | default=DEFAULT_PORT, 23 | help='Port number to listen on.') 24 | 25 | args = parser.parse_args() 26 | app = Flask(__name__) 27 | tool = execute_tool(args) 28 | 29 | 30 | @auth.get_password 31 | def get_password(username): 32 | """ 33 | Get the password for the specified username 34 | :param username: String containing the username 35 | :return: String containing the user's password. None if not found. 36 | """ 37 | if username == DEFAULT_USERNAME: 38 | return DEFAULT_PASSWORD 39 | return None 40 | 41 | 42 | @auth.error_handler 43 | def unauthorized(): 44 | """ 45 | Handle unauthorized access attempts 46 | :return: 401 Error Response 47 | """ 48 | return make_response(jsonify({'error': 'Unauthorized access'}), 401) 49 | 50 | 51 | # @app.route('/config', methods=['GET']) 52 | # @auth.login_required 53 | # def get_config(): 54 | # return json.dumps(tool.get_config(), indent=4, separators=(',', ':')) 55 | 56 | 57 | @app.route('/config', methods=['POST', 'PUT']) 58 | @auth.login_required 59 | def set_config(): 60 | """ 61 | Push the actual JSON configuration 62 | :return: 200 Response code if successful. 400 error response otherwise 63 | """ 64 | logging.debug('PUT /config request received %s', request.data) 65 | if not request.json: 66 | logging.error('Request is not proper json: %s %s %s %s', 67 | request, dir(request), 68 | request.data, request.content_type) 69 | abort(400) 70 | try: 71 | resp = tool.add_config(request.json) 72 | except ValueError: 73 | abort(400, 'Name too large') 74 | if resp != 'OK': 75 | logging.error('Response is not ok') 76 | abort(400) 77 | # tool.reload_config() 78 | return json.dumps({'Status': 'OK'}, indent=4, separators=(',', ':')) 79 | 80 | if __name__ == '__main__': 81 | app.run(debug=False, host=args.ip, port=int(args.port)) 82 | -------------------------------------------------------------------------------- /applications/configpush/configpush_test1_policies.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/configpush/configpush_test1_policies.json.gz -------------------------------------------------------------------------------- /applications/configpush/configpush_test1_policies_tenant_golden.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/configpush/configpush_test1_policies_tenant_golden.json.gz -------------------------------------------------------------------------------- /applications/configpush/configpush_test1_policies_with_useipEpgs_tenant_golden.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/configpush/configpush_test1_policies_with_useipEpgs_tenant_golden.json.gz -------------------------------------------------------------------------------- /applications/configpush/configpush_test2_policies.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/configpush/configpush_test2_policies.json.gz -------------------------------------------------------------------------------- /applications/configpush/configpush_test2_policies_tenant_golden.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/configpush/configpush_test2_policies_tenant_golden.json.gz -------------------------------------------------------------------------------- /applications/configpush/configpush_test2_policies_with_useipEpgs_tenant_golden.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/configpush/configpush_test2_policies_with_useipEpgs_tenant_golden.json.gz -------------------------------------------------------------------------------- /applications/configpush/configpush_test3_policies.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/configpush/configpush_test3_policies.json.gz -------------------------------------------------------------------------------- /applications/configpush/configpush_test3_policies_tenant_golden.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/configpush/configpush_test3_policies_tenant_golden.json.gz -------------------------------------------------------------------------------- /applications/configpush/configpush_test3_policies_with_useipEpgs_tenant_golden.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/configpush/configpush_test3_policies_with_useipEpgs_tenant_golden.json.gz -------------------------------------------------------------------------------- /applications/configpush/configpush_test4_policies.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/configpush/configpush_test4_policies.json.gz -------------------------------------------------------------------------------- /applications/configpush/configpush_test4_policies_tenant_golden.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/configpush/configpush_test4_policies_tenant_golden.json.gz -------------------------------------------------------------------------------- /applications/configpush/configpush_test4_policies_with_useipEpgs_tenant_golden.json.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/applications/configpush/configpush_test4_policies_with_useipEpgs_tenant_golden.json.gz -------------------------------------------------------------------------------- /applications/connection_search/Forms.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ################################################################################ 3 | # # 4 | # Copyright (c) 2015 Cisco Systems # 5 | # All Rights Reserved. # 6 | # # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); you may # 8 | # not use this file except in compliance with the License. You may obtain # 9 | # a copy of the License at # 10 | # # 11 | # http://www.apache.org/licenses/LICENSE-2.0 # 12 | # # 13 | # Unless required by applicable law or agreed to in writing, software # 14 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # 15 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # 16 | # License for the specific language governing permissions and limitations # 17 | # under the License. # 18 | # # 19 | ################################################################################ 20 | """ 21 | Forms for report GUI 22 | """ 23 | from flask_wtf import Form 24 | from wtforms import StringField, SubmitField, PasswordField, BooleanField 25 | from wtforms import TextAreaField, SelectField 26 | from wtforms.validators import IPAddress 27 | 28 | __author__ = 'edsall' 29 | 30 | 31 | class FeedbackForm(Form): 32 | """ 33 | Form data for feedback 34 | """ 35 | 36 | def generate_csrf_token(self, csrf_context): 37 | """ 38 | 39 | :param csrf_context: 40 | """ 41 | pass 42 | 43 | category = SelectField('', choices=[('bug', 'Bug'), 44 | ('enhancement', 'Enhancement Request'), 45 | ('question', 'General Question'), 46 | ('comment', 'General Comment')]) 47 | comment = TextAreaField('Comment') 48 | submit = SubmitField('Submit') 49 | 50 | 51 | class CredentialsForm(Form): 52 | """ 53 | class to hold the form definition for the credentials 54 | """ 55 | ipaddr = StringField('APIC IP Address:', 56 | validators=[IPAddress()]) 57 | secure = BooleanField('Use secure connection', validators=[]) 58 | username = StringField('APIC Username:', validators=[]) 59 | password = PasswordField('APIC Password:', validators=[]) 60 | submit = SubmitField('Save') 61 | 62 | 63 | class ResetForm(Form): 64 | """ 65 | Reset form 66 | """ 67 | reset = SubmitField('Reset') 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /applications/connection_search/static/connectionSearch.css: -------------------------------------------------------------------------------- 1 | table{ 2 | border-collapse:collapse; 3 | } 4 | 5 | tr.border_bottom th { 6 | border-bottom:2pt solid black; 7 | 8 | }.connectionTable { 9 | border-spacing: 15px; 10 | } 11 | 12 | .connectionTable td { 13 | padding:15px; 14 | } 15 | 16 | .connectionTable tr { 17 | padding:15px; 18 | } 19 | 20 | .blank-row { 21 | margin-top: 10px; 22 | } 23 | .ac-holder { 24 | position: relative; 25 | } 26 | .record_summary { 27 | line-height: 0.7; 28 | } 29 | 30 | .record_title { 31 | font-size:larger; 32 | } 33 | .ac-dropdown { 34 | border-color: #ececec; 35 | border-width: 1px; 36 | border-style: solid; 37 | border-radius: 2px; 38 | width: 250px; 39 | padding: 6px; 40 | cursor: pointer; 41 | z-index: 9999; 42 | position: absolute; 43 | /*top: 32px; 44 | left: 0px; 45 | */ 46 | margin-top: -6px; 47 | background-color: #ffffff; 48 | } 49 | .ac-form-control { 50 | outline: 0; 51 | border-color: #ECECEC; 52 | border-style: solid; 53 | border-width: 1px; 54 | width: 50%; 55 | background-color: #ffffff; 56 | padding: 6px; 57 | border-radius: 2px; 58 | margin-bottom: 0px; 59 | font-size: 14px; 60 | } 61 | .ac-submit-control { 62 | margin-bottom: 10px; 63 | } 64 | .ac-form-control-small { 65 | width: 72%; 66 | } 67 | 68 | .ac-form-control:-webkit-autofill { 69 | background-color: #fff !important; 70 | } 71 | 72 | .input:-webkit-autofill { 73 | -webkit-box-shadow: 0 0 0px 100px white inset; 74 | } 75 | 76 | .ac-searching { 77 | color: #acacac; 78 | font-size: 14px; 79 | } 80 | 81 | .ac-hint { 82 | color: #acacac; 83 | font-size: 10px; 84 | } 85 | .ac-row { 86 | padding: 5px; 87 | color: #000000; 88 | margin-bottom: 4px; 89 | 90 | } 91 | 92 | .ac-selected-row, .ac-row:hover { 93 | background-color: lightblue; 94 | color: #ffffff; 95 | } 96 | 97 | .ac-highlight { 98 | font-weight:bold; 99 | color: #0000FF; 100 | } 101 | 102 | div.tooltip { 103 | position: absolute; 104 | text-align: center; 105 | /*width: 60px;*/ 106 | /*height: 28px;*/ 107 | padding: 2px; 108 | font: 12px sans-serif; 109 | background: cyan; 110 | border: 0px; 111 | border-radius: 5px; 112 | pointer-events: none; 113 | } -------------------------------------------------------------------------------- /applications/connection_search/static/layout.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #EEE; 3 | } 4 | 5 | #content { 6 | background: white; 7 | border: 1px solid #CCC; 8 | padding: 12px; 9 | overflow: scroll; 10 | } 11 | 12 | #brand { 13 | float: left; 14 | font-weight: 300; 15 | margin: 0; 16 | } 17 | 18 | .search-form { 19 | margin: 0 5px; 20 | } 21 | 22 | .search-form form { 23 | margin: 0; 24 | } 25 | 26 | .btn-menu { 27 | margin: 4px 5px 0 0; 28 | float: right; 29 | } 30 | 31 | .btn-menu a, .btn-menu input { 32 | padding: 7px 16px !important; 33 | border-radius: 0 !important; 34 | } 35 | 36 | .btn, textarea, input[type], button, .model-list { 37 | border-radius: 0; 38 | } 39 | 40 | .model-list { 41 | border-radius: 0; 42 | } 43 | 44 | .nav-pills li > a { 45 | border-radius: 0; 46 | } 47 | 48 | .select2-container .select2-choice { 49 | border-radius: 0; 50 | } 51 | -------------------------------------------------------------------------------- /applications/connection_search/templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% block body %} 3 |
4 |

ReportView

5 |

Beta Version 0.1

6 |

aciConSearch is a GUI application for searching connections the ACI policy configuration.

7 | 8 |

License

9 |

Copyright 2015 Cisco Systems, Inc.

10 | 11 |

Licensed under the Apache License, Version 2.0 (the "License"); 12 | you may not use this file except in compliance with the License. 13 | You may obtain a copy of the License at

14 | 15 |
http://www.apache.org/licenses/LICENSE-2.0
16 | 
17 | 18 |

Unless required by applicable law or agreed to in writing, software 19 | distributed under the License is distributed on an "AS IS" BASIS, 20 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 | See the License for the specific language governing permissions and 22 | limitations under the License.

23 | 24 |

Authors

25 |

Tom Edsall edsall@cisco.com

26 | {% endblock %} 27 | -------------------------------------------------------------------------------- /applications/connection_search/templates/admin/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% block body %} 3 | {{ super() }} 4 |
5 |

Search View

6 |

7 | Connection Search Viewer for ACI fabric 8 |

9 |

Beta v0.1

10 |
11 | {% endblock body %} -------------------------------------------------------------------------------- /applications/connection_search/templates/credentials.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block body %} 4 |

Enter the Credentials used to communicate with the APIC.

5 |
6 | {{ wtf.quick_form(form, form_type='horizontal', 7 | horizontal_columns=('lg', 2, 2)) }} 8 | {% if ipaddr %} 9 |
10 |

Current Settings 11 |
APIC Username: {{ username }} 12 |
APIC IP Address: {{ ipaddr }} 13 |
Secure Connection: {{ security }}

14 | {{ wtf.quick_form(reset_form) }} 15 | {% endif %} 16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /applications/connection_search/templates/feedback.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block body %} 4 |

We welcome comments and suggestions on how we can make this tool 5 | better.
Please feel free to provide any constructive feedback below.

6 |
7 | {{ wtf.form_field(form.category) }} 8 | {{ wtf.form_field(form.comment) }} 9 | {{ wtf.form_field(form.submit) }} 10 |
11 | 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /applications/connection_search/templates/layout.html: -------------------------------------------------------------------------------- 1 | {% import 'admin/layout.html' as layout with context -%} 2 | {% extends 'admin/base.html' %} 3 | 4 | {% block head_tail %} 5 | {{ super() }} 6 | 7 | {% endblock %} 8 | 9 | {% block page_body %} 10 |
11 |
12 |
13 | 17 |
18 |
19 |
20 | {% block brand %} 21 |

{{ admin_view.name|capitalize }}

22 |
23 | {% endblock %} 24 | {{ layout.messages() }} 25 | {% block body %}{% endblock %} 26 |
27 |
28 |
29 |
30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /applications/endpointtracker/README.md: -------------------------------------------------------------------------------- 1 | Documentation for this application can be found [here](http://datacenter.github.io/acitoolkit/docsbuild/html/endpointtracker.html) 2 | -------------------------------------------------------------------------------- /applications/endpointtracker/templates/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | ACI Endpoint Tracker 7 | 8 | 9 | 10 | 11 | 12 | 13 | 36 | 37 |

ACI Endpoint Tracker

38 | 39 | 40 |
41 | 42 | 43 | 44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | {{ data|safe }} 75 | 76 |
MacIPTenantAppEPGInterfaceTime StartTime Stop
MacIPTenantAppEPGInterfaceTime StartTime Stop
77 | 78 |
79 | 80 | 86 | 87 | -------------------------------------------------------------------------------- /applications/eventfeeds/.gitignore: -------------------------------------------------------------------------------- 1 | *.json 2 | *.log 3 | *.db -------------------------------------------------------------------------------- /applications/eventfeeds/templates/config.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Configure EventFeeds - ACI Toolkit 6 | 7 | 8 | 9 |
10 |
11 |
12 | {% if config_saved %}{% endif %} 13 |

EventFeeds: ACI Events to Atom Feed Configuration

14 |

Online Documentation

15 | 16 |
17 |
18 | Record Events For... 19 |
20 | 21 | {% for cls in eligible_classes %} 22 |
23 | {% if cls in selected_classes %} 24 | 29 | {% else %} 30 | 34 | {% endif %} 35 |
36 | {% endfor %} 37 |
38 | 39 | Configuration Files 40 |
41 | 42 |
43 |
47 |
48 |
49 |
53 |
54 |
55 | 56 |
57 | 58 |
59 | 60 |
61 |
62 |
63 |
64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /applications/eventfeeds/templates/feeds.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | EventFeeds - ACI Toolkit 6 | 7 | 13 | 14 | 15 |
16 |
17 |
18 |

EventFeeds - Available Feeds

19 |

Online Documentation

20 |

Configuration

21 | 22 | 33 |
34 |

Class Specific

35 | 36 | {% for cls in selected_classes %} 37 |

{{ cls }}

38 | 46 | {% endfor %} 47 |
48 |
49 |
50 |
51 | 52 | 53 | -------------------------------------------------------------------------------- /applications/inheritance/inheritance_apic_credentials.ini: -------------------------------------------------------------------------------- 1 | [Credentials] 2 | Username: admin 3 | Password: password 4 | URL: http://0.0.0.0 5 | 6 | -------------------------------------------------------------------------------- /applications/inheritance/inheritance_rest_server.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, abort, make_response, jsonify 2 | from inheritance import execute_tool, get_arg_parser 3 | import json 4 | import logging 5 | from flask.ext.httpauth import HTTPBasicAuth 6 | 7 | DEFAULT_PORT = '5000' 8 | DEFAULT_IPADDRESS = '127.0.0.1' 9 | 10 | auth = HTTPBasicAuth() 11 | 12 | parser = get_arg_parser() 13 | parser.add_argument('--ip', 14 | default=DEFAULT_IPADDRESS, 15 | help='IP address to listen on.') 16 | parser.add_argument('--port', 17 | default=DEFAULT_PORT, 18 | help='Port number to listen on.') 19 | 20 | args = parser.parse_args() 21 | app = Flask(__name__) 22 | tool = execute_tool(args) 23 | 24 | @auth.get_password 25 | def get_password(username): 26 | if username == 'admin': 27 | return 'acitoolkit' 28 | return None 29 | 30 | 31 | @auth.error_handler 32 | def unauthorized(): 33 | return make_response(jsonify({'error': 'Unauthorized access'}), 401) 34 | 35 | 36 | @app.route('/config', methods=['GET']) 37 | @auth.login_required 38 | def get_config(): 39 | return json.dumps(tool.get_config(), indent=4, separators=(',', ':')) 40 | 41 | 42 | @app.route('/config', methods=['POST', 'PUT']) 43 | @auth.login_required 44 | def set_config(): 45 | logging.debug('PUT /config request received %s', request.data) 46 | if not request.json: 47 | logging.error('Request is not proper json: %s %s %s %s', request, dir(request), request.data, request.content_type) 48 | abort(400) 49 | resp = tool.add_config(request.json) 50 | if resp != 'OK': 51 | logging.error('Response is not ok') 52 | abort(400) 53 | # tool.reload_config() 54 | return json.dumps({'Status': 'OK'}, indent=4, separators=(',', ':')) 55 | 56 | if __name__ == '__main__': 57 | app.run(debug=False, host=args.ip, port=int(args.port)) 58 | -------------------------------------------------------------------------------- /applications/inheritance/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-04/schema#", 3 | "id": "/", 4 | "type": "object", 5 | "title": "Inheritance schema.", 6 | "description": "Top-level object contains the set of all inheritance policies and the APIC policy.", 7 | "definitions": { 8 | "epg": { 9 | "type": "object", 10 | "properties": { 11 | "tenant": { 12 | "id": "tenant", 13 | "type": "string", 14 | "title": "Tenant name" 15 | }, 16 | "epg_container": { 17 | "id": "epg_container", 18 | "type": "object", 19 | "title": "EPG Container", 20 | "properties": { 21 | "name": { "type": "string" }, 22 | "container_type": { "type": "string", 23 | "enum": ["app", "l3out"]} 24 | }, 25 | "required": ["name", "container_type"] 26 | }, 27 | "name": { 28 | "id": "name", 29 | "type": "string", 30 | "title": "EPG name" 31 | } 32 | }, 33 | "required": ["tenant", "epg_container", "name"] 34 | } 35 | }, 36 | "properties": { 37 | "apic": { 38 | "id": "apic", 39 | "type": "object", 40 | "title": "APIC schema.", 41 | "description": "Credentials used to login to APIC", 42 | "properties": { 43 | "user_name": { 44 | "id": "user_name", 45 | "type": "string", 46 | "title": "APIC user name" 47 | }, 48 | "password": { 49 | "id": "user_name", 50 | "type": "string", 51 | "title": "APIC user name" 52 | }, 53 | "ip_address": { 54 | "id": "ip_address", 55 | "type": "string", 56 | "format": "ipv4", 57 | "description": "APIC IP address", 58 | "title": "APIC IP address" 59 | }, 60 | "use_https": { 61 | "id": "use_https", 62 | "type": "boolean", 63 | "description": "Use HTTPS to communicate with APIC", 64 | "title": "Use HTTPS to communicate with APIC" 65 | } 66 | }, 67 | "required": ["user_name", "ip_address", "password", "use_https"] 68 | }, 69 | "inheritance_policies": { 70 | "type": "array", 71 | "items": { 72 | "type": "object", 73 | "title": "Inheritance Policy schema.", 74 | "description": "Inheritance Policy", 75 | "properties": { 76 | "epg": { 77 | "$ref": "#/definitions/epg" 78 | }, 79 | "allowed": { 80 | "id": "allowed", 81 | "type": "boolean", 82 | "description": "Allow inheritance of this EPG", 83 | "title": "allowed" 84 | }, 85 | "enabled": { 86 | "id": "enabled", 87 | "type": "boolean", 88 | "description": "Enable inheritance on this EPG", 89 | "title": "enabled" 90 | }, 91 | "inherit_from": { 92 | "$ref": "#/definitions/epg" 93 | } 94 | }, 95 | "required": [ 96 | "epg", 97 | "allowed", 98 | "enabled" 99 | ] 100 | } 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /applications/intraepg/intraepg_templates.py: -------------------------------------------------------------------------------- 1 | """ 2 | Ansible templates used by intraepg.py 3 | """ 4 | HOSTS_TEMPLATE = """ 5 | [acihosts] 6 | {{ all_host_ip }} 7 | 8 | [newhost] 9 | {{ new_host_ip }} 10 | """ 11 | 12 | MY_PLAYBOOK = """ 13 | --- 14 | - name: Configure new hosts 15 | hosts: newhost 16 | user: {{ user_name }} 17 | sudo: yes 18 | tasks: 19 | 20 | # Install and configure ferm. 21 | # 22 | 23 | # We need to install libselinux-python on the target 24 | # machine to be able to use Ansible to copy the ferm.conf 25 | # file to the /etc/ferm/ directory. 26 | - name: install python-selinux 27 | apt: name=python-selinux 28 | state=present 29 | 30 | - name: install ferm 31 | apt: name=ferm 32 | state=present 33 | 34 | - name: install arptables 35 | apt: name=arptables 36 | state=present 37 | 38 | - name: install ebtables 39 | apt: name=ebtables 40 | state=present 41 | 42 | - name: install conntrack 43 | apt: name=conntrack 44 | state=present 45 | 46 | - name: add /etc/ferm directory 47 | file: path=/etc/ferm 48 | mode=0700 49 | state=directory 50 | 51 | - name: Configure ferm 52 | hosts: acihosts 53 | user: {{ user_name }} 54 | sudo: yes 55 | tasks: 56 | 57 | - name: add the ferm.conf file to /etc/ferm 58 | copy: src={{ ferm_conf }} 59 | dest=/etc/ferm/ferm.conf 60 | notify: run ferm 61 | 62 | handlers: 63 | - name: run ferm 64 | command: ferm /etc/ferm/ferm.conf 65 | notify: save iptables 66 | 67 | - name: save iptables 68 | command: iptables-save 69 | """ -------------------------------------------------------------------------------- /applications/lint/README.md: -------------------------------------------------------------------------------- 1 | Documentation for this application can be found [here](http://datacenter.github.io/acitoolkit/docsbuild/html/acilint.html) 2 | -------------------------------------------------------------------------------- /applications/multisite/README.md: -------------------------------------------------------------------------------- 1 | Documentation for this application can be found [here](http://acitoolkit.readthedocs.org/en/latest/intersite.html) 2 | -------------------------------------------------------------------------------- /applications/multisite/intersite_rest_server.py: -------------------------------------------------------------------------------- 1 | """ 2 | REST API service wrapper for the Intersite tool 3 | """ 4 | from flask import Flask, request, abort, make_response, jsonify 5 | from intersite import execute_tool, get_arg_parser 6 | import json 7 | from flask.ext.httpauth import HTTPBasicAuth 8 | from flask_cors import CORS 9 | import tempfile 10 | 11 | DEFAULT_PORT = '5000' 12 | DEFAULT_IPADDRESS = '127.0.0.1' 13 | 14 | auth = HTTPBasicAuth() 15 | 16 | parser = get_arg_parser() 17 | parser.add_argument('--ip', 18 | default=DEFAULT_IPADDRESS, 19 | help='IP address to listen on.') 20 | parser.add_argument('--port', 21 | default=DEFAULT_PORT, 22 | help='Port number to listen on.') 23 | 24 | args = parser.parse_args() 25 | collector = execute_tool(args, test_mode=True) 26 | app = Flask(__name__) 27 | 28 | # Enable Cross-Origin-Resource-Sharing (CORS) 29 | CORS(app) 30 | 31 | @auth.get_password 32 | def get_password(username): 33 | """ 34 | Get the password 35 | :param username: String containing the username 36 | :return: String containing the password for the user or None if the user does not exist 37 | """ 38 | if username == 'admin': 39 | return 'acitoolkit' 40 | return None 41 | 42 | 43 | @auth.error_handler 44 | def unauthorized(): 45 | """ 46 | Error handler for attempted unauthorized access 47 | :return: 401 Error Response 48 | """ 49 | return make_response(jsonify({'error': 'Unauthorized access'}), 401) 50 | 51 | 52 | @app.route('/config', methods=['GET']) 53 | @auth.login_required 54 | def get_config(): 55 | """ 56 | Get the current configuration 57 | :return: JSON dictionary containing the current configuration 58 | """ 59 | if collector: 60 | return json.dumps(collector.config.get_config(), indent=4, separators=(',', ':')) 61 | else: 62 | return json.dumps({}, indent=4, separators=(',', ':')) 63 | 64 | 65 | 66 | @app.route('/config', methods=['POST', 'PUT']) 67 | @auth.login_required 68 | def set_config(): 69 | """ 70 | Set the current configuration 71 | 72 | If the collector has not been previously initialized (due to no configuration at start up) 73 | a new configuration file is written to disk and then passed to a new instance of 74 | the collector 75 | 76 | :return: JSON dictionary with a Status of OK if successful 77 | """ 78 | global collector 79 | if not request.json: 80 | abort(400) 81 | if not collector: 82 | buffer = tempfile.NamedTemporaryFile(delete=False) 83 | buffer.write(json.dumps(request.json)) 84 | buffer.close() 85 | 86 | args.config = buffer.name 87 | collector = execute_tool(args, test_mode=True) 88 | else: 89 | resp = collector.save_config(request.json) 90 | if resp != 'OK': 91 | abort(400) 92 | collector.reload_config() 93 | return json.dumps({'Status': 'OK'}, indent=4, separators=(',', ':')) 94 | 95 | if __name__ == '__main__': 96 | app.run(debug=False, host=args.ip, port=int(args.port)) 97 | -------------------------------------------------------------------------------- /applications/object_browser/static/style.css: -------------------------------------------------------------------------------- 1 | body { font-family: sans-serif; background: #eee; } 2 | a, h1, h2 { color: #377ba8; } 3 | h1, h2 { font-family: 'Georgia', serif; margin: 0; } 4 | h1 { border-bottom: 2px solid #eee; } 5 | h2 { font-size: 1.2em; } 6 | 7 | .page { margin: 2em auto; width: 55em; border: 5px solid #ccc; 8 | padding: 0.8em; background: white; } 9 | .mo { list-style: none; margin: 0; padding: 0; } 10 | .mo li { margin: 0.8em 1.2em; } 11 | .mo li h2 { margin-left: -1em; } 12 | .class-object { font-size: 0.9em; border-bottom: 1px solid #ccc; } 13 | .class-object dl { font-weight: bold; } 14 | .metanav { text-align: right; font-size: 0.8em; padding: 0.3em; 15 | margin-bottom: 1em; background: #fafafa; } 16 | .flash { background: #cee5F5; padding: 0.5em; 17 | border: 1px solid #aacbe2; } 18 | .error { background: #f0d6d6; padding: 0.5em; } 19 | -------------------------------------------------------------------------------- /applications/object_browser/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | ACI 3 | 4 |
5 |

ACI Object Browser

6 | {% for message in get_flashed_messages() %} 7 |
{{ message }}
8 | {% endfor %} 9 |
10 |
11 | 16 | 17 |
18 |
19 |
20 |
21 | 22 |
23 |
24 |
25 |
Class: 26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
MO: 35 |
36 |
37 |
38 |
39 |
40 | 41 | 42 |
43 | 44 | 45 | {% block body %}{% endblock %} 46 |
47 | -------------------------------------------------------------------------------- /applications/object_browser/templates/show_class.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 14 | {% endblock %} -------------------------------------------------------------------------------- /applications/object_browser/templates/show_mo.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | {% block body %} 3 | 7 |
8 | 35 |
36 | 48 |
49 | 61 | {% endblock %} -------------------------------------------------------------------------------- /applications/reports/static/d3-tablesort.css: -------------------------------------------------------------------------------- 1 | .sort_indicator.sort_asc { 2 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAAEIAAABCAWq6kEQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAXZJREFUOE+lkbtOAlEQhjHGYGKCCZ1PYHwHa9/CKBdXUIwiVsKy7J29r4AI4gvY2GxhaeMLAFJo4QsYtbKhYJyjy4aF06CbfMmcf2f+/HNOBAD+BVWcB6o4D1RxHiKe51HZSWxHC2f5x9zRQZn2fwxVJODgre2aI1VTPveY1Bath0AVmUw6oxvalyhXoKrLwJaLr5goTuudEZKp3XXD1N/cmg2SIoAgcWBaOuQLJw/TvYTQgezNcqXn9nULiIFlG6BqEhrxpB5mD/fFyX5C6JA/Pb7r3LRHtYYLjmuBYWm4ggIyJpFVAZSq/J5mkpuTM0GRyTK5Vqs5bDTrcFFzwHIM0M0qKJiA3AVBN1QosecvmDQWMkilExu2Y310Om24vKrDOAHZXTOUnzXGEHNMeh8ywFsXBbEykGRhIEj8Ey9wfY5n+2Wu1MMX6IZgiz006GKKtcBgGvwWkCVk2SeKLFJ7g+J3aNFvXkFWkbhPzNdmjILib3iRb0IVPz0P1pYQAAAAAElFTkSuQmCC'); 3 | } 4 | 5 | .sort_indicator.sort_desc { 6 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAAEIAAABCAWq6kEQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAZ5JREFUOE+lkstOwlAQhusF1MSNCTsTVy7c4Eu4cWXcmVQSY1sOUMEEL9REE0xtC+VQKKAiYngJnsEYfQpDfAGjO0nGmaqEajeNi6/t/J35Z+a0Qr/f/xeBYhgCxTAEimEIFMPgXXaTu6ssLWeT7AvGlL1kSla/kFSFyRmCpeQ0Y1JaUSRFFMXoyCCVYa266wyrtQqMU3Or4Dbr0LpswFX7Etqda+j17uD07GSABtMjA03Tpo4KB49VpwIX5rmHYelQrpjAHRvQHJotF9o3V3hvvDEmr1HdyIBIyIlFXS8+l2zTM7DKF2BzCxycxG3WcIom3HY7QzWXcX5qfAaEwpQtm5dfqbtlG8CrNq7Bve7dbge0k+MHzJsYr/EZENmc2nXqfKgbRW8KMqDRTct4kSQx9jvfFxB0OIXC4RPtTiZmSQfO7Vfce/13LvFHIHbYzhKex4DWcGr8Q1XTblAeESgS+C9sY+f3fH7/HqeaDMoh/gqCEEHmkYXNzY2NeHxlGZ9jFH/rEV++LxCECWQSmUZmkDlkFol+a/Ru7Cv0hU+pMPz/XT0+1gAAAABJRU5ErkJggg=='); 7 | } 8 | 9 | .sort_indicator { 10 | display: inline-block; 11 | width: 16px; 12 | height: 16px; 13 | vertical-align: -3px; 14 | margin-left: 5px; 15 | cursor: pointer; 16 | } 17 | 18 | .header-table { 19 | overflow-x: auto; 20 | table-layout: fixed; 21 | border-width:15px; 22 | width:150px; 23 | border-collapse: separate; 24 | } 25 | .report_table { 26 | overflow-x: auto; 27 | table-layout: fixed; 28 | border-width:4px; 29 | } 30 | .table_title{ 31 | font-weight:normal; 32 | } 33 | .header-table th { 34 | -webkit-touch-callout: none; 35 | -webkit-user-select: none; 36 | -khtml-user-select: none; 37 | -moz-user-select: none; 38 | -ms-user-select: none; 39 | user-select: none; 40 | font-weight: normal; 41 | overflow-x: visible; 42 | } 43 | 44 | .body-table td { 45 | border-style: solid; 46 | border-width: 1px; 47 | border-color: #000000; 48 | } 49 | 50 | .scroll-table { 51 | overflow-y: auto; 52 | align-content: center; 53 | overflow-x: hidden; 54 | text-align: center; 55 | } 56 | 57 | .body-table tr:nth-child(odd) { 58 | background: #f3f6f9; 59 | } 60 | 61 | .body-table tr:nth-child(even) { 62 | background: #fff; 63 | } -------------------------------------------------------------------------------- /applications/reports/templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% block body %} 3 |
4 |

ReportView

5 |

Beta Version 0.1

6 |

ReportView is a GUI application for viewing reports from the ACI fabric.

7 | 8 |

Full documentation for ReportView can be found at the following 9 | link.

10 | 11 |

License

12 |

Copyright 2015 Cisco Systems, Inc.

13 | 14 |

Licensed under the Apache License, Version 2.0 (the "License"); 15 | you may not use this file except in compliance with the License. 16 | You may obtain a copy of the License at

17 | 18 |
http://www.apache.org/licenses/LICENSE-2.0
19 | 
20 | 21 |

Unless required by applicable law or agreed to in writing, software 22 | distributed under the License is distributed on an "AS IS" BASIS, 23 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | See the License for the specific language governing permissions and 25 | limitations under the License.

26 | 27 |

Authors

28 |

Tom Edsall edsall@cisco.com

29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /applications/reports/templates/admin/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% block body %} 3 | {{ super() }} 4 |
5 |

ReportView

6 |

7 | Report Viewer for ACI fabric 8 |

9 |

Beta v0.1

10 |
11 | {% endblock body %} -------------------------------------------------------------------------------- /applications/reports/templates/credentials.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block body %} 4 |

Enter the Credentials used to communicate with the APIC.

5 |
6 | {{ wtf.quick_form(form, form_type='horizontal', 7 | horizontal_columns=('lg', 2, 2)) }} 8 | {% if ipaddr %} 9 |
10 |

Current Settings 11 |
APIC Username: {{ username }} 12 |
APIC IP Address/FQDN: {{ ipaddr }} 13 |
Secure Connection: {{ security }}

14 | {{ wtf.quick_form(reset_form) }} 15 | {% endif %} 16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /applications/reports/templates/feedback.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block body %} 4 |

We welcome comments and suggestions on how we can make this tool 5 | better.
Please feel free to provide any constructive feedback below.

6 |
7 | {{ wtf.form_field(form.category) }} 8 | {{ wtf.form_field(form.comment) }} 9 | {{ wtf.form_field(form.submit) }} 10 |
11 | 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /applications/reports/templates/layout.html: -------------------------------------------------------------------------------- 1 | {% import 'admin/layout.html' as layout with context -%} 2 | {% extends 'admin/base.html' %} 3 | 4 | {% block head_tail %} 5 | {{ super() }} 6 | 7 | {% endblock %} 8 | 9 | {% block page_body %} 10 |
11 |
12 |
13 | 17 |
18 |
19 |
20 | {% block brand %} 21 |

{{ admin_view.name|capitalize }}

22 |
23 | {% endblock %} 24 | {{ layout.messages() }} 25 | {% block body %}{% endblock %} 26 |
27 |
28 |
29 |
30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /applications/reports/templates/select_switch.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block head %} 4 | {{ super() }} 5 | 6 | {% endblock %} 7 | {% block body %} 8 | 9 | 10 | 11 |

{{ prompt }}

12 |
13 | {{ wtf.quick_form(form) }} 14 | 15 | {% if report %} 16 | {% if report == 'empty' %} 17 |

None

18 | {% else %} 19 | {% for report_table in report %} 20 |
21 |
22 |

{{ report_table.title|safe }}

23 | 24 | 53 | {% endfor %} 54 | {% endif %} 55 | {% endif %} 56 | 57 | {% endblock %} 58 | -------------------------------------------------------------------------------- /applications/search/Forms.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | ################################################################################ 3 | # # 4 | # Copyright (c) 2015 Cisco Systems # 5 | # All Rights Reserved. # 6 | # # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); you may # 8 | # not use this file except in compliance with the License. You may obtain # 9 | # a copy of the License at # 10 | # # 11 | # http://www.apache.org/licenses/LICENSE-2.0 # 12 | # # 13 | # Unless required by applicable law or agreed to in writing, software # 14 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # 15 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # 16 | # License for the specific language governing permissions and limitations # 17 | # under the License. # 18 | # # 19 | ################################################################################ 20 | """ 21 | Forms for report GUI 22 | """ 23 | from flask.ext.wtf import Form 24 | from wtforms import StringField, SubmitField, PasswordField, BooleanField 25 | from wtforms import TextAreaField, SelectField 26 | from wtforms.validators import IPAddress 27 | 28 | __author__ = 'edsall' 29 | 30 | 31 | class FeedbackForm(Form): 32 | """ 33 | Form data for feedback 34 | """ 35 | category = SelectField('', choices=[('bug', 'Bug'), 36 | ('enhancement', 'Enhancement Request'), 37 | ('question', 'General Question'), 38 | ('comment', 'General Comment')]) 39 | comment = TextAreaField('Comment') 40 | submit = SubmitField('Submit') 41 | 42 | 43 | class CredentialsForm(Form): 44 | """ 45 | class to hold the form definition for the credentials 46 | """ 47 | ipaddr = StringField('APIC IP Address:', 48 | validators=[IPAddress()]) 49 | secure = BooleanField('Use secure connection', validators=[]) 50 | username = StringField('APIC Username:', validators=[]) 51 | password = PasswordField('APIC Password:', validators=[]) 52 | submit = SubmitField('Save') 53 | 54 | 55 | class ResetForm(Form): 56 | """ 57 | Reset form 58 | """ 59 | reset = SubmitField('Reset') 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /applications/search/static/autocomplete.css: -------------------------------------------------------------------------------- 1 | .blank-row { 2 | margin-top: 10px; 3 | } 4 | .ac-holder { 5 | position: relative; 6 | } 7 | .record_summary { 8 | line-height: 0.7; 9 | } 10 | 11 | .record_title { 12 | font-size:larger; 13 | } 14 | .ac-dropdown { 15 | border-color: #ececec; 16 | border-width: 1px; 17 | border-style: solid; 18 | border-radius: 2px; 19 | width: 250px; 20 | padding: 6px; 21 | cursor: pointer; 22 | z-index: 9999; 23 | position: absolute; 24 | /*top: 32px; 25 | left: 0px; 26 | */ 27 | margin-top: -6px; 28 | background-color: #ffffff; 29 | } 30 | .ac-form-control { 31 | outline: 0; 32 | border-color: #ECECEC; 33 | border-style: solid; 34 | border-width: 1px; 35 | width: 50%; 36 | background-color: #ffffff; 37 | padding: 6px; 38 | border-radius: 2px; 39 | margin-bottom: 0px; 40 | font-size: 14px; 41 | } 42 | .ac-submit-control { 43 | margin-bottom: 10px; 44 | } 45 | .ac-form-control-small { 46 | width: 72%; 47 | } 48 | 49 | .ac-form-control:-webkit-autofill { 50 | background-color: #fff !important; 51 | } 52 | 53 | .input:-webkit-autofill { 54 | -webkit-box-shadow: 0 0 0px 100px white inset; 55 | } 56 | 57 | .ac-searching { 58 | color: #acacac; 59 | font-size: 14px; 60 | } 61 | 62 | .ac-hint { 63 | color: #acacac; 64 | font-size: 10px; 65 | } 66 | .ac-row { 67 | padding: 5px; 68 | color: #000000; 69 | margin-bottom: 4px; 70 | 71 | } 72 | 73 | .ac-selected-row, .ac-row:hover { 74 | background-color: lightblue; 75 | color: #ffffff; 76 | } 77 | 78 | .ac-highlight { 79 | font-weight:bold; 80 | color: #0000FF; 81 | } 82 | -------------------------------------------------------------------------------- /applications/search/static/d3-searchresult.js: -------------------------------------------------------------------------------- 1 | /* 2 | ################################################################################ 3 | ################################################################################ 4 | # # 5 | # Copyright (c) 2015 Cisco Systems # 6 | # All Rights Reserved. # 7 | # # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); you may # 9 | # not use this file except in compliance with the License. You may obtain # 10 | # a copy of the License at # 11 | # # 12 | # http://www.apache.org/licenses/LICENSE-2.0 # 13 | # # 14 | # Unless required by applicable law or agreed to in writing, software # 15 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # 16 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # 17 | # License for the specific language governing permissions and limitations # 18 | # under the License. # 19 | # # 20 | ################################################################################ 21 | */ 22 | function onClick_show_object(d) { 23 | // var uri = '/atk_object?dn='+d['path']; 24 | var uri = '/acitookkitselectsearchview?dn='+d['uid']; 25 | window.location.assign(encodeURI(uri)) 26 | } 27 | function searchResult(result) { 28 | var report = result['result']; 29 | var total_hits = result['total_hits']; 30 | function gen_summary(d) { 31 | var strng = ""; 32 | strng += '
'; 33 | strng += '

'+d.class+': '+ d.name+'

'; 34 | //strng += "

"+d.class+': '+d.name+ "

"; 35 | strng += '

' + d.uid + '

'; 36 | strng += "

"; 37 | strng += 'Match score:' + d.pscore + '.' + d.sscore + ', '; 38 | strng += 'Matching terms:[' + d.terms + ']

'; 39 | return strng; 40 | } 41 | // determine where to place it and create place holder 42 | d3.select(".span10").select("#records") 43 | .remove(); 44 | 45 | d3.select(".span10").select("#content") 46 | .data(report) 47 | .append("div") 48 | //.attr("id", table_id) 49 | .attr("id", "records"); 50 | 51 | d3.select(".span10").select("#content") 52 | .append("div") 53 | .attr("div", "report_table") 54 | //.attr("style", "width:600px;") 55 | .attr("margin-left", "90px") 56 | .select('#report_table').html(null); 57 | 58 | d3.select("#records") 59 | .selectAll("div") 60 | .data(report).enter().append("div") 61 | .attr("id",function(d, i) {return "record"+i;}) 62 | .attr("class", "record") 63 | .append("div") 64 | .attr("class", "record_summary") 65 | .html(function (d) {return gen_summary(d);}) 66 | .on("click", function (d) { onClick_show_object(d); }); 67 | 68 | spinner.stop(); 69 | 70 | if (report.length==0) { 71 | d3.select('.ac-searching').text('No results').style("display", "block"); 72 | } else { 73 | var index = report.length; 74 | d3.select('.ac-searching').text('Showing '+index+' of ' + total_hits+' results').style("display", "block"); 75 | 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /applications/search/static/d3-tablesort.css: -------------------------------------------------------------------------------- 1 | .subspan11 { 2 | float : none; 3 | margin-left: 0; 4 | } 5 | .subspan12 { 6 | float : left; 7 | } 8 | .attr-table { 9 | clear: left; 10 | } 11 | .atk_object_view { 12 | clear: left; 13 | } 14 | .atk-select { 15 | margin-bottom: 0; 16 | width: 180px; 17 | height: 20px; 18 | } 19 | .sort_indicator.sort_asc { 20 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAAEIAAABCAWq6kEQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAXZJREFUOE+lkbtOAlEQhjHGYGKCCZ1PYHwHa9/CKBdXUIwiVsKy7J29r4AI4gvY2GxhaeMLAFJo4QsYtbKhYJyjy4aF06CbfMmcf2f+/HNOBAD+BVWcB6o4D1RxHiKe51HZSWxHC2f5x9zRQZn2fwxVJODgre2aI1VTPveY1Bath0AVmUw6oxvalyhXoKrLwJaLr5goTuudEZKp3XXD1N/cmg2SIoAgcWBaOuQLJw/TvYTQgezNcqXn9nULiIFlG6BqEhrxpB5mD/fFyX5C6JA/Pb7r3LRHtYYLjmuBYWm4ggIyJpFVAZSq/J5mkpuTM0GRyTK5Vqs5bDTrcFFzwHIM0M0qKJiA3AVBN1QosecvmDQWMkilExu2Y310Om24vKrDOAHZXTOUnzXGEHNMeh8ywFsXBbEykGRhIEj8Ey9wfY5n+2Wu1MMX6IZgiz006GKKtcBgGvwWkCVk2SeKLFJ7g+J3aNFvXkFWkbhPzNdmjILib3iRb0IVPz0P1pYQAAAAAElFTkSuQmCC'); 21 | } 22 | 23 | .sort_indicator.sort_desc { 24 | background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAAEIAAABCAWq6kEQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjExR/NCNwAAAZ5JREFUOE+lkstOwlAQhusF1MSNCTsTVy7c4Eu4cWXcmVQSY1sOUMEEL9REE0xtC+VQKKAiYngJnsEYfQpDfAGjO0nGmaqEajeNi6/t/J35Z+a0Qr/f/xeBYhgCxTAEimEIFMPgXXaTu6ssLWeT7AvGlL1kSla/kFSFyRmCpeQ0Y1JaUSRFFMXoyCCVYa266wyrtQqMU3Or4Dbr0LpswFX7Etqda+j17uD07GSABtMjA03Tpo4KB49VpwIX5rmHYelQrpjAHRvQHJotF9o3V3hvvDEmr1HdyIBIyIlFXS8+l2zTM7DKF2BzCxycxG3WcIom3HY7QzWXcX5qfAaEwpQtm5dfqbtlG8CrNq7Bve7dbge0k+MHzJsYr/EZENmc2nXqfKgbRW8KMqDRTct4kSQx9jvfFxB0OIXC4RPtTiZmSQfO7Vfce/13LvFHIHbYzhKex4DWcGr8Q1XTblAeESgS+C9sY+f3fH7/HqeaDMoh/gqCEEHmkYXNzY2NeHxlGZ9jFH/rEV++LxCECWQSmUZmkDlkFol+a/Ru7Cv0hU+pMPz/XT0+1gAAAABJRU5ErkJggg=='); 25 | } 26 | 27 | .sort_indicator { 28 | display: inline-block; 29 | width: 16px; 30 | height: 16px; 31 | vertical-align: -3px; 32 | margin-left: 5px; 33 | cursor: pointer; 34 | } 35 | 36 | .header-table { 37 | overflow-x: auto; 38 | table-layout: fixed; 39 | border-width:5px; 40 | width:150px; 41 | border-collapse: separate; 42 | } 43 | .report_table { 44 | overflow-x: auto; 45 | table-layout: fixed; 46 | border-width:4px; 47 | } 48 | .table_title{ 49 | font-weight:normal; 50 | } 51 | .header-table th { 52 | -webkit-touch-callout: none; 53 | -webkit-user-select: none; 54 | -khtml-user-select: none; 55 | -moz-user-select: none; 56 | -ms-user-select: none; 57 | user-select: none; 58 | font-weight: normal; 59 | overflow-x: visible; 60 | } 61 | 62 | .body-table td { 63 | border-style: solid; 64 | border-width: 1px; 65 | border-color: #000000; 66 | } 67 | 68 | .scroll-table { 69 | overflow-y: auto; 70 | align-content: center; 71 | overflow-x: hidden; 72 | text-align: center; 73 | } 74 | 75 | .body-table tr:nth-child(odd) { 76 | background: #f3f6f9; 77 | } 78 | 79 | .body-table tr:nth-child(even) { 80 | background: #fff; 81 | } -------------------------------------------------------------------------------- /applications/search/static/layout.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #EEE; 3 | } 4 | 5 | #content { 6 | background: white; 7 | border: 1px solid #CCC; 8 | padding: 12px; 9 | overflow: scroll; 10 | } 11 | 12 | #brand { 13 | float: left; 14 | font-weight: 300; 15 | margin: 0; 16 | } 17 | 18 | .search-form { 19 | margin: 0 5px; 20 | } 21 | 22 | .search-form form { 23 | margin: 0; 24 | } 25 | 26 | .btn-menu { 27 | margin: 4px 5px 0 0; 28 | float: right; 29 | } 30 | 31 | .btn-menu a, .btn-menu input { 32 | padding: 7px 16px !important; 33 | border-radius: 0 !important; 34 | } 35 | 36 | .btn, textarea, input[type], button, .model-list { 37 | border-radius: 0; 38 | } 39 | 40 | .model-list { 41 | border-radius: 0; 42 | } 43 | 44 | .nav-pills li > a { 45 | border-radius: 0; 46 | } 47 | 48 | .select2-container .select2-choice { 49 | border-radius: 0; 50 | } 51 | -------------------------------------------------------------------------------- /applications/search/templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% block body %} 3 |
4 |

ReportView

5 |

Beta Version 0.1

6 |

aciSearchGui is a GUI application for searching the ACI fabric.

7 | 8 |

Full documentation for aciSearchGui can be found at the following 9 | link.

10 | 11 |

License

12 |

Copyright 2015 Cisco Systems, Inc.

13 | 14 |

Licensed under the Apache License, Version 2.0 (the "License"); 15 | you may not use this file except in compliance with the License. 16 | You may obtain a copy of the License at

17 | 18 |
http://www.apache.org/licenses/LICENSE-2.0
19 | 
20 | 21 |

Unless required by applicable law or agreed to in writing, software 22 | distributed under the License is distributed on an "AS IS" BASIS, 23 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24 | See the License for the specific language governing permissions and 25 | limitations under the License.

26 | 27 |

Authors

28 |

Tom Edsall edsall@cisco.com

29 | {% endblock %} 30 | -------------------------------------------------------------------------------- /applications/search/templates/admin/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% block body %} 3 | {{ super() }} 4 |
5 |

Search View

6 |

7 | Search Viewer for ACI fabric 8 |

9 |

Beta v0.1

10 |
11 | {% endblock body %} -------------------------------------------------------------------------------- /applications/search/templates/credentials.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block body %} 4 |

Enter the Credentials used to communicate with the APIC.

5 |
6 | {{ wtf.quick_form(form, form_type='horizontal', 7 | horizontal_columns=('lg', 2, 2)) }} 8 | {% if ipaddr %} 9 |
10 |

Current Settings 11 |
APIC Username: {{ username }} 12 |
APIC IP Address: {{ ipaddr }} 13 |
Secure Connection: {{ security }}

14 | {{ wtf.quick_form(reset_form) }} 15 | {% endif %} 16 | {% endblock %} 17 | -------------------------------------------------------------------------------- /applications/search/templates/feedback.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block body %} 4 |

We welcome comments and suggestions on how we can make this tool 5 | better.
Please feel free to provide any constructive feedback below.

6 |
7 | {{ wtf.form_field(form.category) }} 8 | {{ wtf.form_field(form.comment) }} 9 | {{ wtf.form_field(form.submit) }} 10 |
11 | 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /applications/search/templates/layout.html: -------------------------------------------------------------------------------- 1 | {% import 'admin/layout.html' as layout with context -%} 2 | {% extends 'admin/base.html' %} 3 | 4 | {% block head_tail %} 5 | {{ super() }} 6 | 7 | {% endblock %} 8 | 9 | {% block page_body %} 10 |
11 |
12 |
13 | 17 |
18 |
19 |
20 | {% block brand %} 21 |

{{ admin_view.name|capitalize }}

22 |
23 | {% endblock %} 24 | {{ layout.messages() }} 25 | {% block body %}{% endblock %} 26 |
27 |
28 |
29 |
30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /applications/snapback/static/data.csv: -------------------------------------------------------------------------------- 1 | Version,Deletions,Additions 2 | -------------------------------------------------------------------------------- /applications/snapback/static/layout.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: #EEE; 3 | } 4 | 5 | #content { 6 | background: white; 7 | border: 1px solid #CCC; 8 | padding: 12px; 9 | overflow: scroll; 10 | } 11 | 12 | #brand { 13 | float: left; 14 | font-weight: 300; 15 | margin: 0; 16 | } 17 | 18 | .search-form { 19 | margin: 0 5px; 20 | } 21 | 22 | .search-form form { 23 | margin: 0; 24 | } 25 | 26 | .btn-menu { 27 | margin: 4px 5px 0 0; 28 | float: right; 29 | } 30 | 31 | .btn-menu a, .btn-menu input { 32 | padding: 7px 16px !important; 33 | border-radius: 0 !important; 34 | } 35 | 36 | .btn, textarea, input[type], button, .model-list { 37 | border-radius: 0; 38 | } 39 | 40 | .model-list { 41 | border-radius: 0; 42 | } 43 | 44 | .nav-pills li > a { 45 | border-radius: 0; 46 | } 47 | 48 | .select2-container .select2-choice { 49 | border-radius: 0; 50 | } 51 | -------------------------------------------------------------------------------- /applications/snapback/templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% block body %} 3 |
4 |

Snapback

5 |

Beta Version 0.2

6 |

Snapback is a Configuration Snapshot and Rollback tool for use with 7 | Cisco ACI fabrics.

8 | 9 |

Full documentation for Snapback can be found at the following 10 | link.

11 | 12 |

License

13 |

Copyright 2015 Cisco Systems, Inc.

14 | 15 |

Licensed under the Apache License, Version 2.0 (the "License"); 16 | you may not use this file except in compliance with the License. 17 | You may obtain a copy of the License at

18 | 19 |
http://www.apache.org/licenses/LICENSE-2.0
20 | 
21 | 22 |

Unless required by applicable law or agreed to in writing, software 23 | distributed under the License is distributed on an "AS IS" BASIS, 24 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | See the License for the specific language governing permissions and 26 | limitations under the License.

27 | 28 |

Authors

29 |

Michael Smith michsmit@cisco.com

30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /applications/snapback/templates/admin/index.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% block body %} 3 | {{ super() }} 4 |
5 |

Snapback

6 |

7 | Configuration Snapshot and Rollback for ACI fabrics 8 |

9 |

Beta v0.2

10 |
11 | {% endblock body %} -------------------------------------------------------------------------------- /applications/snapback/templates/credentials.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block body %} 4 |

Enter the Credentials used to communicate with the APIC.

5 |
6 | {{ wtf.quick_form(form, form_type='horizontal', 7 | horizontal_columns=('lg', 2, 2)) }} 8 | {% if ipaddr %} 9 |
10 |

Current Settings 11 |
APIC Username: {{ username }} 12 |
APIC IP address: {{ ipaddr }}

13 | {{ wtf.quick_form(reset_form) }} 14 | {% endif %} 15 | {% endblock %} 16 | -------------------------------------------------------------------------------- /applications/snapback/templates/diffview.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block body %} 4 | 5 | 18 | 19 | {{ table|safe }} 20 | 21 | {% endblock %} 22 | -------------------------------------------------------------------------------- /applications/snapback/templates/feedback.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block body %} 4 |

We welcome comments and suggestions on how we can make this tool 5 | better.
Please feel free to provide any constructive feedback below.

6 |
7 | {{ wtf.form_field(form.category) }} 8 | {{ wtf.form_field(form.comment) }} 9 | {{ wtf.form_field(form.submit) }} 10 |
11 | 12 | {% endblock %} 13 | -------------------------------------------------------------------------------- /applications/snapback/templates/fileview.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block body %} 4 | 25 | 26 | {% for file in files %} 27 |

Filename:{{ file[1] }} Version:{{ file[2] }}

28 |
29 | 
30 | {{ file[0] }}
31 | 
32 | 
33 | {% endfor %} 34 | 35 | {% endblock %} 36 | -------------------------------------------------------------------------------- /applications/snapback/templates/layout.html: -------------------------------------------------------------------------------- 1 | {% import 'admin/layout.html' as layout with context -%} 2 | {% extends 'admin/base.html' %} 3 | 4 | {% block head_tail %} 5 | {{ super() }} 6 | 7 | {% endblock %} 8 | 9 | {% block page_body %} 10 |
11 |
12 |
13 | 17 |
18 |
19 |
20 | {% block brand %} 21 |

{{ admin_view.name|capitalize }}

22 |
23 | {% endblock %} 24 | {{ layout.messages() }} 25 | {% block body %}{% endblock %} 26 |
27 |
28 |
29 |
30 | {% endblock %} 31 | -------------------------------------------------------------------------------- /applications/snapback/templates/list.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/model/list.html' %} 2 | {% import 'admin/model/layout.html' as model_layout with context %} 3 | 4 | {% block brand %} 5 |

Snapshots

6 | {% if admin_view.can_create %} 7 |
8 | {{ _gettext('Create') }} 9 |
10 | {% endif %} 11 | 12 | {% if filter_groups %} 13 |
14 | {{ model_layout.filter_options(btn_class='btn dropdown-toggle btn-title') }} 15 |
16 | {% endif %} 17 | 18 | {% if actions %} 19 |
20 | {{ actionlib.dropdown(actions, btn_class='btn dropdown-toggle btn-title') }} 21 |
22 | {% endif %} 23 | 24 | {% if search_supported %} 25 |
26 | {{ model_layout.search_form(input_class='span2 btn-title') }} 27 |
28 | {% endif %} 29 |
30 |
31 | {% endblock %} 32 | 33 | {% block model_menu_bar %} 34 | {% endblock %} 35 | 36 | {% macro render_changes(model, column) %} 37 | {{ ''|safe + model.changes.split('/')[0] + 38 | ''|safe + '/' + ''|safe + model.changes.split('/')[1] + ''|safe}} 39 | {% endmacro %} -------------------------------------------------------------------------------- /applications/snapback/templates/rollback.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block body %} 4 |

Select the configuration snapshot version to apply to the APIC.

5 | 6 |

Warning: Rollback of APIC configuration may cause service disruption

7 | 8 |
9 | {{ wtf.quick_form(form) }} 10 | {% endblock %} 11 | -------------------------------------------------------------------------------- /applications/snapback/templates/snapshot.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | {% import "bootstrap/wtf.html" as wtf %} 3 | {% block body %} 4 |

Schedule an ongoing automated snapshot of the APIC configuration or 5 | schedule a one time snapshot.

6 |
7 | {{ wtf.form_field(form.frequency) }} 8 | {{ wtf.form_field(form.number, style="float:left") }} 9 | {{ wtf.form_field(form.interval) }} 10 | {{ wtf.form_field(form.date) }} 11 | {{ wtf.form_field(form.time) }} 12 | {{ form.csrf_token }} 13 | {{ wtf.form_field(form.submit) }} 14 |
15 | 16 | {% if lastsnapshot %} 17 |

Last snapshot taken at {{ lastsnapshot }}

18 | {% endif %} 19 | {% if nextsnapshot %} 20 | {% if schedule['interval'] %} 21 |

Next snapshot scheduled for {{ nextsnapshot }} and every {{ schedule['interval'] }} {{ schedule['granularity'] }} beyond that.

22 | {% else %} 23 |

Next snapshot scheduled for {{ nextsnapshot }}

24 | {% endif %} 25 | {{ wtf.quick_form(cancel_form) }} 26 | {% else %} 27 |

No recurring snapshot currently scheduled

28 | {% endif %} 29 | {% endblock %} 30 | 31 | -------------------------------------------------------------------------------- /applications/testharness/sample_apic_test_harness_config.ini: -------------------------------------------------------------------------------- 1 | [ConnectionFailures] 2 | Status: enabled 3 | PercentageOfRequests: 25 4 | 5 | [DelayResponses] 6 | Status: disabled 7 | PercentageOfRequests: 25 8 | DelayInSeconds: 5 9 | -------------------------------------------------------------------------------- /applications/visualizations/README.md: -------------------------------------------------------------------------------- 1 | Documentation for this application can be found [here](http://datacenter.github.io/acitoolkit/docsbuild/html/visualizations.html) 2 | -------------------------------------------------------------------------------- /applications/visualizations/static/acitoolkit.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: verdana; 3 | font-style: normal; 4 | background-color: white; 5 | margin-left: 40px; 6 | } 7 | h1 { 8 | font-weight: bold; 9 | color: SteelBlue; 10 | font-size: 20px; 11 | margin-left: 20px; 12 | } 13 | p { 14 | text-indent: 50px; 15 | } 16 | 17 | a.hlink:link {color:SteelBlue;} 18 | a.hlink:visited {color:lightpurple;} 19 | a.hlink:hover {font-size:125%;} 20 | 21 | .tab { margin-left: 20px; } 22 | 23 | -------------------------------------------------------------------------------- /applications/visualizations/static/endpoint_hierarchical_data.json: -------------------------------------------------------------------------------- 1 | [{"name":"00:50:56:94:07:7E", "imports": ["00:50:56:94:07:7E","00:50:56:94:D8:73"]},{"name":"00:50:56:94:D8:73", "imports": ["00:50:56:94:07:7E","00:50:56:94:D8:73"]},{"name":"A0:EC:F9:85:06:30", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"A0:EC:F9:85:06:30", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:F3:CD", "imports": ["00:50:56:94:F3:CD","00:50:56:94:9A:1C"]},{"name":"00:50:56:94:9A:1C", "imports": ["00:50:56:94:F3:CD","00:50:56:94:9A:1C"]},{"name":"00:50:56:94:17:5E", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:17:5E", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:A9:B5", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:A9:B5", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:93:6F", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:93:6F", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:EF:4B", "imports": ["00:50:56:94:EF:4B"]},{"name":"00:50:56:94:58:9D", "imports": ["00:50:56:94:58:9D"]},{"name":"00:50:56:94:07:7E", "imports": ["00:50:56:94:07:7E","00:50:56:94:D8:73"]},{"name":"00:50:56:94:D8:73", "imports": ["00:50:56:94:07:7E","00:50:56:94:D8:73"]},{"name":"A0:EC:F9:85:06:30", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"A0:EC:F9:85:06:30", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:F3:CD", "imports": ["00:50:56:94:F3:CD","00:50:56:94:9A:1C"]},{"name":"00:50:56:94:9A:1C", "imports": ["00:50:56:94:F3:CD","00:50:56:94:9A:1C"]},{"name":"00:50:56:94:17:5E", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:17:5E", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:A9:B5", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:A9:B5", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:93:6F", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:93:6F", "imports": ["A0:EC:F9:85:06:30","00:50:56:94:17:5E","00:50:56:94:A9:B5","00:50:56:94:93:6F"]},{"name":"00:50:56:94:EF:4B", "imports": ["00:50:56:94:EF:4B"]},{"name":"00:50:56:94:58:9D", "imports": ["00:50:56:94:58:9D"]}] 2 | -------------------------------------------------------------------------------- /applications/visualizations/templates/bubble-tooltips.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 12 | 83 | -------------------------------------------------------------------------------- /applications/visualizations/templates/endpoint-force.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 31 | 32 |

Endpoint Location

33 | 34 | 35 | -------------------------------------------------------------------------------- /applications/visualizations/templates/endpoint-radial.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 29 | 30 |
31 |

Endpoints to EPGs

32 |
33 | 34 | -------------------------------------------------------------------------------- /applications/visualizations/templates/endpoint-sunburst.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | 17 | 18 | 105 | 106 | -------------------------------------------------------------------------------- /applications/visualizations/templates/endpoint-tracker-pie.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 20 | 21 | Endpoints per Tenant 22 |
23 |

Endpoints per Tenant

24 |
25 | 26 | 73 | -------------------------------------------------------------------------------- /applications/visualizations/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | acitoolkit Visualizations 6 | 9 | 10 | 11 | 12 |

ACI Toolkit Visualization Examples

13 | 14 |

Endpoint Physical Location (Force 15 | Diagram)

16 | 17 |

Shows the Endpoints and where they are connected in the physical 18 | topology.

19 | 20 |

Number of Endpoints per Tenant 21 | (Pie Chart)

22 | 23 |

Shows the Number of Endpoints per Tenant in the form of a Pie Chart.

24 | 25 |

EPG to Endpoint (Tree 26 | Diagram)

27 | 28 |

Shows the Endpoints belonging to particular EPGs.

29 | 30 |

EPG to Endpoint (Radial 31 | Diagram)

32 | 33 |

Shows the Endpoints belonging to particular EPGs.

34 | 35 |

EPG to Endpoints (Sunburst Diagram)

36 | 37 |

Shows the Endpoints belonging to EPGs in a zoomable 38 | Sunburst diagram.

39 | 40 |

Endpoint relationships according 41 | to EPGs (Hierarchical Bundling Diagram)

42 | 43 |

Shows the Endpoints that are providing and consuming 44 | services from each other according to the Contracts.

45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /contributors.txt: -------------------------------------------------------------------------------- 1 | Michael Smith michsmit@cisco.com 2 | Bon Huang bonhuan@cisco.com 3 | Tom Edsall edsall@cisco.com 4 | Kevin Corbin kecorbin@cisco.com -------------------------------------------------------------------------------- /docs/source/Connection_Search-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/Connection_Search-welcome.png -------------------------------------------------------------------------------- /docs/source/aci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/aci.png -------------------------------------------------------------------------------- /docs/source/acitoolkit.aciFaults.rst: -------------------------------------------------------------------------------- 1 | aciFaults module 2 | ================ 3 | 4 | .. automodule:: acitoolkit.aciFaults 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/acitoolkit.acibaseobject.rst: -------------------------------------------------------------------------------- 1 | acibaseobject module 2 | ==================== 3 | 4 | .. automodule:: acitoolkit.acibaseobject 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | -------------------------------------------------------------------------------- /docs/source/acitoolkit.aciphysobject.rst: -------------------------------------------------------------------------------- 1 | aciphysobject module 2 | ==================== 3 | 4 | API Reference 5 | --------------------- 6 | 7 | .. include:: acitoolkit-hierarchy.PhysicalModel.gv 8 | 9 | .. automodule:: acitoolkit.aciphysobject 10 | :members: 11 | :inherited-members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | Future Work 16 | -------------------- 17 | Future work items to be added to aciphysobject include: 18 | 19 | * Add an events sub-object. This would work similarly to the stats 20 | object. 21 | 22 | * Add a top level object called Topology that would have Pod as its 23 | child. This object would also contain devices attached to the 24 | fabric, so called loose nodes, external links, and discovered 25 | end-points. 26 | 27 | 28 | -------------------------------------------------------------------------------- /docs/source/acitoolkit.acisession.rst: -------------------------------------------------------------------------------- 1 | acisession module 2 | ================= 3 | 4 | .. automodule:: acitoolkit.acisession 5 | 6 | .. autoclass:: Session 7 | :members: 8 | :inherited-members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /docs/source/acitoolkit.acitoolkit.rst: -------------------------------------------------------------------------------- 1 | acitoolkit module 2 | ================= 3 | 4 | .. include:: acitoolkit-hierarchy.Fabric.gv 5 | 6 | .. automodule:: acitoolkit.acitoolkit 7 | :members: 8 | :inherited-members: 9 | :undoc-members: 10 | :show-inheritance: 11 | -------------------------------------------------------------------------------- /docs/source/acitoolkit.acitoolkitlib.rst: -------------------------------------------------------------------------------- 1 | acitoolkitlib module 2 | ==================== 3 | 4 | .. automodule:: acitoolkit.acitoolkitlib 5 | :members: 6 | :inherited-members: 7 | :undoc-members: 8 | :show-inheritance: 9 | -------------------------------------------------------------------------------- /docs/source/acitoolkit.rst: -------------------------------------------------------------------------------- 1 | acitoolkit package 2 | ================== 3 | 4 | Submodules 5 | ---------- 6 | 7 | .. toctree:: 8 | 9 | acitoolkit.acibaseobject 10 | acitoolkit.aciphysobject 11 | acitoolkit.acisession 12 | acitoolkit.acitoolkit 13 | acitoolkit.acitoolkitlib 14 | acitoolkit.aciFaults 15 | -------------------------------------------------------------------------------- /docs/source/applications.rst: -------------------------------------------------------------------------------- 1 | Applications 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 2 6 | 7 | endpointtracker 8 | acilint 9 | cableplan 10 | snapback 11 | visualizations 12 | eventfeeds 13 | intersite 14 | connectionsearch 15 | fakeapic 16 | reports 17 | testharness 18 | -------------------------------------------------------------------------------- /docs/source/apptopo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/apptopo.png -------------------------------------------------------------------------------- /docs/source/connection-search-example1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/connection-search-example1.png -------------------------------------------------------------------------------- /docs/source/connection-search-example2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/connection-search-example2.png -------------------------------------------------------------------------------- /docs/source/connection-search-example3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/connection-search-example3.png -------------------------------------------------------------------------------- /docs/source/connection_search-credentials-set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/connection_search-credentials-set.png -------------------------------------------------------------------------------- /docs/source/connection_search-credentials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/connection_search-credentials.png -------------------------------------------------------------------------------- /docs/source/connection_search-search-start.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/connection_search-search-start.png -------------------------------------------------------------------------------- /docs/source/credentials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/credentials.png -------------------------------------------------------------------------------- /docs/source/eventfeeds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/eventfeeds.png -------------------------------------------------------------------------------- /docs/source/eventfeeds_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/eventfeeds_config.png -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. acitoolkit documentation master file, created by 2 | sphinx-quickstart on Sat Oct 25 16:49:43 2014. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to acitoolkit's documentation! 7 | ====================================== 8 | .. image:: aci.png 9 | 10 | Contents: 11 | 12 | .. toctree:: 13 | :maxdepth: 4 14 | 15 | introduction 16 | objectmodel 17 | monitor_policy 18 | tutorial 19 | stats 20 | modules 21 | applications 22 | 23 | 24 | Indices and tables 25 | ================== 26 | 27 | * :ref:`genindex` 28 | * :ref:`modindex` 29 | * :ref:`search` 30 | 31 | -------------------------------------------------------------------------------- /docs/source/interfacemodel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/interfacemodel.png -------------------------------------------------------------------------------- /docs/source/introduction.rst: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | The Cisco ACI Fabric is configured using an abstract policy model on the 4 | Cisco Application Policy Infrastructure Controller (APIC). The APIC 5 | has a very rich and complete object model that is accessible through a 6 | programmatic REST API. The acitoolkit exposes a small subset of that 7 | model in a way that is meant to provide an introduction to the 8 | ACI concepts and allow users to get the most common workflows up and 9 | running as quickly as possible. 10 | -------------------------------------------------------------------------------- /docs/source/modules.rst: -------------------------------------------------------------------------------- 1 | API Reference 2 | ============= 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | acitoolkit 8 | -------------------------------------------------------------------------------- /docs/source/monitorpolicyhier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/monitorpolicyhier.png -------------------------------------------------------------------------------- /docs/source/objectModelController.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/objectModelController.png -------------------------------------------------------------------------------- /docs/source/objectModelSwitch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/objectModelSwitch.png -------------------------------------------------------------------------------- /docs/source/objectModelTop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/objectModelTop.png -------------------------------------------------------------------------------- /docs/source/reports-logical.rst: -------------------------------------------------------------------------------- 1 | ACI Logical Reports 2 | ================== 3 | 4 | Logical Tenant level reporting can be dome via this command line application. 5 | 6 | Installation 7 | ------------ 8 | 9 | This reporting application is included in the ``acitoolkit`` package when downloaded using the ``git clone`` method 10 | of installation. The application can be found in the ``acitoolkit/applications/reports`` directory. 11 | 12 | Usage 13 | ----- 14 | 15 | The application is started from the command line. In its simplest form, it can be invoked by the following command:: 16 | 17 | python aci-report-logical.py 18 | 19 | The full command help is shown below:: 20 | 21 | python aci-report-logical.py -h 22 | 23 | usage: aci-report-logical.py [-h] [-u URL] [-l LOGIN] [-p PASSWORD] 24 | [-t TENANT] [-all] [-basic] [-context] 25 | [-bridgedomain] [-contract] [-taboo] [-filter] 26 | [-app_profile] [-epg] [-endpoint] 27 | 28 | Simple application that logs on to the APIC and displays reports for the 29 | logical model. 30 | 31 | optional arguments: 32 | -h, --help show this help message and exit 33 | -u URL, --url URL APIC URL e.g. http://1.2.3.4 34 | -l LOGIN, --login LOGIN 35 | APIC login ID. 36 | -p PASSWORD, --password PASSWORD 37 | APIC login password. 38 | -t TENANT, --tenant TENANT 39 | Specify a particular tenant name 40 | -all Show all detailed information 41 | -basic Show basic tenant info 42 | -context Show Context info 43 | -bridgedomain Show Bridge Domain info 44 | -contract Show Contract info 45 | -taboo Show Taboo (Deny) info 46 | -filter Show Filter info 47 | -app_profile Show Application Profile info 48 | -epg Show Endpoint Group info 49 | -endpoint Show End Point info 50 | 51 | 52 | Notes 53 | ----- 54 | 55 | The reporting application can generate a large amount of data. It may take some time to collect all of 56 | the data depending on the size of the ACI fabric. This is especially true when executing the ``-all`` 57 | command line option. -------------------------------------------------------------------------------- /docs/source/reports-security.rst: -------------------------------------------------------------------------------- 1 | ACI Security Report 2 | =================== 3 | 4 | This application provides simple audit reports that can be used for compliance checks or security audits. 5 | 6 | 7 | Installation 8 | ------------ 9 | 10 | This reporting application is included in the ``acitoolkit`` package when downloaded using the ``git clone`` method 11 | of installation. The application can be found in the ``acitoolkit/applications/reports`` directory. 12 | 13 | Usage 14 | ----- 15 | 16 | The application is started from the command line. In its simplest form, it can be invoked by the following command:: 17 | 18 | python aci-report-security-audit.py 19 | 20 | The full command help is shown below:: 21 | 22 | python aci-report-security-audit.py -h 23 | 24 | usage: aci-report-security-audit.py [-h] [-u URL] [-l LOGIN] [-p PASSWORD] 25 | [--csv CSV] 26 | 27 | Simple application that logs on to the APIC and produces a report that can be 28 | used for security compliance auditing. 29 | 30 | optional arguments: 31 | -h, --help show this help message and exit 32 | -u URL, --url URL APIC URL e.g. http://1.2.3.4 33 | -l LOGIN, --login LOGIN 34 | APIC login ID. 35 | -p PASSWORD, --password PASSWORD 36 | APIC login password. 37 | --csv CSV Output to a CSV file. 38 | 39 | Output 40 | ------ 41 | 42 | By default, the audit report is displayed on the screen as comma separated values. If the ``--csv`` command line option 43 | is provided, the output will be sent to the specified filename in proper CSV format. 44 | 45 | Each row of the report contains the following information:: 46 | 47 | * Tenant name 48 | * Context (VRF) name 49 | * Bridge Domain name 50 | * Application Profile name 51 | * EPG name 52 | * Number of Consumer EPG Endpoints 53 | * Provided Contract name 54 | * Number of Providing EPG Endpoints 55 | * Consumed Contract name 56 | * Protocol specified in the Filter entry 57 | * Source port range specified in the Filter entry 58 | * Destination port range specified in the Filter entry 59 | -------------------------------------------------------------------------------- /docs/source/reports-switch.rst: -------------------------------------------------------------------------------- 1 | ACI Switch Reports 2 | ================== 3 | 4 | Switch level reporting can be dome via this command line application. 5 | 6 | Installation 7 | ------------ 8 | 9 | This reporting application is included in the ``acitoolkit`` package when downloaded using the ``git clone`` method 10 | of installation. The application can be found in the ``acitoolkit/applications/reports`` directory. 11 | 12 | Usage 13 | ----- 14 | 15 | The application is started from the command line. In its simplest form, it can be invoked by the following command:: 16 | 17 | python aci-report-switch.py 18 | 19 | The full command help is shown below:: 20 | 21 | python aci-report-switch.py -h 22 | 23 | Simple application that logs on to the APIC and displays reports for the 24 | switches. 25 | usage: aci-report-switch.py [-h] [-u URL] [-l LOGIN] [-p PASSWORD] [-s SWITCH] 26 | [-all] [-basic] [-linecard] [-supervisor] 27 | [-fantray] [-powersupply] [-arp] [-context] 28 | [-bridgedomain] [-svi] [-accessrule] [-endpoint] 29 | [-portchannel] [-overlay] [-tablefmt TABLEFMT] 30 | 31 | optional arguments: 32 | -h, --help show this help message and exit 33 | -u URL, --url URL APIC URL e.g. http://1.2.3.4 34 | -l LOGIN, --login LOGIN 35 | APIC login ID. 36 | -p PASSWORD, --password PASSWORD 37 | APIC login password. 38 | -s SWITCH, --switch SWITCH 39 | Specify a particular switch id, e.g. "102" 40 | -all Show all detailed information 41 | -basic Show basic switch info 42 | -linecard Show Lincard info 43 | -supervisor Show Supervisor Card info 44 | -fantray Show Fantray info 45 | -powersupply Show Power Supply info 46 | -arp Show ARP info 47 | -context Show Context (VRF) info 48 | -bridgedomain Show Bridge Domain info 49 | -svi Show SVI info 50 | -accessrule Show Access Rule and Filter info 51 | -endpoint Show End Point info 52 | -portchannel Show Port Channel and Virtual Port Channel info 53 | -overlay Show Overlay info 54 | -tablefmt TABLEFMT Table format [fancy_grid, plain, simple, grid, pipe, 55 | orgtbl, rst, mediawiki, latex, latex_booktabs] 56 | 57 | Notes 58 | ----- 59 | 60 | The reporting application can generate a large amount of data. It may take some time to collect all of 61 | the data depending on the size of the ACI fabric. This is especially true when executing the ``-all`` 62 | command line option. -------------------------------------------------------------------------------- /docs/source/reports.rst: -------------------------------------------------------------------------------- 1 | ACI Reports 2 | =========== 3 | 4 | The ``ACI Reports`` is a collection of reporting tools for the APIC logical 5 | and physical model. 6 | 7 | .. toctree:: 8 | :maxdepth: 2 9 | 10 | reports-gui 11 | reports-logical 12 | reports-switch 13 | reports-security 14 | -------------------------------------------------------------------------------- /docs/source/reportview-main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/reportview-main.png -------------------------------------------------------------------------------- /docs/source/saved-credentials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/saved-credentials.png -------------------------------------------------------------------------------- /docs/source/snapback-credentials-set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/snapback-credentials-set.png -------------------------------------------------------------------------------- /docs/source/snapback-credentials.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/snapback-credentials.png -------------------------------------------------------------------------------- /docs/source/snapback-schedule-snapshot-set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/snapback-schedule-snapshot-set.png -------------------------------------------------------------------------------- /docs/source/snapback-schedule-snapshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/snapback-schedule-snapshot.png -------------------------------------------------------------------------------- /docs/source/snapback-snapshots-diffview1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/snapback-snapshots-diffview1.png -------------------------------------------------------------------------------- /docs/source/snapback-snapshots-diffview2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/snapback-snapshots-diffview2.png -------------------------------------------------------------------------------- /docs/source/snapback-snapshots-view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/snapback-snapshots-view.png -------------------------------------------------------------------------------- /docs/source/snapback-snapshots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/snapback-snapshots.png -------------------------------------------------------------------------------- /docs/source/snapback-versiondiffs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/snapback-versiondiffs.png -------------------------------------------------------------------------------- /docs/source/snapback-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/snapback-welcome.png -------------------------------------------------------------------------------- /docs/source/stats.rst: -------------------------------------------------------------------------------- 1 | Statistics 2 | ========== 3 | This documents gives an overview of the statistics. 4 | 5 | .. toctree:: 6 | :maxdepth: 2 7 | 8 | statsbody 9 | statsdetail 10 | -------------------------------------------------------------------------------- /docs/source/statsdetail.rst: -------------------------------------------------------------------------------- 1 | .. _statistics-detail-label: 2 | 3 | Statistics Detail 4 | ================== 5 | The following are details about each of the counters 6 | 7 | .. toctree:: 8 | :maxdepth: 2 9 | 10 | stats/egrBytes.rst 11 | stats/egrTotal.rst 12 | stats/ingrBytes.rst 13 | stats/ingrTotal.rst 14 | stats/egrPkts.rst 15 | stats/ingrPkts.rst 16 | stats/egrDropPkts.rst 17 | stats/ingrDropPkts.rst 18 | stats/ingrUnkBytes.rst 19 | stats/ingrStorm.rst 20 | stats/ingrUnkPkts.rst 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/source/switch-reports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/switch-reports.png -------------------------------------------------------------------------------- /docs/source/tenant-reports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/tenant-reports.png -------------------------------------------------------------------------------- /docs/source/tutorial.rst: -------------------------------------------------------------------------------- 1 | Tutorial 2 | ======== 3 | This document is meant to give a tutorial-like overview of the 4 | acitoolkit package. 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | tutorialsetup 10 | tutorialpackages 11 | tutorialsimpleconfig 12 | subscriptions 13 | -------------------------------------------------------------------------------- /docs/source/tutorialpackages.rst: -------------------------------------------------------------------------------- 1 | Pre-installed Packages 2 | -------------------------- 3 | 4 | The ``acitoolkit`` can be downloaded pre-configured as a virtual machine. 5 | 6 | Virtual Machine for VMware Environments 7 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 | 9 | A pre-installed virtual machine in the form of a OVA file for VMware hypervisors 10 | can be found in the link below: 11 | 12 | `ACI Toolkit OVA `_ 13 | 14 | The virtual machine is configured with the following parameters:: 15 | 16 | Username: acitoolkit 17 | Password: acitoolkit 18 | Operating System: Ubuntu 16.04.2 19 | Processor Cores: 1 20 | Memory: 1GB 21 | 22 | The ``acitoolkit`` and necessary packages are already installed. However, given 23 | the pace of change in datacenter networking, there most likely have been changes 24 | since the VM was created. Luckily, the VM can be updated to the latest version 25 | by entering the following command:: 26 | 27 | sudo ~/install 28 | 29 | This command be re-run any time to get the latest updates. -------------------------------------------------------------------------------- /docs/source/tutorialsetup.rst: -------------------------------------------------------------------------------- 1 | Setting up the environment 2 | -------------------------- 3 | 4 | This tutorial will walk you through installing the acitoolkit using 5 | the sources so that you will be able to edit the samples and even the 6 | acitoolkit source code if so desired. 7 | 8 | Download 9 | ~~~~~~~~ 10 | First, we must download the acitoolkit. This is best done using git, 11 | but can be done by downloading the package as a zip. 12 | 13 | If you have git installed, clone the repository using the following 14 | command:: 15 | 16 | git clone https://github.com/datacenter/acitoolkit.git 17 | 18 | If git is not installed, you can download the acitoolkit as a zip file 19 | instead.:: 20 | 21 | wget https://github.com/datacenter/acitoolkit/archive/master.zip 22 | unzip master.zip 23 | 24 | Install 25 | ~~~~~~~ 26 | 27 | .. sidebar:: Note 28 | 29 | The directory may be named ``acitoolkit-master`` if 30 | downloaded as a zip file. 31 | 32 | Next, cd into the created directory :: 33 | 34 | cd acitoolkit 35 | 36 | and install the acitoolkit :: 37 | 38 | python setup.py install 39 | 40 | Note that when installing on Mac or Linux, you will likely need to run 41 | this as administrator so preface the command with the ``sudo`` keyword 42 | as follows:: 43 | 44 | sudo python setup.py install 45 | 46 | If you plan on modifying the actual toolkit files, you should install the developer 47 | environment that will link the package installation to your development directory. Do 48 | this instead of the install option above :: 49 | 50 | sudo python setup.py develop 51 | 52 | Common Installation Errors 53 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 54 | 55 | **Missing development packages** 56 | 57 | Some of the dependencies may require that the python development environment be installed. 58 | This package is usually called ``python-dev`` or ``python-develop``. This is usually the 59 | case when you see an error message referring to a missing file such as ``Python.h: No such 60 | file or directory``. 61 | 62 | In Ubuntu, you would install this package by ``sudo apt-get install python-dev`` 63 | -------------------------------------------------------------------------------- /docs/source/userabc.crt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/datacenter/acitoolkit/629b84887dd0f0183b81efc8adb16817f985541a/docs/source/userabc.crt.png -------------------------------------------------------------------------------- /docs/source/visualizations.rst: -------------------------------------------------------------------------------- 1 | Visualization Examples 2 | ====================== 3 | 4 | This directory contains a number of visualization examples that can be 5 | used to display information collected using the ``acitoolkit``. Many of 6 | the examples are meant to run alongside the ``ACI Endpoint Tracker`` 7 | application and interact with the MySQL database that the ``ACI Endpoint 8 | Tracker`` populates. Most of the visualization examples are interactive. 9 | 10 | Installation 11 | ------------ 12 | 13 | To run the visualizations, the python package ``Flask`` is required. 14 | This can be installed using ``pip`` as follows:: 15 | 16 | pip install flask 17 | 18 | It is also recommended that the ``ACI Endpoint Tracker`` is installed. 19 | 20 | 21 | Usage 22 | ----- 23 | 24 | Run the visualizations as follows (supplying your own MySQL credentials):: 25 | 26 | python acitoolkit-visualizations.py --mysqlip 127.0.0.1 --mysqllogin root --mysqlpassword password 27 | 28 | Alternatively, you can create a `credentials.py` file in the same 29 | directory with the following:: 30 | 31 | MYSQLIP='127.0.0.1' 32 | MYSQLLOGIN='root' 33 | MYSQLPASSWORD='password' 34 | 35 | If the `credentials.py` file is used, run the visualizations as 36 | follows:: 37 | 38 | python acitoolkit-visualizations.py 39 | 40 | Once the visualizations are running, you should see the following 41 | displayed:: 42 | 43 | * Running on http://127.0.0.1:5000/ 44 | * Restarting with reloader 45 | 46 | 47 | Simply point your favorite web browser to the following URL and explore:: 48 | 49 | http://127.0.0.1:5000/ 50 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Package Requirements 3 | # 4 | requests 5 | websocket-client > 0.33.0 6 | gitpython 7 | flask-httpauth 8 | flask-sqlalchemy 9 | flask-admin 10 | flask-bootstrap 11 | flask-wtf 12 | flask-cors 13 | flask 14 | pymysql 15 | tabulate 16 | py-radix 17 | jsonschema 18 | graphviz 19 | ipaddress 20 | deepdiff==3.3.0 21 | -------------------------------------------------------------------------------- /samples/README.md: -------------------------------------------------------------------------------- 1 | # ACI Toolkit Samples # 2 | 3 | This directory contains sample scripts that use the python library. 4 | 5 | ### Set up ### 6 | 7 | In order to use the examples in this directory, it is important to set the PYTHONPATH variable to include the path to the ACI toolkit or have installed the acitoolkit using setup.py. 8 | 9 | ### credentials.py ### 10 | Many of the samples in this directory use the file credentials.py to login to the APIC. Before running, edit the credentials.py with the username, password, and IP address for your environment. 11 | 12 | -------------------------------------------------------------------------------- /samples/aci-add-static-binding-leaves.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import acitoolkit.acitoolkit as aci 3 | 4 | DEFAULT_TENANT = 'TENANT-001' 5 | DEFAULT_APP = 'APP-001' 6 | DEFAULT_EPG = 'EPG-001' 7 | DEFAULT_NODE_ID = '101' 8 | DEFAULT_ENCAP_TYPE = 'vlan' 9 | DEFAULT_ENCAP_ID = '101' 10 | DEFAULT_ENCAP_MODE = 'regular' 11 | DEFAULT_IMMEDIACY = 'immediate' 12 | DEFAULT_POD = '1' 13 | 14 | 15 | def main(): 16 | """ 17 | Main show EPGs routine 18 | :return: None 19 | """ 20 | # Login to APIC 21 | description = ('Simple application that logs on to the APIC' 22 | ' and add static-binding-leaves.') 23 | creds = aci.Credentials('apic', description) 24 | creds.add_argument('-t', '--tenant', help='Tenant name', default=DEFAULT_TENANT) 25 | creds.add_argument('-a', '--app', help='Application profile name', default=DEFAULT_APP) 26 | creds.add_argument('-e', '--epg', help='EPG name', default=DEFAULT_EPG) 27 | creds.add_argument('-n', '--node', help='Node ID (e.g. 101)', default=DEFAULT_NODE_ID) 28 | creds.add_argument('-y', '--type', help='Encapsulation type (vlan | vxlan | nvgre)', default=DEFAULT_ENCAP_TYPE) 29 | creds.add_argument('-i', '--id', help='Specific identifier representing the virtual L2 network (e.g. 100)', default=DEFAULT_ENCAP_ID) 30 | creds.add_argument('-m', '--mode', help='Encapsulation mode (regular | untagged | native)', default=DEFAULT_ENCAP_MODE) 31 | creds.add_argument('-d', '--deploy', help='Deployment immediacy (immediate | lazy)', default=DEFAULT_IMMEDIACY) 32 | creds.add_argument('-o', '--pod', help='Pod number (e.g. 1)', default=DEFAULT_POD) 33 | 34 | args = creds.get() 35 | session = aci.Session(args.url, args.login, args.password) 36 | resp = session.login() 37 | if not resp.ok: 38 | print('%% Could not login to APIC') 39 | 40 | tenant = aci.Tenant(args.tenant) 41 | app = aci.AppProfile(args.app, tenant) 42 | epg = aci.EPG(args.epg, app) 43 | epg.add_static_leaf_binding(args.node, args.type, args.id, args.mode, args.deploy, args.pod) 44 | 45 | # Push it all to the APIC 46 | resp = session.push_to_apic(tenant.get_url(), tenant.get_json()) 47 | 48 | 49 | if __name__ == '__main__': 50 | try: 51 | main() 52 | except KeyboardInterrupt: 53 | pass 54 | -------------------------------------------------------------------------------- /samples/aci-check-cluster.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that shows all of the processes running on a switch 5 | """ 6 | import sys 7 | import json 8 | from acitoolkit import Credentials, Session, Cluster 9 | 10 | 11 | def main(): 12 | """ 13 | Main show Process routine 14 | :return: None 15 | """ 16 | description = 'Simple application that logs on to the APIC and check cluster information for a fabric' 17 | creds = Credentials('apic', description) 18 | 19 | args = creds.get() 20 | 21 | session = Session(args.url, args.login, args.password) 22 | resp = session.login() 23 | if not resp.ok: 24 | print('%% Could not login to APIC') 25 | sys.exit(0) 26 | 27 | cluster = Cluster.get(session) 28 | 29 | if (cluster.config_size != cluster.cluster_size): 30 | print("*******************************************************") 31 | print("WARNING, configured cluster size "), cluster.config_size 32 | print(": not equal to the actual size "), cluster.cluster_size 33 | print("WARNING, desired stats collection might be lost") 34 | print("*******************************************************") 35 | print("APICs in the cluster"), cluster.name, (":") 36 | for apic in cluster.apics: 37 | print(json.dumps(apic, indent=4, sort_keys=True)) 38 | else: 39 | print("PASS") 40 | 41 | 42 | if __name__ == '__main__': 43 | try: 44 | main() 45 | except KeyboardInterrupt: 46 | pass 47 | -------------------------------------------------------------------------------- /samples/aci-create-bd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Sample of creating a BridgeDomain 4 | """ 5 | 6 | from acitoolkit.acitoolkit import Credentials, Session, Tenant, Context, BridgeDomain, Subnet 7 | 8 | 9 | def main(): 10 | """ 11 | Main execution routine 12 | 13 | :return: None 14 | """ 15 | creds = Credentials('apic') 16 | creds.add_argument('--tenant', help='The name of Tenant') 17 | creds.add_argument('--vrf', help='The name of VRF') 18 | creds.add_argument('--bd', help='The name of BridgeDomain') 19 | creds.add_argument('--address', help='Subnet IPv4 Address') 20 | creds.add_argument('--scope', help='The scope of subnet ("public", "private", "shared", "public,shared", "private,shared", "shared,public", "shared,private")') 21 | creds.add_argument('--json', const='false', nargs='?', help='Json output only') 22 | 23 | args = creds.get() 24 | session = Session(args.url, args.login, args.password) 25 | session.login() 26 | 27 | tenant = Tenant(args.tenant) 28 | vrf = Context(args.vrf) 29 | bd = BridgeDomain(args.bd, tenant) 30 | bd.add_context(vrf) 31 | 32 | if args.address is None: 33 | bd.set_arp_flood('yes') 34 | bd.set_unicast_route('no') 35 | else: 36 | bd.set_arp_flood('no') 37 | bd.set_unicast_route('yes') 38 | 39 | subnet = Subnet('', bd) 40 | subnet.addr = args.address 41 | 42 | if args.scope is None: 43 | subnet.set_scope("private") 44 | else: 45 | subnet.set_scope(args.scope) 46 | 47 | if args.json: 48 | print(tenant.get_json()) 49 | else: 50 | resp = session.push_to_apic(tenant.get_url(), 51 | tenant.get_json()) 52 | 53 | if not resp.ok: 54 | print('%% Error: Could not push configuration to APIC') 55 | print(resp.text) 56 | 57 | if __name__ == '__main__': 58 | main() 59 | -------------------------------------------------------------------------------- /samples/aci-create-epg.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Sample of creating a EPG 4 | """ 5 | 6 | from acitoolkit import Credentials, Session, Tenant, AppProfile, BridgeDomain, EPG 7 | 8 | 9 | def main(): 10 | """ 11 | Main execution routine 12 | 13 | :return: None 14 | """ 15 | creds = Credentials('apic') 16 | creds.add_argument('--tenant', help='The name of Tenant') 17 | creds.add_argument('--app', help='The name of ApplicationProfile') 18 | creds.add_argument('--bd', help='The name of BridgeDomain') 19 | creds.add_argument('--epg', help='The name of EPG') 20 | creds.add_argument('--json', const='false', nargs='?', help='Json output only') 21 | 22 | args = creds.get() 23 | session = Session(args.url, args.login, args.password) 24 | session.login() 25 | 26 | tenant = Tenant(args.tenant) 27 | app = AppProfile(args.app, tenant) 28 | bd = BridgeDomain(args.bd, tenant) 29 | epg = EPG(args.epg, app) 30 | epg.add_bd(bd) 31 | 32 | if args.json: 33 | print(tenant.get_json()) 34 | else: 35 | resp = session.push_to_apic(tenant.get_url(), 36 | tenant.get_json()) 37 | 38 | if not resp.ok: 39 | print('%% Error: Could not push configuration to APIC') 40 | print(resp.text) 41 | 42 | if __name__ == '__main__': 43 | main() 44 | -------------------------------------------------------------------------------- /samples/aci-create-tenant.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ################################################################################ 3 | # _ ____ ___ _____ _ _ _ _ # 4 | # / \ / ___|_ _| |_ _|__ ___ | | | _(_) |_ # 5 | # / _ \| | | | | |/ _ \ / _ \| | |/ / | __| # 6 | # / ___ \ |___ | | | | (_) | (_) | | <| | |_ # 7 | # ____ /_/ \_\____|___|___|_|\___/ \___/|_|_|\_\_|\__| # 8 | # / ___|___ __| | ___ / ___| __ _ _ __ ___ _ __ | | ___ ___ # 9 | # | | / _ \ / _` |/ _ \ \___ \ / _` | '_ ` _ \| '_ \| |/ _ \/ __| # 10 | # | |__| (_) | (_| | __/ ___) | (_| | | | | | | |_) | | __/\__ \ # 11 | # \____\___/ \__,_|\___| |____/ \__,_|_| |_| |_| .__/|_|\___||___/ # 12 | # |_| # 13 | ################################################################################ 14 | # # 15 | # Copyright (c) 2015 Cisco Systems # 16 | # All Rights Reserved. # 17 | # # 18 | # Licensed under the Apache License, Version 2.0 (the "License"); you may # 19 | # not use this file except in compliance with the License. You may obtain # 20 | # a copy of the License at # 21 | # # 22 | # http://www.apache.org/licenses/LICENSE-2.0 # 23 | # # 24 | # Unless required by applicable law or agreed to in writing, software # 25 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # 26 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # 27 | # License for the specific language governing permissions and limitations # 28 | # under the License. # 29 | # # 30 | ################################################################################ 31 | """ 32 | It logs in to the APIC and will create the tenant. 33 | """ 34 | import acitoolkit.acitoolkit as aci 35 | 36 | # Define static values to pass (edit these if you wish to set differently) 37 | DEFAULT_TENANT_NAME = 'tenant_kit' 38 | 39 | 40 | def main(): 41 | """ 42 | Main create tenant routine 43 | :return: None 44 | """ 45 | # Get all the arguments 46 | description = 'It logs in to the APIC and will create the tenant.' 47 | creds = aci.Credentials('apic', description) 48 | creds.add_argument('-t', '--tenant', help='The name of tenant', 49 | default=DEFAULT_TENANT_NAME) 50 | args = creds.get() 51 | 52 | # Login to the APIC 53 | session = aci.Session(args.url, args.login, args.password) 54 | resp = session.login() 55 | if not resp.ok: 56 | print('%% Could not login to APIC') 57 | 58 | # Create the Tenant 59 | tenant = aci.Tenant(args.tenant) 60 | 61 | # Push the tenant to the APIC 62 | resp = session.push_to_apic(tenant.get_url(), 63 | tenant.get_json()) 64 | if not resp.ok: 65 | print('%% Error: Could not push configuration to APIC') 66 | print(resp.text) 67 | 68 | 69 | if __name__ == '__main__': 70 | try: 71 | main() 72 | except KeyboardInterrupt: 73 | pass 74 | -------------------------------------------------------------------------------- /samples/aci-epg-reports-in-yaml.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that logs on to the APIC and displays all 5 | EPGs. 6 | """ 7 | import socket 8 | import yaml 9 | import sys 10 | from acitoolkit import Credentials, Session, Tenant, AppProfile, EPG, Endpoint 11 | 12 | 13 | def main(): 14 | """ 15 | Main show EPGs routine 16 | :return: None 17 | """ 18 | # Login to APIC 19 | description = ('Simple application that logs on to the APIC' 20 | ' and displays all of the EPGs.') 21 | creds = Credentials('apic', description) 22 | args = creds.get() 23 | session = Session(args.url, args.login, args.password) 24 | resp = session.login() 25 | if not resp.ok: 26 | print('%% Could not login to APIC') 27 | return 28 | 29 | # Download all of the tenants, app profiles, and EPGs 30 | # and store the names as tuples in a list 31 | tenants = Tenant.get_deep(session) 32 | tenants_list = [] 33 | for tenant in tenants: 34 | tenants_dict = {} 35 | tenants_dict['name'] = tenant.name 36 | 37 | if tenant.descr: 38 | tenants_dict['description'] = tenant.descr 39 | 40 | tenants_dict['app-profiles'] = [] 41 | for app in tenant.get_children(AppProfile): 42 | app_profiles = {'name': app.name} 43 | if app.descr: 44 | app_profiles['description'] = app.descr 45 | app_profiles['epgs'] = [] 46 | 47 | for epg in app.get_children(EPG): 48 | epgs_info = {'name': epg.name} 49 | if epg.descr: 50 | epgs_info['description'] = epg.descr 51 | epgs_info['endpoints'] = [] 52 | 53 | for endpoint in epg.get_children(Endpoint): 54 | endpoint_info = {'name': endpoint.name} 55 | if endpoint.ip != '0.0.0.0': 56 | endpoint_info['ip'] = endpoint.ip 57 | try: 58 | hostname = socket.gethostbyaddr(endpoint.ip)[0] 59 | except socket.error: 60 | hostname = None 61 | if hostname: 62 | endpoint_info['hostname'] = hostname 63 | if endpoint.descr: 64 | endpoint_info['description'] = endpoint.descr 65 | 66 | epgs_info['endpoints'].append(endpoint_info) 67 | app_profiles['epgs'].append(epgs_info) 68 | tenants_dict['app-profiles'].append(app_profiles) 69 | tenants_list.append(tenants_dict) 70 | 71 | tenants_info = {'tenants': tenants_list} 72 | print(yaml.safe_dump(tenants_info, sys.stdout, 73 | indent=4, default_flow_style=False)) 74 | 75 | if __name__ == '__main__': 76 | try: 77 | main() 78 | except KeyboardInterrupt: 79 | pass 80 | -------------------------------------------------------------------------------- /samples/aci-get-tenantObject-from-json.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that takes a tenant json from a file and returns a tenant object 5 | """ 6 | import acitoolkit.acitoolkit as ACI 7 | import argparse 8 | import json 9 | 10 | 11 | def main(): 12 | """ 13 | Main execution routine 14 | 15 | """ 16 | description = 'Simple application that takes a tenant json from a configfile and returns a tenant object.' 17 | parser = argparse.ArgumentParser(description=description) 18 | parser.add_argument('-t', '--tenantname', required = True, help='name of the tenant') 19 | parser.add_argument('-config','--tenantconfigfile', required=True, 20 | help='file containing tenant json') 21 | args = parser.parse_args() 22 | 23 | tenantObject = None 24 | if args.tenantconfigfile: 25 | with open(args.tenantconfigfile) as data_file: 26 | tenant_json = json.load(data_file) 27 | 28 | tenant = ACI.Tenant(args.tenantname) 29 | ACI.Tenant.get_from_json(tenant,tenant_json,parent=tenant) 30 | print(tenant.get_json()) 31 | 32 | if __name__ == '__main__': 33 | main() 34 | -------------------------------------------------------------------------------- /samples/aci-raw-class-query.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that logs on to the APIC and displays all 5 | the response of an API query given the class name and scope 6 | """ 7 | import sys 8 | from pprint import pprint 9 | import acitoolkit.acitoolkit as aci 10 | 11 | 12 | def main(): 13 | description = ('Simple application that logs on to the APIC and displays the' 14 | ' response of a given query') 15 | creds = aci.Credentials('apic', description) 16 | creds.add_argument('-c', '--class_name', help='The class which is to be queried', required=True) 17 | creds.add_argument('-q', '--query_target', default='self', 18 | help=('This restricts the scope of the query,query_target takes self' 19 | '| children | subtree. ex: -q self. The default is self.')) 20 | args = creds.get() 21 | 22 | if not args.class_name: 23 | args.class_name = raw_input("Class Name: ") 24 | 25 | # Login to APIC 26 | session = aci.Session(args.url, args.login, args.password) 27 | resp = session.login() 28 | if not resp.ok: 29 | print('%% Could not login to APIC') 30 | sys.exit(0) 31 | 32 | class_url = '/api/node/class/'+args.class_name+'.json?query-target='+args.query_target 33 | print("class_url is "+class_url) 34 | ret = session.get(class_url) 35 | response = ret.json() 36 | imdata = response['imdata'] 37 | pprint(imdata) 38 | 39 | if __name__ == '__main__': 40 | main() 41 | -------------------------------------------------------------------------------- /samples/aci-show-cdp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that logs on to the APIC, pull all CDP neighbours, 5 | and display in text table format 6 | """ 7 | import acitoolkit.acitoolkit as ACI 8 | from acitoolkit import Node 9 | from acitoolkit.aciConcreteLib import ConcreteCdp 10 | from tabulate import tabulate 11 | 12 | 13 | def main(): 14 | """ 15 | Main show Cdps routine 16 | :return: None 17 | """ 18 | # Take login credentials from the command line if provided 19 | # Otherwise, take them from your environment variables file ~/.profile 20 | description = ('Simple application that logs on to the APIC' 21 | 'and displays all the CDP neighbours.') 22 | creds = ACI.Credentials('apic', description) 23 | args = creds.get() 24 | 25 | # Login to APIC 26 | session = ACI.Session(args.url, args.login, args.password) 27 | resp = session.login() 28 | if not resp.ok: 29 | print('%% Could not login to APIC') 30 | return 31 | 32 | nodes = Node.get_deep(session, include_concrete=True) 33 | cdps = [] 34 | for node in nodes: 35 | node_concrete_cdp = node.get_children(child_type=ConcreteCdp) 36 | for node_concrete_cdp_obj in node_concrete_cdp: 37 | cdps.append(node_concrete_cdp_obj) 38 | 39 | tables = ConcreteCdp.get_table(cdps) 40 | output_list = [] 41 | for table in tables: 42 | for table_data in table.data: 43 | if table_data not in output_list: 44 | output_list.append(table_data) 45 | print(tabulate(output_list, headers=["Node-ID", 46 | "Local Interface", 47 | "Neighbour Device", 48 | "Neighbour Platform", 49 | "Neighbour Interface"])) 50 | 51 | 52 | if __name__ == '__main__': 53 | main() 54 | -------------------------------------------------------------------------------- /samples/aci-show-contexts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that logs on to the APIC and displays all 5 | of the Contexts. 6 | """ 7 | import sys 8 | import acitoolkit.acitoolkit as ACI 9 | 10 | data = [] 11 | longest_names = {'Tenant': len('Tenant'), 12 | 'Context': len('Context')} 13 | 14 | 15 | def main(): 16 | """ 17 | Main execution routine 18 | 19 | :return: None 20 | """ 21 | # Take login credentials from the command line if provided 22 | # Otherwise, take them from your environment variables file ~/.profile 23 | description = 'Simple application that logs on to the APIC and displays all of the Contexts.' 24 | creds = ACI.Credentials('apic', description) 25 | creds.add_argument('--tenant', help='The name of Tenant') 26 | args = creds.get() 27 | 28 | # Login to APIC 29 | session = ACI.Session(args.url, args.login, args.password) 30 | resp = session.login() 31 | if not resp.ok: 32 | print('%% Could not login to APIC') 33 | sys.exit(0) 34 | 35 | # Download all of the contexts 36 | # and store the data as tuples in a list 37 | tenants = ACI.Tenant.get(session) 38 | for tenant in tenants: 39 | check_longest_name(tenant.name, "Tenant") 40 | if args.tenant is None: 41 | get_context(session, tenant) 42 | else: 43 | if tenant.name == args.tenant: 44 | get_context(session, tenant) 45 | 46 | # IPython.embed() 47 | 48 | # Display the data downloaded 49 | template = '{0:' + str(longest_names["Tenant"]) + '} ' \ 50 | '{1:' + str(longest_names["Context"]) + '}' 51 | print(template.format("Tenant", "Context")) 52 | print(template.format('-' * longest_names["Tenant"], 53 | '-' * longest_names["Context"])) 54 | for rec in sorted(data): 55 | print(template.format(*rec)) 56 | 57 | 58 | def get_context(session, tenant): 59 | contexts = ACI.Context.get(session, tenant) 60 | for context in contexts: 61 | check_longest_name(context.name, "Context") 62 | data.append((tenant.name, context.name)) 63 | 64 | 65 | def check_longest_name(item, title): 66 | if len(item) > longest_names[title]: 67 | longest_names[title] = len(item) 68 | 69 | 70 | if __name__ == '__main__': 71 | main() 72 | -------------------------------------------------------------------------------- /samples/aci-show-contracts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that logs on to the APIC and displays all 5 | of the Contracts. 6 | """ 7 | import sys 8 | import acitoolkit.acitoolkit as aci 9 | 10 | data = [] 11 | longest_names = {'Tenant': len('Tenant'), 12 | 'Contract': len('Contract')} 13 | 14 | 15 | def main(): 16 | """ 17 | Main show contracts routine 18 | :return: None 19 | """ 20 | # Take login credentials from the command line if provided 21 | # Otherwise, take them from your environment variables file ~/.profile 22 | description = ('Simple application that logs on to the APIC' 23 | 'and displays all of the Contracts.') 24 | creds = aci.Credentials('apic', description) 25 | creds.add_argument('--tenant', help='The name of Tenant') 26 | args = creds.get() 27 | 28 | # Login to APIC 29 | session = aci.Session(args.url, args.login, args.password) 30 | resp = session.login() 31 | if not resp.ok: 32 | print('%% Could not login to APIC') 33 | sys.exit(0) 34 | 35 | # Download all of the contracts 36 | # and store the data as tuples in a list 37 | tenants = aci.Tenant.get(session) 38 | for tenant in tenants: 39 | check_longest_name(tenant.name, "Tenant") 40 | if args.tenant is None: 41 | get_contract(session, tenant) 42 | else: 43 | if tenant.name == args.tenant: 44 | get_contract(session, tenant) 45 | 46 | # IPython.embed() 47 | 48 | # Display the data downloaded 49 | template = '{0:' + str(longest_names["Tenant"]) + '} ' \ 50 | '{1:' + str(longest_names["Contract"]) + '}' 51 | print(template.format("Tenant", "Contract")) 52 | print(template.format('-' * longest_names["Tenant"], 53 | '-' * longest_names["Contract"])) 54 | for rec in sorted(data): 55 | print(template.format(*rec)) 56 | 57 | 58 | def get_contract(session, tenant): 59 | contracts = aci.Contract.get(session, tenant) 60 | for contract in contracts: 61 | check_longest_name(contract.name, "Contract") 62 | data.append((tenant.name, contract.name)) 63 | 64 | 65 | def check_longest_name(item, title): 66 | if len(item) > longest_names[title]: 67 | longest_names[title] = len(item) 68 | 69 | 70 | if __name__ == '__main__': 71 | try: 72 | main() 73 | except KeyboardInterrupt: 74 | pass 75 | -------------------------------------------------------------------------------- /samples/aci-show-domains.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that logs on to the APIC and displays all 5 | of the Physical Domains, VMM Domains, and EPG associations. 6 | """ 7 | import sys 8 | import acitoolkit.acitoolkit as aci 9 | 10 | 11 | def main(): 12 | """ 13 | Main Show Domains Routine 14 | :return: None 15 | """ 16 | # Take login credentials from the command line if provided 17 | # Otherwise, take them from your environment variables file ~/.profile 18 | description = ('Simple application that logs on to the APIC' 19 | ' and displays all of the Endpoints.') 20 | creds = aci.Credentials('apic', description) 21 | args = creds.get() 22 | 23 | # Login to APIC 24 | session = aci.Session(args.url, args.login, args.password) 25 | resp = session.login() 26 | if not resp.ok: 27 | print('%% Could not login to APIC') 28 | sys.exit(0) 29 | 30 | domains = aci.PhysDomain.get(session) 31 | 32 | if len(domains) > 0: 33 | print('---------------') 34 | print('Physical Domain') 35 | print('---------------') 36 | 37 | for domain in domains: 38 | print(domain.name) 39 | 40 | if len(domains) > 0: 41 | print('\n') 42 | 43 | domains = aci.VmmDomain.get(session) 44 | 45 | if len(domains) > 0: 46 | print('----------') 47 | print('VMM Domain') 48 | print('----------') 49 | 50 | for domain in domains: 51 | print(domain.name) 52 | 53 | if len(domains) > 0: 54 | print('\n') 55 | 56 | domains = aci.L2ExtDomain.get(session) 57 | 58 | if len(domains) > 0: 59 | print('------------------') 60 | print('L2 External Domain') 61 | print('------------------') 62 | 63 | for domain in domains: 64 | print(domain.name) 65 | 66 | if len(domains) > 0: 67 | print('\n') 68 | 69 | domains = aci.L3ExtDomain.get(session) 70 | 71 | if len(domains) > 0: 72 | print('------------------') 73 | print('L3 External Domain') 74 | print('------------------') 75 | 76 | for domain in domains: 77 | print(domain.name) 78 | 79 | if len(domains) > 0: 80 | print('\n') 81 | 82 | domains = aci.EPGDomain.get(session) 83 | 84 | output = [] 85 | for domain in domains: 86 | association = domain.tenant_name + ':' + domain.app_name + ':' + domain.epg_name 87 | output.append((domain.domain_name, domain.domain_type, 88 | association)) 89 | 90 | if len(domains) > 0: 91 | template = '{0:20} {1:11} {2:26}' 92 | print(template.format('Infra Domain Profile', 'Domain Type', 'TENANT:APP:EPG Association')) 93 | print(template.format("-" * 20, "-" * 11, "-" * 26)) 94 | for rec in output: 95 | print(template.format(*rec)) 96 | print('\n') 97 | 98 | 99 | if __name__ == '__main__': 100 | try: 101 | main() 102 | except KeyboardInterrupt: 103 | pass 104 | -------------------------------------------------------------------------------- /samples/aci-show-epgs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Simple application that logs on to the APIC and displays all 4 | EPGs. 5 | """ 6 | from acitoolkit import Credentials, Session, Tenant, AppProfile, EPG 7 | 8 | data = [] 9 | longest_names = {'Tenant': len('Tenant'), 10 | 'Application Profile': len('Application Profile'), 11 | 'EPG': len('EPG')} 12 | 13 | 14 | def main(): 15 | """ 16 | Main show EPGs routine 17 | :return: None 18 | """ 19 | # Login to APIC 20 | description = ('Simple application that logs on to the APIC' 21 | ' and displays all of the EPGs.') 22 | creds = Credentials('apic', description) 23 | creds.add_argument('--tenant', help='The name of Tenant') 24 | args = creds.get() 25 | 26 | session = Session(args.url, args.login, args.password) 27 | resp = session.login() 28 | if not resp.ok: 29 | print('%% Could not login to APIC') 30 | 31 | # Download all of the tenants, app profiles, and EPGs 32 | # and store the names as tuples in a list 33 | tenants = Tenant.get(session) 34 | for tenant in tenants: 35 | check_longest_name(tenant.name, "Tenant") 36 | if args.tenant is None: 37 | get_epg(session, tenant) 38 | else: 39 | if tenant.name == args.tenant: 40 | get_epg(session, tenant) 41 | 42 | # Display the data downloaded 43 | template = '{0:' + str(longest_names["Tenant"]) + '} ' \ 44 | '{1:' + str(longest_names["Application Profile"]) + '} ' \ 45 | '{2:' + str(longest_names["EPG"]) + '}' 46 | print(template.format("Tenant", "Application Profile", "EPG")) 47 | print(template.format('-' * longest_names["Tenant"], 48 | '-' * longest_names["Application Profile"], 49 | '-' * longest_names["EPG"])) 50 | for rec in sorted(data): 51 | print(template.format(*rec)) 52 | 53 | 54 | def get_epg(session, tenant): 55 | """ 56 | Get the EPG 57 | :param session: Session class instance 58 | :param tenant: String containing the Tenant name 59 | """ 60 | apps = AppProfile.get(session, tenant) 61 | for app in apps: 62 | check_longest_name(app.name, "Application Profile") 63 | epgs = EPG.get(session, app, tenant) 64 | for epg in epgs: 65 | check_longest_name(epg.name, "EPG") 66 | data.append((tenant.name, app.name, epg.name)) 67 | 68 | 69 | def check_longest_name(item, title): 70 | """ 71 | Check the longest name 72 | :param item: String containing the name 73 | :param title: String containing the column title 74 | """ 75 | if len(item) > longest_names[title]: 76 | longest_names[title] = len(item) 77 | 78 | 79 | if __name__ == '__main__': 80 | try: 81 | main() 82 | except KeyboardInterrupt: 83 | pass 84 | -------------------------------------------------------------------------------- /samples/aci-show-faults-by-domain.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | simple application that logs on to apic and displays all the faults. 5 | if a particular tenant is given shows faults of that tenant 6 | and if a domain is given displays faults related to that domain. 7 | list of domains can also be given 8 | """ 9 | from acitoolkit import (Credentials, Session, Faults) 10 | 11 | 12 | def main(): 13 | """ 14 | Main execution routine 15 | """ 16 | description = 'Simple application that logs on to the APIC and displays all of the Tenants.' 17 | creds = Credentials('apic', description) 18 | creds.add_argument( 19 | "-d", 20 | "--domain-name", 21 | type=str, 22 | help="list of domains. usage -d tennat.infra") 23 | creds.add_argument( 24 | "-t", 25 | "--tenant-name", 26 | type=str, 27 | help="name of the tenant of which faults are to be displayed. If not given faults of all the tenants are shown") 28 | creds.add_argument('--continuous', action='store_true', 29 | help='Continuously monitor for faults') 30 | args = creds.get() 31 | 32 | # Login to APIC 33 | session = Session(args.url, args.login, args.password) 34 | resp = session.login() 35 | if not resp.ok: 36 | print('%% Could not login to APIC') 37 | return 38 | 39 | faults_obj = Faults() 40 | fault_filter = None 41 | if args.domain_name is not None: 42 | fault_filter = {'domain': args.domain_name.split(',')} 43 | tenant_name = None 44 | if args.tenant_name is not None: 45 | tenant_name = args.tenant_name 46 | 47 | faults_obj.subscribe_faults(session, fault_filter) 48 | while faults_obj.has_faults(session, fault_filter) or args.continuous: 49 | if faults_obj.has_faults(session, fault_filter): 50 | faults = faults_obj.get_faults( 51 | session, fault_filter=fault_filter, tenant_name=tenant_name) 52 | if faults is not None: 53 | for fault in faults: 54 | if fault is not None: 55 | print("---------------") 56 | if fault.descr is not None: 57 | print(" descr : " + fault.descr) 58 | else: 59 | print(" descr : " + " ") 60 | print(" dn : " + fault.dn) 61 | print(" rule : " + fault.rule) 62 | print(" severity : " + fault.severity) 63 | print(" type : " + fault.type) 64 | print(" domain : " + fault.domain) 65 | 66 | 67 | if __name__ == '__main__': 68 | main() 69 | -------------------------------------------------------------------------------- /samples/aci-show-imported-contracts.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Find out where a contract has been imported and consumed on an EPG. 5 | """ 6 | from acitoolkit import (Credentials, Session, Tenant, ContractInterface, AppProfile, 7 | EPG) 8 | from tabulate import tabulate 9 | 10 | data = [] 11 | 12 | 13 | def main(): 14 | """ 15 | Main execution routine 16 | """ 17 | description = ('Simple application that logs on to the APIC' 18 | ' and displays all the tenant info of the contract_interface related to the imported contract.') 19 | creds = Credentials('apic', description) 20 | creds.add_argument("-t", "--tenant_name", help="Tenant Name of where the contract is created") 21 | creds.add_argument("-i", "--contract_name", help="Imported Contract Name") 22 | args = creds.get() 23 | 24 | if (args.tenant_name is not None) and (args.contract_name is None): 25 | args.contract_name = raw_input("Contract Name: ") 26 | 27 | session = Session(args.url, args.login, args.password) 28 | resp = session.login() 29 | if not resp.ok: 30 | print('%% Could not login to APIC') 31 | 32 | tenants = Tenant.get_deep(session) 33 | for tenant in tenants: 34 | contracts_interfaces = tenant.get_children(only_class=ContractInterface) 35 | for contract_interface in contracts_interfaces: 36 | imported_contract = contract_interface.get_import_contract() 37 | if imported_contract is not None: 38 | if args.tenant_name is not None: 39 | if (imported_contract.name == args.contract_name) and (imported_contract.get_parent().name == args.tenant_name): 40 | apps = AppProfile.get(session, tenant) 41 | for app in apps: 42 | epgs = EPG.get(session, app, tenant) 43 | for epg in epgs: 44 | data.append((imported_contract.name, tenant.name, app.name, epg.name)) 45 | else: 46 | apps = AppProfile.get(session, tenant) 47 | for app in apps: 48 | epgs = EPG.get(session, app, tenant) 49 | for epg in epgs: 50 | data.append((imported_contract.name, tenant.name, app.name, epg.name)) 51 | print(tabulate(data, headers=["IMPORTED_CONTRACT", "TENANT", "APP_PROFILE", "EPG"])) 52 | 53 | 54 | if __name__ == '__main__': 55 | main() 56 | -------------------------------------------------------------------------------- /samples/aci-show-ip-int-brief.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that logs on to the APIC and displays all 5 | of the Interfaces. 6 | """ 7 | import sys 8 | import re 9 | import json 10 | from acitoolkit import Credentials, Session 11 | 12 | data = {} 13 | longest_names = {'Node': len('Node'), 14 | 'Interface': len('Interface'), 15 | 'IP Address': len('IP Address'), 16 | 'Admin Status': len('Admin Status'), 17 | 'Status': len('Status')} 18 | 19 | 20 | def main(): 21 | """ 22 | Main execution routine 23 | 24 | :return: None 25 | """ 26 | # Take login credentials from the command line if provided 27 | # Otherwise, take them from your environment variables file ~/.profile 28 | description = 'Simple application that logs on to the APIC and displays all of the Interfaces.' 29 | creds = Credentials('apic', description) 30 | creds.add_argument('--tenant', help='The name of Tenant') 31 | args = creds.get() 32 | 33 | # Login to APIC 34 | session = Session(args.url, args.login, args.password) 35 | resp = session.login() 36 | if not resp.ok: 37 | print('%% Could not login to APIC') 38 | sys.exit(0) 39 | 40 | resp = session.get('/api/class/ipv4Addr.json') 41 | intfs = json.loads(resp.text)['imdata'] 42 | 43 | for i in intfs: 44 | ip = i['ipv4Addr']['attributes']['addr'] 45 | op = i['ipv4Addr']['attributes']['operSt'] 46 | cfg = i['ipv4Addr']['attributes']['operStQual'] 47 | dn = i['ipv4Addr']['attributes']['dn'] 48 | node = dn.split('/')[2] 49 | intf = re.split(r'\[|\]', dn)[1] 50 | vrf = re.split(r'/|dom-', dn)[7] 51 | tn = vrf 52 | if vrf.find(":") != -1: 53 | tn = re.search("(.*):(.*)", vrf).group(1) 54 | 55 | check_longest_name(node, "Node") 56 | check_longest_name(intf, "Interface") 57 | check_longest_name(ip, "IP Address") 58 | check_longest_name(cfg, "Admin Status") 59 | check_longest_name(op, "Status") 60 | 61 | if args.tenant is None: 62 | if vrf not in data.keys(): 63 | data[vrf] = [] 64 | else: 65 | data[vrf].append((node, intf, ip, cfg, op)) 66 | else: 67 | if tn == args.tenant: 68 | if vrf not in data.keys(): 69 | data[vrf] = [] 70 | else: 71 | data[vrf].append((node, intf, ip, cfg, op)) 72 | 73 | for k in data.keys(): 74 | header = 'IP Interface Status for VRF "{}"'.format(k) 75 | print(header) 76 | template = '{0:' + str(longest_names["Node"]) + '} ' \ 77 | '{1:' + str(longest_names["Interface"]) + '} ' \ 78 | '{2:' + str(longest_names["IP Address"]) + '} ' \ 79 | '{3:' + str(longest_names["Admin Status"]) + '} ' \ 80 | '{4:' + str(longest_names["Status"]) + '}' 81 | print(template.format("Node", "Interface", "IP Address", "Admin Status", "Status")) 82 | print(template.format('-' * longest_names["Node"], 83 | '-' * longest_names["Interface"], 84 | '-' * longest_names["IP Address"], 85 | '-' * longest_names["Admin Status"], 86 | '-' * longest_names["Status"])) 87 | for rec in sorted(data[k]): 88 | print(template.format(*rec)) 89 | print('') 90 | 91 | 92 | def check_longest_name(item, title): 93 | """ 94 | Check the longest name 95 | :param item: String containing the name 96 | :param title: String containing the column title 97 | """ 98 | if len(item) > longest_names[title]: 99 | longest_names[title] = len(item) 100 | 101 | 102 | if __name__ == '__main__': 103 | main() 104 | -------------------------------------------------------------------------------- /samples/aci-show-lldp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that logs on to the APIC, pull all LLDP neighbours, 5 | and display in text table format 6 | """ 7 | import acitoolkit.acitoolkit as ACI 8 | from acitoolkit import Node 9 | from acitoolkit.aciConcreteLib import ConcreteLLdp 10 | from tabulate import tabulate 11 | 12 | 13 | def main(): 14 | """ 15 | Main show LLdps routine 16 | :return: None 17 | """ 18 | # Take login credentials from the command line if provided 19 | # Otherwise, take them from your environment variables file ~/.profile 20 | description = ('Simple application that logs on to the APIC' 21 | 'and displays all the LLDP neighbours.') 22 | creds = ACI.Credentials('apic', description) 23 | args = creds.get() 24 | 25 | # Login to APIC 26 | session = ACI.Session(args.url, args.login, args.password) 27 | resp = session.login() 28 | if not resp.ok: 29 | print('%% Could not login to APIC') 30 | return 31 | 32 | nodes = Node.get_deep(session, include_concrete=True) 33 | lldps = [] 34 | for node in nodes: 35 | node_concrete_lldp = node.get_children(child_type=ConcreteLLdp) 36 | for node_concrete_lldp_obj in node_concrete_lldp: 37 | lldps.append(node_concrete_lldp_obj) 38 | 39 | tables = ConcreteLLdp.get_table(lldps) 40 | output_list = [] 41 | for table in tables: 42 | for table_data in table.data: 43 | if table_data not in output_list: 44 | output_list.append(table_data) 45 | print(tabulate(output_list, headers=["Node-ID", 46 | "Local Interface", 47 | "Ip", 48 | "Name", 49 | "Chassis_id_t", 50 | "Neighbour Platform", 51 | "Neighbour Interface"])) 52 | 53 | if __name__ == '__main__': 54 | main() 55 | -------------------------------------------------------------------------------- /samples/aci-show-nodes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ################################################################################ 3 | # _ ____ ___ _____ _ _ _ _ # 4 | # / \ / ___|_ _| |_ _|__ ___ | | | _(_) |_ # 5 | # / _ \| | | | | |/ _ \ / _ \| | |/ / | __| # 6 | # / ___ \ |___ | | | | (_) | (_) | | <| | |_ # 7 | # ____ /_/ \_\____|___|___|_|\___/ \___/|_|_|\_\_|\__| # 8 | # / ___|___ __| | ___ / ___| __ _ _ __ ___ _ __ | | ___ ___ # 9 | # | | / _ \ / _` |/ _ \ \___ \ / _` | '_ ` _ \| '_ \| |/ _ \/ __| # 10 | # | |__| (_) | (_| | __/ ___) | (_| | | | | | | |_) | | __/\__ \ # 11 | # \____\___/ \__,_|\___| |____/ \__,_|_| |_| |_| .__/|_|\___||___/ # 12 | # |_| # 13 | ################################################################################ 14 | # # 15 | # Copyright (c) 2015 Cisco Systems # 16 | # All Rights Reserved. # 17 | # # 18 | # Licensed under the Apache License, Version 2.0 (the "License"); you may # 19 | # not use this file except in compliance with the License. You may obtain # 20 | # a copy of the License at # 21 | # # 22 | # http://www.apache.org/licenses/LICENSE-2.0 # 23 | # # 24 | # Unless required by applicable law or agreed to in writing, software # 25 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # 26 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # 27 | # License for the specific language governing permissions and limitations # 28 | # under the License. # 29 | # # 30 | ################################################################################ 31 | """ 32 | Simple application that logs on to the APIC and displays all 33 | of the physical nodes; both belonging to and connected to the 34 | fabric. 35 | """ 36 | import sys 37 | 38 | from acitoolkit import Session, Credentials, Node, ExternalSwitch 39 | 40 | 41 | def main(): 42 | """ 43 | Main execution routine 44 | 45 | :return: None 46 | """ 47 | # Take login credentials from the command line if provided 48 | # Otherwise, take them from your environment variables file ~/.profile 49 | description = ('Simple application that logs on to the APIC and displays all' 50 | ' of the physical nodes; both belonging to and connected to the fabric.') 51 | creds = Credentials('apic', description) 52 | args = creds.get() 53 | 54 | # Login to APIC 55 | session = Session(args.url, args.login, args.password) 56 | resp = session.login() 57 | if not resp.ok: 58 | print('%% Could not login to APIC') 59 | sys.exit(0) 60 | 61 | # List of classes to get and print 62 | phy_classes = (Node, ExternalSwitch) 63 | 64 | for phy_class in phy_classes: 65 | # Print the class name 66 | class_name = phy_class.__name__ 67 | print(class_name) 68 | print('=' * len(class_name)) 69 | 70 | # Get and print all of the items from the APIC 71 | items = phy_class.get(session) 72 | for item in items: 73 | print(item.info()) 74 | 75 | if __name__ == '__main__': 76 | main() 77 | -------------------------------------------------------------------------------- /samples/aci-show-physical-inventory.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ################################################################################ 3 | # _ ____ ___ _____ _ _ _ _ # 4 | # / \ / ___|_ _| |_ _|__ ___ | | | _(_) |_ # 5 | # / _ \| | | | | |/ _ \ / _ \| | |/ / | __| # 6 | # / ___ \ |___ | | | | (_) | (_) | | <| | |_ # 7 | # ____ /_/ \_\____|___|___|_|\___/ \___/|_|_|\_\_|\__| # 8 | # / ___|___ __| | ___ / ___| __ _ _ __ ___ _ __ | | ___ ___ # 9 | # | | / _ \ / _` |/ _ \ \___ \ / _` | '_ ` _ \| '_ \| |/ _ \/ __| # 10 | # | |__| (_) | (_| | __/ ___) | (_| | | | | | | |_) | | __/\__ \ # 11 | # \____\___/ \__,_|\___| |____/ \__,_|_| |_| |_| .__/|_|\___||___/ # 12 | # |_| # 13 | ################################################################################ 14 | # # 15 | # Copyright (c) 2015 Cisco Systems # 16 | # All Rights Reserved. # 17 | # # 18 | # Licensed under the Apache License, Version 2.0 (the "License"); you may # 19 | # not use this file except in compliance with the License. You may obtain # 20 | # a copy of the License at # 21 | # # 22 | # http://www.apache.org/licenses/LICENSE-2.0 # 23 | # # 24 | # Unless required by applicable law or agreed to in writing, software # 25 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # 26 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # 27 | # License for the specific language governing permissions and limitations # 28 | # under the License. # 29 | # # 30 | ################################################################################ 31 | """ 32 | Simple application to display the physical inventory 33 | """ 34 | from acitoolkit.acitoolkit import Credentials, Session 35 | import sys 36 | from acitoolkit.aciphysobject import Pod 37 | 38 | 39 | def print_inventory(item): 40 | """ 41 | Display routine 42 | 43 | :param item: Object to print 44 | :return: None 45 | """ 46 | for child in item.get_children(): 47 | print_inventory(child) 48 | print(item.info()) 49 | 50 | 51 | def main(): 52 | """ 53 | Main execution routine 54 | 55 | :return: None 56 | """ 57 | # Take login credentials from the command line if provided 58 | # Otherwise, take them from your environment variables 59 | description = ('Simple application that logs on to the APIC and displays' 60 | ' the physical inventory.') 61 | creds = Credentials('apic', description) 62 | args = creds.get() 63 | 64 | # Login to APIC 65 | session = Session(args.url, args.login, args.password) 66 | resp = session.login() 67 | if not resp.ok: 68 | print('%% Could not login to APIC') 69 | sys.exit(0) 70 | 71 | # Print the inventory of each Pod 72 | pods = Pod.get(session) 73 | for pod in pods: 74 | pod.populate_children(deep=True) 75 | pod_name = 'Pod: %s' % pod.name 76 | print(pod_name) 77 | print('=' * len(pod_name)) 78 | print_inventory(pod) 79 | 80 | if __name__ == '__main__': 81 | try: 82 | main() 83 | except KeyboardInterrupt: 84 | pass 85 | -------------------------------------------------------------------------------- /samples/aci-show-process.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that shows all of the processes running on a switch 5 | """ 6 | import sys 7 | import acitoolkit as ACI 8 | from acitoolkit.acitoolkitlib import Credentials 9 | 10 | 11 | def main(): 12 | """ 13 | Main show Process routine 14 | :return: None 15 | """ 16 | description = 'Simple application that logs on to the APIC and displays process information for a switch' 17 | creds = Credentials('apic', description) 18 | 19 | creds.add_argument('-s', '--switch', 20 | type=str, 21 | default=None, 22 | help='Specify a particular switch id, e.g. "102"') 23 | args = creds.get() 24 | 25 | session = ACI.Session(args.url, args.login, args.password) 26 | resp = session.login() 27 | if not resp.ok: 28 | print('%% Could not login to APIC') 29 | sys.exit(0) 30 | 31 | switches = ACI.Node.get(session, '1', args.switch) 32 | for switch in switches: 33 | if switch.role != 'controller': 34 | processes = ACI.Process.get(session, switch) 35 | tables = ACI.Process.get_table(processes, 'Process list for Switch ' + switch.name + '::') 36 | for table in tables: 37 | try: 38 | print(table.get_text(tablefmt='fancy_grid') + '\n') 39 | except UnicodeEncodeError: 40 | print(table.get_text(tablefmt='plain') + '\n') 41 | 42 | if __name__ == '__main__': 43 | try: 44 | main() 45 | except KeyboardInterrupt: 46 | pass 47 | -------------------------------------------------------------------------------- /samples/aci-show-subnets.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that logs on to the APIC and displays all 5 | of the Subnets. 6 | """ 7 | from acitoolkit import (Credentials, Session, Tenant, 8 | BridgeDomain, Subnet) 9 | 10 | data = [] 11 | longest_names = {'Tenant': len('Tenant'), 12 | 'Bridge Domain': len('Bridge Domain'), 13 | 'Subnet': len('Subnet'), 14 | 'Scope': len('Scope')} 15 | 16 | 17 | def main(): 18 | """ 19 | Main show Subnets routine 20 | :return: None 21 | """ 22 | # Take login credentials from the command line if provided 23 | # Otherwise, take them from your environment variables file ~/.profile 24 | description = ('Simple application that logs on to the APIC' 25 | ' and displays all of the Subnets.') 26 | creds = Credentials('apic', description) 27 | creds.add_argument('--tenant', help='The name of Tenant') 28 | args = creds.get() 29 | 30 | # Login to APIC 31 | session = Session(args.url, args.login, args.password) 32 | resp = session.login() 33 | if not resp.ok: 34 | print('%% Could not login to APIC') 35 | 36 | # Download all of the tenants, app profiles, and Subnets 37 | # and store the names as tuples in a list 38 | tenants = Tenant.get(session) 39 | for tenant in tenants: 40 | check_longest_name(tenant.name, "Tenant") 41 | if args.tenant is None: 42 | get_subnet(session, tenant) 43 | else: 44 | if tenant.name == args.tenant: 45 | get_subnet(session, tenant) 46 | 47 | # Display the data downloaded 48 | template = '{0:' + str(longest_names["Tenant"]) + '} ' \ 49 | '{1:' + str(longest_names["Bridge Domain"]) + '} ' \ 50 | '{2:' + str(longest_names["Subnet"]) + '} ' \ 51 | '{3:' + str(longest_names["Scope"]) + '}' 52 | print(template.format("Tenant", "Bridge Domain", "Subnet", "Scope")) 53 | print(template.format('-' * longest_names["Tenant"], 54 | '-' * longest_names["Bridge Domain"], 55 | '-' * longest_names["Subnet"], 56 | '-' * longest_names["Scope"])) 57 | for rec in sorted(data): 58 | print(template.format(*rec)) 59 | 60 | 61 | def get_subnet(session, tenant): 62 | """ 63 | Get the subnet 64 | :param session: Session class instance 65 | :param tenant: String containing tenant name 66 | """ 67 | bds = BridgeDomain.get(session, tenant) 68 | for bd in bds: 69 | check_longest_name(bd.name, "Bridge Domain") 70 | subnets = Subnet.get(session, bd, tenant) 71 | if len(subnets) == 0: 72 | data.append((tenant.name, bd.name, "", "")) 73 | else: 74 | for subnet in subnets: 75 | check_longest_name(subnet.addr, "Subnet") 76 | check_longest_name(subnet.get_scope(), "Scope") 77 | data.append((tenant.name, bd.name, 78 | subnet.addr, subnet.get_scope())) 79 | 80 | 81 | def check_longest_name(item, title): 82 | """ 83 | Check the longest name 84 | :param item: String containing the name 85 | :param title: String containing the column title 86 | """ 87 | if len(item) > longest_names[title]: 88 | longest_names[title] = len(item) 89 | 90 | 91 | if __name__ == '__main__': 92 | try: 93 | main() 94 | except KeyboardInterrupt: 95 | pass 96 | -------------------------------------------------------------------------------- /samples/aci-show-tenant-detail.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import acitoolkit.acitoolkit as aci 5 | 6 | 7 | def main(): 8 | # Login to APIC 9 | description = ('Simple application that logs on to the APIC' 10 | ' and displays all of the External Subnets.') 11 | creds = aci.Credentials('apic', description) 12 | creds.add_argument('--tenant', help='The name of Tenant') 13 | args = creds.get() 14 | 15 | option = '' 16 | if args.tenant is not None: 17 | option = ' --tenant ' + args.tenant 18 | 19 | execute('show contexts', 'aci-show-contexts.py' + option) 20 | execute('show contracts', 'aci-show-contracts.py' + option) 21 | execute('show epgs', 'aci-show-epgs.py' + option) 22 | execute('show external epgs', 'aci-show-external-networks.py' + option) 23 | execute('show ip interface brief', 'aci-show-ip-int-brief.py' + option) 24 | execute('show subnets', 'aci-show-subnets.py' + option) 25 | 26 | 27 | def execute(title, command): 28 | show_header(title) 29 | os.system('./' + command) 30 | 31 | 32 | def show_header(title): 33 | print("\n==================== " + title + " ====================") 34 | 35 | if __name__ == '__main__': 36 | try: 37 | main() 38 | except KeyboardInterrupt: 39 | pass 40 | -------------------------------------------------------------------------------- /samples/aci-show-tenant-faults.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that logs on to the APIC and displays all 5 | of the faults on all the Tenants. 6 | If a particular tenant is given, shows all the faults of that tenant 7 | and cotinuously keeps logging the faults. 8 | """ 9 | import acitoolkit as ACI 10 | from acitoolkit import Faults 11 | 12 | 13 | def main(): 14 | """ 15 | Main execution routine 16 | """ 17 | description = ('Simple application that logs on to the APIC' 18 | ' and displays all the faults. If tenant name is given, ' 19 | ' shows the faults associated with that tenant') 20 | creds = ACI.Credentials('apic', description) 21 | creds.add_argument("-t", "--tenant_name", 22 | help="name of the tenant of which faults are to be displayed") 23 | creds.add_argument('--continuous', action='store_true', 24 | help='Continuously monitor for tenant faults') 25 | args = creds.get() 26 | 27 | # Login to APIC 28 | session = ACI.Session(args.url, args.login, args.password) 29 | resp = session.login() 30 | if not resp.ok: 31 | print('%% Could not login to APIC') 32 | return 33 | if args.tenant_name is not None: 34 | tenant_name = args.tenant_name 35 | else: 36 | tenant_name = None 37 | 38 | faults_obj = Faults() 39 | faults_obj.subscribe_faults(session) 40 | while faults_obj.has_faults(session) or args.continuous: 41 | if faults_obj.has_faults(session): 42 | faults = faults_obj.get_faults(session, tenant_name=tenant_name) 43 | if faults is not None: 44 | for fault in faults: 45 | if fault is not None: 46 | print("****************") 47 | if fault.descr is not None: 48 | print(" descr : " + fault.descr) 49 | else: 50 | print(" descr : " + " ") 51 | print(" dn : " + fault.dn) 52 | print(" rule : " + fault.rule) 53 | print(" severity : " + fault.severity) 54 | print(" type : " + fault.type) 55 | print(" domain : " + fault.domain) 56 | 57 | if __name__ == '__main__': 58 | main() 59 | -------------------------------------------------------------------------------- /samples/aci-show-tenant-health.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Simple application that logs on to the APIC and displays 5 | health on all the Tenants. 6 | """ 7 | import acitoolkit.acitoolkit as ACI 8 | import re 9 | 10 | 11 | def main(): 12 | """ 13 | Main execution routine 14 | 15 | :return: None 16 | """ 17 | # Take login credentials from the command line if provided 18 | # Otherwise, take them from your environment variables file ~/.profile 19 | description = ('Simple application that logs on to the APIC and displays ' 20 | ' health all of the Tenants,keeps on checking continuously') 21 | creds = ACI.Credentials('apic', description) 22 | creds.add_argument('--continuous', action='store_true', 23 | help='Continuously monitor for tenant health changes') 24 | args = creds.get() 25 | 26 | # Login to APIC 27 | session = ACI.Session(args.url, args.login, args.password) 28 | resp = session.login() 29 | if not resp.ok: 30 | print('%% Could not login to APIC') 31 | return 32 | 33 | extension = '&rsp-subtree-include=health,no-scoped' 34 | 35 | ACI.Tenant.subscribe(session, extension) 36 | 37 | template = "{0:70} {1:6} " 38 | print(template.format("tenant", "current_health")) 39 | print(template.format("---------", "----")) 40 | try: 41 | while ACI.Tenant.has_events(session, extension) or args.continuous: 42 | if ACI.Tenant.has_events(session, extension): 43 | health_object = ACI.Tenant.get_fault(session, extension) 44 | health_inst = health_object['healthInst']['attributes'] 45 | tenant_name = health_inst['dn'] 46 | health = health_inst['cur'] 47 | match_obj = re.match(r'uni/tn-(.*)/health', tenant_name) 48 | print(template.format(match_obj.group(1), health)) 49 | except KeyboardInterrupt: 50 | return 51 | 52 | if __name__ == '__main__': 53 | main() 54 | -------------------------------------------------------------------------------- /samples/aci-show-tenants-in-multisite-orchestrator.py: -------------------------------------------------------------------------------- 1 | # Sample code accessing the Cisco Multisite Orchestrator 2 | from requests import Session 3 | 4 | 5 | # Replace the following variables with the correct values for your deployment. 6 | username = 'admin' 7 | password = 'password' 8 | mso_ip = '10.10.10.10' 9 | 10 | 11 | def show_tenants(): 12 | # Login to Multisite Orchestrator 13 | session = Session() 14 | data = {'username': username, 'password': password} 15 | resp = session.post('https://%s/api/v1/auth/login' % mso_ip, json=data, verify=False) 16 | if not resp.ok: 17 | print('Could not login to Multisite Orchestrator') 18 | return 19 | 20 | # Get the tenants 21 | headers = {"Authorization": "Bearer %s" % resp.json()['token']} 22 | resp = session.get('https://%s/api/v1/tenants' % mso_ip, headers=headers) 23 | if not resp.ok: 24 | print('Could not get tenants from Multisite Orchestrator') 25 | return 26 | 27 | # Print the result 28 | print('Tenants') 29 | print('-' * len('Tenants')) 30 | for tenant in resp.json()['tenants']: 31 | print(tenant['displayName']) 32 | 33 | 34 | if __name__ == '__main__': 35 | show_tenants() -------------------------------------------------------------------------------- /samples/aci-show-tenants.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ################################################################################ 3 | # _ ____ ___ _____ _ _ _ _ # 4 | # / \ / ___|_ _| |_ _|__ ___ | | | _(_) |_ # 5 | # / _ \| | | | | |/ _ \ / _ \| | |/ / | __| # 6 | # / ___ \ |___ | | | | (_) | (_) | | <| | |_ # 7 | # ____ /_/ \_\____|___|___|_|\___/ \___/|_|_|\_\_|\__| # 8 | # / ___|___ __| | ___ / ___| __ _ _ __ ___ _ __ | | ___ ___ # 9 | # | | / _ \ / _` |/ _ \ \___ \ / _` | '_ ` _ \| '_ \| |/ _ \/ __| # 10 | # | |__| (_) | (_| | __/ ___) | (_| | | | | | | |_) | | __/\__ \ # 11 | # \____\___/ \__,_|\___| |____/ \__,_|_| |_| |_| .__/|_|\___||___/ # 12 | # |_| # 13 | ################################################################################ 14 | # # 15 | # Copyright (c) 2015 Cisco Systems # 16 | # All Rights Reserved. # 17 | # # 18 | # Licensed under the Apache License, Version 2.0 (the "License"); you may # 19 | # not use this file except in compliance with the License. You may obtain # 20 | # a copy of the License at # 21 | # # 22 | # http://www.apache.org/licenses/LICENSE-2.0 # 23 | # # 24 | # Unless required by applicable law or agreed to in writing, software # 25 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # 26 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # 27 | # License for the specific language governing permissions and limitations # 28 | # under the License. # 29 | # # 30 | ################################################################################ 31 | """ 32 | Simple application that logs on to the APIC and displays all 33 | of the Tenants. 34 | """ 35 | import sys 36 | import acitoolkit.acitoolkit as ACI 37 | 38 | 39 | def main(): 40 | """ 41 | Main execution routine 42 | 43 | :return: None 44 | """ 45 | # Take login credentials from the command line if provided 46 | # Otherwise, take them from your environment variables file ~/.profile 47 | description = 'Simple application that logs on to the APIC and displays all of the Tenants.' 48 | creds = ACI.Credentials('apic', description) 49 | args = creds.get() 50 | 51 | # Login to APIC 52 | session = ACI.Session(args.url, args.login, args.password) 53 | resp = session.login() 54 | if not resp.ok: 55 | print('%% Could not login to APIC') 56 | sys.exit(0) 57 | 58 | # Download all of the tenants 59 | print("TENANT") 60 | print("------") 61 | tenants = ACI.Tenant.get(session) 62 | for tenant in tenants: 63 | print(tenant.name) 64 | 65 | if __name__ == '__main__': 66 | main() 67 | -------------------------------------------------------------------------------- /samples/aci-where-used.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Find out where a DN is used 5 | """ 6 | from acitoolkit import Credentials, Session 7 | from tabulate import tabulate 8 | 9 | data = [] 10 | 11 | 12 | def main(): 13 | """ 14 | Main execution routine 15 | """ 16 | description = ('Simple application that logs on to the APIC' 17 | ' and displays usage information for a given DN') 18 | creds = Credentials('apic', description) 19 | creds.add_argument("-d", "--dn_name", 20 | help="DN to query for usage information") 21 | 22 | args = creds.get() 23 | 24 | session = Session(args.url, args.login, args.password) 25 | resp = session.login() 26 | if not resp.ok: 27 | print('%% Could not login to APIC') 28 | url = '/api/mo/{}.json?query-target=children&target-subtree-class=relnFrom' 29 | url = url.format(args.dn_name) 30 | 31 | resp = session.get(url) 32 | 33 | if resp.ok: 34 | used_by = resp.json()['imdata'] 35 | for item in used_by: 36 | kls = next(iter(item)) 37 | attributes = item[kls]['attributes'] 38 | data.append((attributes['tDn'], kls)) 39 | print(tabulate(data, headers=["Used by", "Class"])) 40 | 41 | 42 | if __name__ == '__main__': 43 | main() 44 | -------------------------------------------------------------------------------- /samples/credentials.py.sample: -------------------------------------------------------------------------------- 1 | LOGIN = "admin" 2 | PASSWORD = "password" 3 | URL = "https://10.0.0.1" 4 | -------------------------------------------------------------------------------- /samples/switch-commands/README.md: -------------------------------------------------------------------------------- 1 | # ACI Toolkit Samples - Switch Commands # 2 | 3 | This directory contains sample scripts that operate in a similar manner to the commands provided on the individual switches. 4 | -------------------------------------------------------------------------------- /scripts/install_dependencies: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script is used to self initialize the preinstalled acitoolkit VM 4 | 5 | apt-get -y update 6 | apt-get -y upgrade 7 | apt-get install python-dev 8 | cd acitoolkit 9 | git pull 10 | python setup.py develop 11 | /etc/init.d/mysql start 12 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """ 2 | ACIToolkit Installer using setuptools 3 | """ 4 | import os, sys 5 | from setuptools import setup 6 | 7 | base_dir = os.path.dirname(__file__) 8 | 9 | about = {} 10 | with open(os.path.join(base_dir, "acitoolkit", "__about__.py")) as f: 11 | exec(f.read(), about) 12 | 13 | setup( 14 | name=about["__title__"], 15 | version=about["__version__"], 16 | packages=["acitoolkit"], 17 | author=about["__author__"], 18 | author_email=about["__email__"], 19 | url=about["__uri__"], 20 | license=about["__license__"], 21 | install_requires=["requests", 22 | "websocket-client>0.33.0", 23 | "gitpython", 24 | "flask-httpauth", 25 | "flask-sqlalchemy", 26 | "flask-admin", 27 | "flask-bootstrap", 28 | "flask-wtf", 29 | "flask-cors", 30 | "flask", 31 | "pymysql", 32 | "tabulate", 33 | "py-radix", 34 | "jsonschema", 35 | "graphviz", 36 | "ipaddress", 37 | "{}".format("deepdiff==3.3.0" if sys.version_info[0] == 2 else "deepdiff")], 38 | tests_requires=["mock"], 39 | description="This library allows basic Cisco ACI APIC configuration.", 40 | ) 41 | -------------------------------------------------------------------------------- /shippable.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.7" 5 | cache: true 6 | 7 | build: 8 | ci: 9 | - mkdir -p shippable/codecoverage 10 | - shippable_retry pip install --upgrade pip 11 | - shippable_retry pip install -r requirements.txt 12 | - shippable_retry pip install coverage 13 | - "python setup.py -q develop" 14 | - coverage run -p tests/acitoolkit_test.py 15 | - coverage run -p tests/aciphysobject_test.py 16 | - coverage run -p tests/acitoolkitlib_test.py 17 | on_success: 18 | - coverage combine 19 | - coverage report --include=*acitoolkit* 20 | - coverage xml -o shippable/codecoverage/coverage.xml --include=*acitoolkit* 21 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | Toolkit Unit Tests 2 | ================== 3 | 4 | The acitoolkit package has a unit test suite that strives for a 5 | minimum of 100% code coverage. The main test suite is contained 6 | within the ``acitoolkit_test.py`` file. Within the test suite, the 7 | tests can be classified into 2 types; live tests and offline tests. 8 | Live tests are those that actually communicate with an APIC and push 9 | configuration to/from the APIC. Offline tests run locally and do not 10 | communicate with the APIC in any way. 11 | 12 | The tests are can be run in the following ways:: 13 | 14 | python acitoolkit_test.py [offline | live | full ] 15 | 16 | The optional keyword allows ``offline``, ``live``, or the ``full`` 17 | testsuite to be run. If the keyword is not provided, the default of 18 | ``offline`` will be used. 19 | 20 | When adding additional code or making changes to the toolkit, please 21 | ensure that unit tests are added to cover the new functionality and 22 | that the entire test suite is run against the modified toolkit before 23 | submitting the code. Minimal code coverage can be verified using 24 | tools such as 25 | [coverage.py](https://pypi.python.org/pypi/coverage). For instance, 26 | after installing coverage.py, the toolkit can be run with the 27 | command:: 28 | 29 | coverage run acitoolkit_test.py 30 | 31 | and an HTML report of the code coverage can be generated with the 32 | command:: 33 | 34 | coverage html 35 | 36 | If changes are made to the ``acitoolkit.py`` file, please ensure that 37 | the ``acitoolkit_test.py`` is run and that code coverage remains at 38 | 100%. 39 | 40 | -------------------------------------------------------------------------------- /tests/aci_configuration_randomizer.ini: -------------------------------------------------------------------------------- 1 | # Configuration file for the ACI Configuration Randomizer tool 2 | # A random configuration will be created based on the constraints entered here 3 | [GlobalDefaults] 4 | MaximumStringLength: 40 5 | # MaximumStringLength: 64 6 | TenantPrefix: acitoolkitrandomized- 7 | 8 | [Tenants] 9 | Minimum: 3 10 | Maximum: 5 11 | GlobalMaximum: 3000 12 | 13 | [BridgeDomains] 14 | Minimum: 0 15 | Maximum: 3 16 | MaximumEPGs: 3499 17 | GlobalMaximum: 15000 18 | AllowFloodUnkMacUcast: True 19 | AllowOptimizedFloodUnknownMcast: True 20 | AllowArpFlood: True 21 | AllowDisableUnicastRoute: True 22 | AllowNonDefaultMultiDstPkt: True 23 | 24 | [BridgeDomainSettings] 25 | UnknownMacUnicast: ["proxy", "flood"] 26 | UnknownMulticast: ["flood", "opt-flood"] 27 | ArpFlood: ["yes", "no"] 28 | UnicastRoute: ["yes", "no"] 29 | Multidestination: ["drop", "bd-flood", "encap-flood"] 30 | 31 | [Contexts] 32 | Minimum: 0 33 | Maximum: 5 34 | MaximumPerTenant: 8 35 | GlobalMaximum: 3000 36 | AllowUnenforced: True 37 | 38 | [ApplicationProfiles] 39 | Minimum: 3 40 | Maximum: 5 41 | 42 | [EPGs] 43 | Minimum: 5 44 | Maximum: 10 45 | GlobalMaximum: 15000 46 | #TODO: need to finish the settings for this after handling domains 47 | 48 | [Taboos] 49 | Minimum: 0 50 | Maximum: 2 51 | 52 | [Contracts] 53 | Minimum: 3 54 | Maximum: 8 55 | MaximumConsumingEPGs: 10 56 | MaximumProvidingEPGs: 10 57 | GlobalMaximum: 1000 58 | 59 | [ContractSubjects] 60 | Minimum: 0 61 | Maximum: 10 62 | 63 | [TabooContractSubjects] 64 | Minimum: 0 65 | Maximum: 10 66 | 67 | [Filters] 68 | Minimum: 10 69 | Maximum: 15 70 | GlobalMaximum: 10000 71 | 72 | [FilterEntries] 73 | Minimum: 20 74 | Maximum: 30 75 | GlobalMaximum: 10000 76 | 77 | [Interfaces] 78 | Interfaces: ["eth 1/101/1/17", "eth 1/102/1/17"] 79 | 80 | # VLANs to use when attaching EPGs to Interfaces 81 | [VLANs] 82 | Minimum: 1 83 | Maximum: 4095 84 | 85 | # Ethertypes and protocols used 86 | [Ethertypes] 87 | Choice20PC: ["arp"] 88 | Choice16PC: ["trill", "mpls_ucast", "mac_security", "fcoe"] 89 | Choice74PC: ["ip"] 90 | 91 | [IPProtocols] 92 | Choice20PC: ["igmp", "egp", "igp", "eigrp", "ospfigp", "pim", "l2tp"] 93 | Choice80PC: ["icmp", "tcp", "udp", "icmpv6"] 94 | 95 | # Options to be used in filters for different traffic types 96 | [FilterEntryOptions] 97 | Fragmentation: ["0", "1"] 98 | ARPCode: ["req", "reply"] 99 | TCPRules: ["est", "syn", "ack", "fin", "rst"] 100 | ICMP4Types: ["echo-rep", "dst-unreach", "src-quench", "echo", "time-exceeded", "unspecified", "not-given"] 101 | ICMP6Types: ["unspecified", "dst-unreach", "time-exceeded", "echo-req", "echo-rep", "nbr-solicit", "nbr-advert", "redirect", "not-given"] 102 | PortRangeMin: 0 103 | PortRangeMax: 65535 104 | 105 | [NegativeFlowOptions] 106 | Ethertypes: ["ip", "arp"] 107 | IPProtocols: ["icmp", "tcp", "udp", "l2tp"] 108 | ARPCode: ["req", "reply"] 109 | TCPRules: ["est", "syn", "ack", "fin", "rst"] 110 | ICMP4Types: ["echo-rep", "dst-unreach", "src-quench", "echo", "time-exceeded", "unspecified"] 111 | ICMP6Types: ["unspecified", "dst-unreach", "time-exceeded", "echo-req", "echo-rep", "nbr-solicit", "nbr-advert", "redirect"] 112 | PortRangeMin: 1 113 | PortRangeMax: 65535 114 | MaxNegativeFlows: 5 -------------------------------------------------------------------------------- /tests/acitoolkit_randomized_test.py: -------------------------------------------------------------------------------- 1 | from acitoolkit_test import TestLiveAPIC 2 | from acitoolkit import Tenant 3 | import unittest 4 | 5 | 6 | class TestRandomizationCleanup(TestLiveAPIC): 7 | """ 8 | Tests used in conjunction with randomized configurations 9 | """ 10 | def test_verify_all_tenants_deleted(self): 11 | """ 12 | Test that all of the randomied tenants have been deleted 13 | """ 14 | session = self.login_to_apic() 15 | tenants = Tenant.get(session) 16 | for tenant in tenants: 17 | self.assertFalse(tenant.name.startswith('acitoolkitrandomized-')) 18 | 19 | if __name__ == '__main__': 20 | unittest.main() 21 | -------------------------------------------------------------------------------- /tests/acitoolkitlib_test.py: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # _ ____ ___ # 3 | # / \ / ___|_ _| # 4 | # / _ \| | | | # 5 | # / ___ \ |___ | | # 6 | # _____/_/ \_\____|___|_ _ # 7 | # |_ _|__ ___ | | | _(_) |_ # 8 | # | |/ _ \ / _ \| | |/ / | __| # 9 | # | | (_) | (_) | | <| | |_ # 10 | # |_|\___/ \___/|_|_|\_\_|\__| # 11 | # # 12 | ################################################################################ 13 | # # 14 | # Copyright (c) 2015 Cisco Systems # 15 | # All Rights Reserved. # 16 | # # 17 | # Licensed under the Apache License, Version 2.0 (the "License"); you may # 18 | # not use this file except in compliance with the License. You may obtain # 19 | # a copy of the License at # 20 | # # 21 | # http://www.apache.org/licenses/LICENSE-2.0 # 22 | # # 23 | # Unless required by applicable law or agreed to in writing, software # 24 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # 25 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # 26 | # License for the specific language governing permissions and limitations # 27 | # under the License. # 28 | # # 29 | ################################################################################ 30 | """acitoolkitlib.py Test module 31 | """ 32 | from acitoolkit.acitoolkitlib import Credentials 33 | import unittest 34 | 35 | 36 | class TestCredentials(unittest.TestCase): 37 | """ 38 | Test Credentials class from acitoolkitlib.py 39 | """ 40 | def test_create_all(self): 41 | """ 42 | Basic test for all Credentials qualifiers 43 | """ 44 | creds = Credentials(['apic', 'mysql']) 45 | 46 | def return_empty_string(disp): 47 | """ Return an empty string """ 48 | return '' 49 | 50 | creds._get_from_user = return_empty_string 51 | creds._get_password = return_empty_string 52 | self.assertTrue(isinstance(creds, Credentials)) 53 | creds.get() 54 | creds.verify() 55 | 56 | def test_create_apic_string_only(self): 57 | """ 58 | Basic test for only APIC Credentials qualifiers 59 | passed as a single string 60 | """ 61 | creds = Credentials('apic') 62 | self.assertTrue(isinstance(creds, Credentials)) 63 | 64 | def test_create_apic_list_only(self): 65 | """ 66 | Basic test for only APIC Credentials qualifiers 67 | passed as a single string in a list 68 | """ 69 | creds = Credentials(['apic']) 70 | self.assertTrue(isinstance(creds, Credentials)) 71 | 72 | if __name__ == '__main__': 73 | 74 | offline = unittest.TestSuite() 75 | offline.addTest(unittest.makeSuite(TestCredentials)) 76 | 77 | unittest.main() 78 | --------------------------------------------------------------------------------