Major rework of gRPC handling (do not merge yet)

Includes the following chages:

* Refactored proto files
  - separation of logical devices vs devices
  - common flow related message types moved to openflow_13
  - most RPC is defined in voltha.proto now
* Expanded RPC definitions to cover now most of what we
  need (a few device provisioning RPCs are still missing)
* Reworked RPC handlers to work with new config tree
* Implemented test cases for all existing RPCs, tested via
  chameleon's REST service
* Did away wih the OrderedDict internal representation
  in the config nodes (3x performance boost on bulk
  add, and negligible penalty in other ops)
* Refactored transacton merge handling to align with
  new structures

Change-Id: I3740ec13b8296943b307782e86e6b596af78140e
diff --git a/grpc_client/grpc_client.py b/grpc_client/grpc_client.py
index 36618be..74933cd 100644
--- a/grpc_client/grpc_client.py
+++ b/grpc_client/grpc_client.py
@@ -30,7 +30,7 @@
 from grpc._channel import _Rendezvous
 from structlog import get_logger
 from twisted.internet import reactor
-from twisted.internet.defer import inlineCallbacks
+from twisted.internet.defer import inlineCallbacks, returnValue
 from werkzeug.exceptions import ServiceUnavailable
 
 from common.utils.asleep import asleep
@@ -251,7 +251,8 @@
             log.debug('test-import', modname=modname)
             _ = __import__(modname)
 
-    def invoke(self, stub, method_name, request):
+    @inlineCallbacks
+    def invoke(self, stub, method_name, request, retry=1):
         """
         Invoke a gRPC call to the remote server and return the response.
         :param stub: Reference to the *_pb2 service stub
@@ -265,16 +266,22 @@
 
         try:
             response = getattr(stub(self.channel), method_name)(request)
-            return response
+            returnValue(response)
 
         except grpc._channel._Rendezvous, e:
             if e.code() == grpc.StatusCode.UNAVAILABLE:
                 e = ServiceUnavailable()
+
+                if self.connected:
+                    self.connected = False
+                    yield self.connect()
+                    if retry > 0:
+                        response = yield self.invoke(stub, method_name,
+                                                     request,
+                                                     retry=retry - 1)
+                        returnValue(response)
+
             else:
                 log.exception(e)
 
-            if self.connected :
-                self.connected = False
-                reactor.callLater(0, self.connect)
-
             raise e
diff --git a/protoc_plugins/gw_gen.py b/protoc_plugins/gw_gen.py
index 4596bef..c5a8875 100755
--- a/protoc_plugins/gw_gen.py
+++ b/protoc_plugins/gw_gen.py
@@ -32,7 +32,9 @@
 
 from simplejson import dumps, load
 from structlog import get_logger
-from protobuf_to_dict import protobuf_to_dict, dict_to_protobuf
+from protobuf_to_dict import dict_to_protobuf
+from google.protobuf.json_format import MessageToDict
+from twisted.internet.defer import inlineCallbacks, returnValue
 
 {% set package = file_name.replace('.proto', '') %}
 
@@ -54,6 +56,7 @@
     {% set method_name = method['service'].rpartition('.')[2] + '_' + method['method'] %}
     {% set path = method['path'].replace('{', '<string:').replace('}', '>') %}
     @app.route('{{ path }}', methods=['{{ method['verb'].upper() }}'])
+    @inlineCallbacks
     def {{ method_name }}(server, request, **kw):
         log.debug('{{ method_name }}', request=request, server=server, **kw)
         {% if method['body'] == '*' %}
@@ -69,11 +72,11 @@
         except Exception, e:
             log.error('cannot-convert-to-protobuf', e=e, data=data)
             raise
-        res = grpc_client.invoke(
+        res = yield grpc_client.invoke(
             {{ type_map[method['service']] }}Stub,
             '{{ method['method'] }}', req)
         try:
-            out_data = protobuf_to_dict(res, use_enum_labels=True)
+            out_data = MessageToDict(res, True, True)
         except AttributeError, e:
             filename = '/tmp/chameleon_failed_to_convert_data.pbd'
             with file(filename, 'w') as f:
@@ -82,7 +85,7 @@
             raise
         request.setHeader('Content-Type', 'application/json')
         log.debug('{{ method_name }}', **out_data)
-        return dumps(out_data)
+        returnValue(dumps(out_data))
 
     {% endfor %}