VOL-270: Investigate and support clustering support for xPON protos

 * Ensuring global-scope for channel_termination
 * Making changes to corresponding itests

Change-Id: I6cceb0dbd5cce138c439a381101bd2cfc3956b2a
diff --git a/tests/itests/voltha/test_dispatcher.py b/tests/itests/voltha/test_dispatcher.py
index 293f6f1..3c58f07 100644
--- a/tests/itests/voltha/test_dispatcher.py
+++ b/tests/itests/voltha/test_dispatcher.py
@@ -1,7 +1,7 @@
 from random import randint
 from time import time, sleep
 
-from google.protobuf.json_format import MessageToDict
+from google.protobuf.json_format import MessageToDict, ParseDict
 from unittest import main
 from voltha.protos.device_pb2 import Device
 from tests.itests.voltha.rest_base import RestBase
@@ -18,6 +18,7 @@
 from voltha.protos import voltha_pb2
 from voltha.core.flow_decomposer import *
 from voltha.protos.openflow_13_pb2 import FlowTableUpdate
+from voltha.protos import bbf_fiber_base_pb2 as fb
 
 LOCAL_CONSUL = "localhost:8500"
 DOCKER_COMPOSE_FILE = "compose/docker-compose-system-test.yml"
@@ -41,6 +42,29 @@
     kafka_kpis="kafkacat -o end -b {} -C -t voltha.kpis -c 5"
 )
 
+xpon_scenario = [
+    {'cterm-add': {
+        'pb2': fb.ChannelterminationConfig(),
+        'rpc': {
+                "interface": {
+                    "enabled": True,
+                    "name": "PON port",
+                    "description": "Channel Termination for Freedom Tower"
+                    },
+                "data": {
+                    "channelpair_ref": "",
+                    "location": "AT&T WTC OLT"
+                    },
+                "name": "PON port"
+                }
+            }
+        },
+    {'cterm-del': {
+        'pb2': fb.ChannelterminationConfig(),
+        'rpc': {"name": "PON port"}}
+    }
+]
+
 
 class DispatcherTest(RestBase):
     def setUp(self):
@@ -105,6 +129,8 @@
         self._get_device_type_rest(dtypes['items'][0]['id'])
         alarm_filter = self._create_device_filter_rest(olt_id)
         self._remove_device_filter_rest(alarm_filter['id'])
+        channel_termination = self._create_channel_termination_rest(olt_id)
+        self._delete_channel_termination_rest(olt_id)
         # TODO: PM APIs test
 
     def test_02_cross_instances_dispatch(self):
@@ -234,6 +260,48 @@
         res = self._get_olt_flows_grpc(self.empty_voltha_stub_global,
                                        ponsim_logical_device_id)
 
+        # Test 8:
+        # A. Create Channel Termination on particular device instance using REST
+        # B. Ensuring that it is present on that specific instance
+        # C. Retrieve Channel Termination from global grpc using empty
+        #    voltha instance
+        channel_termination = self._create_channel_termination_rest(
+            ponsim_olt.id)
+        global_cterm = self._get_channel_terminations_rest(ponsim_olt.id)
+        cterm = self._get_channel_terminations_grpc(
+            self.ponsim_voltha_stub_global, ponsim_olt.id)
+        assert global_cterm == MessageToDict(cterm,
+            including_default_value_fields = True,
+            preserving_proto_field_name = True)
+        cterm = self._get_channel_terminations_grpc(
+            self.ponsim_voltha_stub_local, ponsim_olt.id)
+        assert global_cterm == MessageToDict(cterm,
+            including_default_value_fields = True,
+            preserving_proto_field_name = True)
+        #Checking with empty instance
+        cterm = self._get_channel_terminations_grpc(
+            self.empty_voltha_stub_global, ponsim_olt.id)
+        assert global_cterm == MessageToDict(cterm,
+            including_default_value_fields = True,
+            preserving_proto_field_name = True)
+        #Simulated OLT
+        channel_termination = self._create_channel_termination_rest(
+            simulated_olt.id)
+        global_cterm = self._get_channel_terminations_rest(simulated_olt.id)
+        cterm = self._get_channel_terminations_grpc(
+            self.simulated_voltha_stub_global, simulated_olt.id)
+        assert global_cterm == MessageToDict(cterm,
+            including_default_value_fields = True,
+            preserving_proto_field_name = True)
+        cterm = self._get_channel_terminations_grpc(
+            self.simulated_voltha_stub_local, simulated_olt.id)
+        assert global_cterm == MessageToDict(cterm,
+            including_default_value_fields = True,
+            preserving_proto_field_name = True)
+        #Deleting Channel Termination
+        self._delete_channel_termination_rest(ponsim_olt.id)
+        self._delete_channel_termination_rest(simulated_olt.id)
+
         # TODO:  More tests to be added as new features are added
 
 
@@ -701,6 +769,31 @@
         res = stub.ListLogicalDeviceFlows(voltha_pb2.ID(id=logical_device_id))
         return res
 
+    #For xPon objects
+    def _get_channel_terminations_rest(self, device_id):
+        res = self.get('/api/v1/devices/{}/channel_terminations'.format(
+            device_id))
+        return res
+
+    def _get_channel_terminations_grpc(self, stub, device_id):
+        res = stub.GetAllChannelterminationConfig(voltha_pb2.ID(id=device_id))
+        return res
+
+    def _create_channel_termination_rest(self, device_id):
+        value = xpon_scenario[0]['cterm-add']
+        ParseDict(value['rpc'], value['pb2'])
+        request = value['pb2']
+        self.post('/api/v1/devices/{}/channel_terminations/{}'.format(
+            device_id, value['rpc']['name']),
+                  MessageToDict(request, preserving_proto_field_name = True),
+                  expected_code = 200)
+        return request
+
+    def _delete_channel_termination_rest(self, device_id):
+        value = xpon_scenario[1]['cterm-del']
+        self.delete('/api/v1/devices/{}/channel_terminations/{}/delete'.format(
+            device_id, value['rpc']['name']),
+                  expected_code = 200)
 
 if __name__ == '__main__':
     main()
diff --git a/tests/itests/voltha/test_voltha_xpon.py b/tests/itests/voltha/test_voltha_xpon.py
index ebaed72..af1cabf 100644
--- a/tests/itests/voltha/test_voltha_xpon.py
+++ b/tests/itests/voltha/test_voltha_xpon.py
@@ -8,9 +8,9 @@
 from common.utils.consulhelpers import get_endpoint_from_consul
 
 '''
-These tests uses the ponsim OLT to verfiy addition, modification and deletion 
-of channelgroups, channelpartition, channelpair, channeltermination, vOntAni, OntAni
-and VEnets for xpon
+These tests uses the ponsim OLT to verfiy addition, modification and deletion
+of channelgroups, channelpartition, channelpair, channeltermination, vOntAni,
+OntAni and VEnets for xpon
 The prerequisite for this test are:
  1. voltha ensemble is running
       docker-compose -f compose/docker-compose-system-test.yml up -d
@@ -24,154 +24,177 @@
 host_and_port = '172.17.0.1:50060'
 scenario = [
         {'cg-add': {
-                'pb2': fb.ChannelgroupConfig(),
-                'rpc': {
-                        "interface": {
-                            "enabled": True,
-                            "name": "Manhattan",
-                            "description": "Channel Group for Manhattan.."
-                            },
-                        "data": {
-                            "polling_period": 100,
-                            "system_id": "000000",
-                            "raman_mitigation": "RAMAN_NONE"
-                            },
-                        "name": "Manhattan" 
-                        }
-                    }
-                },
+            'pb2': fb.ChannelgroupConfig(),
+            'rpc': {
+                "interface": {
+                    "enabled": True,
+                    "name": "Manhattan",
+                    "description": "Channel Group for Manhattan.."
+                    },
+                "data": {
+                    "polling_period": 100,
+                    "system_id": "000000",
+                    "raman_mitigation": "RAMAN_NONE"
+                    },
+                "name": "Manhattan"
+                }
+            }
+        },
         {'cpart-add': {
-                'pb2': fb.ChannelpartitionConfig(),
-                'rpc': {
-                        "interface": {
-                            "enabled": True,
-                            "name": "WTC",
-                            "description": "Channel Partition for World Trade Center in Manhattan"
-                            },
-                        "data": {
-                            "differential_fiber_distance": 20,
-                            "closest_ont_distance": 0,
-                            "fec_downstream": False,
-                            "multicast_aes_indicator": False,
-                            "authentication_method": "SERIAL_NUMBER",
-                            "channelgroup_ref": "Manhattan"
-                            },
-                        "name": "WTC"
-                        }
-                    }
-                },
+            'pb2': fb.ChannelpartitionConfig(),
+            'rpc': {
+                "interface": {
+                    "enabled": True,
+                    "name": "WTC",
+                    "description": "Channel Partition for World Trade \
+Center in Manhattan"
+                    },
+                "data": {
+                    "differential_fiber_distance": 20,
+                    "closest_ont_distance": 0,
+                    "fec_downstream": False,
+                    "multicast_aes_indicator": False,
+                    "authentication_method": "SERIAL_NUMBER",
+                    "channelgroup_ref": "Manhattan"
+                    },
+                "name": "WTC"
+                }
+            }
+        },
         {'cpair-add': {
-                'pb2': fb.ChannelpairConfig(),
-                'rpc': {
-                        "interface": {
-                            "enabled": True,
-                            "name": "PON port",
-                            "description": "Channel Pair for Freedom Tower in WTC"
-                            },
-                        "data": {
-                            "channelpair_linerate": "down_10_up_10",
-                            "channelpair_type": "channelpair",
-                            "channelgroup_ref": "Manhattan",
-                            "gpon_ponid_interval": 0,
-                            "channelpartition_ref": "WTC",
-                            "gpon_ponid_odn_class": "CLASS_A"
-                            },
-                        "name": "PON port"
-                        }
-                    }
-                },
+            'pb2': fb.ChannelpairConfig(),
+            'rpc': {
+                "interface": {
+                    "enabled": True,
+                    "name": "PON port",
+                    "description": "Channel Pair for Freedom Tower in WTC"
+                    },
+                "data": {
+                    "channelpair_linerate": "down_10_up_10",
+                    "channelpair_type": "channelpair",
+                    "channelgroup_ref": "Manhattan",
+                    "gpon_ponid_interval": 0,
+                    "channelpartition_ref": "WTC",
+                    "gpon_ponid_odn_class": "CLASS_A"
+                    },
+                "name": "PON port"
+                }
+            }
+        },
         {'cterm-add': {
-                'pb2': fb.ChannelterminationConfig(),
-                'rpc': {
-                        "interface": {
-                            "enabled": True,
-                            "name": "PON port",
-                            "description": "Channel Termination for Freedom Tower"
-                            },
-                        "data": {
-                            "channelpair_ref": "PON port",
-                            "location": "AT&T WTC OLT"
-                            },
-                        "name": "PON port"
-                        }
-                    }
-                },
+            'pb2': fb.ChannelterminationConfig(),
+            'rpc': {
+                "interface": {
+                    "enabled": True,
+                    "name": "PON port",
+                    "description": "Channel Termination for Freedom Tower"
+                    },
+                "data": {
+                    "channelpair_ref": "PON port",
+                    "location": "AT&T WTC OLT"
+                    },
+                "name": "PON port"
+                }
+            }
+        },
         {'vontani-add': {
-                'pb2': fb.VOntaniConfig(),
-                'rpc': {
-                        "interface": {
-                            "enabled": True,
-                            "name": "ATT Silver User",
-                            "description": "ATT Silver User in Freedom Tower"
-                            },
-                        "data": {
-                            "preferred_chanpair": "PON port",
-                            "expected_serial_number": "ALCL00000000",
-                            "parent_ref": "WTC",
-                            "onu_id": 1
-                            },
-                        "name": "ATT Silver User"
-                        }
-                    }
-                },
+            'pb2': fb.VOntaniConfig(),
+            'rpc': {
+                "interface": {
+                    "enabled": True,
+                    "name": "ATT Golden User",
+                    "description": "ATT Golden User in Freedom Tower"
+                    },
+                "data": {
+                    "preferred_chanpair": "PON port",
+                    "expected_serial_number": "ALCL00000000",
+                    "parent_ref": "WTC",
+                    "onu_id": 1
+                    },
+                "name": "ATT Golden User"
+                }
+            }
+        },
         {'ontani-add': {
-                'pb2': fb.OntaniConfig(),
-                'rpc': {
-                        "interface": {
-                            "enabled": True,
-                            "name": "ATT Silver User",
-                            "description": "ATT Silver User in Freedom Tower"
-                            }, 
-                        "data": { 
-                            "upstream_fec_indicator": True, 
-                            "mgnt_gemport_aes_indicator": False  
-                            }, 
-                        "name": "ATT Silver User" 
-                        }
-                    }
-                },
+            'pb2': fb.OntaniConfig(),
+            'rpc': {
+                "interface": {
+                    "enabled": True,
+                    "name": "ATT Golden User",
+                    "description": "ATT Golden User in Freedom Tower"
+                    },
+                "data": {
+                    "upstream_fec_indicator": True,
+                    "mgnt_gemport_aes_indicator": False
+                    },
+                "name": "ATT Golden User"
+                }
+            }
+        },
         {'venet-add': {
-                'pb2': fb.VEnetConfig(),
-                'rpc': {
-                        "interface": {
-                            "enabled": True,
-                            "name": "ATT SU Enet UNI-1-1",
-                            "description": "Ethernet port - 1"
-                            },
-                        "data": {
-                            "v_ontani_ref": "ATT Silver User"
-                            },
-                        "name": "ATT SU Enet UNI-1-1"
-                        }
-                    }
-                },
+            'pb2': fb.VEnetConfig(),
+            'rpc': {
+                "interface": {
+                    "enabled": True,
+                    "name": "ATT SU Enet UNI-1-1",
+                    "description": "Ethernet port - 1"
+                    },
+                "data": {
+                    "v_ontani_ref": "ATT Golden User"
+                    },
+                "name": "ATT SU Enet UNI-1-1"
+                }
+            }
+        },
         {'cg-mod': {
-                'pb2': fb.ChannelgroupConfig(),
-                'rpc': {
-                        "interface": {
-                            "enabled": True,
-                            "name": "Manhattan",
-                            "description": "Channel Group for Manhattan"
-                            },
-                        "data": {
-                            "polling_period": 100,
-                            "system_id": "000000",
-                            "raman_mitigation": "RAMAN_NONE"
-                            },
-                        "name": "Manhattan"
-                        }
-                    }
-                },
-        {'venet-del': { 'rpc': {"name": "ATT SU Enet UNI-1-1"}, 'pb2': fb.VEnetConfig()}},
-        {'ontani-del': { 'rpc': {"name": "ATT Silver User"}, 'pb2': fb.OntaniConfig()}},
-        {'vontani-del': { 'rpc': {"name": "ATT Silver User"}, 'pb2': fb.VOntaniConfig()}},
-        {'cterm-del': { 'rpc': {"name": "PON port"}, 'pb2': fb.ChannelterminationConfig()}},
-        {'cpair-del': { 'rpc': {"name": "PON port"}, 'pb2': fb.ChannelpairConfig()}},
-        {'cpart-del': { 'rpc': {"name": "WTC"}, 'pb2': fb.ChannelpartitionConfig()}},
-        {'cg-del': { 'rpc': {"name": "Manhattan"}, 'pb2': fb.ChannelgroupConfig()}}
+            'pb2': fb.ChannelgroupConfig(),
+            'rpc': {
+                "interface": {
+                    "enabled": True,
+                    "name": "Manhattan",
+                    "description": "Channel Group for Manhattan"
+                    },
+                "data": {
+                    "polling_period": 100,
+                    "system_id": "000000",
+                    "raman_mitigation": "RAMAN_NONE"
+                    },
+                "name": "Manhattan"
+                }
+            }
+        },
+        {'venet-del': {
+            'pb2': fb.VEnetConfig(),
+            'rpc': {"name": "ATT SU Enet UNI-1-1"}}
+        },
+        {'ontani-del': {
+            'pb2': fb.OntaniConfig(),
+            'rpc': {"name": "ATT Golden User"}}
+        },
+        {'vontani-del': {
+            'pb2': fb.VOntaniConfig(),
+            'rpc': {"name": "ATT Golden User"}}
+        },
+        {'cterm-del': {
+            'pb2': fb.ChannelterminationConfig(),
+            'rpc': {"name": "PON port"}}
+        },
+        {'cpair-del': {
+            'pb2': fb.ChannelpairConfig(),
+            'rpc': {"name": "PON port"}}
+        },
+        {'cpart-del': {
+            'pb2': fb.ChannelpartitionConfig(),
+            'rpc': {"name": "WTC"}}
+        },
+        {'cg-del': {
+            'pb2': fb.ChannelgroupConfig(),
+            'rpc': {"name": "Manhattan"}}
+        }
     ]
 
-id = 3      #for ordering the test cases
+#for ordering the test cases
+id = 3
 LOCAL_CONSUL = "localhost:8500"
 # Retrieve details of the REST entry point
 rest_endpoint = get_endpoint_from_consul(LOCAL_CONSUL, 'chameleon-rest')
@@ -264,12 +287,13 @@
     # Retrieve the desired item upon Post message
     def verify(self, type):
         if(type == 'channel_terminations'):
-            return self.get('/api/v1/local/devices/{}/{}'.format(device['id'], type))
+            return self.get('/api/v1/devices/{}/{}'.format(device['id'], type))
         return self.get('/api/v1/local/{}'.format(type))
 
     def get_path(self, type, name, operation):
         if(type == 'channel_terminations'):
-            return 'api/v1/local/devices/{}/{}/{}{}'.format(device['id'], type, name, operation)
+            return 'api/v1/devices/{}/{}/{}{}'.format(device['id'],
+                type, name, operation)
         return 'api/v1/local/{}/{}{}'.format(type, name, operation)
 
     # Method to check if the result is same as the change requested
@@ -281,8 +305,10 @@
                     if(v == dict1['name']):
                         dict2 = item
                         break
-        itfDiff = [k for k in dict1['interface'] if dict1['interface'][k] != dict2['interface'][k]]
-        dataDiff = [k for k in dict1['data'] if dict1['data'][k] != dict2['data'][k]]
+        itfDiff = [k for k in dict1['interface'] if dict1['interface'][k] \
+                   != dict2['interface'][k]]
+        dataDiff = [k for k in dict1['data'] if dict1['data'][k] \
+                    != dict2['data'][k]]
         if(len(itfDiff) == 0 and len(dataDiff) == 0):
             return True
         return False
@@ -290,14 +316,16 @@
 #~~~~~~~~~~~~~~ Function to create test cases on the fly ~~~~~~~~~~~~~~~~
 def create_dynamic_method(key, value):
     obj_type_config = {
-            'cg': { 'type': 'channel_groups', 'config' : 'channelgroup_config' },
-            'cpart': { 'type': 'channel_partitions', 'config' : 'channelpartition_config' },
-            'cpair': { 'type': 'channel_pairs', 'config' : 'channelpair_config' },
-            'cterm': { 'type': 'channel_terminations', 'config' : 'channeltermination_config' },
-            'vontani': { 'type': 'v_ont_anis', 'config': 'v_ontani_config' },
-            'ontani': { 'type': 'ont_anis', 'config': 'ontani_config' },
-            'venet': { 'type': 'v_enets', 'config': 'v_enet_config' }
-        }
+        'cg':{'type':'channel_groups','config':'channelgroup_config'},
+        'cpart':{'type':'channel_partitions',
+                 'config':'channelpartition_config'},
+        'cpair':{'type':'channel_pairs','config':'channelpair_config'},
+        'cterm':{'type':'channel_terminations',
+                 'config':'channeltermination_config'},
+        'vontani':{'type':'v_ont_anis','config':'v_ontani_config'},
+        'ontani':{'type':'ont_anis','config':'ontani_config'},
+        'venet':{'type':'v_enets','config':'v_enet_config'}
+    }
 
     def _add(self, type, config, req, name):
         result, prev_len = self.add(type, config, req, name)
diff --git a/voltha/core/global_handler.py b/voltha/core/global_handler.py
index f681816..08da69f 100644
--- a/voltha/core/global_handler.py
+++ b/voltha/core/global_handler.py
@@ -647,48 +647,84 @@
             context)
 
     @twisted_async
+    @inlineCallbacks
     def GetAllChannelterminationConfig(self, request, context):
-        log.warning('temp-limited-implementation')
-        # TODO dispatching to local instead of collecting all
-        return self.dispatcher.dispatch(
-            self.instance_id,
-            VolthaLocalServiceStub,
+        log.info('grpc-request', request=request)
+        response = yield self.dispatcher.dispatch(
             'GetAllChannelterminationConfig',
             request,
-            context)
+            context,
+            id=request.id)
+        log.info('grpc-response', response=response)
+        if isinstance(response, DispatchError):
+            log.info('grpc-error-response', error=response.error_code)
+            context.set_details('Channeltermination \'{}\' error'.format(
+                request.id))
+            context.set_code(response.error_code)
+            returnValue(Empty())
+        else:
+            log.info('grpc-success-response', response=response)
+            returnValue(response)
 
     @twisted_async
+    @inlineCallbacks
     def CreateChanneltermination(self, request, context):
-        log.warning('temp-limited-implementation')
-        # TODO dispatching to local instead of collecting all
-        return self.dispatcher.dispatch(
-            self.instance_id,
-            VolthaLocalServiceStub,
+        log.info('grpc-request', request=request)
+        response = yield self.dispatcher.dispatch(
             'CreateChanneltermination',
             request,
-            context)
+            context,
+            id=request.id)
+        log.info('grpc-response', response=response)
+        if isinstance(response, DispatchError):
+            log.info('grpc-error-response', error=response.error_code)
+            context.set_details('Channeltermination \'{}\' error'.format(
+                request.id))
+            context.set_code(response.error_code)
+            returnValue(Empty())
+        else:
+            log.info('grpc-success-response', response=response)
+            returnValue(response)
 
     @twisted_async
+    @inlineCallbacks
     def UpdateChanneltermination(self, request, context):
-        log.warning('temp-limited-implementation')
-        # TODO dispatching to local instead of collecting all
-        return self.dispatcher.dispatch(
-            self.instance_id,
-            VolthaLocalServiceStub,
+        log.info('grpc-request', request=request)
+        response = yield self.dispatcher.dispatch(
             'UpdateChanneltermination',
             request,
-            context)
+            context,
+            id=request.id)
+        log.info('grpc-response', response=response)
+        if isinstance(response, DispatchError):
+            log.info('grpc-error-response', error=response.error_code)
+            context.set_details('Channeltermination \'{}\' error'.format(
+                request.id))
+            context.set_code(response.error_code)
+            returnValue(Empty())
+        else:
+            log.info('grpc-success-response', response=response)
+            returnValue(response)
 
     @twisted_async
+    @inlineCallbacks
     def DeleteChanneltermination(self, request, context):
-        log.warning('temp-limited-implementation')
-        # TODO dispatching to local instead of collecting all
-        return self.dispatcher.dispatch(
-            self.instance_id,
-            VolthaLocalServiceStub,
+        log.info('grpc-request', request=request)
+        response =  yield self.dispatcher.dispatch(
             'DeleteChanneltermination',
             request,
-            context)
+            context,
+            id=request.id)
+        log.info('grpc-response', response=response)
+        if isinstance(response, DispatchError):
+            log.info('grpc-error-response', error=response.error_code)
+            context.set_details('Channeltermination \'{}\' error'.format(
+                request.id))
+            context.set_code(response.error_code)
+            returnValue(Empty())
+        else:
+            log.info('grpc-success-response', response=response)
+            returnValue(response)
 
     @twisted_async
     def GetAllOntaniConfig(self, request, context):