PANTHEONtech / lighty

Lightweight OpenDaylight runtime library
https://lighty.io
Eclipse Public License 1.0
134 stars 74 forks source link

Lighty.io doesn't support post method to add item to list, even related yang file has one key leaf in a list. #714

Closed MuhendisBey closed 3 years ago

MuhendisBey commented 3 years ago

Lighty.io renders yang endpoint but it doesn't properly work as it said. Rendered endpoint and input are like this: image

If i call in this way error message is like this: image

Branch lighty.io branch [v 14.x]

To Reproduce Steps to reproduce the behavior:

  1. git checkout https://...
  2. cd lighty
  3. mvn clean install
  4. run restconf-netconf example
  5. add valid netconf device
  6. goto restconf swagger page
  7. go to dhcpd-kea module dhcp-kea container subnets list to post request
  8. make request

Expected behavior user shouldn't get an error.

Environment (please complete the following information):

Here is the yang file module dhcpd-kea {

namespace "http://xxx-dhcp.xxx.com/ns/example/dhcpd"; prefix dhcpd;

import ietf-inet-types { prefix inet; }

import tailf-xsd-types { prefix xs; }

organization "xxx AG";

contact "onur.gursoy@xxx.com";

description "YANG datamodel for kea server subnet config (C) 2021-2024 xxx AG";

revision 2021-06-15 { description "Adding key leaf as key into the subnet list"; }

revision 2019-02-14 { description "Normalized YANG identifier names."; }

revision 2018-11-20 { description "YANG header information updated"; }

revision 2009-05-19 { description "Initial revision."; }

typedef loglevel { type enumeration { enum kern; enum mail; enum local7; } }

grouping subnet4-list { list subnets { key id; unique "net mask"; leaf id { type uint32; } leaf net { type inet:ipv4-address; } leaf mask { type inet:ipv4-address; } container range { presence ""; leaf dynamic-bootp { type boolean; default false; description "Enable BOOTP for this instance."; } leaf low-addr { type inet:ipv4-address; mandatory true; description "Enable BOOTP for this instance."; } leaf high-addr { type inet:ipv4-address; mandatory true; description "Enable BOOTP for this instance."; } } leaf routers { type string; } leaf tftpAddrs { type string; } leaf ntpAddrs { type string; } leaf dnsAddrs { type string; } leaf max-lease-time { type xs:duration; default PT7200S; } leaf default-lease-time { type xs:duration; default PT600S; } } }

container dhcp-kea { leaf default-lease-time { type xs:duration; default PT600S; } leaf max-lease-time { type xs:duration; default PT7200S; } leaf log-facility { type loglevel; default local7; } uses subnet4-list; list shared-network { key name; max-elements 1024; leaf name { type string; } uses subnet4-list; } } }

caladi commented 3 years ago

Hello @MuhendisBey,

The POST method 's message-body MUST contain exactly one instance of the expected data resource. Please try request in the format:

curl -X POST \
  http://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=xxx-dhcp/yang-ext:mount/dhcpd-kea:dhcp-kea/subnets=11 \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
  "range": {
    "dynamic-bootp": false,
    "low-addr": "192.168.1.1",
    "high-addr": "192.168.1.10"
  }
}'

reference: RFC8040 RESTCONF: https://datatracker.ietf.org/doc/html/rfc8040#section-4.4.1

We are sorry for the confusion caused by the swagger plugin, which shows multiple instances of the expected data resource in the body of the POST message in this example.

Please let us know if you have any questions.

MuhendisBey commented 3 years ago

Hello @caladi First of all thanks for your response and time.

reference: RFC8040 RESTCONF: https://datatracker.ietf.org/doc/html/rfc8040#section-4.4.1

We are sorry for the confusion caused by the swagger plugin, which shows multiple instances of the expected data resource in the body of the POST message in this example.

You mean that, swagger is wrong? swagger renders in wrong way. Again is this ODL issue ? Dou you know that is there any bug report for ODL, if there is not, i can create it.

curl -X POST \
  http://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=xxx-dhcp/yang-ext:mount/dhcpd-kea:dhcp-kea/subnets=11 \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -d '{
  "range": {
    "dynamic-bootp": false,
    "low-addr": "192.168.1.1",
    "high-addr": "192.168.1.10"
  }
}'

Btw, your example request is working. I couldn't understand exactly, why it's working. if put just "net" field or something like that except range, is it work ? you can give more example ? RFC is limited about this topic.

Many Thanks, With My Best Regards,

MuhendisBey commented 3 years ago

Hello @caladi

I got your point while you're saying only one instance. Sorry for my late understanding. During the post request, i can put one item in the post body. I can add multiple item in the post body.

This is terrible design. Indeed, why i use this request, i don't know. anyway, many thanks for your helps.

With My Best Regards.

caladi commented 3 years ago

Hello @MuhendisBey,

The POST method is used to CREATE data sources. If data exists in the datastore, an error is shown. If you need to update or replace data, you should use PUT or PATCH. The POST request MUST contain only one instance (top-level element). For example:

curl -X POST \
  http://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=xxx-dhcp/yang-ext:mount/dhcpd-kea:dhcp-kea/subnets=11 \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -H 'postman-token: f5488333-c435-cdc1-2e09-7c229c201a1a' \
  -d '{
  "net": "192.168.1.10"
}'

This will work only if "net" element doesn't exist. The Request contains only one top-level element and this element doesn't exists. or

curl -X POST \
  http://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=xxx-dhcp/yang-ext:mount/dhcpd-kea:dhcp-kea/subnets=11 \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -H 'postman-token: 49837517-f750-ff7e-b390-e3738a2d207d' \
  -d '{
  "mask": "255.255.255.0"
}'

The Element "mask" cannot be present in datastore in subnets with id 11.

Error example:

curl -X POST \
  http://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=xxx-dhcp/yang-ext:mount/dhcpd-kea:dhcp-kea/subnets=11 \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -H 'postman-token: 1df4eb29-7b95-7c3c-cba8-366150f299ab' \
  -d '{
  "net": "192.168.1.10",
  "mask": "255.255.255.0"
}'

This request include multiple top-level resources so you will get error:

"Error parsing json input: Failed to create new parse result data. Are you creating multiple resources/subresources in POST request?"

If POST request includes one top-level element "range" and it has child element, it will work. for example:

curl -X POST \
  http://localhost:8888/restconf/data/network-topology:network-topology/topology=topology-netconf/node=xxx-dhcp/yang-ext:mount/dhcpd-kea:dhcp-kea/subnets=11 \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json' \
  -H 'postman-token: 85cf8b08-5426-8ff0-a0b1-b05358854e75' \
  -d '{
  "range": {
    "dynamic-bootp": false,
    "low-addr": "192.168.1.1",
    "high-addr": "192.168.1.10"
  }
}'

The POST method request has a few restrictions:

Please let us know if you have any questions. Best Regards

caladi commented 3 years ago

Hello @MuhendisBey,

I didn't notice your next message. We are glad that we could help. Do not hesitate to ask in case you have any questions.

Thanks, Best Regards