[VOL-4616] Prevent enabling while reboot is in progress
Change-Id: Ie8add7b9d8be185b8714ab6eff899ed55d5945ed
diff --git a/internal/bbsim/api/grpc_api_server.go b/internal/bbsim/api/grpc_api_server.go
index 8a9101d..c7d7e38 100644
--- a/internal/bbsim/api/grpc_api_server.go
+++ b/internal/bbsim/api/grpc_api_server.go
@@ -19,10 +19,11 @@
import (
"context"
"fmt"
- "google.golang.org/grpc/status"
"strings"
"time"
+ "google.golang.org/grpc/status"
+
"github.com/opencord/bbsim/api/bbsim"
"github.com/opencord/bbsim/internal/bbsim/devices"
"github.com/opencord/bbsim/internal/common"
@@ -172,7 +173,7 @@
res := &bbsim.Response{}
o := devices.GetOLT()
- if err := o.InternalState.Event("initialize"); err != nil {
+ if err := o.InternalState.Event(devices.OltInternalTxInitialize); err != nil {
log.Errorf("Error initializing OLT: %v", err)
res.StatusCode = int32(codes.FailedPrecondition)
return res, err
@@ -186,7 +187,7 @@
res := &bbsim.Response{}
o := devices.GetOLT()
- if err := o.InternalState.Event("disable"); err != nil {
+ if err := o.InternalState.Event(devices.OltInternalTxDisable); err != nil {
log.Errorf("Error disabling OLT: %v", err)
res.StatusCode = int32(codes.FailedPrecondition)
return res, err
diff --git a/internal/bbsim/devices/olt.go b/internal/bbsim/devices/olt.go
index a6e55c0..0a50d59 100644
--- a/internal/bbsim/devices/olt.go
+++ b/internal/bbsim/devices/olt.go
@@ -58,6 +58,18 @@
// The flow ids are no more necessary by the adapter, but still need to pass something dummy. Pass a very small valid range.
flowIdStart = 1
flowIdEnd = flowIdStart + 1
+
+ //InternalState FSM states and transitions
+ OltInternalStateCreated = "created"
+ OltInternalStateInitialized = "initialized"
+ OltInternalStateEnabled = "enabled"
+ OltInternalStateDisabled = "disabled"
+ OltInternalStateDeleted = "deleted"
+
+ OltInternalTxInitialize = "initialize"
+ OltInternalTxEnable = "enable"
+ OltInternalTxDisable = "disable"
+ OltInternalTxDelete = "delete"
)
type OltDevice struct {
@@ -170,20 +182,20 @@
// OLT State machine
// NOTE do we need 2 state machines for the OLT? (InternalState and OperState)
olt.InternalState = fsm.NewFSM(
- "created",
+ OltInternalStateCreated,
fsm.Events{
- {Name: "initialize", Src: []string{"created", "deleted"}, Dst: "initialized"},
- {Name: "enable", Src: []string{"initialized", "disabled"}, Dst: "enabled"},
- {Name: "disable", Src: []string{"enabled"}, Dst: "disabled"},
+ {Name: OltInternalTxInitialize, Src: []string{OltInternalStateCreated, OltInternalStateDeleted}, Dst: OltInternalStateInitialized},
+ {Name: OltInternalTxEnable, Src: []string{OltInternalStateInitialized, OltInternalStateDisabled}, Dst: OltInternalStateEnabled},
+ {Name: OltInternalTxDisable, Src: []string{OltInternalStateEnabled}, Dst: OltInternalStateDisabled},
// delete event in enabled state below is for reboot OLT case.
- {Name: "delete", Src: []string{"disabled", "enabled"}, Dst: "deleted"},
+ {Name: OltInternalTxDelete, Src: []string{OltInternalStateDisabled, OltInternalStateEnabled}, Dst: OltInternalStateDeleted},
},
fsm.Callbacks{
"enter_state": func(e *fsm.Event) {
oltLogger.Debugf("Changing OLT InternalState from %s to %s", e.Src, e.Dst)
},
- "enter_initialized": func(e *fsm.Event) { olt.InitOlt() },
- "enter_deleted": func(e *fsm.Event) {
+ fmt.Sprintf("enter_%s", OltInternalStateInitialized): func(e *fsm.Event) { olt.InitOlt() },
+ fmt.Sprintf("enter_%s", OltInternalStateDeleted): func(e *fsm.Event) {
// remove all the resource allocations
olt.clearAllResources()
},
@@ -224,7 +236,7 @@
}
if !isMock {
- if err := olt.InternalState.Event("initialize"); err != nil {
+ if err := olt.InternalState.Event(OltInternalTxInitialize); err != nil {
log.Errorf("Error initializing OLT: %v", err)
return nil
}
@@ -276,7 +288,7 @@
"oltId": o.ID,
}).Infof("Simulating OLT restart... (%ds)", rebootDelay)
- if o.InternalState.Is("enabled") {
+ if o.InternalState.Is(OltInternalStateEnabled) {
oltLogger.WithFields(log.Fields{
"oltId": o.ID,
}).Info("This is an OLT soft reboot")
@@ -284,7 +296,7 @@
}
// transition internal state to deleted
- if err := o.InternalState.Event("delete"); err != nil {
+ if err := o.InternalState.Event(OltInternalTxDelete); err != nil {
oltLogger.WithFields(log.Fields{
"oltId": o.ID,
}).Errorf("Error deleting OLT: %v", err)
@@ -326,10 +338,13 @@
// terminate the OLT's processOltMessages go routine
close(o.channel)
+ //Prevents Enable to progress before the reboot is completed (VOL-4616)
+ o.Lock()
o.enableContextCancel()
time.Sleep(time.Duration(rebootDelay) * time.Second)
+ o.Unlock()
- if err := o.InternalState.Event("initialize"); err != nil {
+ if err := o.InternalState.Event(OltInternalTxInitialize); err != nil {
oltLogger.WithFields(log.Fields{
"oltId": o.ID,
}).Errorf("Error initializing OLT: %v", err)
@@ -387,8 +402,18 @@
// Device Methods
// Enable implements the OpenOLT EnableIndicationServer functionality
-func (o *OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) {
+func (o *OltDevice) Enable(stream openolt.Openolt_EnableIndicationServer) error {
oltLogger.Debug("Enable OLT called")
+
+ if o.InternalState.Is(OltInternalStateDeleted) {
+ err := fmt.Errorf("Cannot enable OLT while it is rebooting")
+ oltLogger.WithFields(log.Fields{
+ "oltId": o.SerialNumber,
+ "internalState": o.InternalState.Current(),
+ }).Error(err)
+ return err
+ }
+
rebootFlag := false
// If enabled has already been called then an enabled context has
@@ -486,6 +511,8 @@
oltLogger.WithFields(log.Fields{
"stream": stream,
}).Debug("OpenOLT Stream closed")
+
+ return nil
}
func (o *OltDevice) periodicPortStats(ctx context.Context, wg *sync.WaitGroup, stream openolt.Openolt_EnableIndicationServer) {
@@ -696,7 +723,7 @@
}
func (o *OltDevice) sendPortStatsIndication(stats *openolt.PortStatistics, portID uint32, portType string, stream openolt.Openolt_EnableIndicationServer) {
- if o.InternalState.Current() == "enabled" {
+ if o.InternalState.Current() == OltInternalStateEnabled {
oltLogger.WithFields(log.Fields{
"Type": portType,
"IntfId": portID,
@@ -749,10 +776,10 @@
case types.OltIndication:
msg, _ := message.Data.(types.OltIndicationMessage)
if msg.OperState == types.UP {
- _ = o.InternalState.Event("enable")
+ _ = o.InternalState.Event(OltInternalTxEnable)
_ = o.OperState.Event("enable")
} else if msg.OperState == types.DOWN {
- _ = o.InternalState.Event("disable")
+ _ = o.InternalState.Event(OltInternalTxDisable)
_ = o.OperState.Event("disable")
}
o.sendOltIndication(msg, stream)
@@ -919,7 +946,7 @@
}
// ONU Re-Discovery
- if o.InternalState.Current() == "enabled" && pon.InternalState.Current() == "enabled" {
+ if o.InternalState.Current() == OltInternalStateEnabled && pon.InternalState.Current() == "enabled" {
go _onu.ReDiscoverOnu()
}
@@ -994,8 +1021,7 @@
func (o *OltDevice) EnableIndication(_ *openolt.Empty, stream openolt.Openolt_EnableIndicationServer) error {
oltLogger.WithField("oltId", o.ID).Info("OLT receives EnableIndication call from VOLTHA")
publishEvent("OLT-enable-received", -1, -1, "")
- o.Enable(stream)
- return nil
+ return o.Enable(stream)
}
func (o *OltDevice) EnablePonIf(_ context.Context, intf *openolt.Interface) (*openolt.Empty, error) {