The commit consists of:

1) Support metadata (e.g. get-depth) for rpc request.
2) Support parameters in rpc requests
3) Generate the code for netconf rpc to Voltha grpc mapping
4) Initial Support custom rpc requests (those defined in the voltha YANG schemas).

Change-Id: I24dc7fd75b5f71d0d8591637579672b25fda57ec
diff --git a/netconf/nc_rpc/rpc_factory.py b/netconf/nc_rpc/rpc_factory.py
index d51942c..47c1eaa 100644
--- a/netconf/nc_rpc/rpc_factory.py
+++ b/netconf/nc_rpc/rpc_factory.py
@@ -30,14 +30,15 @@
 from base.kill_session import KillSession
 from ext.get_schemas import GetSchemas
 from ext.get_schema import GetSchema
-from ext.get_voltha import GetVoltha
+from ext.voltha_rpc import VolthaRpc
 import netconf.nc_common.error as ncerror
 from netconf.nc_common.utils import qmap, ns
+from netconf.grpc_client.nc_rpc_mapper import get_nc_rpc_mapper_instance
 from lxml import etree
 
-
 log = structlog.get_logger()
 
+
 class RpcFactory:
     instance = None
 
@@ -52,10 +53,14 @@
             if tup[0] == name:
                 return tup[1]
 
+    def get_filtered_attributes(self, names_to_filter_out, attributes):
+        result = []
+        for tup in attributes.items():
+            if tup[0] not in names_to_filter_out:
+                result.append((tup[0], tup[1]))
+        return result
 
     # Parse a request (node is an ElementTree) and return a dictionary
-    # TODO:  This parser is specific for a GET/GET SCHEMAS request.  Need to be
-    #  it more generic
     def parse_xml_request(self, node):
         request = {}
         if not len(node):
@@ -70,17 +75,37 @@
                 elif elem_name == 'filter':
                     request['filter'] = self.get_attribute_value('type',
                                                                  elem.attrib)
+                    # Get the metadata
+                    request['metadata'] = self.get_filtered_attributes(
+                        ['type'],
+                        elem.attrib)
                 else:
-                    request['command'] = elem_name  # attribute is empty for now
+                    request[
+                        'command'] = elem_name  # attribute is empty for now
             elif elem.tag.find(qmap(C.VOLTHA)) != -1:  # found
                 request['namespace'] = ns(C.VOLTHA)
                 if request.has_key('class'):
-                    request['subclass'] = elem.tag.replace(qmap(C.VOLTHA),"")
+                    request['subclass'] = elem.tag.replace(qmap(C.VOLTHA), "")
                 else:
                     elem_name = elem.tag.replace(qmap(C.VOLTHA), "")
                     request['class'] = elem_name
                     if not request.has_key('command'):
                         request['command'] = elem_name
+                        request['metadata'] = self.get_filtered_attributes(
+                            ['xmlns'],
+                            elem.attrib)
+            elif elem.tag.find(qmap(C.HEALTH)) != -1:  # found
+                request['namespace'] = ns(C.HEALTH)
+                if request.has_key('class'):
+                    request['subclass'] = elem.tag.replace(qmap(C.HEALTH), "")
+                else:
+                    elem_name = elem.tag.replace(qmap(C.HEALTH), "")
+                    request['class'] = elem_name
+                    if not request.has_key('command'):
+                        request['command'] = elem_name
+                        request['metadata'] = self.get_filtered_attributes(
+                            ['xmlns'],
+                            elem.attrib)
             elif elem.tag.find(qmap(C.NCM)) != -1:  # found
                 request['namespace'] = ns(C.NCM)
                 elem_name = elem.tag.replace(qmap(C.NCM), "")
@@ -95,7 +120,6 @@
 
         return request
 
-
     def get_rpc_handler(self, rpc_node, msg, grpc_channel, session,
                         capabilities):
         try:
@@ -114,8 +138,8 @@
                 log.error("request-no-message-id")
                 raise ncerror.BadMsg(rpc_node)
 
-            class_handler = self.rpc_class_handlers.get(request['command'],
-                                                        None)
+            class_handler = self._get_rpc_handler(request['command'])
+
             if class_handler is not None:
                 return class_handler(request, rpc_node, grpc_channel, session,
                                      capabilities)
@@ -128,10 +152,19 @@
             raise ncerror.BadMsg(rpc_node)
 
         except Exception as e:
+            log.exception('exception', e=e)
             raise ncerror.ServerException(rpc_node, exception=e)
 
+    def _get_rpc_handler(self, command):
+        # If there is a generic mapping of that command then use it
+        rpc_mapper = get_nc_rpc_mapper_instance()
+        rpc = command.replace('-', '_')
+        if rpc_mapper.is_rpc_exist(rpc):
+            return VolthaRpc
+        else:
+            return self.rpc_class_handlers.get(command, None)
+
     rpc_class_handlers = {
-        'getvoltha': GetVoltha,
         'get-config': GetConfig,
         'get': Get,
         'get-schemas': GetSchemas,