diff --git a/translib/pfm_app.go b/translib/pfm_app.go index f2dab02a3..6a1cc9b9e 100644 --- a/translib/pfm_app.go +++ b/translib/pfm_app.go @@ -27,17 +27,33 @@ import ( "github.com/openconfig/ygot/ygot" "reflect" "strconv" + "strings" ) type PlatformApp struct { - path *PathInfo - reqData []byte - ygotRoot *ygot.GoStruct - ygotTarget *interface{} - eepromTs *db.TableSpec - eepromTable map[string]dbEntry + path *PathInfo + reqData []byte + ygotRoot *ygot.GoStruct + ygotTarget *interface{} + eepromTs *db.TableSpec + transceiverInfoTs *db.TableSpec + transceiverDomSensorTs *db.TableSpec + transceiverDomThresholdTs *db.TableSpec + applPortTs *db.TableSpec + eepromTable map[string]dbEntry + transceiverInfoTable map[string]dbEntry + transceiverDomSensorTable map[string]dbEntry + transceiverDomThresholdTable map[string]dbEntry + applPortTable map[string]dbEntry } +const ( + fractionDigits1 = 10 + fractionDigits2 = 100 + fractionDigits3 = 1000 + fractionDigits18 = 1000000000000000000 +) + func init() { log.Info("Init called for Platform module") err := register("/openconfig-platform:components", @@ -64,6 +80,10 @@ func (app *PlatformApp) initialize(data appData) { app.ygotRoot = data.ygotRoot app.ygotTarget = data.ygotTarget app.eepromTs = &db.TableSpec{Name: "EEPROM_INFO"} + app.transceiverInfoTs = &db.TableSpec{Name: "TRANSCEIVER_INFO"} + app.transceiverDomSensorTs = &db.TableSpec{Name: "TRANSCEIVER_DOM_SENSOR"} + app.transceiverDomThresholdTs = &db.TableSpec{Name: "TRANSCEIVER_DOM_THRESHOLD"} + app.applPortTs = &db.TableSpec{Name: "PORT_TABLE"} } @@ -160,10 +180,11 @@ func (app *PlatformApp) processGet(dbs [db.MaxDB]*db.DB, fmtType TranslibFmtType pathInfo.Template, pathInfo.Path, pathInfo.Vars) stateDb := dbs[db.StateDB] + applDb := dbs[db.ApplDB] var payload []byte - // Read eeprom info from DB + // Read eeprom info from STATE_DB app.eepromTable = make(map[string]dbEntry) tbl, derr := stateDb.GetTable(app.eepromTs) @@ -183,6 +204,86 @@ func (app *PlatformApp) processGet(dbs [db.MaxDB]*db.DB, fmtType TranslibFmtType app.eepromTable[key.Get(0)] = dbEntry{entry: e} } + // Read transceiver info from STATE_DB + app.transceiverInfoTable = make(map[string]dbEntry) + + transceiverInfoTbl, derr := stateDb.GetTable(app.transceiverInfoTs) + if derr != nil { + log.Error("TRANSCEIVER_INFO table get failed!") + return GetResponse{Payload: payload}, derr + } + + transceiverInfoTblKeys, _ := transceiverInfoTbl.GetKeys() + for _, key := range transceiverInfoTblKeys { + e, kerr := transceiverInfoTbl.GetEntry(key) + if kerr != nil { + log.Error("TRANSCEIVER_INFO entry get failed!") + return GetResponse{Payload: payload}, kerr + } + + app.transceiverInfoTable[key.Get(0)] = dbEntry{entry: e} + } + + // Read transceiver dom sensor from STATE_DB + app.transceiverDomSensorTable = make(map[string]dbEntry) + + transceiverDomSensorTbl, derr := stateDb.GetTable(app.transceiverDomSensorTs) + if derr != nil { + log.Error("TRANSCEIVER_DOM_SENSOR table get failed!") + return GetResponse{Payload: payload}, derr + } + + transceiverDomSensorTblKeys, _ := transceiverDomSensorTbl.GetKeys() + for _, key := range transceiverDomSensorTblKeys { + e, kerr := transceiverDomSensorTbl.GetEntry(key) + if kerr != nil { + log.Error("TRANSCEIVER_DOM_SENSOR entry get failed!") + return GetResponse{Payload: payload}, kerr + } + + app.transceiverDomSensorTable[key.Get(0)] = dbEntry{entry: e} + } + + // Read transceiver dom threshold from STATE_DB + app.transceiverDomThresholdTable = make(map[string]dbEntry) + + transceiverDomThresholdTbl, derr := stateDb.GetTable(app.transceiverDomThresholdTs) + if derr != nil { + log.Error("TRANSCEIVER_DOM_THRESHOLD table get failed!") + return GetResponse{Payload: payload}, derr + } + + transceiverDomThresholdTblKeys, _ := transceiverDomThresholdTbl.GetKeys() + for _, key := range transceiverDomThresholdTblKeys { + e, kerr := transceiverDomThresholdTbl.GetEntry(key) + if kerr != nil { + log.Error("TRANSCEIVER_DOM_THRESHOLD entry get failed!") + return GetResponse{Payload: payload}, kerr + } + + app.transceiverDomThresholdTable[key.Get(0)] = dbEntry{entry: e} + } + + // Read port from APPL_DB + app.applPortTable = make(map[string]dbEntry) + + applPortTbl, derr := applDb.GetTable(app.applPortTs) + if derr != nil { + log.Error("APPL PORT table get failed!") + return GetResponse{Payload: payload}, derr + } + + applPortTblKeys, _ := applPortTbl.GetKeys() + for _, key := range applPortTblKeys { + e, kerr := applPortTbl.GetEntry(key) + if kerr != nil { + log.Error("PORT entry get failed!") + return GetResponse{Payload: payload}, kerr + } + + app.applPortTable[key.Get(0)] = dbEntry{entry: e} + } + targetUriPath, perr := getYangPathFromUri(app.path.Path) if perr != nil { log.Infof("getYangPathFromUri failed.") @@ -192,7 +293,7 @@ func (app *PlatformApp) processGet(dbs [db.MaxDB]*db.DB, fmtType TranslibFmtType var err error if isSubtreeRequest(targetUriPath, "/openconfig-platform:components") { - err = app.doGetSysEeprom() + err = app.doGetPlatformInfo() } else { err = errors.New("Not supported component") } @@ -430,42 +531,291 @@ func (app *PlatformApp) getSysEepromFromDb(eeprom *ocbinds.OpenconfigPlatform_Co return nil } -func (app *PlatformApp) doGetSysEeprom() error { +// getTransceiverInfoEntry returns the cached TRANSCEIVER_INFO entry for ifName +// and a boolean indicating whether the interface was present in STATE_DB. +// The returned db.Value is still safe to call .Has / .Get on if ok is false +// (both return zero values for a nil Field map), but callers SHOULD inspect +// ok and short-circuit so a missing entry is not silently treated as a row +// with every field absent. +func (app *PlatformApp) getTransceiverInfoEntry(ifName string) (db.Value, bool) { + e, ok := app.transceiverInfoTable[ifName] + return e.entry, ok +} + +// getTransceiverDomSensorEntry returns the cached TRANSCEIVER_DOM_SENSOR entry +// for ifName. See getTransceiverInfoEntry for ok semantics. +func (app *PlatformApp) getTransceiverDomSensorEntry(ifName string) (db.Value, bool) { + e, ok := app.transceiverDomSensorTable[ifName] + return e.entry, ok +} + +// getTransceiverDomThresholdEntry returns the cached TRANSCEIVER_DOM_THRESHOLD +// entry for ifName. See getTransceiverInfoEntry for ok semantics. +func (app *PlatformApp) getTransceiverDomThresholdEntry(ifName string) (db.Value, bool) { + e, ok := app.transceiverDomThresholdTable[ifName] + return e.entry, ok +} + +// getApplPortEntry returns the cached APPL_DB PORT_TABLE entry for ifName. +// See getTransceiverInfoEntry for ok semantics. +func (app *PlatformApp) getApplPortEntry(ifName string) (db.Value, bool) { + e, ok := app.applPortTable[ifName] + return e.entry, ok +} + +type CompStateDb struct { + Serial string + Model string +} + +func (app *PlatformApp) getCompStateDbObj(ifName string) CompStateDb { + log.Infof("parseCompStateDb Enter ifName=%s", ifName) + + var compStateDbObj CompStateDb + + transceiverInfoTable, ok := app.getTransceiverInfoEntry(ifName) + if !ok { + log.Warningf("getCompStateDbObj: TRANSCEIVER_INFO entry missing for ifName=%s", ifName) + return compStateDbObj + } + + compStateDbObj.Serial = transceiverInfoTable.Get("serial") + compStateDbObj.Model = transceiverInfoTable.Get("model") + + return compStateDbObj +} + +func (app *PlatformApp) getCompStateFromDb(oc_val *ocbinds.OpenconfigPlatform_Components_Component_State, all bool, compName string) error { + log.Infof("getCompStateFromDb Enter compName=%s", compName) + + ifName := strings.Replace(compName, "transceiver_", "", -1) + compStateDb := app.getCompStateDbObj(ifName) + + targetUriPath, _ := getYangPathFromUri(app.path.Path) + + if all || targetUriPath == "/openconfig-platform:components/component/state/serial-no" { + transceiverInfoTable := app.transceiverInfoTable[ifName].entry + if transceiverInfoTable.Has("serial") { + oc_val.SerialNo = &compStateDb.Serial + } + } + if all || targetUriPath == "/openconfig-platform:components/component/state/part-no" { + transceiverInfoTable := app.transceiverInfoTable[ifName].entry + if transceiverInfoTable.Has("model") { + oc_val.PartNo = &compStateDb.Model + } + } + + return nil +} - log.Infof("Preparing collection for system eeprom") +func (app *PlatformApp) doGetPlatformInfo() error { + log.Infof("Preparing collection for platform info") var err error pf_cpts := app.getAppRootObject() + var compName string + var severityName string targetUriPath, _ := getYangPathFromUri(app.path.Path) switch targetUriPath { case "/openconfig-platform:components": + log.Info("case /openconfig-platform:components root") pf_comp, _ := pf_cpts.NewComponent("System Eeprom") ygot.BuildEmptyTree(pf_comp) err = app.getSysEepromFromDb(pf_comp.State, true) + if err != nil { + break + } + + for epItem, _ := range app.transceiverInfoTable { + compName = "transceiver_" + epItem + pf_comp, _ := pf_cpts.NewComponent(compName) + ygot.BuildEmptyTree(pf_comp) + + err = app.getCompStateFromDb(pf_comp.State, true, compName) + if err != nil { + break + } + err = app.getCompTransceiverStateFromDb(pf_comp.Transceiver.State, true, compName) + if err != nil { + break + } + err = app.getCompTransceiverStateSupplyVoltageFromDb(pf_comp.Transceiver.State.SupplyVoltage, true, compName) + if err != nil { + break + } + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + pf_channel_0, _ := pf_comp.Transceiver.PhysicalChannels.NewChannel(0) + if pf_channel_0 != nil { + ygot.BuildEmptyTree(pf_channel_0) + err = app.getCompTransceiverPhysicalChannelStateLaserTemperatureFromDb(pf_channel_0.State.LaserTemperature, true, compName) + if err != nil { + break + } + } + + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + pf_channel, _ := pf_comp.Transceiver.PhysicalChannels.NewChannel(uint16(laneNum)) + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel) + err = app.getCompTransceiverPhysicalChannelStateOutputPowerFromDb(pf_channel.State.OutputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateInputPowerFromDb(pf_channel.State.InputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateLaserBiasCurrentFromDb(pf_channel.State.LaserBiasCurrent, true, compName, uint16(index)) + if err != nil { + break + } + } + } + } case "/openconfig-platform:components/component": - compName := app.path.Var("name") + log.Info("case /openconfig-platform:components/component root") + compName = app.path.Var("name") if compName == "" { pf_comp, _ := pf_cpts.NewComponent("System Eeprom") ygot.BuildEmptyTree(pf_comp) err = app.getSysEepromFromDb(pf_comp.State, true) + if err != nil { + break + } + + for epItem, _ := range app.transceiverInfoTable { + compName = "transceiver_" + epItem + pf_comp, _ := pf_cpts.NewComponent(compName) + ygot.BuildEmptyTree(pf_comp) + + err = app.getCompStateFromDb(pf_comp.State, true, compName) + if err != nil { + break + } + err = app.getCompTransceiverStateFromDb(pf_comp.Transceiver.State, true, compName) + if err != nil { + break + } + err = app.getCompTransceiverStateSupplyVoltageFromDb(pf_comp.Transceiver.State.SupplyVoltage, true, compName) + if err != nil { + break + } + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + pf_channel_0, _ := pf_comp.Transceiver.PhysicalChannels.NewChannel(0) + if pf_channel_0 != nil { + ygot.BuildEmptyTree(pf_channel_0) + err = app.getCompTransceiverPhysicalChannelStateLaserTemperatureFromDb(pf_channel_0.State.LaserTemperature, true, compName) + if err != nil { + break + } + } + + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + pf_channel, _ := pf_comp.Transceiver.PhysicalChannels.NewChannel(uint16(laneNum)) + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel) + err = app.getCompTransceiverPhysicalChannelStateOutputPowerFromDb(pf_channel.State.OutputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateInputPowerFromDb(pf_channel.State.InputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateLaserBiasCurrentFromDb(pf_channel.State.LaserBiasCurrent, true, compName, uint16(index)) + if err != nil { + break + } + } + } + } } else { - if compName != "System Eeprom" { + if compName != "System Eeprom" && !strings.Contains(compName, "transceiver_Ethernet") { err = errors.New("Invalid component name") break } pf_comp := pf_cpts.Component[compName] if pf_comp != nil { ygot.BuildEmptyTree(pf_comp) - err = app.getSysEepromFromDb(pf_comp.State, true) + + if compName == "System Eeprom" { + err = app.getSysEepromFromDb(pf_comp.State, true) + } + + if strings.Contains(compName, "transceiver_Ethernet") { + err = app.getCompStateFromDb(pf_comp.State, true, compName) + if err != nil { + break + } + err = app.getCompTransceiverStateFromDb(pf_comp.Transceiver.State, true, compName) + if err != nil { + break + } + err = app.getCompTransceiverStateSupplyVoltageFromDb(pf_comp.Transceiver.State.SupplyVoltage, true, compName) + if err != nil { + break + } + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + pf_channel_0, _ := pf_comp.Transceiver.PhysicalChannels.NewChannel(0) + if pf_channel_0 != nil { + ygot.BuildEmptyTree(pf_channel_0) + err = app.getCompTransceiverPhysicalChannelStateLaserTemperatureFromDb(pf_channel_0.State.LaserTemperature, true, compName) + if err != nil { + break + } + } + + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + pf_channel, _ := pf_comp.Transceiver.PhysicalChannels.NewChannel(uint16(laneNum)) + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel) + err = app.getCompTransceiverPhysicalChannelStateOutputPowerFromDb(pf_channel.State.OutputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateInputPowerFromDb(pf_channel.State.InputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateLaserBiasCurrentFromDb(pf_channel.State.LaserBiasCurrent, true, compName, uint16(index)) + if err != nil { + break + } + } + } + } } else { err = errors.New("Invalid input component name") } } case "/openconfig-platform:components/component/state": - compName := app.path.Var("name") - if compName != "" && compName == "System Eeprom" { + log.Info("case /openconfig-platform:components/component/state root") + compName = app.path.Var("name") + if compName == "System Eeprom" { pf_comp := pf_cpts.Component[compName] if pf_comp != nil { ygot.BuildEmptyTree(pf_comp) @@ -473,23 +823,695 @@ func (app *PlatformApp) doGetSysEeprom() error { } else { err = errors.New("Invalid input component name") } + } else if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + err = app.getCompStateFromDb(pf_comp.State, true, compName) + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid component name ") + } + case "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver": + log.Info("case /openconfig-platform:components/component/openconfig-platform-transceiver:transceiver root") + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp.Transceiver) + err = app.getCompTransceiverStateFromDb(pf_comp.Transceiver.State, true, compName) + if err != nil { + break + } + err = app.getCompTransceiverStateSupplyVoltageFromDb(pf_comp.Transceiver.State.SupplyVoltage, true, compName) + if err != nil { + break + } + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + pf_channel_0, _ := pf_comp.Transceiver.PhysicalChannels.NewChannel(0) + if pf_channel_0 != nil { + ygot.BuildEmptyTree(pf_channel_0) + err = app.getCompTransceiverPhysicalChannelStateLaserTemperatureFromDb(pf_channel_0.State.LaserTemperature, true, compName) + if err != nil { + break + } + } + + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + pf_channel, _ := pf_comp.Transceiver.PhysicalChannels.NewChannel(uint16(laneNum)) + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel) + err = app.getCompTransceiverPhysicalChannelStateOutputPowerFromDb(pf_channel.State.OutputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateInputPowerFromDb(pf_channel.State.InputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateLaserBiasCurrentFromDb(pf_channel.State.LaserBiasCurrent, true, compName, uint16(index)) + if err != nil { + break + } + } + } + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid component name ") + } + case "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state": + log.Info("case /openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state root") + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp.Transceiver.State) + err = app.getCompTransceiverStateFromDb(pf_comp.Transceiver.State, true, compName) + if err != nil { + break + } + err = app.getCompTransceiverStateSupplyVoltageFromDb(pf_comp.Transceiver.State.SupplyVoltage, true, compName) + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid component name ") + } + case "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state/supply-voltage": + log.Info("case /openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state/supply-voltage root") + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + err = app.getCompTransceiverStateSupplyVoltageFromDb(pf_comp.Transceiver.State.SupplyVoltage, true, compName) + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid component name ") + } + case "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels": + log.Info("case /openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels root") + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + pf_channel_0, _ := pf_comp.Transceiver.PhysicalChannels.NewChannel(0) + if pf_channel_0 != nil { + ygot.BuildEmptyTree(pf_channel_0) + err = app.getCompTransceiverPhysicalChannelStateLaserTemperatureFromDb(pf_channel_0.State.LaserTemperature, true, compName) + if err != nil { + break + } + } + + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + pf_channel, _ := pf_comp.Transceiver.PhysicalChannels.NewChannel(uint16(laneNum)) + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel) + err = app.getCompTransceiverPhysicalChannelStateOutputPowerFromDb(pf_channel.State.OutputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateInputPowerFromDb(pf_channel.State.InputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateLaserBiasCurrentFromDb(pf_channel.State.LaserBiasCurrent, true, compName, uint16(index)) + if err != nil { + break + } + } + } + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid component name ") + } + case "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel": + log.Info("case /openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel root") + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + indexName := app.path.Var("index") + if indexName == "" { + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + pf_channel_0, _ := pf_comp.Transceiver.PhysicalChannels.NewChannel(0) + if pf_channel_0 != nil { + ygot.BuildEmptyTree(pf_channel_0) + err = app.getCompTransceiverPhysicalChannelStateLaserTemperatureFromDb(pf_channel_0.State.LaserTemperature, true, compName) + if err != nil { + break + } + } + + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + pf_channel, _ := pf_comp.Transceiver.PhysicalChannels.NewChannel(uint16(laneNum)) + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel) + err = app.getCompTransceiverPhysicalChannelStateOutputPowerFromDb(pf_channel.State.OutputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateInputPowerFromDb(pf_channel.State.InputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateLaserBiasCurrentFromDb(pf_channel.State.LaserBiasCurrent, true, compName, uint16(index)) + if err != nil { + break + } + } + } + } else { + compIndex, _ := strconv.ParseUint(indexName, 10, 16) + log.Info("compIndex =", compIndex) + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + if compIndex == 0 { + pf_channel := pf_comp.Transceiver.PhysicalChannels.Channel[uint16(compIndex)] + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel) + err = app.getCompTransceiverPhysicalChannelStateLaserTemperatureFromDb(pf_channel.State.LaserTemperature, true, compName) + } else { + err = errors.New("Invalid input component index") + } + } else { + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + if uint16(laneNum) == uint16(compIndex) { + pf_channel := pf_comp.Transceiver.PhysicalChannels.Channel[uint16(compIndex)] + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel) + err = app.getCompTransceiverPhysicalChannelStateOutputPowerFromDb(pf_channel.State.OutputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateInputPowerFromDb(pf_channel.State.InputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateLaserBiasCurrentFromDb(pf_channel.State.LaserBiasCurrent, true, compName, uint16(index)) + if err != nil { + break + } + } else { + err = errors.New("Invalid input component index") + } + break + } else { + err = errors.New("Invalid input component index") + } + } + } + } + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid component name ") + } + case "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state": + log.Info("case /openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state root") + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + compIndex, _ := strconv.ParseUint(app.path.Var("index"), 10, 16) + log.Info("compIndex =", compIndex) + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + if compIndex == 0 { + pf_channel := pf_comp.Transceiver.PhysicalChannels.Channel[uint16(compIndex)] + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel.State) + err = app.getCompTransceiverPhysicalChannelStateLaserTemperatureFromDb(pf_channel.State.LaserTemperature, true, compName) + } else { + err = errors.New("Invalid input component index") + } + } else { + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + if uint16(laneNum) == uint16(compIndex) { + pf_channel := pf_comp.Transceiver.PhysicalChannels.Channel[uint16(compIndex)] + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel.State) + err = app.getCompTransceiverPhysicalChannelStateOutputPowerFromDb(pf_channel.State.OutputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateInputPowerFromDb(pf_channel.State.InputPower, true, compName, uint16(index)) + if err != nil { + break + } + err = app.getCompTransceiverPhysicalChannelStateLaserBiasCurrentFromDb(pf_channel.State.LaserBiasCurrent, true, compName, uint16(index)) + if err != nil { + break + } + } else { + err = errors.New("Invalid input component index") + } + break + } else { + err = errors.New("Invalid input component index") + } + } + } + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid component name ") + } + case "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/laser-temperature": + log.Info("case /openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/laser-temperature root") + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + compIndex, _ := strconv.ParseUint(app.path.Var("index"), 10, 16) + log.Info("compIndex =", compIndex) + + if compIndex == 0 { + pf_channel := pf_comp.Transceiver.PhysicalChannels.Channel[uint16(compIndex)] + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel.State) + err = app.getCompTransceiverPhysicalChannelStateLaserTemperatureFromDb(pf_channel.State.LaserTemperature, true, compName) + } else { + err = errors.New("Invalid input component index") + } + } else { + err = errors.New("Invalid input component index") + } + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid component name ") + } + case "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/output-power": + log.Info("case /openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/output-power root") + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + compIndex, _ := strconv.ParseUint(app.path.Var("index"), 10, 16) + log.Info("compIndex =", compIndex) + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + if uint16(laneNum) == uint16(compIndex) { + pf_channel := pf_comp.Transceiver.PhysicalChannels.Channel[uint16(compIndex)] + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel.State) + err = app.getCompTransceiverPhysicalChannelStateOutputPowerFromDb(pf_channel.State.OutputPower, true, compName, uint16(index)) + } else { + err = errors.New("Invalid input component index") + } + break + } else { + err = errors.New("Invalid input component index") + } + } + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid component name ") + } + case "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/input-power": + log.Info("case /openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/input-power root") + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + compIndex, _ := strconv.ParseUint(app.path.Var("index"), 10, 16) + log.Info("compIndex =", compIndex) + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + if uint16(laneNum) == uint16(compIndex) { + pf_channel := pf_comp.Transceiver.PhysicalChannels.Channel[uint16(compIndex)] + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel.State) + err = app.getCompTransceiverPhysicalChannelStateInputPowerFromDb(pf_channel.State.InputPower, true, compName, uint16(index)) + } else { + err = errors.New("Invalid input component index") + } + break + } else { + err = errors.New("Invalid input component index") + } + } + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid component name ") + } + case "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/laser-bias-current": + log.Info("case /openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/laser-bias-current root") + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + compIndex, _ := strconv.ParseUint(app.path.Var("index"), 10, 16) + log.Info("compIndex =", compIndex) + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + if uint16(laneNum) == uint16(compIndex) { + pf_channel := pf_comp.Transceiver.PhysicalChannels.Channel[uint16(compIndex)] + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel.State) + err = app.getCompTransceiverPhysicalChannelStateLaserBiasCurrentFromDb(pf_channel.State.LaserBiasCurrent, true, compName, uint16(index)) + if err != nil { + break + } + } else { + err = errors.New("Invalid input component index") + } + break + } else { + err = errors.New("Invalid input component index") + } + } + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid component name ") + } + case "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state": + log.Info("case /openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state root") + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + severityName = app.path.Var("severity") + if strings.Contains(severityName, "CRITICAL") { + pf_threshold := pf_comp.Transceiver.Thresholds.Threshold[ocbinds.OpenconfigAlarmTypes_OPENCONFIG_ALARM_SEVERITY_CRITICAL] + if pf_threshold != nil { + ygot.BuildEmptyTree(pf_threshold.State) + err = app.getCompTransceiverThresholdStateFromDb(pf_threshold.State, true, compName, severityName) + } else { + err = errors.New("Invalid input severity name") + } + } else if strings.Contains(severityName, "WARNING") { + pf_threshold := pf_comp.Transceiver.Thresholds.Threshold[ocbinds.OpenconfigAlarmTypes_OPENCONFIG_ALARM_SEVERITY_WARNING] + if pf_threshold != nil { + ygot.BuildEmptyTree(pf_threshold.State) + err = app.getCompTransceiverThresholdStateFromDb(pf_threshold.State, true, compName, severityName) + } else { + err = errors.New("Invalid input severity name") + } + } else { + err = errors.New("Invalid input severity name") + } + } else { + err = errors.New("Invalid input component name") + } } else { err = errors.New("Invalid component name ") } default: if isSubtreeRequest(targetUriPath, "/openconfig-platform:components/component/state") { - compName := app.path.Var("name") - if compName == "" || compName != "System Eeprom" { + compName = app.path.Var("name") + if compName == "System Eeprom" { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + err = app.getSysEepromFromDb(pf_comp.State, false) + } else { + err = errors.New("Invalid input component name") + } + } else if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + err = app.getCompStateFromDb(pf_comp.State, false, compName) + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid input component name") + } + } else if isSubtreeRequest(targetUriPath, "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state/supply-voltage") { + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + err = app.getCompTransceiverStateSupplyVoltageFromDb(pf_comp.Transceiver.State.SupplyVoltage, false, compName) + } else { + err = errors.New("Invalid input component name") + } + } else { err = errors.New("Invalid input component name") + } + } else if isSubtreeRequest(targetUriPath, "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state") { + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + err = app.getCompTransceiverStateFromDb(pf_comp.Transceiver.State, false, compName) + } else { + err = errors.New("Invalid input component name") + } } else { + err = errors.New("Invalid input component name") + } + } else if isSubtreeRequest(targetUriPath, "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/laser-temperature") { + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { pf_comp := pf_cpts.Component[compName] if pf_comp != nil { ygot.BuildEmptyTree(pf_comp) - err = app.getSysEepromFromDb(pf_comp.State, false) + compIndex, _ := strconv.ParseUint(app.path.Var("index"), 10, 16) + + if compIndex == 0 { + pf_channel := pf_comp.Transceiver.PhysicalChannels.Channel[uint16(compIndex)] + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel.State) + err = app.getCompTransceiverPhysicalChannelStateLaserTemperatureFromDb(pf_channel.State.LaserTemperature, false, compName) + } else { + err = errors.New("Invalid input component index") + } + } else { + err = errors.New("Invalid input component index") + } + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid input component name") + } + } else if isSubtreeRequest(targetUriPath, "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/output-power") { + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + compIndex, _ := strconv.ParseUint(app.path.Var("index"), 10, 16) + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + if uint16(laneNum) == uint16(compIndex) { + pf_channel := pf_comp.Transceiver.PhysicalChannels.Channel[uint16(compIndex)] + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel.State) + err = app.getCompTransceiverPhysicalChannelStateOutputPowerFromDb(pf_channel.State.OutputPower, false, compName, uint16(index)) + } else { + err = errors.New("Invalid input component index") + } + break + } else { + err = errors.New("Invalid input component index") + } + } + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid input component name") + } + } else if isSubtreeRequest(targetUriPath, "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/input-power") { + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + compIndex, _ := strconv.ParseUint(app.path.Var("index"), 10, 16) + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + if uint16(laneNum) == uint16(compIndex) { + pf_channel := pf_comp.Transceiver.PhysicalChannels.Channel[uint16(compIndex)] + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel.State) + err = app.getCompTransceiverPhysicalChannelStateInputPowerFromDb(pf_channel.State.InputPower, false, compName, uint16(index)) + } else { + err = errors.New("Invalid input component index") + } + break + } else { + err = errors.New("Invalid input component index") + } + } + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid input component name") + } + } else if isSubtreeRequest(targetUriPath, "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/laser-bias-current") { + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + compIndex, _ := strconv.ParseUint(app.path.Var("index"), 10, 16) + ifName := strings.Replace(compName, "transceiver_", "", -1) + applPortTable, _ := app.getApplPortEntry(ifName) + + for index, lane := range strings.Split(applPortTable.Get("lanes"), ",") { + laneNum, parseErr := strconv.ParseUint(lane, 10, 16) + if parseErr != nil { + log.Warningf("doGetPlatformInfo: invalid lane %q for ifName=%s: %v", lane, ifName, parseErr) + continue + } + if uint16(laneNum) == uint16(compIndex) { + pf_channel := pf_comp.Transceiver.PhysicalChannels.Channel[uint16(compIndex)] + if pf_channel != nil { + ygot.BuildEmptyTree(pf_channel.State) + err = app.getCompTransceiverPhysicalChannelStateLaserBiasCurrentFromDb(pf_channel.State.LaserBiasCurrent, false, compName, uint16(index)) + if err != nil { + break + } + } else { + err = errors.New("Invalid input component index") + } + break + } else { + err = errors.New("Invalid input component index") + } + } + } else { + err = errors.New("Invalid input component name") + } + } else { + err = errors.New("Invalid input component name") + } + } else if isSubtreeRequest(targetUriPath, "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state") { + compName = app.path.Var("name") + if strings.Contains(compName, "transceiver_Ethernet") { + pf_comp := pf_cpts.Component[compName] + if pf_comp != nil { + ygot.BuildEmptyTree(pf_comp) + severityName = app.path.Var("severity") + if strings.Contains(severityName, "CRITICAL") { + pf_threshold := pf_comp.Transceiver.Thresholds.Threshold[ocbinds.OpenconfigAlarmTypes_OPENCONFIG_ALARM_SEVERITY_CRITICAL] + if pf_threshold != nil { + ygot.BuildEmptyTree(pf_threshold.State) + err = app.getCompTransceiverThresholdStateFromDb(pf_threshold.State, false, compName, severityName) + } else { + err = errors.New("Invalid input severity name") + } + } else if strings.Contains(severityName, "WARNING") { + pf_threshold := pf_comp.Transceiver.Thresholds.Threshold[ocbinds.OpenconfigAlarmTypes_OPENCONFIG_ALARM_SEVERITY_WARNING] + if pf_threshold != nil { + ygot.BuildEmptyTree(pf_threshold.State) + err = app.getCompTransceiverThresholdStateFromDb(pf_threshold.State, false, compName, severityName) + } else { + err = errors.New("Invalid input severity name") + } + } else { + err = errors.New("Invalid input severity name") + } } else { err = errors.New("Invalid input component name") } + } else { + err = errors.New("Invalid input component name") } } else { err = errors.New("Invalid Path") diff --git a/translib/pfm_app_test.go b/translib/pfm_app_test.go index 0ad27bb36..d1184c2ef 100644 --- a/translib/pfm_app_test.go +++ b/translib/pfm_app_test.go @@ -36,6 +36,22 @@ const ( TEST_MANUF_NAME = "TestManufacture" ) +// Test transceiver fixture values for TRANSCEIVER_INFO|Ethernet0, +// TRANSCEIVER_DOM_SENSOR|Ethernet0 and TRANSCEIVER_DOM_THRESHOLD|Ethernet0 +// in STATE_DB. The interface name is the same one used by the existing +// PORT_TABLE entries to make scoped GETs land on a real component path. +const ( + TEST_XCVR_IFNAME = "Ethernet0" + TEST_XCVR_COMPONENT = "transceiver_Ethernet0" + TEST_XCVR_SERIAL = "TESTSERIAL0001" + TEST_XCVR_MODEL = "TESTMODEL-100G-LR" + TEST_XCVR_CONNECTOR = "LC" + TEST_XCVR_MANUFACTURER = "TestVendor" + TEST_XCVR_VENDOR_OUI = "00-11-22" + TEST_XCVR_VENDOR_REV = "A1" + TEST_XCVR_VENDOR_DATE = "2024-01-01 00:00:00" +) + type EepromEntry struct { TlvType string Name string @@ -58,6 +74,10 @@ func init() { } else { fmt.Printf("Failed to remove All Platform Data from Db: %v", err) } + + if err := clearTransceiverDataFromDb(); err != nil { + fmt.Printf("Failed to remove Transceiver Data from Db: %v\n", err) + } } // This will test GET on /openconfig-platform:components @@ -74,6 +94,100 @@ func Test_PfmApp_TopLevelPath(t *testing.T) { t.Run("Get_Full_Pfm_Tree_Top_Level", processGetRequest(url, bulkPfmShowAllJsonResponse, false)) } +// Test_PfmApp_TransceiverState exercises the OpenConfig transceiver state +// subtree against STATE_DB fixtures for TRANSCEIVER_INFO, TRANSCEIVER_DOM_SENSOR +// and TRANSCEIVER_DOM_THRESHOLD. The assertions are intentionally lenient: we +// verify that each GET returns without error or panic, which is the regression +// guard for the nil-pointer concerns raised on PR #201 (map lookups against +// transceiverInfoTable / transceiverDomSensorTable / transceiverDomThresholdTable). +// +// Fixtures are loaded inside the test and torn down on cleanup so the +// existing Test_PfmApp_TopLevelPath bulk EEPROM test is unaffected by run +// ordering. +func Test_PfmApp_TransceiverState(t *testing.T) { + if err := createTransceiverFactoryDb(); err != nil { + t.Fatalf("Failed to add Transceiver data to Db: %v", err) + } + t.Cleanup(func() { + if err := clearTransceiverDataFromDb(); err != nil { + t.Logf("Cleanup: failed to remove Transceiver Data from Db: %v", err) + } + }) + + cases := []struct { + name string + url string + }{ + {"State_Subtree", "/openconfig-platform:components/component[name=" + TEST_XCVR_COMPONENT + "]/openconfig-platform-transceiver:transceiver/state"}, + {"State_SerialNo", "/openconfig-platform:components/component[name=" + TEST_XCVR_COMPONENT + "]/openconfig-platform-transceiver:transceiver/state/serial-no"}, + {"State_Vendor", "/openconfig-platform:components/component[name=" + TEST_XCVR_COMPONENT + "]/openconfig-platform-transceiver:transceiver/state/vendor"}, + {"State_VendorPart", "/openconfig-platform:components/component[name=" + TEST_XCVR_COMPONENT + "]/openconfig-platform-transceiver:transceiver/state/vendor-part"}, + {"State_VendorRev", "/openconfig-platform:components/component[name=" + TEST_XCVR_COMPONENT + "]/openconfig-platform-transceiver:transceiver/state/vendor-rev"}, + {"State_DateCode", "/openconfig-platform:components/component[name=" + TEST_XCVR_COMPONENT + "]/openconfig-platform-transceiver:transceiver/state/date-code"}, + {"State_ConnectorType", "/openconfig-platform:components/component[name=" + TEST_XCVR_COMPONENT + "]/openconfig-platform-transceiver:transceiver/state/connector-type"}, + {"State_SupplyVoltage", "/openconfig-platform:components/component[name=" + TEST_XCVR_COMPONENT + "]/openconfig-platform-transceiver:transceiver/state/supply-voltage"}, + {"Thresholds_Critical", "/openconfig-platform:components/component[name=" + TEST_XCVR_COMPONENT + "]/openconfig-platform-transceiver:transceiver/thresholds/threshold[severity=CRITICAL]/state"}, + {"Thresholds_Warning", "/openconfig-platform:components/component[name=" + TEST_XCVR_COMPONENT + "]/openconfig-platform-transceiver:transceiver/thresholds/threshold[severity=WARNING]/state"}, + } + + for _, tc := range cases { + t.Run(tc.name, verifyTransceiverGetNoError(tc.url)) + } +} + +// Test_PfmApp_TransceiverState_Missing covers the case where no transceiver +// fixture is present in STATE_DB. The current pre-#201 code may return an +// empty response or surface a "data missing" tlerr depending on the path; the +// important regression property is that the handler does NOT panic from a +// nil map lookup on transceiverInfoTable / transceiverDomSensorTable / +// transceiverDomThresholdTable. Both nil-error and non-nil-error outcomes are +// accepted here; only a panic constitutes failure (recovered via t.Failed). +func Test_PfmApp_TransceiverState_Missing(t *testing.T) { + // Ensure no transceiver entries exist. + if err := clearTransceiverDataFromDb(); err != nil { + t.Logf("setup: cleanup failed (continuing): %v", err) + } + + cases := []struct { + name string + url string + }{ + {"Missing_State_SerialNo", "/openconfig-platform:components/component[name=transceiver_EthernetMissing]/openconfig-platform-transceiver:transceiver/state/serial-no"}, + {"Missing_State_SupplyVoltage", "/openconfig-platform:components/component[name=transceiver_EthernetMissing]/openconfig-platform-transceiver:transceiver/state/supply-voltage"}, + {"Missing_Thresholds_Critical", "/openconfig-platform:components/component[name=transceiver_EthernetMissing]/openconfig-platform-transceiver:transceiver/thresholds/threshold[severity=CRITICAL]/state"}, + } + + for _, tc := range cases { + t.Run(tc.name, verifyTransceiverGetDoesNotPanic(tc.url)) + } +} + +// verifyTransceiverGetNoError returns a t.Run-compatible function that issues +// a GET and fails the test if it surfaces an error. Body content is not +// inspected; this is regression scaffolding around the handler reaching +// completion against valid fixtures. +func verifyTransceiverGetNoError(url string) func(*testing.T) { + return func(t *testing.T) { + if _, err := Get(GetRequest{Path: url}); err != nil { + t.Fatalf("GET %s returned error: %v", url, err) + } + } +} + +// verifyTransceiverGetDoesNotPanic asserts the handler returns (either a +// response or a recoverable error) instead of panicking. Both error and +// success are acceptable; only an unrecovered panic fails the test. +func verifyTransceiverGetDoesNotPanic(url string) func(*testing.T) { + return func(t *testing.T) { + defer func() { + if r := recover(); r != nil { + t.Fatalf("GET %s panicked: %v", url, r) + } + }() + _, _ = Get(GetRequest{Path: url}) + } +} + // THis will delete Platform Table from DB func clearPfmDataFromDb() error { var err error @@ -116,6 +230,110 @@ func createPfmFactoryDb() error { return err } +// clearTransceiverDataFromDb deletes the TRANSCEIVER_INFO, TRANSCEIVER_DOM_SENSOR +// and TRANSCEIVER_DOM_THRESHOLD tables from STATE_DB. Errors from individual +// DeleteTable calls are collected but a missing table is not treated as fatal: +// the helper is also used in init() where the tables may not exist yet. +func clearTransceiverDataFromDb() error { + d := getStateDB() + if d == nil { + return errors.New("Failed to connect to state Db") + } + for _, name := range []string{"TRANSCEIVER_INFO", "TRANSCEIVER_DOM_SENSOR", "TRANSCEIVER_DOM_THRESHOLD"} { + ts := db.TableSpec{Name: name} + _ = d.DeleteTable(&ts) + } + return nil +} + +// createTransceiverFactoryDb loads a single Ethernet0 transceiver entry into +// each of TRANSCEIVER_INFO, TRANSCEIVER_DOM_SENSOR and TRANSCEIVER_DOM_THRESHOLD +// in STATE_DB. Values are static and mirror the schema fields consumed by +// translib/pfm_app.go's getCompTransceiver*FromDb functions. +func createTransceiverFactoryDb() error { + d := getStateDB() + if d == nil { + return errors.New("Failed to connect to state Db") + } + + infoTable := db.TableSpec{Name: "TRANSCEIVER_INFO"} + infoKey := db.Key{Comp: []string{TEST_XCVR_IFNAME}} + infoValue := db.Value{Field: map[string]string{ + "serial": TEST_XCVR_SERIAL, + "model": TEST_XCVR_MODEL, + "connector": TEST_XCVR_CONNECTOR, + "manufacturer": TEST_XCVR_MANUFACTURER, + "vendor_oui": TEST_XCVR_VENDOR_OUI, + "vendor_rev": TEST_XCVR_VENDOR_REV, + "vendor_date": TEST_XCVR_VENDOR_DATE, + }} + if err := d.SetEntry(&infoTable, infoKey, infoValue); err != nil { + return fmt.Errorf("SetEntry TRANSCEIVER_INFO: %w", err) + } + + sensorTable := db.TableSpec{Name: "TRANSCEIVER_DOM_SENSOR"} + sensorValue := db.Value{Field: map[string]string{ + "voltage": "3.30", + "temperature": "42.5", + "tx1power": "1.05", + "tx2power": "1.05", + "tx3power": "1.05", + "tx4power": "1.05", + "tx5power": "1.05", + "tx6power": "1.05", + "tx7power": "1.05", + "tx8power": "1.05", + "rx1power": "-2.10", + "rx2power": "-2.10", + "rx3power": "-2.10", + "rx4power": "-2.10", + "rx5power": "-2.10", + "rx6power": "-2.10", + "rx7power": "-2.10", + "rx8power": "-2.10", + "tx1bias": "8.50", + "tx2bias": "8.50", + "tx3bias": "8.50", + "tx4bias": "8.50", + "tx5bias": "8.50", + "tx6bias": "8.50", + "tx7bias": "8.50", + "tx8bias": "8.50", + }} + if err := d.SetEntry(&sensorTable, infoKey, sensorValue); err != nil { + return fmt.Errorf("SetEntry TRANSCEIVER_DOM_SENSOR: %w", err) + } + + thresholdTable := db.TableSpec{Name: "TRANSCEIVER_DOM_THRESHOLD"} + thresholdValue := db.Value{Field: map[string]string{ + "temphighalarm": "85.0", + "templowalarm": "-10.0", + "vcchighalarm": "3.6", + "vcclowalarm": "3.0", + "temphighwarning": "75.0", + "templowwarning": "-5.0", + "vcchighwarning": "3.5", + "vcclowwarning": "3.1", + "txpowerhighalarm": "3.0", + "txpowerlowalarm": "-5.0", + "rxpowerhighalarm": "3.0", + "rxpowerlowalarm": "-15.0", + "txbiashighalarm": "12.0", + "txbiaslowalarm": "2.0", + "txpowerhighwarning": "2.5", + "txpowerlowwarning": "-4.0", + "rxpowerhighwarning": "2.5", + "rxpowerlowwarning": "-13.0", + "txbiashighwarning": "11.0", + "txbiaslowwarning": "3.0", + }} + if err := d.SetEntry(&thresholdTable, infoKey, thresholdValue); err != nil { + return fmt.Errorf("SetEntry TRANSCEIVER_DOM_THRESHOLD: %w", err) + } + + return nil +} + func getStateDB() *db.DB { stateDb, _ := db.NewDB(db.Options{ DBNo: db.StateDB, diff --git a/translib/pfm_app_transceiver.go b/translib/pfm_app_transceiver.go new file mode 100644 index 000000000..d0191cc79 --- /dev/null +++ b/translib/pfm_app_transceiver.go @@ -0,0 +1,598 @@ +////////////////////////////////////////////////////////////////////////// +// +// Copyright 2019 Dell, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +////////////////////////////////////////////////////////////////////////// + +// pfm_app_transceiver.go holds the per-component OpenConfig Platform +// Transceiver getters and their STATE_DB-backed Db structs. The code was +// moved out of pfm_app.go to keep that file focused on the PlatformApp +// lifecycle (init / translate* / process* / doGetPlatformInfo) and the +// non-transceiver Component-state path. doGetPlatformInfo continues to be +// the single entry point that dispatches GETs to these getters. + +package translib + +import ( + "fmt" + "math" + "regexp" + "strconv" + "strings" + "time" + + "github.com/Azure/sonic-mgmt-common/translib/ocbinds" + log "github.com/golang/glog" +) + +type CompTransceiverStateDb struct { + Connector string + Manufacturer string + VendorOui string + VendorRev string + Serial string + VendorDate string +} + +func (app *PlatformApp) getCompTransceiverStateDbObj(ifName string) CompTransceiverStateDb { + log.Infof("parseCompTransceiverStateDb Enter ifName=%s", ifName) + + var compTransceiverStateDbObj CompTransceiverStateDb + + transceiverInfoTable, ok := app.getTransceiverInfoEntry(ifName) + if !ok { + log.Warningf("getCompTransceiverStateDbObj: TRANSCEIVER_INFO entry missing for ifName=%s", ifName) + return compTransceiverStateDbObj + } + + compTransceiverStateDbObj.Connector = transceiverInfoTable.Get("connector") + compTransceiverStateDbObj.Manufacturer = transceiverInfoTable.Get("manufacturer") + compTransceiverStateDbObj.VendorOui = transceiverInfoTable.Get("vendor_oui") + compTransceiverStateDbObj.VendorRev = transceiverInfoTable.Get("vendor_rev") + compTransceiverStateDbObj.Serial = transceiverInfoTable.Get("serial") + compTransceiverStateDbObj.VendorDate = transceiverInfoTable.Get("vendor_date") + + return compTransceiverStateDbObj +} + +func (app *PlatformApp) getCompTransceiverStateFromDb(oc_val *ocbinds.OpenconfigPlatform_Components_Component_Transceiver_State, all bool, compName string) error { + log.Infof("getCompTransceiverStateFromDb Enter compName=%s", compName) + + ifName := strings.Replace(compName, "transceiver_", "", -1) + compTransceiverStateDb := app.getCompTransceiverStateDbObj(ifName) + + targetUriPath, _ := getYangPathFromUri(app.path.Path) + + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state/connector-type" { + transceiverInfoTable := app.transceiverInfoTable[ifName].entry + if transceiverInfoTable.Has("connector") { + if strings.HasPrefix(compTransceiverStateDb.Connector, "AOC") { + oc_val.ConnectorType = ocbinds.OpenconfigTransportTypes_FIBER_CONNECTOR_TYPE_AOC_CONNECTOR + } else if strings.HasPrefix(compTransceiverStateDb.Connector, "DAC") { + oc_val.ConnectorType = ocbinds.OpenconfigTransportTypes_FIBER_CONNECTOR_TYPE_DAC_CONNECTOR + } else if strings.HasPrefix(compTransceiverStateDb.Connector, "LC") { + oc_val.ConnectorType = ocbinds.OpenconfigTransportTypes_FIBER_CONNECTOR_TYPE_LC_CONNECTOR + } else if strings.HasPrefix(compTransceiverStateDb.Connector, "MPO") { + oc_val.ConnectorType = ocbinds.OpenconfigTransportTypes_FIBER_CONNECTOR_TYPE_MPO_CONNECTOR + } else if strings.HasPrefix(compTransceiverStateDb.Connector, "SC") { + oc_val.ConnectorType = ocbinds.OpenconfigTransportTypes_FIBER_CONNECTOR_TYPE_SC_CONNECTOR + } else { + oc_val.ConnectorType = ocbinds.OpenconfigTransportTypes_FIBER_CONNECTOR_TYPE_UNSET + } + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state/vendor" { + transceiverInfoTable := app.transceiverInfoTable[ifName].entry + if transceiverInfoTable.Has("manufacturer") { + oc_val.Vendor = &compTransceiverStateDb.Manufacturer + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state/vendor-part" { + transceiverInfoTable := app.transceiverInfoTable[ifName].entry + if transceiverInfoTable.Has("vendor_oui") { + // Per HLD (sonic-net/SONiC PR #1858, "Mapping between Openconfig + // YANG and Redis DB" Table 2): vendor-part is sourced from + // STATE_DB TRANSCEIVER_INFO.vendor_oui. + oc_val.VendorPart = &compTransceiverStateDb.VendorOui + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state/vendor-rev" { + transceiverInfoTable := app.transceiverInfoTable[ifName].entry + if transceiverInfoTable.Has("vendor_rev") { + oc_val.VendorRev = &compTransceiverStateDb.VendorRev + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state/serial-no" { + transceiverInfoTable := app.transceiverInfoTable[ifName].entry + if transceiverInfoTable.Has("serial") { + oc_val.SerialNo = &compTransceiverStateDb.Serial + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state/date-code" { + transceiverInfoTable := app.transceiverInfoTable[ifName].entry + if transceiverInfoTable.Has("vendor_date") { + // xcvrd writes vendor_date as a string with a YYYY-MM-DD prefix + // (followed by an optional time portion). Pull the leading three + // digit groups and feed them through time.Parse so a calendar + // impossibility such as Feb 30 is rejected rather than passed + // through the previous regex which accepted any 30/31-day month. + rex := regexp.MustCompile("[0-9]+") + subMatchString := rex.FindAllString(compTransceiverStateDb.VendorDate, -1) + if len(subMatchString) >= 3 && len(subMatchString[0]) == 4 && len(subMatchString[1]) == 2 && len(subMatchString[2]) == 2 { + rawDate := fmt.Sprintf("%s-%s-%s", subMatchString[0], subMatchString[1], subMatchString[2]) + if t, err := time.Parse("2006-01-02", rawDate); err == nil { + vendorDate := t.UTC().Format("2006-01-02T15:04:05.000Z") + oc_val.DateCode = &vendorDate + } else { + log.Warningf("getCompTransceiverStateFromDb: invalid date-code %q for ifName=%s: %v", compTransceiverStateDb.VendorDate, ifName, err) + } + } + } + } + + return nil +} + +type CompTransceiverStateSupplyVoltageDb struct { + voltage float64 +} + +func (app *PlatformApp) getCompTransceiverStateSupplyVoltageDbObj(ifName string) CompTransceiverStateSupplyVoltageDb { + log.Infof("parseCompTransceiverStateSupplyVoltageDb Enter ifName=%s", ifName) + + var compTransceiverStateSupplyVoltageDbObj CompTransceiverStateSupplyVoltageDb + + transceiverDomSensorTable, ok := app.getTransceiverDomSensorEntry(ifName) + if !ok { + log.Warningf("getCompTransceiverStateSupplyVoltageDbObj: TRANSCEIVER_DOM_SENSOR entry missing for ifName=%s", ifName) + compTransceiverStateSupplyVoltageDbObj.voltage = math.NaN() + return compTransceiverStateSupplyVoltageDbObj + } + + v := transceiverDomSensorTable.Get("voltage") + if v == "N/A" { + compTransceiverStateSupplyVoltageDbObj.voltage = math.NaN() + } else if parsed, err := strconv.ParseFloat(v, 64); err == nil { + compTransceiverStateSupplyVoltageDbObj.voltage = parsed + } else { + log.Warningf("getCompTransceiverStateSupplyVoltageDbObj: ifName=%s field=voltage value=%q parse error: %v", ifName, v, err) + compTransceiverStateSupplyVoltageDbObj.voltage = math.NaN() + } + + return compTransceiverStateSupplyVoltageDbObj +} + +func (app *PlatformApp) getCompTransceiverStateSupplyVoltageFromDb(oc_val *ocbinds.OpenconfigPlatform_Components_Component_Transceiver_State_SupplyVoltage, all bool, compName string) error { + log.Infof("getCompTransceiverStateSupplyVoltageFromDb Enter compName=%s", compName) + + ifName := strings.Replace(compName, "transceiver_", "", -1) + compTransceiverStateSupplyVoltageDb := app.getCompTransceiverStateSupplyVoltageDbObj(ifName) + + targetUriPath, _ := getYangPathFromUri(app.path.Path) + + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/state/supply-voltage/instant" { + transceiverDomSensorTable := app.transceiverDomSensorTable[ifName].entry + if transceiverDomSensorTable.Has("voltage") { + voltage := math.Floor(compTransceiverStateSupplyVoltageDb.voltage*fractionDigits2) / fractionDigits2 + oc_val.Instant = &voltage + } + } + + return nil +} + +type CompTransceiverPhysicalChannelStateLaserTemperatureDb struct { + temperature float64 +} + +func (app *PlatformApp) getCompTransceiverPhysicalChannelStateLaserTemperatureDbObj(ifName string) CompTransceiverPhysicalChannelStateLaserTemperatureDb { + log.Infof("parseCompTransceiverPhysicalChannelStateLaserTemperatureDb Enter ifName=%s", ifName) + + var compTransceiverPhysicalChannelStateLaserTemperatureDbObj CompTransceiverPhysicalChannelStateLaserTemperatureDb + + transceiverDomSensorTable, ok := app.getTransceiverDomSensorEntry(ifName) + if !ok { + log.Warningf("getCompTransceiverPhysicalChannelStateLaserTemperatureDbObj: TRANSCEIVER_DOM_SENSOR entry missing for ifName=%s", ifName) + compTransceiverPhysicalChannelStateLaserTemperatureDbObj.temperature = math.NaN() + return compTransceiverPhysicalChannelStateLaserTemperatureDbObj + } + + v := transceiverDomSensorTable.Get("temperature") + if v == "N/A" { + compTransceiverPhysicalChannelStateLaserTemperatureDbObj.temperature = math.NaN() + } else if parsed, err := strconv.ParseFloat(v, 64); err == nil { + compTransceiverPhysicalChannelStateLaserTemperatureDbObj.temperature = parsed + } else { + log.Warningf("getCompTransceiverPhysicalChannelStateLaserTemperatureDbObj: ifName=%s field=temperature value=%q parse error: %v", ifName, v, err) + compTransceiverPhysicalChannelStateLaserTemperatureDbObj.temperature = math.NaN() + } + + return compTransceiverPhysicalChannelStateLaserTemperatureDbObj +} + +func (app *PlatformApp) getCompTransceiverPhysicalChannelStateLaserTemperatureFromDb(oc_val *ocbinds.OpenconfigPlatform_Components_Component_Transceiver_PhysicalChannels_Channel_State_LaserTemperature, all bool, compName string) error { + log.Infof("getCompTransceiverPhysicalChannelStateLaserTemperatureFromDb Enter compName=%s", compName) + + ifName := strings.Replace(compName, "transceiver_", "", -1) + compTransceiverPhysicalChannelStateLaserTemperatureDb := app.getCompTransceiverPhysicalChannelStateLaserTemperatureDbObj(ifName) + + targetUriPath, _ := getYangPathFromUri(app.path.Path) + + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/laser-temperature/instant" { + transceiverDomSensorTable := app.transceiverDomSensorTable[ifName].entry + if transceiverDomSensorTable.Has("temperature") { + temperature := math.Floor(compTransceiverPhysicalChannelStateLaserTemperatureDb.temperature*fractionDigits1) / fractionDigits1 + oc_val.Instant = &temperature + } + } + + return nil +} + +type CompTransceiverPhysicalChannelStateOutputPowerDb struct { + TxPower [8]float64 +} + +func (app *PlatformApp) getCompTransceiverPhysicalChannelStateOutputPowerDbObj(ifName string) CompTransceiverPhysicalChannelStateOutputPowerDb { + log.Infof("parseCompTransceiverPhysicalChannelStateOutputPowerDb Enter ifName=%s", ifName) + + var compTransceiverPhysicalChannelStateOutputPowerDbObj CompTransceiverPhysicalChannelStateOutputPowerDb + + transceiverDomSensorTable, ok := app.getTransceiverDomSensorEntry(ifName) + if !ok { + log.Warningf("getCompTransceiverPhysicalChannelStateOutputPowerDbObj: TRANSCEIVER_DOM_SENSOR entry missing for ifName=%s", ifName) + return compTransceiverPhysicalChannelStateOutputPowerDbObj + } + + for i := 0; i < 8; i++ { + compTransceiverPhysicalChannelStateOutputPowerDbObj.TxPower[i], _ = strconv.ParseFloat(transceiverDomSensorTable.Get(fmt.Sprintf("tx%dpower", i+1)), 64) + } + + return compTransceiverPhysicalChannelStateOutputPowerDbObj +} + +func (app *PlatformApp) getCompTransceiverPhysicalChannelStateOutputPowerFromDb(oc_val *ocbinds.OpenconfigPlatform_Components_Component_Transceiver_PhysicalChannels_Channel_State_OutputPower, all bool, compName string, laneIndex uint16) error { + log.Infof("getCompTransceiverPhysicalChannelStateOutputPowerFromDb Enter compName=%s laneIndex=%d", compName, laneIndex) + + ifName := strings.Replace(compName, "transceiver_", "", -1) + compTransceiverPhysicalChannelStateOutputPowerDb := app.getCompTransceiverPhysicalChannelStateOutputPowerDbObj(ifName) + + targetUriPath, _ := getYangPathFromUri(app.path.Path) + + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/output-power/instant" { + if int(laneIndex) < 8 { + fieldName := fmt.Sprintf("tx%dpower", laneIndex+1) + transceiverDomSensorTable := app.transceiverDomSensorTable[ifName].entry + if transceiverDomSensorTable.Has(fieldName) { + txpower := math.Floor(compTransceiverPhysicalChannelStateOutputPowerDb.TxPower[laneIndex]*fractionDigits2) / fractionDigits2 + oc_val.Instant = &txpower + } + } + } + + return nil +} + +type CompTransceiverPhysicalChannelStateInputPowerDb struct { + RxPower [8]float64 +} + +func (app *PlatformApp) getCompTransceiverPhysicalChannelStateInputPowerDbObj(ifName string) CompTransceiverPhysicalChannelStateInputPowerDb { + log.Infof("parseCompTransceiverPhysicalChannelStateInputPowerDb Enter ifName=%s", ifName) + + var compTransceiverPhysicalChannelStateInputPowerDbObj CompTransceiverPhysicalChannelStateInputPowerDb + + transceiverDomSensorTable, ok := app.getTransceiverDomSensorEntry(ifName) + if !ok { + log.Warningf("getCompTransceiverPhysicalChannelStateInputPowerDbObj: TRANSCEIVER_DOM_SENSOR entry missing for ifName=%s", ifName) + return compTransceiverPhysicalChannelStateInputPowerDbObj + } + + for i := 0; i < 8; i++ { + compTransceiverPhysicalChannelStateInputPowerDbObj.RxPower[i], _ = strconv.ParseFloat(transceiverDomSensorTable.Get(fmt.Sprintf("rx%dpower", i+1)), 64) + } + + return compTransceiverPhysicalChannelStateInputPowerDbObj +} + +func (app *PlatformApp) getCompTransceiverPhysicalChannelStateInputPowerFromDb(oc_val *ocbinds.OpenconfigPlatform_Components_Component_Transceiver_PhysicalChannels_Channel_State_InputPower, all bool, compName string, laneIndex uint16) error { + log.Infof("getCompTransceiverPhysicalChannelStateInputPowerFromDb Enter compName=%s laneIndex=%d", compName, laneIndex) + + ifName := strings.Replace(compName, "transceiver_", "", -1) + compTransceiverPhysicalChannelStateInputPowerDb := app.getCompTransceiverPhysicalChannelStateInputPowerDbObj(ifName) + + targetUriPath, _ := getYangPathFromUri(app.path.Path) + + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/input-power/instant" { + if int(laneIndex) < 8 { + fieldName := fmt.Sprintf("rx%dpower", laneIndex+1) + transceiverDomSensorTable := app.transceiverDomSensorTable[ifName].entry + if transceiverDomSensorTable.Has(fieldName) { + rxpower := math.Floor(compTransceiverPhysicalChannelStateInputPowerDb.RxPower[laneIndex]*fractionDigits2) / fractionDigits2 + oc_val.Instant = &rxpower + } + } + } + + return nil +} + +type CompTransceiverPhysicalChannelStateLaserBiasCurrentDb struct { + TxBias [8]float64 +} + +func (app *PlatformApp) getCompTransceiverPhysicalChannelStateLaserBiasCurrentDbObj(ifName string) CompTransceiverPhysicalChannelStateLaserBiasCurrentDb { + log.Infof("parseCompTransceiverPhysicalChannelStateLaserBiasCurrentDb Enter ifName=%s", ifName) + + var compTransceiverPhysicalChannelStateLaserBiasCurrentDbObj CompTransceiverPhysicalChannelStateLaserBiasCurrentDb + + transceiverDomSensorTable, ok := app.getTransceiverDomSensorEntry(ifName) + if !ok { + log.Warningf("getCompTransceiverPhysicalChannelStateLaserBiasCurrentDbObj: TRANSCEIVER_DOM_SENSOR entry missing for ifName=%s", ifName) + for i := 0; i < 8; i++ { + compTransceiverPhysicalChannelStateLaserBiasCurrentDbObj.TxBias[i] = math.NaN() + } + return compTransceiverPhysicalChannelStateLaserBiasCurrentDbObj + } + + for i := 0; i < 8; i++ { + field := fmt.Sprintf("tx%dbias", i+1) + raw := transceiverDomSensorTable.Get(field) + if raw != "N/A" { + compTransceiverPhysicalChannelStateLaserBiasCurrentDbObj.TxBias[i], _ = strconv.ParseFloat(raw, 64) + } else { + compTransceiverPhysicalChannelStateLaserBiasCurrentDbObj.TxBias[i] = math.NaN() + } + } + + return compTransceiverPhysicalChannelStateLaserBiasCurrentDbObj +} + +func (app *PlatformApp) getCompTransceiverPhysicalChannelStateLaserBiasCurrentFromDb(oc_val *ocbinds.OpenconfigPlatform_Components_Component_Transceiver_PhysicalChannels_Channel_State_LaserBiasCurrent, all bool, compName string, laneIndex uint16) error { + log.Infof("getCompTransceiverPhysicalChannelStateLaserBiasCurrentFromDb Enter compName=%s laneIndex=%d", compName, laneIndex) + + ifName := strings.Replace(compName, "transceiver_", "", -1) + compTransceiverPhysicalChannelStateLaserBiasCurrentDb := app.getCompTransceiverPhysicalChannelStateLaserBiasCurrentDbObj(ifName) + + targetUriPath, _ := getYangPathFromUri(app.path.Path) + + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/physical-channels/channel/state/laser-bias-current/instant" { + if int(laneIndex) < 8 { + fieldName := fmt.Sprintf("tx%dbias", laneIndex+1) + transceiverDomSensorTable := app.transceiverDomSensorTable[ifName].entry + if transceiverDomSensorTable.Has(fieldName) { + txbias := math.Floor(compTransceiverPhysicalChannelStateLaserBiasCurrentDb.TxBias[laneIndex]*fractionDigits2) / fractionDigits2 + oc_val.Instant = &txbias + } + } + } + + return nil +} + +type CompTransceiverThresholdStateDb struct { + TempHighAlarm float64 + TempLowAlarm float64 + VccHighAlarm float64 + VccLowAlarm float64 + TempHighWarning float64 + TempLowWarning float64 + VccHighWarning float64 + VccLowWarning float64 + TxPowerHighAlarm float64 + TxPowerLowAlarm float64 + RxPowerHighAlarm float64 + RxPowerLowAlarm float64 + TxBiasHighAlarm float64 + TxBiasLowAlarm float64 + TxPowerHighWarning float64 + TxPowerLowWarning float64 + RxPowerHighWarning float64 + RxPowerLowWarning float64 + TxBiasHighWarning float64 + TxBiasLowWarning float64 +} + +func (app *PlatformApp) getCompTransceiverThresholdStateDbObj(ifName string) CompTransceiverThresholdStateDb { + log.Infof("parseCompTransceiverThresholdStateDb Enter ifName=%s", ifName) + + var compTransceiverThresholdStateDbObj CompTransceiverThresholdStateDb + + transceiverDomThresholdTable, ok := app.getTransceiverDomThresholdEntry(ifName) + if !ok { + log.Warningf("getCompTransceiverThresholdStateDbObj: TRANSCEIVER_DOM_THRESHOLD entry missing for ifName=%s", ifName) + return compTransceiverThresholdStateDbObj + } + + compTransceiverThresholdStateDbObj.TempHighAlarm, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("temphighalarm"), 64) + compTransceiverThresholdStateDbObj.TempLowAlarm, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("templowalarm"), 64) + compTransceiverThresholdStateDbObj.VccHighAlarm, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("vcchighalarm"), 64) + compTransceiverThresholdStateDbObj.VccLowAlarm, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("vcclowalarm"), 64) + compTransceiverThresholdStateDbObj.TempHighWarning, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("temphighwarning"), 64) + compTransceiverThresholdStateDbObj.TempLowWarning, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("templowwarning"), 64) + compTransceiverThresholdStateDbObj.VccHighWarning, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("vcchighwarning"), 64) + compTransceiverThresholdStateDbObj.VccLowWarning, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("vcclowwarning"), 64) + compTransceiverThresholdStateDbObj.TxPowerHighAlarm, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("txpowerhighalarm"), 64) + compTransceiverThresholdStateDbObj.TxPowerLowAlarm, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("txpowerlowalarm"), 64) + compTransceiverThresholdStateDbObj.RxPowerHighAlarm, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("rxpowerhighalarm"), 64) + compTransceiverThresholdStateDbObj.RxPowerLowAlarm, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("rxpowerlowalarm"), 64) + compTransceiverThresholdStateDbObj.TxBiasHighAlarm, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("txbiashighalarm"), 64) + compTransceiverThresholdStateDbObj.TxBiasLowAlarm, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("txbiaslowalarm"), 64) + compTransceiverThresholdStateDbObj.TxPowerHighWarning, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("txpowerhighwarning"), 64) + compTransceiverThresholdStateDbObj.TxPowerLowWarning, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("txpowerlowwarning"), 64) + compTransceiverThresholdStateDbObj.RxPowerHighWarning, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("rxpowerhighwarning"), 64) + compTransceiverThresholdStateDbObj.RxPowerLowWarning, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("rxpowerlowwarning"), 64) + compTransceiverThresholdStateDbObj.TxBiasHighWarning, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("txbiashighwarning"), 64) + compTransceiverThresholdStateDbObj.TxBiasLowWarning, _ = strconv.ParseFloat(transceiverDomThresholdTable.Get("txbiaslowwarning"), 64) + + return compTransceiverThresholdStateDbObj +} + +func (app *PlatformApp) getCompTransceiverThresholdStateFromDb(oc_val *ocbinds.OpenconfigPlatform_Components_Component_Transceiver_Thresholds_Threshold_State, all bool, compName string, severityName string) error { + log.Infof("getCompTransceiverThresholdStateFromDb Enter compName=%s severityName=%s", compName, severityName) + + ifName := strings.Replace(compName, "transceiver_", "", -1) + compTransceiverThresholdStateDb := app.getCompTransceiverThresholdStateDbObj(ifName) + + targetUriPath, _ := getYangPathFromUri(app.path.Path) + + if severityName == "CRITICAL" { + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/laser-temperature-upper" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("temphighalarm") { + temphighalarm := math.Floor(compTransceiverThresholdStateDb.TempHighAlarm*fractionDigits1) / fractionDigits1 + oc_val.LaserTemperatureUpper = &temphighalarm + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/laser-temperature-lower" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("templowalarm") { + templowalarm := math.Floor(compTransceiverThresholdStateDb.TempLowAlarm*fractionDigits1) / fractionDigits1 + oc_val.LaserTemperatureLower = &templowalarm + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/supply-voltage-upper" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("vcchighalarm") { + vcchighalarm := math.Floor(compTransceiverThresholdStateDb.VccHighAlarm*fractionDigits2) / fractionDigits2 + oc_val.SupplyVoltageUpper = &vcchighalarm + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/supply-voltage-lower" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("vcclowalarm") { + vcclowalarm := math.Floor(compTransceiverThresholdStateDb.VccLowAlarm*fractionDigits2) / fractionDigits2 + oc_val.SupplyVoltageLower = &vcclowalarm + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/output-power-upper" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("txpowerhighalarm") { + txpowerhighalarm := math.Floor(compTransceiverThresholdStateDb.TxPowerHighAlarm*fractionDigits2) / fractionDigits2 + oc_val.OutputPowerUpper = &txpowerhighalarm + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/output-power-lower" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("txpowerlowalarm") { + txpowerlowalarm := math.Floor(compTransceiverThresholdStateDb.TxPowerLowAlarm*fractionDigits2) / fractionDigits2 + oc_val.OutputPowerLower = &txpowerlowalarm + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/input-power-upper" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("rxpowerhighalarm") { + rxpowerhighalarm := math.Floor(compTransceiverThresholdStateDb.RxPowerHighAlarm*fractionDigits2) / fractionDigits2 + oc_val.InputPowerUpper = &rxpowerhighalarm + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/input-power-lower" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("rxpowerlowalarm") { + rxpowerlowalarm := math.Floor(compTransceiverThresholdStateDb.RxPowerLowAlarm*fractionDigits2) / fractionDigits2 + oc_val.InputPowerLower = &rxpowerlowalarm + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/laser-bias-current-upper" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("txbiashighalarm") { + txbiashighalarm := math.Floor(compTransceiverThresholdStateDb.TxBiasHighAlarm*fractionDigits2) / fractionDigits2 + oc_val.LaserBiasCurrentUpper = &txbiashighalarm + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/laser-bias-current-lower" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("txbiaslowalarm") { + txbiaslowalarm := math.Floor(compTransceiverThresholdStateDb.TxBiasLowAlarm*fractionDigits2) / fractionDigits2 + oc_val.LaserBiasCurrentLower = &txbiaslowalarm + } + } + } + + if severityName == "WARNING" { + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/laser-temperature-upper" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("temphighwarning") { + temphighwarning := math.Floor(compTransceiverThresholdStateDb.TempHighWarning*fractionDigits1) / fractionDigits1 + oc_val.LaserTemperatureUpper = &temphighwarning + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/laser-temperature-lower" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("templowwarning") { + templowwarning := math.Floor(compTransceiverThresholdStateDb.TempLowWarning*fractionDigits1) / fractionDigits1 + oc_val.LaserTemperatureLower = &templowwarning + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/supply-voltage-upper" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("vcchighwarning") { + vcchighwarning := math.Floor(compTransceiverThresholdStateDb.VccHighWarning*fractionDigits2) / fractionDigits2 + oc_val.SupplyVoltageUpper = &vcchighwarning + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/supply-voltage-lower" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("vcclowwarning") { + vcclowwarning := math.Floor(compTransceiverThresholdStateDb.VccLowWarning*fractionDigits2) / fractionDigits2 + oc_val.SupplyVoltageLower = &vcclowwarning + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/output-power-upper" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("txpowerhighwarning") { + v := math.Floor(compTransceiverThresholdStateDb.TxPowerHighWarning*fractionDigits2) / fractionDigits2 + oc_val.OutputPowerUpper = &v + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/output-power-lower" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("txpowerlowwarning") { + v := math.Floor(compTransceiverThresholdStateDb.TxPowerLowWarning*fractionDigits2) / fractionDigits2 + oc_val.OutputPowerLower = &v + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/input-power-upper" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("rxpowerhighwarning") { + v := math.Floor(compTransceiverThresholdStateDb.RxPowerHighWarning*fractionDigits2) / fractionDigits2 + oc_val.InputPowerUpper = &v + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/input-power-lower" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("rxpowerlowwarning") { + v := math.Floor(compTransceiverThresholdStateDb.RxPowerLowWarning*fractionDigits2) / fractionDigits2 + oc_val.InputPowerLower = &v + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/laser-bias-current-upper" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("txbiashighwarning") { + v := math.Floor(compTransceiverThresholdStateDb.TxBiasHighWarning*fractionDigits2) / fractionDigits2 + oc_val.LaserBiasCurrentUpper = &v + } + } + if all || targetUriPath == "/openconfig-platform:components/component/openconfig-platform-transceiver:transceiver/thresholds/threshold/state/laser-bias-current-lower" { + transceiverDomThresholdTable := app.transceiverDomThresholdTable[ifName].entry + if transceiverDomThresholdTable.Has("txbiaslowwarning") { + v := math.Floor(compTransceiverThresholdStateDb.TxBiasLowWarning*fractionDigits2) / fractionDigits2 + oc_val.LaserBiasCurrentLower = &v + } + } + } + + return nil +}