SEBA-406 OLT Admin_state as declarative instead of feedback state

Change-Id: I5ae35f02bfc23d966049b39db5141d52311da297
diff --git a/xos/synchronizer/steps/sync_olt_device.py b/xos/synchronizer/steps/sync_olt_device.py
index 40f884e..e1c1c4a 100644
--- a/xos/synchronizer/steps/sync_olt_device.py
+++ b/xos/synchronizer/steps/sync_olt_device.py
@@ -80,15 +80,17 @@
 
         log.info("Add device json res", res=res)
 
+        # TODO(smbaker): Potential partial failure. If device is created in Voltha but synchronizer crashes before the
+        # model is saved, then synchronizer will continue to try to preprovision and fail due to preexisting
+        # device.
+
         if not res['id']:
             raise Exception(
                 'VOLTHA Device Id is empty. This probably means that the OLT device is already provisioned in VOLTHA')
         else:
             model.device_id = res['id']
             model.serial_number = res['serial_number']
-
-
-        return model
+            model.save()
 
     def activate_olt(self, model):
 
@@ -113,8 +115,6 @@
             request = requests.get("%s:%d/api/v1/devices/%s" % (voltha['url'], voltha['port'], model.device_id)).json()
             attempted = attempted + 1
 
-
-        model.admin_state = request['admin_state']
         model.oper_status = request['oper_status']
         model.serial_number = request['serial_number']
 
@@ -122,10 +122,17 @@
             raise Exception("It was not possible to activate OLTDevice with id %s" % model.id)
 
         # Find the of_id of the device
-        model = self.get_ids_from_logical_device(model)
+        self.get_ids_from_logical_device(model)
         model.save()
 
-        return model
+    def deactivate_olt(self, model):
+        voltha = Helpers.get_voltha_info(model.volt_service)
+
+        # Disable device
+        request = requests.post("%s:%d/api/v1/devices/%s/disable" % (voltha['url'], voltha['port'], model.device_id))
+
+        if request.status_code != 200:
+            raise Exception("Failed to disable OLT device: %s" % request.text)
 
     def configure_onos(self, model):
 
@@ -158,22 +165,36 @@
                 print request.json()
             except Exception:
                 print request.text
-        return model
 
     def sync_record(self, model):
         log.info("Synching device", object=str(model), **model.tologdict())
 
+        if model.admin_state not in ["ENABLED", "DISABLED"]:
+            raise Exception("OLT Device %s admin_state has invalid value %s" % (model.id, model.admin_state))
+
         # If the device has feedback_state is already present in voltha
-        if not model.device_id and not model.admin_state and not model.oper_status and not model.of_id:
+        if not model.device_id and not model.oper_status and not model.of_id:
             log.info("Pushing OLT device to VOLTHA", object=str(model), **model.tologdict())
-            model = self.pre_provision_olt_device(model)
-            self.activate_olt(model)
-        elif model.oper_status != "ACTIVE":
-            raise Exception("It was not possible to activate OLTDevice with id %s" % model.id)
+            self.pre_provision_olt_device(model)
+            model.oper_status = "UNKNOWN" # fall-though to activate OLT
         else:
             log.info("OLT device already exists in VOLTHA", object=str(model), **model.tologdict())
 
-        self.configure_onos(model)
+        # Reconcile admin_state and oper_status, activating or deactivating the OLT as necessary.
+
+        if model.oper_status != "ACTIVE" and model.admin_state == "ENABLED":
+            self.activate_olt(model)
+        elif model.oper_status == "ACTIVE" and model.admin_state == "DISABLED":
+            self.deactivate_olt(model)
+
+        if model.admin_state == "ENABLED":
+            # If we were not able to reconcile ENABLE/ACTIVE, then throw an exception and do not proceed to onos
+            # configuration.
+            if model.oper_status != "ACTIVE":
+                raise Exception("It was not possible to activate OLTDevice with id %s" % model.id)
+
+            # At this point OLT is enabled and active. Configure ONOS.
+            self.configure_onos(model)
 
     def delete_record(self, model):
         log.info("Deleting OLT device", object=str(model), **model.tologdict())