1. Organization of sources:

   main.py ........ program driver
   entity.py ...... NSX entities, edge, lrouter, lswitch, l2forwarder ...
   entity_db.py ... Database of different types of entity
   build.py ....... Build NSX topology based on bundle or appctl (live setup)
   stats.py ....... port drop statistics
   defs.py ........ static definitions
   utils.py ....... utilities (to be merged with that in CLI component)
   steps.py ....... steps to obtain any interesting data, starting with entity
   artifact.py .... where all sanity checks live
   transport.py ... SSH or NAPI access (work-in-progress)
   inconsistency_check.py .... driver for CLI form of the tool

1. Spanning entities are first-class citizen. E.g. lswitch, lrouter, etc,
   represented by class 'Entity' in source 'entity.py'. An 'Lswitch' object is
   not a lswitch on any edge, but the collection of all instances for this
   lswitch on all edges it spans to by config. Each instance of an entity is
   represented by a 'XXXSpan' class. E.g. a particular instance of lswitch on
   edge X will be represented by an LswitchSpan object; on Y, by another
   such object ...

1. Entity hierarchies

   TransportNode
      |
      +-- Edge
      +-- (ESX/KVM??) // not yet implemented

    Xtep
      |
      +-- Vtep
      +-- Rtep

   Entity
      |
      +-- Lswitch -------- [LswitchSpan] ----- {L2FIB}
      +-- LswitchPort ---- [LswitchPortSpan]
      +-- Lrouter -------- [LrouterSpan] --+-- {ARP}
      |      |                             +-- {L3FIB}
      +-- ServiceRouter -- [ServiceRouterSpan]
      +-- ServiceRouterCluster -- [ServiceRouterClusterSpan]
      +-- LrouterPort -- [LrouterPortSpan]
      +-- L2Forwarder -- [L2ForwarderSpan]
      +-- XtepGroup ---- [XtepGroupSpan]
      +-- Pnic --------- [PnicSpan]
      +-- PnicStats ---- [PnicStatsSpan]
      +-- Tunnel ------- [TunnelSpan]
      +-- Bfd ---------- [BfdSpan]
      +-- BfdStats ----- [BfdStatsSpan]

3. Each span contains JSON from all sources producing data for this type of
   entity. E.g. an LrouterSpan would have JSON output from nsxa and datapath
   as it has state in both processes. There is no limit on data source.
   An entity span can have source from nsxa, dp, lb/iked ... per requirement.
   A source is called "copmonent". JSON data extraction per component is
   done in build.py.

4. 'build.py' mainly relies on build.json to build all entities. Build.json
   lays out necessary steps, as defined in steps.py to pinpoint the right
   data in JSON output to represent an entity. All these can be done much
   more quickly with hardcoding, but we hope that in this way, we can separate
   entity data location from the core logic. People can provide their own
   build.json to extract data only for, say, service X. It should also be
   easy, though not without updating build.py, to add more entity data location
   in build.json

2. Inside each type of span, we provide simple APIs to access the actual
   data from JSON. All other sources must use such API to obtain the desired
   state vs. directly accessing JSON. This way, hopefully we can localize
   future JSON changes in backend process in entity.py alone

4. For most entities created so far in this tool, DP is the default data source.
   If DP source is not available, the corresponding output of an entity in
   topology dump would be suffixed with "(nsxa data)". This is true even for
   entities that by design exist only in nsxa, e.g. service-router, internal-vrf
   router.

5. Relationship among entities are statically established, in whatever we deem
   reasonable at the time of development. Some relationships feel more "natural"
   than others. E.g. Lswitch is parent of lswitch ports. Some feel a bit
   arbitrary and created solely due to limitations in how we structure the
   build.json. E.g. tunnel --> bfd ---> bfd stats.
