VOL-2447: Order reconcile class id by needed prerequisities

Some onu require some ME to exist before other during reconciliation
Having this order prevents repeated reconcile failure and re-attempts,
shortening the amount of time needed to recover from an onu reboot

Change-Id: I6fa8a02300f545b577069a43cece5cce8856c8bc
diff --git a/pyvoltha/adapters/extensions/omci/omci_entities.py b/pyvoltha/adapters/extensions/omci/omci_entities.py
index e6b5ea0..3df13e1 100644
--- a/pyvoltha/adapters/extensions/omci/omci_entities.py
+++ b/pyvoltha/adapters/extensions/omci/omci_entities.py
@@ -31,6 +31,7 @@
 import six
 from six.moves import range
 
+RECONCILE_LOW_PRIORITY=1000
 
 class EntityClassAttribute(object):
 
@@ -143,6 +144,7 @@
     mandatory_operations = set()
     optional_operations = set()
     notifications = set()
+    reconcile_sort_order = RECONCILE_LOW_PRIORITY
     alarms = dict()       # Alarm Number -> Alarm Name
     hidden = False        # If true, this attribute is not reported by a MIB upload.
                           # This attribute is needed to be able to properly perform
@@ -373,6 +375,7 @@
 
 class MacBridgeServiceProfile(EntityClass):
     class_id = 45
+    reconcile_sort_order = 2
     attributes = [
         ECA(ShortField("managed_entity_id", None), {AA.R, AA.SBC}),
         ECA(ByteField("spanning_tree_ind", None), {AA.R, AA.W, AA.SBC},
@@ -400,6 +403,7 @@
 
 class MacBridgePortConfigurationData(EntityClass):
     class_id = 47
+    reconcile_sort_order = 4
     attributes = [
         ECA(ShortField("managed_entity_id", None), {AA.R, AA.SBC}),
         ECA(ShortField("bridge_id_pointer", None), {AA.R, AA.W, AA.SBC}),
@@ -474,6 +478,7 @@
 
 class Ieee8021pMapperServiceProfile(EntityClass):
     class_id = 130
+    reconcile_sort_order = 3
     attributes = [
         ECA(ShortField("managed_entity_id", None), {AA.R, AA.SBC}),
         ECA(ShortField("tp_pointer", None), {AA.R, AA.W, AA.SBC}),
@@ -761,6 +766,7 @@
 
 class Tcont(EntityClass):
     class_id = 262
+    reconcile_sort_order = 5
     attributes = [
         ECA(ShortField("managed_entity_id", None), {AA.R}),
         ECA(ShortField("alloc_id", None), {AA.R, AA.W}),
@@ -826,6 +832,7 @@
 
 class GemInterworkingTp(EntityClass):
     class_id = 266
+    reconcile_sort_order = 7
     attributes = [
         ECA(ShortField("managed_entity_id", None), {AA.R, AA.SBC}),
         ECA(ShortField("gem_port_network_ctp_pointer", None),
@@ -850,6 +857,7 @@
 
 class GemPortNetworkCtp(EntityClass):
     class_id = 268
+    reconcile_sort_order = 6
     attributes = [
         ECA(ShortField("managed_entity_id", None), {AA.R, AA.SBC}),
         ECA(ShortField("port_id", None), {AA.R, AA.W, AA.SBC}),
@@ -878,6 +886,7 @@
 
 class GalEthernetProfile(EntityClass):
     class_id = 272
+    reconcile_sort_order = 1
     attributes = [
         ECA(ShortField("managed_entity_id", None), {AA.R, AA.SBC}),
         ECA(ShortField("max_gem_payload_size", None), {AA.R, AA.W, AA.SBC}),
diff --git a/pyvoltha/adapters/extensions/omci/tasks/mib_reconcile_task.py b/pyvoltha/adapters/extensions/omci/tasks/mib_reconcile_task.py
index f377863..875440a 100644
--- a/pyvoltha/adapters/extensions/omci/tasks/mib_reconcile_task.py
+++ b/pyvoltha/adapters/extensions/omci/tasks/mib_reconcile_task.py
@@ -23,6 +23,7 @@
 from pyvoltha.adapters.extensions.omci.omci_me import OntDataFrame
 from pyvoltha.adapters.extensions.omci.omci_frame import OmciFrame, OmciDelete, OmciCreate, OmciSet
 from pyvoltha.adapters.extensions.omci.omci_fields import OmciTableField
+from pyvoltha.adapters.extensions.omci.omci_entities import RECONCILE_LOW_PRIORITY
 from pyvoltha.adapters.extensions.omci.database.mib_db_api import ATTRIBUTES_KEY
 
 OP = EntityOperations
@@ -202,6 +203,7 @@
         # First the undecodables and onu-created (treated the same)
         undecodable = self._undecodable(onu, me_map)
         onu_created = self._onu_created(onu, me_map)
+        self.log.debug("sorted-class-list", onu_created=onu_created)
 
         if len(undecodable) or len(onu_created):
             results = yield self.fix_onu_only_save_to_db(undecodable, onu_created, onu_db)
@@ -212,6 +214,7 @@
         # Last the OLT created values, resend these to the ONU
 
         olt_created = self._olt_created(onu, me_map)
+        self.log.debug("sorted-class-list", olt_created=olt_created)
         if len(olt_created):
             results = yield self.fix_onu_only_remove_from_onu(olt_created)
             successes += results[0]
@@ -347,6 +350,7 @@
         # from OpenOMCI database
         undecodable = self._undecodable(olt, me_map)
         onu_created = self._onu_created(olt, me_map)
+        self.log.debug("sorted-class-list", onu_created=onu_created)
 
         if len(undecodable) or len(onu_created):
             good, bad = self.fix_olt_only_remove_from_db(undecodable, onu_created)
@@ -357,6 +361,7 @@
         # Last the OLT created
 
         olt_created = self._olt_created(olt, me_map)
+        self.log.debug("sorted-class-list", olt_created=olt_created)
         if len(olt_created):
             results = yield self.fix_olt_only_create_on_onu(olt_created, me_map)
             successes += results[0]
@@ -743,12 +748,12 @@
         return [(cid, eid) for cid, eid in cid_eid_list if cid not in me_map]
 
     def _onu_created(self, cid_eid_list, me_map):
-        return [(cid, eid) for cid, eid in cid_eid_list if cid in me_map and
+        return [(cid, eid) for cid, eid in sorted(cid_eid_list, key=self.entitysorter) if cid in me_map and
                 (OP.Create not in me_map[cid].mandatory_operations and
                  OP.Create not in me_map[cid].optional_operations)]
 
     def _olt_created(self, cid_eid_list, me_map):
-        return [(cid, eid) for cid, eid in cid_eid_list if cid in me_map and
+        return [(cid, eid) for cid, eid in sorted(cid_eid_list, key=self.entitysorter) if cid in me_map and
                 (OP.Create in me_map[cid].mandatory_operations or
                  OP.Create in me_map[cid].optional_operations)]
 
@@ -759,3 +764,11 @@
             new_mds_value = 1
 
         return new_mds_value
+
+    def entitysorter(self, key):
+        me_map = self._device.me_map
+        try:
+            clsid = key[0]
+            return me_map[clsid].reconcile_sort_order
+        except KeyError:
+            return RECONCILE_LOW_PRIORITY