openconfig / ygot

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

Presence container support #329

Open rajeshs1 opened 5 years ago

rajeshs1 commented 5 years ago

ygot version 0.6.0

My yang file has a presence container (interfaces-ip-dhcp:dhcp-client). https://tools.ietf.org/html/rfc6020#page-52

While using the EmitJSON() method, the JSON output does not have the empty container. Ideally the input cfgjson data after marshal and emitjson should result in the same.

in ygot/render.go, the structJson method skips if the container is empty.

                if util.IsYgotAnnotation(fType) {
            value, err = jsonAnnotationSlice(field)
        } else {
            value, err = jsonValue(field, pmod, args)
        }
        if err != nil {
            errs.Add(err)
            continue
        }
        if value == nil {
            continue
        }

After the jsondata is Unmarshalled, the value of the dhcp-client is nil. And the structJson method skips this dhcp-client container during EmitJSON Is there any plan to support the presence container. Here are some details:

cfg

{
  "interface": [
    {
      "name": "inst0",
      "admin-state": "enable",
      "subinterface": [
        {
          "index": 0,
          "admin-state": "enable",
          "ipv4": {
            "interfaces-ip-dhcp:dhcp-client": {  
            }
          }
        }
      ]
    }
  ]
}   

Here’s a snippet of my code:

device := &oc.Device{}
    err := oc.Unmarshal(cfg, device, &ytypes.IgnoreExtraFields{})

    cfgdata, err = ygot.EmitJSON(device, &ygot.EmitJSONConfig{
        Format:         ygot.RFC7951,
        Indent:         "",
        RFC7951Config: &ygot.RFC7951JSONConfig{
            AppendModuleName: false,
        },
    })

Actual cfgData

{
   "interface":[
      {
         "admin-state":"enable",
         "name":"inst0",
         "subinterface":[
            {
               "admin-state":"enable",
               "index":0
            }
         ]
      }
   ]
}

Expected cfgData

{
   "interface":[
      {
         "admin-state":"enable",
         "name":"inst0",
         "subinterface":[
            {
               "admin-state":"enable",
               "index":0,
                "ipv4": {
                  "interfaces-ip-dhcp:dhcp-client": {  //Presence container
                }
              }
            }
         ]
      }
   ]
}
rajeshs1 commented 4 years ago

Hi @robshakir , is there any plan for this enhancement?

robshakir commented 4 years ago

hi,

There isn't currently a plan to add presence support to ygot. I'd be happy to review a patch for this though. I suggest that the easiest way to do this is to add an annotation to presence containers within the struct tag, and then make the struct rendering method check for whether that tag is there before deleting the empty container.

Cheers, r.

soumiksamanta commented 3 years ago

Hi Rob,

I plan to add this support. Can you please provide some pointers in the ygot code which I can take a look?

Thanks Soumik

wenovus commented 3 years ago

Hi Soumik, this is where the JSON marshalling routine skips over empty containers. https://github.com/openconfig/ygot/blob/2713b986ad5a22464ae5e72e919be9f519466246/ygot/render.go#L1078-L1080

Like Rob said, I think it makes sense to add a struct tag when generating code to make this do something different for presence containers.

The most involved part is probably modifying ygen to generate the tags. One way to do this is to access this field during the population of the struct tags here: https://github.com/openconfig/ygot/blob/2713b986ad5a22464ae5e72e919be9f519466246/ygen/gogen.go#L1563-L1587 You can get the presence field from targetStruct.Entry.Node after casting it to the Container type.