Initial commit for the PM management apis and placeholders for
implementation
Amendment: Made changes recommended by reviewers with the actual
changes this time.

Change-Id: I9a0d98d456f95a0eee67614f0bec43923815537b
diff --git a/voltha/adapters/interface.py b/voltha/adapters/interface.py
index c7016d1..9aef84f 100644
--- a/voltha/adapters/interface.py
+++ b/voltha/adapters/interface.py
@@ -150,6 +150,13 @@
         :return:
         """
 
+    #def update_pm_collection(device, pm_collection_config):
+        """
+        Called every time a request is made to change pm collection behavior
+        :param device: A Voltha.Device object
+        :param pm_collection_config: A Pms
+        """
+
     def send_proxied_message(proxy_address, msg):
         """
         Forward a msg to a child device of device, addressed by the given
diff --git a/voltha/adapters/simulated_olt/simulated_olt.py b/voltha/adapters/simulated_olt/simulated_olt.py
index b5a6c3f..067ab2f 100644
--- a/voltha/adapters/simulated_olt/simulated_olt.py
+++ b/voltha/adapters/simulated_olt/simulated_olt.py
@@ -35,7 +35,8 @@
 from voltha.core.flow_decomposer import *
 from voltha.core.logical_device_agent import mac_str_to_tuple
 from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
-from voltha.protos.device_pb2 import DeviceType, DeviceTypes, Device, Port
+from voltha.protos.device_pb2 import DeviceType, DeviceTypes, Device, Port, \
+PmConfigs, PmConfig, PmGroupConfig
 from voltha.protos.events_pb2 import KpiEvent, KpiEventType, MetricValuePairs
 from voltha.protos.health_pb2 import HealthStatus
 from voltha.protos.common_pb2 import LogLevel, OperStatus, ConnectStatus, \
@@ -46,6 +47,7 @@
     OFPC_GROUP_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS
 from voltha.protos.events_pb2 import AlarmEvent, AlarmEventType, \
     AlarmEventSeverity, AlarmEventState, AlarmEventCategory
+import sys
 
 log = structlog.get_logger()
 
@@ -330,6 +332,50 @@
             oper_status=OperStatus.ACTIVE
         ))
 
+        # then shortly after, add the supported pms for the device
+        yield asleep(0.05)
+        try:
+            log.info("Setting p")
+            p = PmsConfig(
+                default_freq=150,
+                grouped=False,
+                freq_override=False)
+            p.metrics.extend([PmConfig(name='tx_64',type=PmConfig.COUNTER,
+                                       enabled=True)])
+            p.metrics.extend([PmConfig(name='tx_65_127',
+                                       type=PmConfig.COUNTER,enabled=True)])
+            p.metrics.extend([PmConfig(name='tx_128_255',
+                                       type=PmConfig.COUNTER,enabled=True)])
+            p.metrics.extend([PmConfig(name='tx_256_511',
+                                       type=PmConfig.COUNTER,enabled=True)])
+            p.metrics.extend([PmConfig(name='tx_512_1023',
+                                       type=PmConfig.COUNTER,enabled=True)])
+            p.metrics.extend([PmConfig(name='tx_1024_1518',
+                                       type=PmConfig.COUNTER,enabled=True)])
+            p.metrics.extend([PmConfig(name='tx_1519_9k',
+                                       type=PmConfig.COUNTER,enabled=True)])
+            p.metrics.extend([PmConfig(name='rx_64',
+                                       type=PmConfig.COUNTER,enabled=True)])
+            p.metrics.extend([PmConfig(name='rx_65_127',
+                                       type=PmConfig.COUNTER,enabled=True)])
+            p.metrics.extend([PmConfig(name='rx_128_255',
+                                       type=PmConfig.COUNTER,enabled=True)])
+            p.metrics.extend([PmConfig(name='rx_256_511',
+                                       type=PmConfig.COUNTER,enabled=True)])
+            p.metrics.extend([PmConfig(name='rx_512_1023',
+                                       type=PmConfig.COUNTER,enabled=True)])
+            p.metrics.extend([PmConfig(name='rx_1024_1518',
+                                       type=PmConfig.COUNTER,enabled=True)])
+            p.metrics.extend([PmConfig(name='rx_1519_9k',
+                                       type=PmConfig.COUNTER,enabled=True)])
+
+
+            #TODO Call the adapter agend to update the pm config
+            #self.adapter_agent.update_pms_config(device.id,p)
+        except:
+            e = sys.exec_info()
+            log.error("error", error=e)
+
         # then shortly after we create the logical device with one port
         # that will correspond to the NNI port
         yield asleep(0.05)
@@ -414,6 +460,12 @@
         vlan_id = seq + 100
         return vlan_id
 
+    #def update_pm_collection(self, device, pm_collection_config):
+        # This is where the metrics to be collected are configured and where
+        # the sampling frequency is set.
+        #TODO: Here.
+    #    pass
+
     def update_flows_bulk(self, device, flows, groups):
         log.debug('bulk-flow-update', device_id=device.id,
                   flows=flows, groups=groups)
diff --git a/voltha/core/adapter_agent.py b/voltha/core/adapter_agent.py
index 4859d27..7ba382b 100644
--- a/voltha/core/adapter_agent.py
+++ b/voltha/core/adapter_agent.py
@@ -34,10 +34,13 @@
 from voltha.protos.device_pb2 import Device, Port
 from voltha.protos.events_pb2 import KpiEvent, AlarmEvent, AlarmEventType, \
     AlarmEventSeverity, AlarmEventState, AlarmEventCategory
+from voltha.protos.device_pb2 import Device, Port, PmConfigs
+from voltha.protos.events_pb2 import KpiEvent
 from voltha.protos.voltha_pb2 import DeviceGroup, LogicalDevice, \
     LogicalPort, AdminState, OperStatus
 from voltha.registry import registry
 from voltha.core.flow_decomposer import OUTPUT
+import sys
 
 
 @implementer(IAdapterAgent)
@@ -177,6 +180,10 @@
         return self.update_flows_incrementally(
             device, flow_changes, group_changes)
 
+    #def update_pm_collection(self, device, pm_collection_config):
+    #    return self.adapter.update_pm_collection(device, pm_collection_config)
+
+
     # ~~~~~~~~~~~~~~~~~~~ Adapter-Facing Service ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
     def get_device(self, device_id):
diff --git a/voltha/core/global_handler.py b/voltha/core/global_handler.py
index 7d52d29..eff422e 100644
--- a/voltha/core/global_handler.py
+++ b/voltha/core/global_handler.py
@@ -369,6 +369,16 @@
             request,
             context)
 
+    #TODO: create the global PM config query function
+    @twisted_async
+    def ListDevicePmConfigs(self, request, context):
+        raise NotImplementedError('Method not implemented!')
+
+    #TODO: create the global PM config update function.
+    @twisted_async
+    def UpdateDevicePmConfigs(self, request, context):
+        raise NotImplementedError('Method not implemented!')
+
     @twisted_async
     def ListDeviceFlows(self, request, context):
         log.info('grpc-request', request=request)
diff --git a/voltha/core/local_handler.py b/voltha/core/local_handler.py
index e7a4912..a8800b9 100644
--- a/voltha/core/local_handler.py
+++ b/voltha/core/local_handler.py
@@ -420,6 +420,16 @@
             context.set_code(StatusCode.NOT_FOUND)
             return Ports()
 
+    #TODO: create the global PM config query function
+    @twisted_async
+    def ListDevicePmConfigs(self, request, context):
+        raise NotImplementedError('Method not implemented!')
+
+    #TODO: create the global PM config update function.
+    @twisted_async
+    def UpdateDevicePmConfigs(self, request, context):
+        raise NotImplementedError('Method not implemented!')
+
     @twisted_async
     def ListDeviceFlows(self, request, context):
         log.info('grpc-request', request=request)
diff --git a/voltha/protos/device.proto b/voltha/protos/device.proto
index b4d3c46..8cc22d4 100644
--- a/voltha/protos/device.proto
+++ b/voltha/protos/device.proto
@@ -29,6 +29,35 @@
     repeated DeviceType items = 1;
 }
 
+message PmConfig {
+    enum PmType {
+    	COUNTER = 0;
+	GUAGE = 1;
+	STATE = 2;
+    }
+    string name = 1;
+    PmType type = 2;
+    bool enabled = 3; // Whether or not this metric makes it to Kafka
+    uint32 sample_freq = 4; // Sample rate in 10ths of a second
+}
+
+message PmGroupConfig {
+    string group_name = 1;
+    uint32 group_freq = 2; // Frequency applicable to the grop
+    bool enabled = 3; // Enable/disable group level only
+    repeated PmConfig metrics = 4;
+}
+
+message PmConfigs {
+    uint32 default_freq = 1; // Default sample rate
+    // Forces group names and group semantics
+    bool grouped = 2 [(access) = READ_ONLY];
+    // Allows Pm to set an individual sample frequency
+    bool freq_override = 3 [(access) = READ_ONLY];
+    repeated PmGroupConfig groups = 4; // The groups if grouped is true
+    repeated PmConfig metrics = 5; // The metrics themselves if grouped is false.
+}
+
 message Port {
     option (voltha.yang_child_rule) = MOVE_TO_PARENT_LEVEL;
 
@@ -135,6 +164,7 @@
     repeated Port ports = 128  [(child_node) = {key: "port_no"}];
     openflow_13.Flows flows = 129 [(child_node) = {}];
     openflow_13.FlowGroups flow_groups = 130 [(child_node) = {}];
+    PmConfigs kpis = 131 [(child_node) = {}];
 
 }
 
diff --git a/voltha/protos/voltha.proto b/voltha/protos/voltha.proto
index db98c2a..911dfb8 100644
--- a/voltha/protos/voltha.proto
+++ b/voltha/protos/voltha.proto
@@ -240,6 +240,21 @@
         option (voltha.yang_xml_tag).xml_tag = 'ports';
     }
 
+    // List pm config of a device
+    rpc ListDevicePmConfigs(ID) returns(PmConfigs) {
+        option (google.api.http) = {
+            get: "/api/v1/devices/{id}/pm_configs"
+        };
+    }
+
+    // Update the pm config of a device
+    rpc UpdateDevicePmConfigs(ID) returns(PmConfigs) {
+        option (google.api.http) = {
+            post: "/api/v1/devices/{id}/pm_configs"
+            body: "*"
+        };
+    }
+
     // List all flows of a device
     rpc ListDeviceFlows(ID) returns(openflow_13.Flows) {
         option (google.api.http) = {
@@ -441,6 +456,21 @@
         option (voltha.yang_xml_tag).xml_tag = 'ports';
     }
 
+    // List pm config of a device
+    rpc ListDevicePmConfigs(ID) returns(PmConfigs) {
+        option (google.api.http) = {
+            get: "/api/v1/local/devices/{id}/pm_configs"
+        };
+    }
+
+    // Update the pm config of a device
+    rpc UpdateDevicePmConfigs(ID) returns(PmConfigs) {
+        option (google.api.http) = {
+            post: "/api/v1/local/devices/{id}/pm_configs"
+            body: "*"
+        };
+    }
+
     // List all flows of a device
     rpc ListDeviceFlows(ID) returns(openflow_13.Flows) {
         option (google.api.http) = {