Edit Transaction Examples

Edit transactions are used to modify configuration datastores. The Database Operations section explains the callback functions that are used to implement an edit transaction. This section provides guidelines and examples for handling various editing procedures.

There are several operations that cause an edit transaction to be executed. The Database Deployment Variants section describes the different internal database deployment options. The Databases variant used on the server will determine which operations are available.

Newval, Curval and Update Parameters

The newval and curval parameters that are passed to SIL and SIL-SA callback functions can be used to implement YANG instrumentation for configuration data nodes.

The properties and usage of these parameters are explained in this section.

  • newval: edit callback input parameter

    • non-NULL: the new value that will be set if the edit succeeds.

    • NULL: no new value if the edit is a delete operation

  • curval: edit callback input parameter

    • non-NULL: the current value that will be replaced if the edit succeeds.

    • NULL: there is no current value for the node.

The advent of the EDIT3 Callback marks a significant shift in YANG instrumentation for configuration data nodes, pivoting primarily on the utilization of the update value.

The update value streamlines the update process by providing a composite Update value, that incorporates latest changes proposed by the user (newval) along with relevant current values from the datastore (curval).

  • update: a merged value of all new and current values from the datastore,

    streamlining the update process.

    • non-NULL: replace the existing data with this composite update value

    • NULL: operation is delete - Delete all data from the device

A data node can either be created by YANG default or created by a client edit operation. The edit transaction processing details for YANG defaults depend on the --default-style parameter value used on the server and the YANG data model being processed.

The following example use-cases will be examined:

  • Leaf with a Default

  • Leaf without a Default

  • Non-Presence Container with a Default

  • Non-Presence Container without a Default

  • Presence Container with a Default

  • Presence Container without a Default

The default processing is handled during an edit operation before the SIL or SIL-SA callbacks are invoked. This section contains the following examples:

  • the details for a first edit to a node by a client operation

  • the details for an edit to an existing node by a client operation

  • the details for a delete edit to an existing node by a client operation

The actual edit operations can change in different scenarios. For example, a 'delete' operation followed by a 'create' operation on the <candidate> datastore can be changed to a 'replace' operation on the <running> datastore.

Printing the Value Path String from a SIL Edit Callback

It is very common to print a debug trace when entering a SIL callback function. There is such a debug trace in the auto-generated code by yangdump-pro.

The 'val_gen_instance_id' function is used to get the string value for the path string of the object node for the callback.

status_t val_gen_instance_id(xml_msg_hdr_t *mhdr, const val_value_t *val, ncx_instfmt_t format, xmlChar **buff)

Malloc and Generate the instance ID string for this value node,.

Parameters:
  • mhdr -- [inout] message hdr w/ prefix map or NULL to just use the internal prefix mappings

    • mhdr.pmap may have entries added if prefixes used in the instance identifier which are not already in the pmap

  • val -- node to generate the instance ID for

  • format -- desired output format (NCX or Xpath)

  • buff -- [out] pointer to address of buffer to use

    • *buff malloced buffer with the instance ID

Returns:

status

The following example uses this small YANG module to show path strings for the 'test3' list node:

container test1 {
  list test2 {
     key "a b";
     leaf a { type int32; }
     leaf b { type string; }

     list test3 {
       key "c d";
       leaf c { type string; }
       leaf d { type string; }
     }
  }
}

The following code snippet shows how this function can be used.

if (LOGDEBUG) {
    log_debug("\nEnter u_tlist_test3_edit callback for %s phase",
        agt_cbtype_name(cbtyp));

    /* print the edit operation */
    log_debug_append(" op=%s", op_editop_name(editop));

    /* print the path string */
    val_value_t *useval = newval;
    if (useval == NULL) {
        useval = curval;
    }
    if (useval != NULL) {
        ncx_instfmt_t format = NCX_IFMT_XPATH2;
        xmlChar *buff = NULL;
        res = val_gen_instance_id(RPC_MHDR(msg),
                                  useval,
                                  format,
                                  &buff);
        if ((res == NO_ERR) && (buff != NULL)) {
            log_debug_append("\nPath: %s", buff);
        }
        m__free(buff);
    }
}

The following log trace shows an example list entry being created:

Enter test3_edit callback for commit phase
Enter u_tlist_test3_edit callback for commit phase op=create
Path: /tlist:test1/tlist:test2[tlist:a="100"][tlist:b="test-b"]/tlist:test3[tlist:c="test-c"][tlist:d="test-d"]

Example YANG Module: testdef2

The YANG module modules/test/pass/testdef2.yang is used as an example for default handling.

module testdef2 {
  yang-version 1.1;
  namespace "urn:yumaworks:params:xml:ns:yang:testdef2";
  prefix "tdef2";
  revision 2023-04-07;

  leaf defleaf {
    type uint32;
    default 42;
  }

  leaf nodefleaf {
    type uint32;
  }

  container npcon {
    leaf defleaf2 {
      type uint32;
      default 142;
    }
    leaf nodefleaf2 {
      type uint32;
    }
  }

  container pcon {
    presence "enabled";
    leaf defleaf3 {
      type uint32;
      default 242;
    }
    leaf nodefleaf3 {
      type uint32;
    }
  }

}

Each example shows the value and source of the newval, curval, and update parameters that are passed to the edit callback function.

Note

Update value is used only in EDIT3 Callback

A simple debug trace function was added to the edit functions:

static void dump_edit_vals (val_value_t *newval,
                            val_value_t *curval,
                            val_value_t *update)
{
    if (!LOGDEBUG) {
        return;
    }
    log_debug("\nEdit values:");
    if (newval) {
        log_debug_append("\nnewval set %s",
                         val_set_by_default(newval) ?
                         "by default" : "by client");
        val_dump_value(newval, 2, DBG);
    } else {
        log_debug_append("\nnewval NULL");
    }
    if (curval) {
        log_debug_append("\ncurval set %s",
                         val_set_by_default(curval) ?
                         "by default" : "by client");
        val_dump_value(curval, 2, DBG);
    } else {
        log_debug_append("\ncurval NULL");
    }
    if (update) {
        log_debug_append("\nupdate set %s",
                         val_set_by_default(update) ?
                         "by default" : "by client");
        val_dump_value(update, 2, DBG);
    } else {
        log_debug_append("\nupdate NULL");
    }

}  /* dump_edit_vals */

Default Nodes Created During Load Config

The server will usually create default leafs and NP containers during the system <load-config> operation. The defaults are added to an empty datastore or to a datastore with the previous contents from non-volatile storage.

A val_value_t data structure is created for both default and non-default nodes leafs:

  • The newval, curval, or update parameters could be set by default

  • Use function val_set_by_default to check if the value was added by the system

  • Use function val_is_default to check if the value is equal to the YANG default value

For this example it is assumed the initial datastore is empty. This is possible many ways, included by use of the --no-startup parameter.

  • The curval is NULL during a load since the datastore is initially empty.

  • The newval is set by default.

  • The update is the same as newval in EDIT3 callbacks.

  • The editop will be OP_EDITOP_LOAD

  • The --default-style parameter is ignored during processing.

  • The newval will be set-by-default in all 3 default styles

  • The datastore will be <running>.

In this example, there will be SIL callbacks for the 2 nodes that are created by default.

  • Leaf /defleaf = 42

    Start invoking validate SIL callback for load on testdef2:defleaf
    Enter defleaf_edit callback for validate phase
    Enter u_tdef2_defleaf_edit callback for validate phase
    Edit values:
    newval set by default
      tdef2:defleaf 42
    curval NULL
    update NULL
    Finished invoking user callback on testdef2:defleaf
    
  • Container /npcon (contains defleaf2 = 142)

    Enter npcon_edit callback for validate phase
    Enter u_tdef2_npcon_edit callback for validate phase
    Edit values:
    newval set by default
      tdef2:npcon {
        defleaf2 142
      }
    curval NULL
    update set by default
      tdef2:npcon {
        defleaf2 142
      }
    Finished invoking user callback on testdef2:defleaf
    

Edit Processing For Leafs

The callback details for a leaf are is the simplest of all YANG objects. There is only one instance possible of a leaf.

Note

Top level leafy nodes cannot have EDIT2 nor EDIT3 callbacks. In this case there will be an EDIT1 callback, thus no update value.

For non-delete operations:

  • The newval is non-NULL and is set by a client.

  • The curval is non-NULL if there is an existing value for the leaf.

  • The edit operation is a 'set' operation if the editop is one of:

    • OP_EDITOP_CREATE

    • OP_EDITOP_MERGE

    • OP_EDITOP_REPLACE

  • These operations mean the same thing for leafs and should be treated the same.

For delete operations:

  • The newval is NULL

  • The curval is set-by-default or NULL

  • The edit operation is a 'delete' operation if the editop is one of:

    • OP_EDITOP_DELETE

    • OP_EDITOP_REMOVE

  • For SIL or SIL-SA callback purposes the value of editop will always be OP_EDITOP_DELETE for any form of delete operation used by the client.

Leaf with a Default Value

  • create /defleaf value=100

    Enter u_tdef2_defleaf_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:defleaf 100
    curval set by default
      tdef2:defleaf 42
    update NULL
    Finished invoking user callback on testdef2:defleaf
    

    There is always a current value for a leaf with a YANG default, even if it is deleted.

  • replace /defleaf value=101

    Enter defleaf_edit callback for validate phase
    Enter u_tdef2_defleaf_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:defleaf 101
    curval set by client
      tdef2:defleaf 100
    update NULL
    Finished invoking user callback on testdef2:defleaf
    
  • delete /defleaf

    Enter u_tdef2_defleaf_edit callback for validate phase
    Edit values:
    newval set by default
      tdef2:defleaf 42
    curval set by client
      tdef2:defleaf 101
    update NULL
    Finished invoking user callback on testdef2:defleaf
    

Leaf Without a Default Value

  • create /nodefleaf value=200

    Enter u_tdef2_nodefleaf_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:nodefleaf 200
    curval NULL
    update NULL
    Finished invoking user callback on testdef2:nodefleaf
    
  • replace /nodefleaf value=201

    Enter u_tdef2_nodefleaf_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:nodefleaf 201
    curval set by client
      tdef2:nodefleaf 200
    update NULL
    Finished invoking user callback on testdef2:nodefleaf
    
  • delete /nodefleaf

    Enter u_tdef2_nodefleaf_edit callback for commit phase
    Edit values:
    newval NULL
    curval set by client
      tdef2:nodefleaf 201
    update NULL
    Finished invoking user callback on testdef2:nodefleaf
    

Edit Processing For Containers and Lists

There are 2 types of YANG data nodes that can have child nodes:

  • non-presence container:

    • These nodes are created automatically.

    • The --create-empty-npcontainers parameter controls this behavior during edit operations.

    • The value can either be set-by-default or set-by-client

  • presence container or list:

    • These nodes are not created automatically.

    • The value is always set-by-client

For non-delete operations:

  • The newval is non-NULL and is set by a client.

  • The curval is non-NULL if there is an existing value for the node.

  • The update is non-NULL and is a merged value of new and current values.

  • The edit operation is a 'set' operation if the editop is one of:

    • OP_EDITOP_CREATE

    • OP_EDITOP_MERGE

    • OP_EDITOP_REPLACE

  • These operations mean the same thing only if the current value is set-by-default or NULL.

For delete operations:

  • The newval is NULL

  • The curval is set-by-default or NULL

  • The update is NULL

  • The edit operation is a 'delete' operation if the editop is one of:

    • OP_EDITOP_DELETE

    • OP_EDITOP_REMOVE

  • For SIL or SIL-SA callback purposes the value of editop will always be OP_EDITOP_DELETE for any form of delete operation used by the client.

  • If the --allow-list-delete-all parameter is 'true' then the following edit operations can be in the edit request. - OP_EDITOP_DELETE_ALL - OP_EDITOP_REMOVE_ALL

    • The server will set editop to OP_EDITOP_DELETE for each individual list instance.

Non Presence Container with a Default Value

  • create /npcon (defleaf2 = 242, nodefleaf2 = 243)

    Enter u_tdef2_npcon_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:npcon {
        defleaf2 242
        nodefleaf2 243
      }
    curval set by default
      tdef2:npcon {
        defleaf2 142
      }
    update set by client
      tdef2:npcon {
        defleaf2 242
        nodefleaf2 243
      }
    Finished invoking user callback on testdef2:npcon
    

    Update value is the same as newval for CREATE operation.

  • replace /npcon (defleaf2 = 143, nodefleaf2 NOT SET)

    Enter u_tdef2_npcon_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:npcon {
        defleaf2 143
      }
    curval set by client
      tdef2:npcon {
        defleaf2 242
        nodefleaf2 243
      }
    update set by client
      tdef2:npcon {
        defleaf2 143
        nodefleaf2 243
      }
    Finished invoking user callback on testdef2:npcon
    

    There is no instance of the 'nodefleaf2' node in 'newval'. The SIL callback for 'npcon' must remove any internal value held for this leaf if its configuration instance is removed.

    Update value can be used to update internal values. The technique here is to replace the existing data with this composite Update value.

  • replace /npcon (defleaf2 NOT SET, nodefleaf2 = 256)

    Enter u_tdef2_npcon_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:npcon {
        nodefleaf2 256
      }
    curval set by client
      tdef2:npcon {
        defleaf2 143
        nodefleaf2 243
      }
    update set by client
      tdef2:npcon {
        defleaf2 143
        nodefleaf2 256
      }
    Finished invoking user callback on testdef2:npcon
    

    Update value can be used to update internal values. The technique here is to replace the existing data with this composite Update value.

  • delete /npcon

    Enter u_tdef2_npcon_edit callback for validate phase
    Edit values:
    newval set by default
      tdef2:npcon {
        defleaf2 142
      }
    curval set by client
      tdef2:npcon {
        defleaf2 143
        nodefleaf2 256
      }
    update NULL
    Finished invoking user callback on testdef2:npcon
    

    Update value is NULL during DELETE operation. Newval contains only defaults.

Presence Containers and Lists

An example for a presence container pcon is shown. The callbacks would be quite similar for lists, except additional key leaf parameters are used.

  • create /pcon (defleaf3 = 300, nodefleaf3 = 400)

    Enter u_tdef2_pcon_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:pcon {
        defleaf3 300
        nodefleaf3 400
      }
    curval NULL
    update set by client
      tdef2:pcon {
        defleaf3 300
        nodefleaf3 400
      }
    Finished invoking user callback on testdef2:pcon
    

    Update value is the same as newval for CREATE operation.

  • replace /pcon (defleaf3 = 243, nodefleaf3 NOT SET)

    Enter u_tdef2_pcon_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:pcon {
        defleaf3 243
      }
    curval set by client
      tdef2:pcon {
        defleaf3 300
        nodefleaf3 400
      }
    update set by client
      tdef2:pcon {
        defleaf3 243
        nodefleaf3 400
      }
    Finished invoking user callback on testdef2:pcon
    

    Update value can be used to update internal values. The technique here is to replace the existing data with this composite Update value.

  • replace /npcon (defleaf3 NOT SET, nodefleaf3 = 256)

    Enter u_tdef2_pcon_edit callback for validate phase
    Edit values:
    newval set by client
      tdef2:pcon {
        nodefleaf3 256
      }
    curval set by client
      tdef2:pcon {
        defleaf3 243
        nodefleaf3 400
      }
    update set by client
      tdef2:pcon {
        defleaf3 243
        nodefleaf3 256
      }
    Finished invoking user callback on testdef2:pcon
    

    Update value can be used to update internal values. The technique here is to replace the existing data with this composite Update value.

  • delete /pcon

    Enter u_tdef2_pcon_edit callback for validate phase
    Edit values:
    newval NULL
    curval set by client
      tdef2:pcon {
        defleaf3 242
        nodefleaf3 256
      }
    update NULL
    Finished invoking user callback on testdef2:pcon
    

    Update value is NULL during DELETE operation. Newval does not contain any defaults and is also NULL.

Replace Operation Examples

The following section describes and exemplifies the Replace operation in edit-config requests.

Operation Replace

Elements in the <config> subtree May contain an "operation" attribute. The attribute identifies the point in the configuration to perform the operation. If the "operation" attribute is specified to be Replace:

The configuration data identified by the element containing this attribute replaces any related configuration in the configuration datastore identified by the <target> parameter. If no such configuration data exists in the configuration datastore, it is created. Unlike a <copy-config> operation, which replaces the entire target configuration, only the configuration actually present in the <config> parameter is affected.

Default-Operation Replace

If the default-operation is set to "replace" and a top-level data node within the <config> subtree does not have an nc:operation attribute, then the operation will be "replace" for that data node.

Only data nodes present in the <config> subtree can be replaced.

The <copy-config> operation must be used to replace all top-level nodes, and delete any nodes not present in the <config> subtree.

Replace Operation Usage

The following examples use the following YANG module:

module defcont {
  namespace "http://netconfcentral.org/ns/example";
  prefix "defcont";

  container deftest0 {
    container deftest1 {
      list deftest2 {
        key "profile-name";

        leaf profile-name {
          type string;
        }

        leaf defc3 {
          type boolean;
          default "false";
        }

        container deftest3 {
          leaf defc4 {
            type boolean;
            default "false";
          }

          leaf defc5 {
            type boolean;
          }
        }
      }
    }
  }
}

Example 2: Replace on container "deftest1"

Prior to replacing any nodes, two lists will be created within the container using the following edit-config command:

<edit-config>
    <target>
      <candidate/>
    </target>
    <default-operation>merge</default-operation>
    <test-option>set</test-option>
    <config>
        <deftest0 xmlns="http://netconfcentral.org/ns/example">
            <deftest1>
                <deftest2>
                    <profile-name>first-list-name</profile-name>
                    <defc3>true</defc3>
                    <deftest3>
                        <defc4>true</defc4>
                        <defc5>false</defc5>
                    </deftest3>
                </deftest2>
                <deftest2>
                    <profile-name>second-list-name</profile-name>
                    <defc3>true</defc3>
                    <deftest3>
                        <defc4>false</defc4>
                        <defc5>true</defc5>
                    </deftest3>
                </deftest2>
            </deftest1>
      </deftest0>
    </config>
</edit-config>

Assuming the netconfd-pro server is running with --target=candidate, a <commit> operation must be executed following the above edit to apply all changes made in the edit-config.

After the edits the running datastore may look as follows:

{
        "defcont:deftest0": {
            "deftest1": {
                "deftest2": [
                    {
                        "profile-name": "first-list-name",
                        "defc3": true,
                        "deftest3": {
                            "defc4": true,
                            "defc5": false
                        }
                    },
                    {
                        "profile-name": "second-list-name",
                        "defc3": true,
                        "deftest3": {
                            "defc4": false,
                            "defc5": true
                        }
                    }
                ]
            }
        }
}

Now, in order to demonstrate Replace operation the following <edit-config> request is used:

<edit-config>
    <target>
      <candidate/>
    </target>
    <config>
        <deftest0 xmlns="http://netconfcentral.org/ns/example"
                  xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
            <deftest1 nc:operation="replace">
                <deftest2>
                    <profile-name>new-first-list-name</profile-name>
                    <defc3>true</defc3>
                    <deftest3>
                        <defc4>false</defc4>
                        <defc5>true</defc5>
                    </deftest3>
                </deftest2>
            </deftest1>
      </deftest0>
    </config>
</edit-config>

As a result of this request and after <commit> operation the server will produce the following callback invocations.

To summarize the <edit-config> result, the server invokes the following callbacks:

  • SIL callback for Replace on deftest1

  • SIL callback for Create on deftest2

  • SIL callback for Create on deftest3

  • SIL callback for Delete on deftest2

  • SIL callback for Delete on deftest2

Note: that the server in order to Replace resources, it deletes the old one and creates a new to ensure that the Replace is fully done.

Example 2: Replace on list "deftest2" (a new list replace)

Assume there are existing lists in the running datastore configurations that looks as follows:

{
        "defcont:deftest0": {
            "deftest1": {
                "deftest2": [
                    {
                        "profile-name": "first-list-name",
                        "defc3": true,
                        "deftest3": {
                            "defc4": true,
                            "defc5": false
                        }
                    },
                    {
                        "profile-name": "second-list-name",
                        "defc3": true,
                        "deftest3": {
                            "defc4": false,
                            "defc5": true
                        }
                    }
                ]
            }
        }
}

And now we are ready to run a replace operation on a list node as follows:

<edit-config>
    <target>
      <candidate/>
    </target>
    <config>
        <deftest0 xmlns="http://netconfcentral.org/ns/example"
                  xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
            <deftest1>
                <deftest2 nc:operation="replace">
                    <profile-name>new-first-list-name</profile-name>
                    <defc3>true</defc3>
                    <deftest3>
                        <defc4>false</defc4>
                        <defc5>true</defc5>
                    </deftest3>
                </deftest2>
            </deftest1>
      </deftest0>
    </config>
</edit-config>

Note that the Replace operation is done on a list entry that does not exist. As a result of this operation the netconfd-pro server creates this new entry since there is no any entries to replace it with.

As a result of this request and after <commit> operation the server will produce the following callback invocations.

To summarize the above log and the <edit-config> results, the server invokes the following callbacks:

  • SIL callback for Create on deftest2

  • SIL callback for Create on deftest3

Example 3: Replace on list "deftest2" (an existing list replace)

The following example demonstrates replacing an existing list entry. Assuming the same configurations are present in the datastore, execute the following <edit-config>:

<edit-config>
    <target>
      <candidate/>
    </target>
    <config>
        <deftest0 xmlns="http://netconfcentral.org/ns/example"
                  xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
            <deftest1>
                <deftest2 nc:operation="replace">
                    <profile-name>first-list-name</profile-name>
                    <defc3>false</defc3>
                    <deftest3>
                        <defc4>true</defc4>
                        <defc5>false</defc5>
                    </deftest3>
                </deftest2>
            </deftest1>
      </deftest0>
    </config>
</edit-config>

As a result of this request and after <commit> operation the server will produce the following callback invocations.

To summarize the <edit-config> result, the server invokes the following callbacks:

  • SIL callback for Replace on deftest2

  • SIL callback for Replace on deftest3

Example 4: Replace on leafs

Assume there are existing lists with a leafs in the running datastore configurations that looks as follows:

{
        "defcont:deftest0": {
            "deftest1": {
                "deftest2": [
                    {
                        "profile-name": "first-list-name",
                        "defc3": true,
                        "deftest3": {
                            "defc4": true,
                            "defc5": false
                        }
                    },
                    {
                        "profile-name": "second-list-name",
                        "defc3": true,
                        "deftest3": {
                            "defc4": false,
                            "defc5": true
                        }
                    }
                ]
            }
        }
}

To replace a leaf node within a list entry, use the following <edit-config>:

<edit-config>
    <target>
      <candidate/>
    </target>
    <config>
        <deftest0 xmlns="http://netconfcentral.org/ns/example"
                  xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
            <deftest1>
                <deftest2>
                    <profile-name>first-list-name</profile-name>
                    <defc3 nc:operation="replace">false</defc3>
                </deftest2>
            </deftest1>
      </deftest0>
    </config>
</edit-config>

As a result of this request and after <commit> operation the server will produce the following callback invocations.

To summarize the <edit-config> result, the server invokes the following callbacks:

  • SIL callback for Merge on deftest2

Rollback with Replace operation

The rollback procedure is identical to that of any other operation. If the server applies edits during the Apply Phase and encounters a callback failure during the Commit Phase, it will initiate Reverse Edits to undo all changes made during the Apply Phase.

Replace Operation with Nested Operations Examples

Note

Nested operations within top replace operation are NOT allowed and must NOT be used in order to avoid unexpected errors.

This section provides examples of edit-config scenarios utilizing the Replace operation, covering top-level replacements, default-operation settings as "replace," and nested operations within a top Replace operation.

It illustrates the expected behavior of the server and the expected responses to specific edit-config requests containing Replace operations.

The four examples included in this section are:

  • Replace as a New Value

  • Replace Operation with Changes

  • Default-Operation Merge, Top-level Edit Operation Replace (No Changes)

  • Default-Operation Replace (No Changes)

The following examples use the following YANG module:

module onecont_onelist {
  namespace "http://example.com/ns/yang/onecont_onelist";
  prefix onecont_onelist;

  revision "2024-06-27";

  container CONT1 {
    list LIST2 {
      key "name";

      leaf name {
        type string;
      }
      leaf wait-to-restore {
        type uint32 {
        }
        default 5;
      }
      leaf hold-str {
        type string;
      }
    }
  }
}

Replace as a New Value

Scenario: The configuration is initially empty, and the following is the first edit.

Note: If the Replace operation is applied to a node that does not exist, the netconfd-pro server will create a new entry, as there is nothing available to replace. Meaning the Replace is treated as Create in this scenario.

<edit-config>
    <target>
        <running/>
    </target>
    <default-operation>merge</default-operation>
    <test-option>test-then-set</test-option>
    <config>
        <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist" nc:operation="replace">
            <LIST2>
                <name nc:operation="merge">abc</name>
            </LIST2>
        </CONT1>
    </config>
</edit-config>

Or the following XML request:

<edit-config>
    <target>
        <running/>
    </target>
    <default-operation>replace</default-operation>
    <test-option>test-then-set</test-option>
    <config>
        <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist">
            <LIST2>
                <name nc:operation="merge">abc</name>
            </LIST2>
        </CONT1>
    </config>
</edit-config>

Expected Result: The server returns an error as nested edit operations within a Replace operation are not supported.

<errors xmlns:ncx="http://netconfcentral.org/ns/yuma-ncx"
 xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf">
 <error>
  <error-type>rpc</error-type>
  <error-tag>operation-not-supported</error-tag>
  <error-app-tag>no-support</error-app-tag>
  <error-path>/edit-config</error-path>
  <error-message xml:lang="en">nested edit operation not supported</error-message>
  <error-info>
   <error-number>438</error-number>
  </error-info>
 </error>
</errors>

Replace Operation with Changes

Scenario: Initialize the configuration with the following data then replace it with NOT the same configurations but with nested operations.

<edit-config>
    <target>
        <running/>
    </target>
    <default-operation>merge</default-operation>
    <test-option>test-then-set</test-option>
    <config>
        <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist">
            <LIST2>
                <name>1</name>
                <hold-str>abcd</hold-str>
            </LIST2>
        </CONT1>
    </config>
</edit-config>

Request: Send a Replace operation to the server as follows:

<edit-config>
    <target>
        <running/>
    </target>
    <default-operation>replace</default-operation>
    <test-option>test-then-set</test-option>
    <config>
        <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist">
            <LIST2>
                <name nc:operation="merge">1</name>
            </LIST2>
        </CONT1>
    </config>
</edit-config>

Or the following XML request:

<edit-config>
    <target>
        <running/>
    </target>
    <default-operation>merge</default-operation>
    <test-option>test-then-set</test-option>
    <config>
        <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist" nc:operation="replace">
            <LIST2>
                <name nc:operation="merge">1</name>
            </LIST2>
        </CONT1>
    </config>
</edit-config>

Expected Result: The server attempts to apply the Replace edit but returns an error due to unsupported nested operations within a Replace operation.

The "hold-str" node is missing from the second edit-config thus the server must apply this replace edit and attempt deletion of this "hold-str" node. However, there is a nested operation within replace operation thus the error is reported.

<errors xmlns:ncx="http://netconfcentral.org/ns/yuma-ncx"
 xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf">
 <error>
  <error-type>rpc</error-type>
  <error-tag>operation-not-supported</error-tag>
  <error-app-tag>no-support</error-app-tag>
  <error-path>/edit-config</error-path>
  <error-message xml:lang="en">nested edit operation not supported</error-message>
  <error-info>
   <error-number>438</error-number>
  </error-info>
 </error>
</errors>

Default-Operation Merge, Top-level Edit Operation Replace (No Changes)

Scenario: Initialize the configuration with the following data then replace it with the same configurations but with nested operations.

<edit-config>
    <target>
        <running/>
    </target>
    <default-operation>merge</default-operation>
    <test-option>test-then-set</test-option>
    <config>
        <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist">
            <LIST2>
                <name>1</name>
            </LIST2>
        </CONT1>
    </config>
</edit-config>

Request: A Replace operation on the top node with a merge at a nested level.

<edit-config>
    <target>
        <running/>
    </target>
    <default-operation>merge</default-operation>
    <test-option>test-then-set</test-option>
    <config>
        <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist" nc:operation="replace">
            <LIST2>
                <name nc:operation="merge">1</name>
            </LIST2>
        </CONT1>
    </config>
</edit-config>

Expected Result: The server detects the unsupported nested operation and returns an error.

When the default-operation is set to Replace, the server follows a distinct code path compared to Merge. In default-operation Replace mode, the server checks each node individually, allowing it to detect and flag any disallowed nested edit operations.

<errors xmlns:ncx="http://netconfcentral.org/ns/yuma-ncx"
 xmlns="urn:ietf:params:xml:ns:yang:ietf-restconf">
 <error>
  <error-type>rpc</error-type>
  <error-tag>operation-not-supported</error-tag>
  <error-app-tag>no-support</error-app-tag>
  <error-path>/edit-config</error-path>
  <error-message xml:lang="en">nested edit operation not supported</error-message>
  <error-info>
   <error-number>438</error-number>
  </error-info>
 </error>
</errors>

The same result is expected if there are extra nodes within the list entry. Assume these extra nodes already created in the initial configurations:

<edit-config>
    <target>
        <running/>
    </target>
    <default-operation>merge</default-operation>
    <test-option>test-then-set</test-option>
    <config>
        <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist" nc:operation="replace">
            <LIST2>
                <name nc:operation="merge">1</name>
                <wait-to-restore>5</wait-to-restore>
            </LIST2>
        </CONT1>
    </config>
</edit-config>

OR

<edit-config>
    <target>
        <running/>
    </target>
    <test-option>test-then-set</test-option>
    <config>
        <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist" nc:operation="replace">
            <LIST2>
                <name nc:operation="merge">1</name>
                <hold-str>abcd</hold-str>
            </LIST2>
        </CONT1>
    </config>
</edit-config>

Expected Result: The server detects the unsupported nested operation and returns an error.

Default-Operation Replace (No Changes)

Scenario: Initialize the configuration with the following data then replace it with the same configurations but with nested operations.

<edit-config>
    <target>
        <running/>
    </target>
    <default-operation>merge</default-operation>
    <test-option>test-then-set</test-option>
    <config>
        <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist">
            <LIST2>
                <name>abc</name>
            </LIST2>
        </CONT1>
    </config>
</edit-config>

Request: Send an edit with default-operation Replace with a nested merge operation within the config:

<edit-config>
    <target>
        <running/>
    </target>
    <default-operation>replace</default-operation>
    <test-option>test-then-set</test-option>
    <config>
        <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist">
            <LIST2>
                <name nc:operation="merge">abc</name>
            </LIST2>
        </CONT1>
    </config>
</edit-config>

Expected Result: Since the incoming configuration matches the running configuration, the server skips the edit-config request, resulting in no error.

When the default-operation Replace the server just compares the two configurations: running and the incoming new configuration. As a result to make a decision it needs to start the transaction process.

As a new configuration in the edit-config is exactly the same as in running configuration, the server skips over this edit-config completely, resulting in no error.

The same result is expected if there are extra nodes within the list entry. Assume these extra nodes already created in the initial configurations:

   <edit-config>
     <target>
      <running/>
     </target>
     <default-operation>replace</default-operation>
     <test-option>test-then-set</test-option>
     <config>
      <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist">
       <LIST2>
        <name nc:operation="merge">abc</name>
        <wait-to-restore>5</wait-to-restore>
       </LIST2>
      </CONT1>
     </config>
   </edit-config>

OR
<edit-config>
  <target>
   <running/>
  </target>
  <default-operation>replace</default-operation>
  <test-option>test-then-set</test-option>
  <config>
   <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist">
    <LIST2>
     <name nc:operation="merge">abc</name>
     <wait-to-restore>100</wait-to-restore>
    </LIST2>
   </CONT1>
  </config>
</edit-config>

OR

<edit-config>
  <target>
   <running/>
  </target>
  <default-operation>replace</default-operation>
  <test-option>test-then-set</test-option>
  <config>
   <CONT1 xmlns="http://example.com/ns/yang/onecont_onelist">
    <LIST2>
     <name nc:operation="merge">abc</name>
      <hold-str>abcd</hold-str>
    </LIST2>
   </CONT1>
  </config>
</edit-config>