When I look at the IETF model file (at https://github.com/mbj4668/pyang/blob/master/modules/ietf/ietf-netconf-acm.yang) , it appears to me that the nacm container itself is not marked as mandatory.
But Yangson seems to be parsing the container (rather than some of its leaf nodes) as mandatory. I tested this with the YANGSON CLI, but I get the same result when parsing JSON data that was translated from a NETCONF XML response using a PYANG-generated XSLT file. If the NETCONF response does not contain nacm data, then validation of the JSON data fails.
Here is an excerpt of the CLI output, with the issue highlighted in boldface:
yangson -d -p /usr/local/share/yang ./yang-library-data.json | jq -a
{
"kind": "schematree",
"mandatory": true,
"description": "Data model ID: ",
"children": {
"notifications:notification": {
"kind": "container",
"mandatory": true,
"description": "internal struct to start a notification",
"children": {
"eventTime": {
"kind": "leaf",
"mandatory": true,
"type": {
"base": "string",
"derived": "date-and-time",
"patterns": [
"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[\+\-]\d{2}:\d{2})"
]
}
}
},
"presence": false,
"config": false
},
"ietf-netconf-acm:nacm": {
"kind": "container",
"mandatory": true,
"description": "Parameters for NETCONF access control model.",
"children": {
"enable-nacm": {
"kind": "leaf",
"description": "Enables or disables all NETCONF access control\n enforcement. If 'true', then enforcement\n is enabled. If 'false', then enforcement\n is disabled.",
"type": {
"base": "boolean"
},
"default": true
},
"read-default": {
"kind": "leaf",
"description": "Controls whether read access is granted if\n no appropriate rule is found for a\n particular read request.",
"type": {
"base": "enumeration",
"derived": "action-type",
"enums": [
"permit",
"deny"
]
},
"default": "permit"
},
"write-default": {
"kind": "leaf",
"description": "Controls whether create, update, or delete access\n is granted if no appropriate rule is found for a\n particular write request.",
"type": {
"base": "enumeration",
"derived": "action-type",
"enums": [
"permit",
"deny"
]
},
"default": "deny"
},
"exec-default": {
"kind": "leaf",
"description": "Controls whether exec access is granted if no appropriate\n rule is found for a particular protocol operation request.",
"type": {
"base": "enumeration",
"derived": "action-type",
"enums": [
"permit",
"deny"
]
},
"default": "permit"
},
"enable-external-groups": {
"kind": "leaf",
"description": "Controls whether the server uses the groups reported by the\n NETCONF transport layer when it assigns the user to a set of\n NACM groups. If this leaf has the value 'false', any group\n names reported by the transport layer are ignored by the\n server.",
"type": {
"base": "boolean"
},
"default": true
},
"denied-operations": {
"kind": "leaf",
"mandatory": true,
"description": "Number of times since the server last restarted that a\n protocol operation request was denied.",
"type": {
"base": "uint32",
"derived": "zero-based-counter32"
},
"config": false
},
"denied-data-writes": {
"kind": "leaf",
"mandatory": true,
"description": "Number of times since the server last restarted that a\n protocol operation request to alter\n a configuration datastore was denied.",
"type": {
"base": "uint32",
"derived": "zero-based-counter32"
},
"config": false
},
"denied-notifications": {
"kind": "leaf",
"mandatory": true,
"description": "Number of times since the server last restarted that\n a notification was dropped for a subscription because\n access to the event type was denied.",
"type": {
"base": "uint32",
"derived": "zero-based-counter32"
},
"config": false
},
"groups": {
"kind": "container",
"description": "NETCONF access control groups.",
"children": {
"group": {
"kind": "list",
"description": "One NACM group entry. This list will only contain\n configured entries, not any entries learned from\n any transport protocols.",
"children": {
"name": {
"kind": "leaf",
"mandatory": true,
"description": "Group name associated with this entry.",
"type": {
"base": "string",
"derived": "group-name-type",
"length": [
[
1,
4294967295
]
],
"patterns": [
"[^\\*]."
]
}
},
"user-name": {
"kind": "leaf-list",
"description": "Each entry identifies the username of\n a member of the group associated with\n this entry.",
"type": {
"base": "string",
"derived": "user-name-type",
"length": [
[
1,
4294967295
]
]
}
}
},
"keys": [
"name"
]
}
},
"presence": false
},
"rule-list": {
"kind": "list",
"description": "An ordered collection of access control rules.",
"children": {
"name": {
"kind": "leaf",
"mandatory": true,
"description": "Arbitrary name assigned to the rule-list.",
"type": {
"base": "string",
"length": [
[
1,
4294967295
]
]
}
},
"group": {
"kind": "leaf-list",
"description": "List of administrative groups that will be\n assigned the associated access rights\n defined by the 'rule' list.\n\n The string '' indicates that all groups apply to the\n entry.",
"type": {
"base": "union"
}
},
"rule": {
"kind": "list",
"description": "One access control rule.\n\n Rules are processed in user-defined order until a match is\n found. A rule matches if 'module-name', 'rule-type', and\n 'access-operations' match the request. If a rule\n matches, the 'action' leaf determines whether or not\n access is granted.",
"children": {
"name": {
"kind": "leaf",
"mandatory": true,
"description": "Arbitrary name assigned to the rule.",
"type": {
"base": "string",
"length": [
[
1,
4294967295
]
]
}
},
"module-name": {
"kind": "leaf",
"description": "Name of the module associated with this rule.\n\n This leaf matches if it has the value '' or if the\n object being accessed is defined in the module with the\n specified module name.",
"type": {
"base": "union"
},
"default": ""
},
"rpc-name": {
"kind": "leaf",
"description": "This leaf matches if it has the value '' or if\n its value equals the requested protocol operation\n name.",
"type": {
"base": "union"
}
},
"notification-name": {
"kind": "leaf",
"description": "This leaf matches if it has the value '' or if its\n value equals the requested notification name.",
"type": {
"base": "union"
}
},
"path": {
"kind": "leaf",
"mandatory": true,
"description": "Data node instance-identifier associated with the\n data node, action, or notification controlled by\n this rule.\n\n Configuration data or state data\n instance-identifiers start with a top-level\n data node. A complete instance-identifier is\n required for this type of path value.\n\n The special value '/' refers to all possible\n datastore contents.",
"type": {
"base": "string",
"derived": "node-instance-identifier"
}
},
"access-operations": {
"kind": "leaf",
"description": "Access operations associated with this rule.\n\n This leaf matches if it has the value '' or if the\n bit corresponding to the requested operation is set.",
"type": {
"base": "union"
},
"default": ""
},
"action": {
"kind": "leaf",
"mandatory": true,
"description": "The access control action associated with the\n rule. If a rule has been determined to match a\n particular request, then this object is used\n to determine whether to permit or deny the\n request.",
"type": {
"base": "enumeration",
"derived": "action-type",
"enums": [
"permit",
"deny"
]
}
},
"comment": {
"kind": "leaf",
"description": "A textual description of the access rule.",
"type": {
"base": "string"
}
}
},
"keys": [
"name"
]
}
},
"keys": [
"name"
]
}
},
"presence": false
},
...