From 8f110331d565256e591d29ca25400691d1ce8b3f Mon Sep 17 00:00:00 2001 From: Alan Yaniger Date: Thu, 12 Aug 2021 21:01:48 +0300 Subject: [PATCH] Add tests for yang patch --- test/example.sh | 234 +++++++ test/interfaces.sh | 1130 ++++++++++++++++++++++++++++++ test/test_restconf_yang_patch.sh | 338 +++++++++ test/yang-patch.sh | 396 +++++++++++ 4 files changed, 2098 insertions(+) create mode 100755 test/example.sh create mode 100755 test/interfaces.sh create mode 100755 test/test_restconf_yang_patch.sh create mode 100755 test/yang-patch.sh diff --git a/test/example.sh b/test/example.sh new file mode 100755 index 00000000..6663cae2 --- /dev/null +++ b/test/example.sh @@ -0,0 +1,234 @@ +#!/usr/bin/env bash +# clixon example +# Assumes fexample is set to name of yang file + +cat < $fexample +module clixon-example { + yang-version 1.1; + namespace "urn:example:clixon"; + prefix ex; + import ietf-interfaces { + /* is in yang/optional which means clixon must be installed using --opt-yang-installdir */ + prefix if; + } + import ietf-ip { + prefix ip; + } + import iana-if-type { + prefix ianaift; + } + import ietf-datastores { + prefix ds; + } + description + "Clixon example used as a part of the Clixon test suite. + It can be used as a basis for making new Clixon applications. + Note, may change without updating revision, just for testing current master. + "; + revision 2020-12-01 { + description "Added table/paramater/value as the primary data example"; + } + revision 2020-03-11 { + description "Added container around translation list. Released in Clixon 4.4.0"; + } + revision 2019-11-05 { + description "Augment interface. Released in Clixon 4.3.0"; + } + revision 2019-07-23 { + description "Extension e4. Released in Clixon 4.1.0"; + } + revision 2019-01-13 { + description "Released in Clixon 3.9"; + } + /* Example interface type for tests, local callbacks, etc */ + identity eth { + base if:interface-type; + } + identity loopback { + base if:interface-type; + } + /* Generic config data */ + container table{ + list parameter{ + key name; + leaf name{ + type string; + } + leaf value{ + type string; + } + leaf stat{ + description "Inline state data for example application"; + config false; + type int32; + } + } + } + /* State data (not config) for the example application*/ + container state { + config false; + description "state data for the example application (must be here for example get operation)"; + leaf-list op { + type string; + } + } + augment "/if:interfaces/if:interface" { + container my-status { + config false; + description "For testing augment+state"; + leaf int { + type int32; + } + leaf str { + type string; + } + } + } + /* yang extension implemented by the example backend code. */ + extension e4 { + description + "The first child of the ex:e4 (unknown) statement is inserted into + the module as a regular data statement. This means that 'uses bar;' + in the ex:e4 statement below is a valid data node"; + argument arg; + } + grouping bar { + leaf bar{ + type string; + } + } + ex:e4 arg1{ + uses bar; + } + /* Example notification as used in RFC 5277 and RFC 8040 */ + notification event { + description "Example notification event."; + leaf event-class { + type string; + description "Event class identifier."; + } + container reportingEntity { + description "Event specific information."; + leaf card { + type string; + description "Line card identifier."; + } + } + leaf severity { + type string; + description "Event severity description."; + } + } + rpc client-rpc { + description "Example local client-side RPC that is processed by the + the netconf/restconf and not sent to the backend. + This is a clixon implementation detail: some rpc:s + are better processed by the client for API or perf reasons"; + input { + leaf x { + type string; + } + } + output { + leaf x { + type string; + } + } + } + rpc empty { + description "Smallest possible RPC with no input or output sections"; + } + rpc optional { + description "Small RPC with optional input and output"; + input { + leaf x { + type string; + } + } + output { + leaf x { + type string; + } + } + } + rpc example { + description "Some example input/output for testing RFC7950 7.14. + RPC simply echoes the input for debugging."; + input { + leaf x { + description + "If a leaf in the input tree has a 'mandatory' statement with + the value 'true', the leaf MUST be present in an RPC invocation."; + type string; + mandatory true; + } + leaf y { + description + "If a leaf in the input tree has a 'mandatory' statement with the + value 'true', the leaf MUST be present in an RPC invocation."; + type string; + default "42"; + } + leaf-list z { + description + "If a leaf-list in the input tree has one or more default + values, the server MUST use these values (XXX not supported)"; + type string; + } + leaf w { + description + "If any node has a 'when' statement that would evaluate to + 'false',then this node MUST NOT be present in the input tree. + (XXX not supported)"; + type string; + } + list u0 { + description "list without key"; + leaf uk{ + type string; + } + } + list u1 { + description "list with key"; + key uk; + leaf uk{ + type string; + } + leaf val{ + type string; + } + } + } + output { + leaf x { + type string; + } + leaf y { + type string; + } + leaf z { + type string; + } + leaf w { + type string; + } + list u0 { + leaf uk{ + type string; + } + } + list u1 { + key uk; + leaf uk{ + type string; + } + leaf val{ + type string; + } + } + } + } +} +EOF2 + + diff --git a/test/interfaces.sh b/test/interfaces.sh new file mode 100755 index 00000000..107e2b99 --- /dev/null +++ b/test/interfaces.sh @@ -0,0 +1,1130 @@ +#!/usr/bin/env bash +# for rfc 8072 +# Assumes finterfaces is set to name of interfaces file + +cat < $finterfaces + +module ietf-interfaces { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-interfaces"; + prefix if; + + import ietf-yang-types { + prefix yang; + } + + organization + "IETF NETMOD (Network Modeling) Working Group"; + + contact + "WG Web: + WG List: + + Editor: Martin Bjorklund + "; + + description + "This module contains a collection of YANG definitions for + managing network interfaces. + + Copyright (c) 2018 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (https://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 8343; see + the RFC itself for full legal notices."; + + revision 2018-02-20 { + description + "Updated to support NMDA."; + reference + "RFC 8343: A YANG Data Model for Interface Management"; + } + + revision 2014-05-08 { + description + "Initial revision."; + reference + "RFC 7223: A YANG Data Model for Interface Management"; + } + + /* + * Typedefs + */ + + typedef interface-ref { + type leafref { + path "/if:interfaces/if:interface/if:name"; + } + description + "This type is used by data models that need to reference + interfaces."; + } + + /* + * Identities + */ + + identity interface-type { + description + "Base identity from which specific interface types are + derived."; + } + + /* + * Features + */ + + feature arbitrary-names { + description + "This feature indicates that the device allows user-controlled + interfaces to be named arbitrarily."; + } + feature pre-provisioning { + description + "This feature indicates that the device supports + pre-provisioning of interface configuration, i.e., it is + possible to configure an interface whose physical interface + hardware is not present on the device."; + } + feature if-mib { + description + "This feature indicates that the device implements + the IF-MIB."; + reference + "RFC 2863: The Interfaces Group MIB"; + } + + /* + * Data nodes + */ + + container interfaces { + description + "Interface parameters."; + + list interface { + key "name"; + + description + "The list of interfaces on the device. + + The status of an interface is available in this list in the + operational state. If the configuration of a + system-controlled interface cannot be used by the system + (e.g., the interface hardware present does not match the + interface type), then the configuration is not applied to + the system-controlled interface shown in the operational + state. If the configuration of a user-controlled interface + cannot be used by the system, the configured interface is + not instantiated in the operational state. + + System-controlled interfaces created by the system are + always present in this list in the operational state, + whether or not they are configured."; + + leaf name { + type string; + description + "The name of the interface. + + A device MAY restrict the allowed values for this leaf, + possibly depending on the type of the interface. + For system-controlled interfaces, this leaf is the + device-specific name of the interface. + + If a client tries to create configuration for a + system-controlled interface that is not present in the + operational state, the server MAY reject the request if + the implementation does not support pre-provisioning of + interfaces or if the name refers to an interface that can + never exist in the system. A Network Configuration + Protocol (NETCONF) server MUST reply with an rpc-error + with the error-tag 'invalid-value' in this case. + + If the device supports pre-provisioning of interface + configuration, the 'pre-provisioning' feature is + advertised. + + If the device allows arbitrarily named user-controlled + interfaces, the 'arbitrary-names' feature is advertised. + + When a configured user-controlled interface is created by + the system, it is instantiated with the same name in the + operational state. + + A server implementation MAY map this leaf to the ifName + MIB object. Such an implementation needs to use some + mechanism to handle the differences in size and characters + allowed between this leaf and ifName. The definition of + such a mechanism is outside the scope of this document."; + reference + "RFC 2863: The Interfaces Group MIB - ifName"; + } + + leaf description { + type string; + description + "A textual description of the interface. + + A server implementation MAY map this leaf to the ifAlias + MIB object. Such an implementation needs to use some + mechanism to handle the differences in size and characters + allowed between this leaf and ifAlias. The definition of + such a mechanism is outside the scope of this document. + + Since ifAlias is defined to be stored in non-volatile + storage, the MIB implementation MUST map ifAlias to the + value of 'description' in the persistently stored + configuration."; + reference + "RFC 2863: The Interfaces Group MIB - ifAlias"; + } + + leaf type { + type identityref { + base interface-type; + } + mandatory true; + description + "The type of the interface. + + When an interface entry is created, a server MAY + initialize the type leaf with a valid value, e.g., if it + is possible to derive the type from the name of the + interface. + + If a client tries to set the type of an interface to a + value that can never be used by the system, e.g., if the + type is not supported or if the type does not match the + name of the interface, the server MUST reject the request. + A NETCONF server MUST reply with an rpc-error with the + error-tag 'invalid-value' in this case."; + reference + "RFC 2863: The Interfaces Group MIB - ifType"; + } + + leaf enabled { + type boolean; + default "true"; + description + "This leaf contains the configured, desired state of the + interface. + + Systems that implement the IF-MIB use the value of this + leaf in the intended configuration to set + IF-MIB.ifAdminStatus to 'up' or 'down' after an ifEntry + has been initialized, as described in RFC 2863. + + Changes in this leaf in the intended configuration are + reflected in ifAdminStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; + } + + leaf link-up-down-trap-enable { + if-feature if-mib; + type enumeration { + enum enabled { + value 1; + description + "The device will generate linkUp/linkDown SNMP + notifications for this interface."; + } + enum disabled { + value 2; + description + "The device will not generate linkUp/linkDown SNMP + notifications for this interface."; + } + } + description + "Controls whether linkUp/linkDown SNMP notifications + should be generated for this interface. + + If this node is not configured, the value 'enabled' is + operationally used by the server for interfaces that do + not operate on top of any other interface (i.e., there are + no 'lower-layer-if' entries), and 'disabled' otherwise."; + reference + "RFC 2863: The Interfaces Group MIB - + ifLinkUpDownTrapEnable"; + } + + leaf admin-status { + if-feature if-mib; + type enumeration { + enum up { + value 1; + description + "Ready to pass packets."; + } + enum down { + value 2; + description + "Not ready to pass packets and not in some test mode."; + } + enum testing { + value 3; + description + "In some test mode."; + } + } + config false; + mandatory true; + description + "The desired state of the interface. + + This leaf has the same read semantics as ifAdminStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; + } + + leaf oper-status { + type enumeration { + enum up { + value 1; + description + "Ready to pass packets."; + } + enum down { + value 2; + + description + "The interface does not pass any packets."; + } + enum testing { + value 3; + description + "In some test mode. No operational packets can + be passed."; + } + enum unknown { + value 4; + description + "Status cannot be determined for some reason."; + } + enum dormant { + value 5; + description + "Waiting for some external event."; + } + enum not-present { + value 6; + description + "Some component (typically hardware) is missing."; + } + enum lower-layer-down { + value 7; + description + "Down due to state of lower-layer interface(s)."; + } + } + config false; + mandatory true; + description + "The current operational state of the interface. + + This leaf has the same semantics as ifOperStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifOperStatus"; + } + + leaf last-change { + type yang:date-and-time; + config false; + description + "The time the interface entered its current operational + state. If the current state was entered prior to the + last re-initialization of the local network management + subsystem, then this node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - ifLastChange"; + } + + leaf if-index { + if-feature if-mib; + type int32 { + range "1..2147483647"; + } + config false; + mandatory true; + description + "The ifIndex value for the ifEntry represented by this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifIndex"; + } + + leaf phys-address { + type yang:phys-address; + config false; + description + "The interface's address at its protocol sub-layer. For + example, for an 802.x interface, this object normally + contains a Media Access Control (MAC) address. The + interface's media-specific modules must define the bit + and byte ordering and the format of the value of this + object. For interfaces that do not have such an address + (e.g., a serial line), this node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - ifPhysAddress"; + } + + leaf-list higher-layer-if { + type interface-ref; + config false; + description + "A list of references to interfaces layered on top of this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifStackTable"; + } + + leaf-list lower-layer-if { + type interface-ref; + config false; + + description + "A list of references to interfaces layered underneath this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifStackTable"; + } + + leaf speed { + type yang:gauge64; + units "bits/second"; + config false; + description + "An estimate of the interface's current bandwidth in bits + per second. For interfaces that do not vary in + bandwidth or for those where no accurate estimation can + be made, this node should contain the nominal bandwidth. + For interfaces that have no concept of bandwidth, this + node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - + ifSpeed, ifHighSpeed"; + } + + container statistics { + config false; + description + "A collection of interface-related statistics objects."; + + leaf discontinuity-time { + type yang:date-and-time; + mandatory true; + description + "The time on the most recent occasion at which any one or + more of this interface's counters suffered a + discontinuity. If no such discontinuities have occurred + since the last re-initialization of the local management + subsystem, then this node contains the time the local + management subsystem re-initialized itself."; + } + + leaf in-octets { + type yang:counter64; + description + "The total number of octets received on the interface, + including framing characters. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCInOctets"; + } + + leaf in-unicast-pkts { + type yang:counter64; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were not addressed to a + multicast or broadcast address at this sub-layer. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts"; + } + + leaf in-broadcast-pkts { + type yang:counter64; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were addressed to a broadcast + address at this sub-layer. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCInBroadcastPkts"; + } + + leaf in-multicast-pkts { + type yang:counter64; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were addressed to a multicast + address at this sub-layer. For a MAC-layer protocol, + this includes both Group and Functional addresses. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCInMulticastPkts"; + } + + leaf in-discards { + type yang:counter32; + description + "The number of inbound packets that were chosen to be + discarded even though no errors had been detected to + prevent their being deliverable to a higher-layer + protocol. One possible reason for discarding such a + packet could be to free up buffer space. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInDiscards"; + } + + leaf in-errors { + type yang:counter32; + description + "For packet-oriented interfaces, the number of inbound + packets that contained errors preventing them from being + deliverable to a higher-layer protocol. For character- + oriented or fixed-length interfaces, the number of + inbound transmission units that contained errors + preventing them from being deliverable to a higher-layer + protocol. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInErrors"; + } + + leaf in-unknown-protos { + type yang:counter32; + + description + "For packet-oriented interfaces, the number of packets + received via the interface that were discarded because + of an unknown or unsupported protocol. For + character-oriented or fixed-length interfaces that + support protocol multiplexing, the number of + transmission units received via the interface that were + discarded because of an unknown or unsupported protocol. + For any interface that does not support protocol + multiplexing, this counter is not present. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos"; + } + + leaf out-octets { + type yang:counter64; + description + "The total number of octets transmitted out of the + interface, including framing characters. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCOutOctets"; + } + + leaf out-unicast-pkts { + type yang:counter64; + description + "The total number of packets that higher-level protocols + requested be transmitted and that were not addressed + to a multicast or broadcast address at this sub-layer, + including those that were discarded or not sent. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts"; + } + + leaf out-broadcast-pkts { + type yang:counter64; + description + "The total number of packets that higher-level protocols + requested be transmitted and that were addressed to a + broadcast address at this sub-layer, including those + that were discarded or not sent. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCOutBroadcastPkts"; + } + + leaf out-multicast-pkts { + type yang:counter64; + description + "The total number of packets that higher-level protocols + requested be transmitted and that were addressed to a + multicast address at this sub-layer, including those + that were discarded or not sent. For a MAC-layer + protocol, this includes both Group and Functional + addresses. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCOutMulticastPkts"; + } + + leaf out-discards { + type yang:counter32; + description + "The number of outbound packets that were chosen to be + discarded even though no errors had been detected to + prevent their being transmitted. One possible reason + for discarding such a packet could be to free up buffer + space. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifOutDiscards"; + } + + leaf out-errors { + type yang:counter32; + description + "For packet-oriented interfaces, the number of outbound + packets that could not be transmitted because of errors. + For character-oriented or fixed-length interfaces, the + number of outbound transmission units that could not be + transmitted because of errors. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifOutErrors"; + } + } + + } + } + + /* + * Legacy typedefs + */ + + typedef interface-state-ref { + type leafref { + path "/if:interfaces-state/if:interface/if:name"; + } + status deprecated; + description + "This type is used by data models that need to reference + the operationally present interfaces."; + } + + /* + * Legacy operational state data nodes + */ + + container interfaces-state { + config false; + status deprecated; + description + "Data nodes for the operational state of interfaces."; + + list interface { + key "name"; + status deprecated; + + description + "The list of interfaces on the device. + + System-controlled interfaces created by the system are + always present in this list, whether or not they are + configured."; + + leaf name { + type string; + status deprecated; + description + "The name of the interface. + + A server implementation MAY map this leaf to the ifName + MIB object. Such an implementation needs to use some + mechanism to handle the differences in size and characters + allowed between this leaf and ifName. The definition of + such a mechanism is outside the scope of this document."; + reference + "RFC 2863: The Interfaces Group MIB - ifName"; + } + + leaf type { + type identityref { + base interface-type; + } + mandatory true; + status deprecated; + description + "The type of the interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifType"; + } + + leaf admin-status { + if-feature if-mib; + type enumeration { + enum up { + value 1; + description + "Ready to pass packets."; + } + enum down { + value 2; + description + "Not ready to pass packets and not in some test mode."; + } + enum testing { + value 3; + description + "In some test mode."; + } + } + mandatory true; + status deprecated; + description + "The desired state of the interface. + + This leaf has the same read semantics as ifAdminStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifAdminStatus"; + } + + leaf oper-status { + type enumeration { + enum up { + value 1; + description + "Ready to pass packets."; + } + enum down { + value 2; + description + "The interface does not pass any packets."; + } + enum testing { + value 3; + description + "In some test mode. No operational packets can + be passed."; + } + enum unknown { + value 4; + description + "Status cannot be determined for some reason."; + } + enum dormant { + value 5; + description + "Waiting for some external event."; + } + enum not-present { + value 6; + description + "Some component (typically hardware) is missing."; + } + enum lower-layer-down { + value 7; + description + "Down due to state of lower-layer interface(s)."; + } + } + mandatory true; + status deprecated; + description + "The current operational state of the interface. + + This leaf has the same semantics as ifOperStatus."; + reference + "RFC 2863: The Interfaces Group MIB - ifOperStatus"; + } + + leaf last-change { + type yang:date-and-time; + status deprecated; + description + "The time the interface entered its current operational + state. If the current state was entered prior to the + last re-initialization of the local network management + subsystem, then this node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - ifLastChange"; + } + + leaf if-index { + if-feature if-mib; + type int32 { + range "1..2147483647"; + } + mandatory true; + status deprecated; + description + "The ifIndex value for the ifEntry represented by this + interface."; + + reference + "RFC 2863: The Interfaces Group MIB - ifIndex"; + } + + leaf phys-address { + type yang:phys-address; + status deprecated; + description + "The interface's address at its protocol sub-layer. For + example, for an 802.x interface, this object normally + contains a Media Access Control (MAC) address. The + interface's media-specific modules must define the bit + and byte ordering and the format of the value of this + object. For interfaces that do not have such an address + (e.g., a serial line), this node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - ifPhysAddress"; + } + + leaf-list higher-layer-if { + type interface-state-ref; + status deprecated; + description + "A list of references to interfaces layered on top of this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifStackTable"; + } + + leaf-list lower-layer-if { + type interface-state-ref; + status deprecated; + description + "A list of references to interfaces layered underneath this + interface."; + reference + "RFC 2863: The Interfaces Group MIB - ifStackTable"; + } + + leaf speed { + type yang:gauge64; + units "bits/second"; + status deprecated; + description + "An estimate of the interface's current bandwidth in bits + per second. For interfaces that do not vary in + bandwidth or for those where no accurate estimation can + + be made, this node should contain the nominal bandwidth. + For interfaces that have no concept of bandwidth, this + node is not present."; + reference + "RFC 2863: The Interfaces Group MIB - + ifSpeed, ifHighSpeed"; + } + + container statistics { + status deprecated; + description + "A collection of interface-related statistics objects."; + + leaf discontinuity-time { + type yang:date-and-time; + mandatory true; + status deprecated; + description + "The time on the most recent occasion at which any one or + more of this interface's counters suffered a + discontinuity. If no such discontinuities have occurred + since the last re-initialization of the local management + subsystem, then this node contains the time the local + management subsystem re-initialized itself."; + } + + leaf in-octets { + type yang:counter64; + status deprecated; + description + "The total number of octets received on the interface, + including framing characters. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCInOctets"; + } + + leaf in-unicast-pkts { + type yang:counter64; + status deprecated; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were not addressed to a + multicast or broadcast address at this sub-layer. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCInUcastPkts"; + } + + leaf in-broadcast-pkts { + type yang:counter64; + status deprecated; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were addressed to a broadcast + address at this sub-layer. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCInBroadcastPkts"; + } + + leaf in-multicast-pkts { + type yang:counter64; + status deprecated; + description + "The number of packets, delivered by this sub-layer to a + higher (sub-)layer, that were addressed to a multicast + address at this sub-layer. For a MAC-layer protocol, + this includes both Group and Functional addresses. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCInMulticastPkts"; + } + + leaf in-discards { + type yang:counter32; + status deprecated; + + description + "The number of inbound packets that were chosen to be + discarded even though no errors had been detected to + prevent their being deliverable to a higher-layer + protocol. One possible reason for discarding such a + packet could be to free up buffer space. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInDiscards"; + } + + leaf in-errors { + type yang:counter32; + status deprecated; + description + "For packet-oriented interfaces, the number of inbound + packets that contained errors preventing them from being + deliverable to a higher-layer protocol. For character- + oriented or fixed-length interfaces, the number of + inbound transmission units that contained errors + preventing them from being deliverable to a higher-layer + protocol. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInErrors"; + } + + leaf in-unknown-protos { + type yang:counter32; + status deprecated; + description + "For packet-oriented interfaces, the number of packets + received via the interface that were discarded because + of an unknown or unsupported protocol. For + character-oriented or fixed-length interfaces that + support protocol multiplexing, the number of + transmission units received via the interface that were + discarded because of an unknown or unsupported protocol. + For any interface that does not support protocol + multiplexing, this counter is not present. + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifInUnknownProtos"; + } + + leaf out-octets { + type yang:counter64; + status deprecated; + description + "The total number of octets transmitted out of the + interface, including framing characters. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCOutOctets"; + } + + leaf out-unicast-pkts { + type yang:counter64; + status deprecated; + description + "The total number of packets that higher-level protocols + requested be transmitted and that were not addressed + to a multicast or broadcast address at this sub-layer, + including those that were discarded or not sent. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifHCOutUcastPkts"; + } + + leaf out-broadcast-pkts { + type yang:counter64; + status deprecated; + + description + "The total number of packets that higher-level protocols + requested be transmitted and that were addressed to a + broadcast address at this sub-layer, including those + that were discarded or not sent. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCOutBroadcastPkts"; + } + + leaf out-multicast-pkts { + type yang:counter64; + status deprecated; + description + "The total number of packets that higher-level protocols + requested be transmitted and that were addressed to a + multicast address at this sub-layer, including those + that were discarded or not sent. For a MAC-layer + protocol, this includes both Group and Functional + addresses. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - + ifHCOutMulticastPkts"; + } + + leaf out-discards { + type yang:counter32; + status deprecated; + description + "The number of outbound packets that were chosen to be + discarded even though no errors had been detected to + prevent their being transmitted. One possible reason + for discarding such a packet could be to free up buffer + space. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifOutDiscards"; + } + + leaf out-errors { + type yang:counter32; + status deprecated; + description + "For packet-oriented interfaces, the number of outbound + packets that could not be transmitted because of errors. + For character-oriented or fixed-length interfaces, the + number of outbound transmission units that could not be + transmitted because of errors. + + Discontinuities in the value of this counter can occur + at re-initialization of the management system and at + other times as indicated by the value of + 'discontinuity-time'."; + reference + "RFC 2863: The Interfaces Group MIB - ifOutErrors"; + } + } + } + } +} +EOF2 diff --git a/test/test_restconf_yang_patch.sh b/test/test_restconf_yang_patch.sh new file mode 100755 index 00000000..4253a4df --- /dev/null +++ b/test/test_restconf_yang_patch.sh @@ -0,0 +1,338 @@ +#!/usr/bin/env bash +# Restconf RFC8072 yang patch +# XXX enable YANG_PACTH in include/clixon_custom.h to run this test +# Use nacm module in example/main/example_restconf.c hardcoded to +# andy:bar and wilma:bar + +# Magic line must be first in script (see README.md) +s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi + +#echo "...skipped: YANG_PATCH NYI" +#if [ "$s" = $0 ]; then exit 0; else return 0; fi + +APPNAME=example + +cfg=$dir/conf.xml +startupdb=$dir/startup_db +fjukebox=$dir/example-jukebox.yang +fyangpatch=$dir/ietf-yang-patch.yang +finterfaces=$dir/ietf-interfaces.yang +fexample=$dir/clixon-example.yang + +# Define default restconfig config: RESTCONFIG +RESTCONFIG=$(restconf_config user false) + +cat < $cfg + + $cfg + /usr/local/share/clixon + $IETFRFC + $dir + /usr/local/var/$APPNAME/$APPNAME.sock + ietf-netconf:startup + /usr/local/lib/$APPNAME/restconf + $dir/restconf.pidfile + $dir + internal + true + $RESTCONFIG + +EOF + +NACM0=" + true + deny + deny + permit + + + admin + andy + + + limited + wilma + + + + admin + admin + + permit-all + * + * + permit + + Allow the 'admin' group complete access to all operations and data. + + + + + limited + limited + + limit-jukebox + jukebox-example + read create delete + deny + + + +" + +cat< $startupdb +<${DATASTORE_TOP}> + $NACM0 + +EOF + +# An extra testmodule that includes nacm +cat < $dir/example-system.yang + module example-system { + namespace "http://example.com/ns/example-system"; + prefix "ex"; + import ietf-netconf-acm { + prefix nacm; + } + container system { + leaf enable-jukebox-streaming { + type boolean; + } + leaf extraleaf { + type string; + } + } + } +EOF + +# Yang Patch spec (fyangpatch must be set) +. ./yang-patch.sh + +# Interfaces spec (finterfaces must be set) +. ./interfaces.sh + +# clixon example spec (fexample must be set) +. ./example.sh + +# Common Jukebox spec (fjukebox must be set) +. ./jukebox.sh + +new "test params: -s startup -f $cfg" +if [ $BE -ne 0 ]; then + new "kill old backend" + sudo clixon_backend -zf $cfg + if [ $? -ne 0 ]; then + err + fi + sudo pkill -f clixon_backend # to be sure + + new "start backend -s startup -f $cfg" + start_backend -s startup -f $cfg +fi + +new "wait backend" +wait_backend + +if [ $RC -ne 0 ]; then + new "kill old restconf daemon" + stop_restconf_pre + + new "start restconf daemon" + start_restconf -f $cfg +fi + +new "wait restconf" +wait_restconf + +# Modify several interfaces with a YANG patch, testing create, merge, and delete +REQ='{ + "ietf-yang-patch:yang-patch": { + "patch-id": "alan-test-patch", + "edit": [ + { + "edit-id": "edit-1", + "operation": "create", + "target": "/interface=eth1", + "value": { + "interface": [ + { + "name": "eth1", + "type": "clixon-example:eth", + "enabled": "false" + } + ] + } + }, + { + "edit-id": "edit-2", + "operation": "create", + "target": "/interface=eth2", + "value": { + "interface": [ + { + "name": "eth2", + "type": "clixon-example:eth", + "enabled": "false" + } + ] + } + }, + { + "edit-id": "edit-3", + "operation": "create", + "target": "/interface=eth4", + "value": { + "interface": [ + { + "name": "eth4", + "type": "clixon-example:eth", + "enabled": "false" + } + ] + } + }, + { + "edit-id": "edit-4", + "operation": "merge", + "target": "/interface=eth2", + "value": { + "interface": [ + { + "enabled": "true" + } + ] + } + }, + { + "edit-id": "edit-5", + "operation": "delete", + "target": "/interface=eth1" + } + ] + } +}' +new "RFC 8072 YANG Patch: Error." +expectpart "$(curl -u andy:bar $CURLOPTS -X PATCH -H 'Content-Type: application/yang-patch+json' -H 'Accept: application/yang-patch+json' $RCPROTO://localhost/restconf/data/ietf-interfaces:interfaces -d "$REQ")" 0 "HTTP/$HVER 204 No Content" +# +# Create artist in jukebox example +REQ='{"example-jukebox:artist":[{"name":"Foo Fighters"}]}' +new "RFC 8072 YANG Patch jukebox example 1: Error." +expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library -d "$REQ")" 0 "HTTP/$HVER 201 Created" + +# Create album in jukebox example +REQ='Wasting Light2011' +new "RFC 8072 YANG Patch jukebox example 2: Error." +expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+xml' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters -d "$REQ")" 0 "HTTP/$HVER 201 Created" + +# Add fields to album in jukebox example +REQ='{"example-jukebox:album":[{"name":"Wasting Light","genre":"example-jukebox:alternative","year":2011}]}' +new "RFC 8072 YANG Patch jukebox example 3: Error." +expectpart "$(curl -u andy:bar $CURLOPTS -X PUT -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library/artist=Foo%20Fighters/album=Wasting%20Light -d "$REQ")" 0 "HTTP/$HVER 204 No Content" + +# Uncomment to get info about album in jukebox example +#new "RFC 8072 YANG Patch jukebox example get 2: Error." +#expectpart "$(curl -u andy:bar $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/library)" 0 "HTTP/$HVER 201 OK" + +# Add songs to playlist in jukebox example +REQ="{\"example-jukebox:song\":[{\"index\":1,\"id\":\"/example-jukebox:jukebox/library/artist[name='Foo Fighters']/album[name='Wasting Light']/song[name='Rope']\"}]}" +new "RFC 8072 YANG Patch jukebox example 4: Error." +expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=first -d "$REQ")" 0 "HTTP/$HVER 201 Created" + +# Add song at end of playlist +REQ="{\"example-jukebox:song\":[{\"index\":2,\"id\":\"/example-jukebox:jukebox/library/artist[name='Foo Fighters']/album[name='Wasting Light']/song[name='Bridge Burning']\"}]}" +new "RFC 8072 YANG Patch jukebox example 5: Error." +expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=last -d "$REQ")" 0 "HTTP/$HVER 201 Created" + +# Add song at end of playlist +REQ="{\"example-jukebox:song\":[{\"index\":4,\"id\":\"/example-jukebox:jukebox/library/artist[name='Foo Fighters']/album[name='Wasting Light']/song[name='Still More Rope']\"}]}" +new "RFC 8072 YANG Patch jukebox example 6: Error." +expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=last -d "$REQ")" 0 "HTTP/$HVER 201 Created" + +# Add song at end of playlist +REQ="{\"example-jukebox:song\":[{\"index\":3,\"id\":\"/example-jukebox:jukebox/library/artist[name='Foo Fighters']/album[name='Wasting Light']/song[name='More Rope']\"}]}" +new "RFC 8072 YANG Patch jukebox example 7: Error." +expectpart "$(curl -u andy:bar $CURLOPTS -X POST -H 'Content-Type: application/yang-data+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One?insert=last -d "$REQ")" 0 "HTTP/$HVER 201 Created" + +# Run YANG patch on the playlist, testing "insert after" and "insert before" +REQ='{ + "ietf-yang-patch:yang-patch": { + "patch-id": "alan-test-patch-jukebox", + "edit": [ + { + "edit-id": "edit-2", + "operation": "insert", + "target": "/song=5", + "point": "/song=1", + "where" : "after", + "value": { + "example-jukebox:song": [ + { + "index": 5, + "id" : "Rope Galore" + } + ] + } + }, + { + "edit-id": "edit-3", + "operation": "insert", + "target": "/song=6", + "point": "/song=4", + "where" : "before", + "value": { + "example-jukebox:song": [ + { + "index": 6, + "id" : "How Much Rope Does a Man Need" + } + ] + } + }, + { + "edit-id": "edit-2", + "operation": "insert", + "target": "/song=24", + "point": "/song=6", + "where" : "after", + "value": { + "example-jukebox:song": [ + { + "index": 24, + "id" : "The twenty fourth song" + } + ] + } + } + ] + } +}' +new "RFC 8072 YANG Patch jukebox example: Error." +expectpart "$(curl -u andy:bar $CURLOPTS -X PATCH -H 'Content-Type: application/yang-patch+json' -H 'Accept: application/yang-patch+json' $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One -d "$REQ")" 0 "HTTP/$HVER 201 Created" + +# Uncomment to get info about playlist in jukebox example +#new "RFC 8072 YANG Patch jukebox example get : Error." +#expectpart "$(curl -u andy:bar $CURLOPTS -X GET $RCPROTO://localhost/restconf/data/example-jukebox:jukebox/playlist=Foo-One)" 0 "HTTP/$HVER 201 OK" + +if [ $RC -ne 0 ]; then + new "Kill restconf daemon" + stop_restconf +fi + +if [ $BE -ne 0 ]; then + new "Kill backend" + # Check if premature kill + pid=$(pgrep -u root -f clixon_backend) + if [ -z "$pid" ]; then + err "backend already dead" + fi + # kill backend + stop_backend -f $cfg +fi + +# Set by restconf_config +unset RESTCONFIG + +rm -rf $dir + +new "endtest" +endtest diff --git a/test/yang-patch.sh b/test/yang-patch.sh new file mode 100755 index 00000000..1d718725 --- /dev/null +++ b/test/yang-patch.sh @@ -0,0 +1,396 @@ +#!/usr/bin/env bash +# for rfc 8072 +# Assumes fyangpatch is set to name of yang file + +cat < $fyangpatch + module ietf-yang-patch { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:ietf-yang-patch"; + prefix "ypatch"; + + import ietf-restconf { prefix rc; } + + organization + "IETF NETCONF (Network Configuration) Working Group"; + + contact + "WG Web: + WG List: + + Author: Andy Bierman + + + Author: Martin Bjorklund + + + Author: Kent Watsen + "; + + description + "This module contains conceptual YANG specifications + for the YANG Patch and YANG Patch Status data structures. + + Note that the YANG definitions within this module do not + represent configuration data of any kind. + The YANG grouping statements provide a normative syntax + for XML and JSON message-encoding purposes. + + Copyright (c) 2017 IETF Trust and the persons identified as + authors of the code. All rights reserved. + + Redistribution and use in source and binary forms, with or + without modification, is permitted pursuant to, and subject + to the license terms contained in, the Simplified BSD License + set forth in Section 4.c of the IETF Trust's Legal Provisions + Relating to IETF Documents + (http://trustee.ietf.org/license-info). + + This version of this YANG module is part of RFC 8072; see + the RFC itself for full legal notices."; + + revision 2017-02-22 { + description + "Initial revision."; + reference + "RFC 8072: YANG Patch Media Type."; + } + + typedef target-resource-offset { + type string; + description + "Contains a data resource identifier string representing + a sub-resource within the target resource. + The document root for this expression is the + target resource that is specified in the + protocol operation (e.g., the URI for the PATCH request). + + This string is encoded according to the same rules as those + for a data resource identifier in a RESTCONF request URI."; + reference + "RFC 8040, Section 3.5.3."; + } + + rc:yang-data "yang-patch" { + uses yang-patch; + } + + rc:yang-data "yang-patch-status" { + uses yang-patch-status; + } + + grouping yang-patch { + + description + "A grouping that contains a YANG container representing the + syntax and semantics of a YANG Patch edit request message."; + + container yang-patch { + description + "Represents a conceptual sequence of datastore edits, + called a patch. Each patch is given a client-assigned + patch identifier. Each edit MUST be applied + in ascending order, and all edits MUST be applied. + If any errors occur, then the target datastore MUST NOT + be changed by the YANG Patch operation. + + It is possible for a datastore constraint violation to occur + due to any node in the datastore, including nodes not + included in the 'edit' list. Any validation errors MUST + be reported in the reply message."; + + reference + "RFC 7950, Section 8.3."; + + leaf patch-id { + type string; + mandatory true; + description + "An arbitrary string provided by the client to identify + the entire patch. Error messages returned by the server + that pertain to this patch will be identified by this + 'patch-id' value. A client SHOULD attempt to generate + unique 'patch-id' values to distinguish between + transactions from multiple clients in any audit logs + maintained by the server."; + } + + leaf comment { + type string; + description + "An arbitrary string provided by the client to describe + the entire patch. This value SHOULD be present in any + audit logging records generated by the server for the + patch."; + } + + list edit { + key edit-id; + ordered-by user; + + description + "Represents one edit within the YANG Patch request message. + The 'edit' list is applied in the following manner: + + - The first edit is conceptually applied to a copy + of the existing target datastore, e.g., the + running configuration datastore. + - Each ascending edit is conceptually applied to + the result of the previous edit(s). + - After all edits have been successfully processed, + the result is validated according to YANG constraints. + - If successful, the server will attempt to apply + the result to the target datastore."; + + leaf edit-id { + type string; + description + "Arbitrary string index for the edit. + Error messages returned by the server that pertain + to a specific edit will be identified by this value."; + } + + leaf operation { + type enumeration { + enum create { + description + "The target data node is created using the supplied + value, only if it does not already exist. The + 'target' leaf identifies the data node to be + created, not the parent data node."; + } + enum delete { + description + "Delete the target node, only if the data resource + currently exists; otherwise, return an error."; + } + + enum insert { + description + "Insert the supplied value into a user-ordered + list or leaf-list entry. The target node must + represent a new data resource. If the 'where' + parameter is set to 'before' or 'after', then + the 'point' parameter identifies the insertion + point for the target node."; + } + enum merge { + description + "The supplied value is merged with the target data + node."; + } + enum move { + description + "Move the target node. Reorder a user-ordered + list or leaf-list. The target node must represent + an existing data resource. If the 'where' parameter + is set to 'before' or 'after', then the 'point' + parameter identifies the insertion point to move + the target node."; + } + enum replace { + description + "The supplied value is used to replace the target + data node."; + } + enum remove { + description + "Delete the target node if it currently exists."; + } + } + mandatory true; + description + "The datastore operation requested for the associated + 'edit' entry."; + } + + leaf target { + type target-resource-offset; + mandatory true; + description + "Identifies the target data node for the edit + operation. If the target has the value '/', then + the target data node is the target resource. + The target node MUST identify a data resource, + not the datastore resource."; + } + + leaf point { + when "(../operation = 'insert' or ../operation = 'move')" + + "and (../where = 'before' or ../where = 'after')" { + description + "This leaf only applies for 'insert' or 'move' + operations, before or after an existing entry."; + } + type target-resource-offset; + description + "The absolute URL path for the data node that is being + used as the insertion point or move point for the + target of this 'edit' entry."; + } + + leaf where { + when "../operation = 'insert' or ../operation = 'move'" { + description + "This leaf only applies for 'insert' or 'move' + operations."; + } + type enumeration { + enum before { + description + "Insert or move a data node before the data resource + identified by the 'point' parameter."; + } + enum after { + description + "Insert or move a data node after the data resource + identified by the 'point' parameter."; + } + + enum first { + description + "Insert or move a data node so it becomes ordered + as the first entry."; + } + enum last { + description + "Insert or move a data node so it becomes ordered + as the last entry."; + } + } + default last; + description + "Identifies where a data resource will be inserted + or moved. YANG only allows these operations for + list and leaf-list data nodes that are + 'ordered-by user'."; + } + + anydata value { + when "../operation = 'create' " + + "or ../operation = 'merge' " + + "or ../operation = 'replace' " + + "or ../operation = 'insert'" { + description + "The anydata 'value' is only used for 'create', + 'merge', 'replace', and 'insert' operations."; + } + description + "Value used for this edit operation. The anydata 'value' + contains the target resource associated with the + 'target' leaf. + + For example, suppose the target node is a YANG container + named foo: + + container foo { + leaf a { type string; } + leaf b { type int32; } + } + + The 'value' node contains one instance of foo: + + + + some value + 42 + + + "; + } + } + } + + } // grouping yang-patch + + grouping yang-patch-status { + + description + "A grouping that contains a YANG container representing the + syntax and semantics of a YANG Patch Status response + message."; + + container yang-patch-status { + description + "A container representing the response message sent by the + server after a YANG Patch edit request message has been + processed."; + + leaf patch-id { + type string; + mandatory true; + description + "The 'patch-id' value used in the request."; + } + + choice global-status { + description + "Report global errors or complete success. + If there is no case selected, then errors + are reported in the 'edit-status' container."; + + case global-errors { + uses rc:errors; + description + "This container will be present if global errors that + are unrelated to a specific edit occurred."; + } + leaf ok { + type empty; + description + "This leaf will be present if the request succeeded + and there are no errors reported in the 'edit-status' + container."; + } + } + + container edit-status { + description + "This container will be present if there are + edit-specific status responses to report. + If all edits succeeded and the 'global-status' + returned is 'ok', then a server MAY omit this + container."; + + list edit { + key edit-id; + + description + "Represents a list of status responses, + corresponding to edits in the YANG Patch + request message. If an 'edit' entry was + skipped or not reached by the server, + then this list will not contain a corresponding + entry for that edit."; + + leaf edit-id { + type string; + description + "Response status is for the 'edit' list entry + with this 'edit-id' value."; + } + + choice edit-status-choice { + description + "A choice between different types of status + responses for each 'edit' entry."; + leaf ok { + type empty; + description + "This 'edit' entry was invoked without any + errors detected by the server associated + with this edit."; + } + case errors { + uses rc:errors; + description + "The server detected errors associated with the + edit identified by the same 'edit-id' value."; + } + } + } + } + } + } // grouping yang-patch-status + + } +EOF1