[VOL-3084][VOL-3097] Added support for ONU Re-Discovery and OLT PON Port Disable/Enable

Change-Id: I21f20ffc5edc95652946007baffa4b22ecfd9b92
diff --git a/VERSION b/VERSION
index ee1372d..6b2eab2 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-0.2.2
+0.2.3-dev
diff --git a/docs/source/onu-state-machine.rst b/docs/source/onu-state-machine.rst
index b966300..7117e57 100644
--- a/docs/source/onu-state-machine.rst
+++ b/docs/source/onu-state-machine.rst
@@ -21,7 +21,7 @@
       - created
       -
     * - initialize
-      - created, disabled
+      - created, disabled, pon_disabled
       - initialized
       -
     * - discover
@@ -29,7 +29,7 @@
       - discovered
       -
     * - enable
-      - discovered, disabled
+      - discovered, disabled, pon_disabled
       - enabled
       -
     * - receive_eapol_flow
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index 4caf5b6..fae3dd5 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -677,11 +677,31 @@
 				msg, _ := message.Data.(PonIndicationMessage)
 				pon, _ := o.GetPonById(msg.PonPortID)
 				if msg.OperState == UP {
-					pon.OperState.Event("enable")
-					pon.InternalState.Event("enable")
+					if err := pon.OperState.Event("enable"); err != nil {
+						oltLogger.WithFields(log.Fields{
+							"IntfId": msg.PonPortID,
+							"Err": err,
+						}).Error("Can't Enable Oper state for PON Port")
+					}
+					if err := pon.InternalState.Event("enable"); err != nil {
+						oltLogger.WithFields(log.Fields{
+							"IntfId": msg.PonPortID,
+							"Err": err,
+						}).Error("Can't Enable Internal state for PON Port")
+					}
 				} else if msg.OperState == DOWN {
-					pon.OperState.Event("disable")
-					pon.InternalState.Event("disable")
+					if err := pon.OperState.Event("disable"); err != nil {
+						oltLogger.WithFields(log.Fields{
+							"IntfId": msg.PonPortID,
+							"Err": err,
+						}).Error("Can't Disable Oper state for PON Port")
+					}
+					if err := pon.InternalState.Event("disable"); err != nil {
+						oltLogger.WithFields(log.Fields{
+							"IntfId": msg.PonPortID,
+							"Err": err,
+						}).Error("Can't Disable Internal state for PON Port")
+					}
 				}
 			default:
 				oltLogger.Warnf("Received unknown message data %v for type %v in OLT Channel", message.Data, message.Type)
@@ -872,12 +892,33 @@
 		}).Error("Can't find Onu")
 	}
 
-	if err := _onu.InternalState.Event("initialize"); err != nil {
+	if err := _onu.InternalState.Event("disable"); err != nil {
 		oltLogger.WithFields(log.Fields{
 			"IntfId": _onu.PonPortID,
 			"OnuSn":  _onu.Sn(),
 			"OnuId":  _onu.ID,
-		}).Infof("Failed to transition ONU to initialized state: %s", err.Error())
+		}).Infof("Failed to transition ONU to disabled state: %s", err.Error())
+	}
+
+	time.Sleep(1 * time.Second)
+
+	// ONU Re-Discovery
+	if o.InternalState.Current() == "enabled" && pon.InternalState.Current() == "enabled" {
+		if err := _onu.InternalState.Event("initialize"); err != nil {
+			oltLogger.WithFields(log.Fields{
+				"IntfId": _onu.PonPortID,
+				"OnuSn":  _onu.Sn(),
+				"OnuId":  _onu.ID,
+			}).Infof("Failed to transition ONU to initialized state: %s", err.Error())
+		}
+
+		if err := _onu.InternalState.Event("discover"); err != nil {
+			oltLogger.WithFields(log.Fields{
+				"IntfId": _onu.PonPortID,
+				"OnuSn":  _onu.Sn(),
+				"OnuId":  _onu.ID,
+			}).Infof("Failed to transition ONU to discovered state: %s", err.Error())
+		}
 	}
 
 	return new(openolt.Empty), nil
@@ -919,19 +960,9 @@
 }
 
 func (o OltDevice) DisablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
-	oltLogger.Errorf("DisablePonIf request received for PON %d", intf.IntfId)
+	oltLogger.Infof("DisablePonIf request received for PON %d", intf.IntfId)
 	ponID := intf.GetIntfId()
 	pon, _ := o.GetPonById(intf.IntfId)
-	errInternalState := pon.InternalState.Event("disable")
-	oltLogger.WithFields(log.Fields{
-		"IntfId": ponID,
-		"err":    errInternalState,
-	}).Error("Can't disable Internal state for PonPort")
-	errOperState := pon.OperState.Event("disable")
-	oltLogger.WithFields(log.Fields{
-		"IntfId": ponID,
-		"err":    errOperState,
-	}).Error("Can't disable Oper state for PonPort")
 
 	msg := Message{
 		Type: PonIndication,
@@ -965,19 +996,9 @@
 }
 
 func (o OltDevice) EnablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {
-	oltLogger.Errorf("EnablePonIf request received for PON %d", intf.IntfId)
+	oltLogger.Infof("EnablePonIf request received for PON %d", intf.IntfId)
 	ponID := intf.GetIntfId()
 	pon, _ := o.GetPonById(intf.IntfId)
-	errInternalState := pon.InternalState.Event("enable")
-	oltLogger.WithFields(log.Fields{
-		"IntfId": ponID,
-		"err":    errInternalState,
-	}).Error("Can't enable Internal state for PonPort")
-	errOperState := pon.OperState.Event("enable")
-	oltLogger.WithFields(log.Fields{
-		"IntfId": ponID,
-		"err":    errOperState,
-	}).Error("Can't enable Oper state for PonPort")
 
 	msg := Message{
 		Type: PonIndication,
diff --git a/internal/bbsim/devices/onu.go b/internal/bbsim/devices/onu.go
index d6962c1..ecb91f8 100644
--- a/internal/bbsim/devices/onu.go
+++ b/internal/bbsim/devices/onu.go
@@ -124,9 +124,9 @@
 		"created",
 		fsm.Events{
 			// DEVICE Lifecycle
-			{Name: "initialize", Src: []string{"created", "disabled"}, Dst: "initialized"},
-			{Name: "discover", Src: []string{"initialized", "pon_disabled"}, Dst: "discovered"},
-			{Name: "enable", Src: []string{"discovered"}, Dst: "enabled"},
+			{Name: "initialize", Src: []string{"created", "disabled", "pon_disabled"}, Dst: "initialized"},
+			{Name: "discover", Src: []string{"initialized"}, Dst: "discovered"},
+			{Name: "enable", Src: []string{"discovered", "pon_disabled"}, Dst: "enabled"},
 			{Name: "receive_eapol_flow", Src: []string{"enabled", "gem_port_added"}, Dst: "eapol_flow_received"},
 			{Name: "add_gem_port", Src: []string{"enabled", "eapol_flow_received"}, Dst: "gem_port_added"},
 			// NOTE should disabled state be different for oper_disabled (emulating an error) and admin_disabled (received a disabled call via VOLTHA)?
diff --git a/internal/bbsim/devices/pon.go b/internal/bbsim/devices/pon.go
index c2847b1..d1f7d2a 100644
--- a/internal/bbsim/devices/pon.go
+++ b/internal/bbsim/devices/pon.go
@@ -78,17 +78,44 @@
 				} else if e.Src == "disabled" {
 					for _, onu := range ponPort.Onus {
 						if onu.InternalState.Current() == "pon_disabled" {
-							if err := onu.InternalState.Event("discover"); err != nil {
-								log.Errorf("Error discover ONU: %v", err)
+							if err := onu.InternalState.Event("enable"); err != nil {
+								log.WithFields(log.Fields{
+									"Err": err,
+									"OnuSn": onu.Sn(),
+									"IntfId": onu.PonPortID,
+								}).Error("Error enabling ONU")
 							}
 						} else if onu.InternalState.Current() == "disabled" {
 							if err := onu.InternalState.Event("initialize"); err != nil {
-								log.Errorf("Error initialize ONU: %v", err)
+								log.WithFields(log.Fields{
+									"Err": err,
+									"OnuSn": onu.Sn(),
+									"IntfId": onu.PonPortID,
+								}).Error("Error initializing ONU")
 								continue
 							}
 							if err := onu.InternalState.Event("discover"); err != nil {
-								log.Errorf("Error discover ONU: %v", err)
+								log.WithFields(log.Fields{
+									"Err": err,
+									"OnuSn": onu.Sn(),
+									"IntfId": onu.PonPortID,
+								}).Error("Error discovering ONU")
 							}
+						} else if onu.InternalState.Current() == "initialized" {
+							if err := onu.InternalState.Event("discover"); err != nil {
+								log.WithFields(log.Fields{
+									"Err": err,
+									"OnuSn": onu.Sn(),
+									"IntfId": onu.PonPortID,
+								}).Error("Error discovering ONU")
+							}
+						} else {
+							// this is to loudly report unexpected states in order to address them
+							log.WithFields(log.Fields{
+								"OnuSn": onu.Sn(),
+								"IntfId": onu.PonPortID,
+								"InternalState": onu.InternalState.Current(),
+							}).Error("Unexpected ONU state in PON enabling")
 						}
 					}
 				}