openconfig / ygot

A YANG-centric Go toolkit - Go/Protobuf Code Generation; Validation; Marshaling/Unmarshaling
Apache License 2.0
286 stars 107 forks source link

TogNMINotifications errors for generated GoStruct union containing Int64 fields #353

Closed gsindigi closed 4 years ago

gsindigi commented 4 years ago

The GoStructs are generated in package "ocd" for OpenConfig-platform*yang modules, using generator tool as described. The generated code contains different GoStructs and utility functions to convert an appropriate value into corresponding GoStruct implementing the requisite interface for some specific yang types e.g., union; sample below.

// To_OpenconfigPlatform_Components_Component_Properties_Property_State_Value_Union takes an input interface{} and attempts to convert it to a struct
// which implements the OpenconfigPlatform_Components_Component_Properties_Property_State_Value_Union union. It returns an error if the interface{} supplied
// cannot be converted to a type within the union.
func (t *OpenconfigPlatform_Components_Component_Properties_Property_State) To_OpenconfigPlatform_Components_Component_Properties_Property_State_Value_Union(i interface{}) (OpenconfigPlatform_Components_Component_Properties_Property_State_Value_Union, error) {
    switch v := i.(type) {
    case bool:
        return &OpenconfigPlatform_Components_Component_Properties_Property_State_Value_Union_Bool{v}, nil
    case float64:
        return &OpenconfigPlatform_Components_Component_Properties_Property_State_Value_Union_Float64{v}, nil
    case int64:
        return &OpenconfigPlatform_Components_Component_Properties_Property_State_Value_Union_Int64{v}, nil
    case string:
        return &OpenconfigPlatform_Components_Component_Properties_Property_State_Value_Union_String{v}, nil
    case uint64:
        return &OpenconfigPlatform_Components_Component_Properties_Property_State_Value_Union_Uint64{v}, nil
    default:
        return nil, fmt.Errorf("cannot convert %v to OpenconfigPlatform_Components_Component_Properties_Property_State_Value_Union, unknown union type, got: %T, want any of [bool, float64, int64, string, uint64]", i, i)
    }
}

When such a GoStruct of such type or other GoStructs having such type as member are passed to ygot.TogNMINotifications, it results in an error "cannot represent field value as TypedValue". This is happening in ygot/render.go's func EncodeTypedValue(val interface{}, enc gnmipb.Encoding) (*gnmipb.TypedValue, error) line#640. Perhaps its expecting an Enum instead of Int64 here! but, the generated code do use Int64.

Sample usage code below. Note that, no error is thrown while initializing the structs though. Could not figure out an easy way to put this as a test code with a YangUnion usage; hence posting with actual Structs usage.

func cmpntToNotification(device *ocd.Device) {
    name := "cmpnt-1"
    cmpnt, _ := device.Components.NewComponent(name)
    sType := &ocd.OpenconfigPlatform_Components_Component_State_Type_Union_E_OpenconfigPlatformTypes_OPENCONFIG_HARDWARE_COMPONENT{}
    sType.E_OpenconfigPlatformTypes_OPENCONFIG_HARDWARE_COMPONENT = ocd.OpenconfigPlatformTypes_OPENCONFIG_HARDWARE_COMPONENT_CPU
    cmpnt.State = &ocd.OpenconfigPlatform_Components_Component_State{Name: ygot.String(name), Type: sType}
    prop1 := cmpnt.GetOrCreateProperties().GetOrCreateProperty("prop1")
    prop1State := prop1.GetOrCreateState()
    v, err := prop1State.To_OpenconfigPlatform_Components_Component_Properties_Property_State_Value_Union(int64(543))
    log.Infof("UnionValue = %v, error = %v", v, err)
    log.Infof("Component = %v", cmpnt)
    pep, _ := ygot.StringToStructuredPath(fmt.Sprintf("/components/component[name=%s]", *cmpnt.Name))
    cfg := ygot.GNMINotificationsConfig{UsePathElem: true, PathElemPrefix: pep.Elem}
    now := time.Now().UnixNano()
    g, err := ygot.TogNMINotifications(cmpnt, now, cfg)
    if err != nil {
        log.Fatalf("Failed while converting to gNMINotifications:  %v", err)
    }
    log.Infof("Notifications: %v", g)
}

Is anything wrong with the above usage ? If not, how to overcome this?

Thanks.

gsindigi commented 4 years ago

This issue is prevalent for any of the generated structs, with *Int64 fields. Picked up a different struct with such a field and found same error. How do we use such fields and overcome the issue ? Any suggestions to address the issue will help.

test_int64.go:282] JSON: {
  "last-update": "345"
}
test_int64.go:287] Failed while converting to gNMINotifications:  cannot represent field value 345 as TypedValue
// OpenconfigLldp_Lldp_Interfaces_Interface_Neighbors_Neighbor_State represents the /openconfig-lldp/lldp/interfaces/interface/neighbors/neighbor/state YANG schema element.
type OpenconfigLldp_Lldp_Interfaces_Interface_Neighbors_Neighbor_State struct {
...
    LastUpdate  *int64  `path:"last-update" module:"openconfig-lldp"`
...
}

func validateInt64() {
    st := &ocd.OpenconfigLldp_Lldp_Interfaces_Interface_Neighbors_Neighbor_State{LastUpdate: ygot.Int64(345)}
    ejc := &ygot.EmitJSONConfig{
        Format: ygot.RFC7951,
        Indent: "  ",
        RFC7951Config: &ygot.RFC7951JSONConfig{
            AppendModuleName: false,
        },
    }
    dJSON, e := ygot.EmitJSON(st, ejc)
    if e != nil {
        log.Errorf("failed converting to JSON: %v", e)
        return
    }
    log.Infof("JSON: %v", dJSON)
    cfg := ygot.GNMINotificationsConfig{UsePathElem: true}
    now := time.Now().UnixNano()
    g, err := ygot.TogNMINotifications(st, now, cfg)
    if err != nil {
        log.Fatalf("Failed while converting to gNMINotifications:  %v", err)
    }
    log.Infof("Notifications: %v", g)
}
robshakir commented 4 years ago

hi!

PTAL at #356 -- this adds a fix for the int64 rendering issue, there were a couple of defects in that codepath.

thanks, r.

gsindigi commented 4 years ago

Thanks @robshakir . Hope the fixes will be merged soon.