Config/management model framework initial version

This is the initial commit of the internal config
model tree for Voltha.

A system that borrows key concepts from Docker, repo,
and git for multi-revision configuration handling with
transaction (commit/abort) logic, tagging, and the
ability to diff between config versions.

Key features:
* Stored model is defined using *annotated* Google protobuf
  (*.proto) files
* Model is kept in memory as Python protobuf message objects
* The whole configuration is arranged in a nested (tree)
  structure, made up of ConfigNode objects. Each
  ConfigNode holds its config data as (possibly nested)
  protobuf message object, as well as lists of "pointers"
  to its logically nested children nodes. What message
  fields are considered part of the node-local config vs.
  what is stored as a child node is controlled by "child_node"
  annotations in the *.proto files.
* Each ConifgNode stores its config in immutable
  ConfigRevision obects, each revision being identified
  by a unique hash value, calculated from a unique
  hash value of its local configuration as well as
  the list of hash values of all its children node.
* Collection type children nodes can be indexed (keyed)
  so that they can be addressed with "path" notation
  friendly to REST and other interfaces/APIs. Which
  field is used as key is defined in the parent message
  using "key" attribute of the "child_node" annotation.
  Currently string and integer type fields can be used
  as keys.
* Changes to the model create new revisions in all
  affected nodes, which are rolled up as new revisions
  to the root node.
* Root revisions can be tagged, tags can be moved
* The root node by default keeps a rev, but provides
  a mechanism to purge untagged revs.
* All branch and leaf nodes auto-purge interim revs
  not needed. A rev is not needed if no one refers
  to it.
* Diffing between revs is supported, it yields RFC6902
  jsonpatch objects. Diffing can be done between any
  revs.
* The main operations are: CRUD (we call them .add,
  .get, .update, .remove)
* Get can be recursive to an optionally limited depth.
* There is support for Read-Only attributes (fields)
* All CRUD operation support "path" based addressing.
* There is support for an branch/leaf node perspective
  implemented by ConfigProxy. This proxy, when attached
  to an arbitrary node in the tree, provides all the
  CRUD operations in that context, that is, path args
  are used relative to that node.
* Transaction support: All mutations made in a transaction
  are invisible to others until the transaction is committed.
  The commit is atomic (either all changes are applied
  to the tree or none). Conflicts between transactions
  are detected at the per-node level and a conflict
  results in rejecting the conflicting transaction (first
  one wins).
* Registered callbacks: via the proxy objects an
  observer can register for pre- and post- operation
  callbacks. Also, there is a post-get callback which
  can be used to augment stored data with real-time
  data.

I started hooking up the new config infrastructure to
Voltha's CORE, but this is still in progress, as not
all existing APIs have bee moved over yet.

Note: I also lumped in some experimental files working
with "Any" types in protobufs

Change-Id: Ic547b36e9b893d54e6d9ce67bdfcb32a6e8acd4c
diff --git a/voltha/main.py b/voltha/main.py
index a19c1ba..39ff1f4 100755
--- a/voltha/main.py
+++ b/voltha/main.py
@@ -30,9 +30,14 @@
     get_my_primary_local_ipv4
 from voltha.adapters.loader import AdapterLoader
 from voltha.coordinator import Coordinator
+from voltha.core.core import VolthaCore
 from voltha.northbound.grpc.grpc_server import VolthaGrpcServer
 from voltha.northbound.kafka.kafka_proxy import KafkaProxy, get_kafka_proxy
 from voltha.northbound.rest.health_check import init_rest_service
+from voltha.protos.common_pb2 import INFO
+from voltha.registry import registry
+
+VERSION = '0.9.0'
 
 defs = dict(
     config=os.environ.get('CONFIG', './voltha.yml'),
@@ -214,12 +219,6 @@
         # configurable variables from voltha.yml file
         #self.configurable_vars = self.config.get('Constants', {})
 
-        # components
-        self.coordinator = None
-        self.grpc_server = None
-        self.kafka_proxy = None
-        self.adapter_loader = None
-
         if not args.no_banner:
             print_banner(self.log)
 
@@ -236,40 +235,49 @@
     def startup_components(self):
         try:
             self.log.info('starting-internal-components')
-            self.coordinator = yield Coordinator(
+
+            coordinator = yield Coordinator(
                 internal_host_address=self.args.internal_host_address,
                 external_host_address=self.args.external_host_address,
                 rest_port=self.args.rest_port,
                 instance_id=self.args.instance_id,
                 config=self.config,
                 consul=self.args.consul).start()
+            registry.register('coordinator', coordinator)
+
             init_rest_service(self.args.rest_port)
 
-            self.grpc_server = yield VolthaGrpcServer(self.args.grpc_port).start()
+            grpc_server = \
+                yield VolthaGrpcServer(self.args.grpc_port).start()
+            registry.register('grpc_server', grpc_server)
 
-            # initialize kafka proxy singleton
-            self.kafka_proxy = yield KafkaProxy(self.args.consul, self.args.kafka)
+            core = \
+                yield VolthaCore(
+                    instance_id=self.args.instance_id,
+                    version=VERSION,
+                    log_level=INFO
+                ).start()
+            registry.register('core', core)
 
-            # adapter loader
-            self.adapter_loader = yield AdapterLoader(
+            kafka_proxy = \
+                yield KafkaProxy(self.args.consul, self.args.kafka).start()
+            registry.register('kafka_proxy', kafka_proxy)
+
+            adapter_loader = yield AdapterLoader(
                 config=self.config.get('adapter_loader', {})).start()
+            registry.register('adapter_loader', adapter_loader)
 
             self.log.info('started-internal-services')
 
         except Exception as e:
             self.log.exception('Failure to start all components {}'.format(e))
 
-
     @inlineCallbacks
     def shutdown_components(self):
         """Execute before the reactor is shut down"""
         self.log.info('exiting-on-keyboard-interrupt')
-        if self.adapter_loader is not None:
-            yield self.adapter_loader.stop()
-        if self.coordinator is not None:
-            yield self.coordinator.stop()
-        if self.grpc_server is not None:
-            yield self.grpc_server.stop()
+        for component in reversed(registry.iterate()):
+            yield component.stop()
 
     def start_reactor(self):
         from twisted.internet import reactor