The following article 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.
Usage
SIL code and YANG module are attached to this article.
YANG Data model
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 1: Replace on container "deftest1"
Before we replace any nodes, we are going to create two lists in the container by using the following edit-config:
<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>
Assume we are running netconfd-pro server with --target=candidate. Thus, after the above edit we need to run <commit> operation in order to apply all the changes that were done 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 output, from the netconfd-pro server log:
***** start commit phase on running for session 10, transaction 1472337 ***** Start full commit of transaction 1472337: 1 edit on running config Start invoking commit SIL callback for replace on defcont:deftest1 (deftest1) Enter EDIT-2 callback ------PHASE:commit;EDITOP:replace newval deftest1 P:[0x7f19e0004150] : deftest1 { deftest2 new-first-list-name { profile-name new-first-list-name defc3 true deftest3 { defc4 false defc5 true } } } curval deftest1 P:[0x7f19e00030f0] : deftest1 { deftest2 first-list-name { profile-name first-list-name defc3 true deftest3 { defc4 true defc5 false } } deftest2 second-list-name { profile-name second-list-name defc3 true deftest3 { defc4 false defc5 true } } } Finished invoking user callback on defcont:deftest1 Start invoking commit SIL callback for create on defcont:deftest2 (deftest2) Enter EDIT-2 callback ------PHASE:commit;EDITOP:create newval deftest2 P:[0x7f19e0004220] : deftest2 new-first-list-name { profile-name new-first-list-name defc3 true deftest3 { defc4 false defc5 true } } child Q of simple childs: profile-name='new-first-list-name' child Q of simple childs: defc3='true' curval null P:[(nil)] : Finished invoking user callback on defcont:deftest2 Start invoking commit SIL callback for create on defcont:deftest3 (deftest3) Enter EDIT-2 callback ------PHASE:commit;EDITOP:create newval deftest3 P:[0x7f19e0004480] : deftest3 { defc4 false defc5 true } child Q of simple childs: defc4='false' child Q of simple childs: defc5='true' curval null P:[(nil)] : Finished invoking user callback on defcont:deftest3 Start invoking commit SIL callback for delete on defcont:deftest2 (deftest2) Enter EDIT-2 callback ------PHASE:commit;EDITOP:delete newval null P:[(nil)] : curval deftest2 P:[0x7f19e00031a0] : deftest2 first-list-name { profile-name first-list-name defc3 true deftest3 { defc4 true defc5 false } } child Q of simple childs: profile-name='first-list-name' child Q of simple childs: defc3='true' Finished invoking user callback on defcont:deftest2 Start invoking commit SIL callback for delete on defcont:deftest2 (deftest2) Enter EDIT-2 callback ------PHASE:commit;EDITOP:delete newval null P:[(nil)] : curval deftest2 P:[0x7f19e0003860] : deftest2 second-list-name { profile-name second-list-name defc3 true deftest3 { defc4 false defc5 true } } child Q of simple childs: profile-name='second-list-name' child Q of simple childs: defc3='true' Finished invoking user callback on defcont:deftest2 edit-transaction 1472337: on session 10 by restconf@::1 time: 2021-09-14T17:15:51Z message-id: -- trace-id: -- datastore: running operation: replace target: /defcont:deftest0/defcont:deftest1 comment: none Complete commit OK of transaction 1472337 on running database
To summarize the above log and the <edit-config> results, 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 if done on a list entry that does not exist. As a result of this operation the netconfd-pro server will create this new entry since there is no any entries to replace it with.
As a result of the above operation the server will produce the following output:
***** start commit phase on running for session 6, transaction 1472342 ***** Start full commit of transaction 1472342: 1 edit on running config Start invoking commit SIL callback for create on defcont:deftest2 (deftest2) Enter EDIT-2 callback ------PHASE:commit;EDITOP:create newval deftest2 P:[0x7faf88003a20] : deftest2 new-first-list-name { profile-name new-first-list-name defc3 true deftest3 { defc4 false defc5 true } } child Q of simple childs: profile-name='new-first-list-name' child Q of simple childs: defc3='true' curval null P:[(nil)] : Finished invoking user callback on defcont:deftest2 Start invoking commit SIL callback for create on defcont:deftest3 (deftest3) Enter EDIT-2 callback ------PHASE:commit;EDITOP:create newval deftest3 P:[0x7faf88009630] : deftest3 { defc4 false defc5 true } child Q of simple childs: defc4='false' child Q of simple childs: defc5='true' curval null P:[(nil)] : Finished invoking user callback on defcont:deftest3 edit-transaction 1472342: on session 6 by restconf@::1 time: 2021-09-14T18:00:40Z message-id: -- trace-id: -- datastore: running operation: replace target: /defcont:deftest0/defcont:deftest1/defcont:deftest2[defcont:profile-name="new-first-list-name"] comment: none Complete commit OK of transaction 1472342 on running database
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)
Now lets replace a list entry that already exist, assume we have the same configurations in the datastore and run 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 the above operation the server will produce the following output:
***** start commit phase on running for session 9, transaction 1472344 ***** Start full commit of transaction 1472344: 1 edit on running config Start invoking commit SIL callback for replace on defcont:deftest2 (deftest2) Enter EDIT-2 callback ------PHASE:commit;EDITOP:replace newval deftest2 P:[0x7faf8800af30] : deftest2 first-list-name { profile-name first-list-name defc3 false deftest3 { defc4 true defc5 false } } child Q of simple childs: profile-name='first-list-name' child Q of simple childs: defc3='false' curval deftest2 P:[0x7faf88003e30] : deftest2 first-list-name { profile-name first-list-name defc3 true deftest3 { defc4 true defc5 false } } child Q of simple childs: profile-name='first-list-name' child Q of simple childs: defc3='true' Finished invoking user callback on defcont:deftest2 Start invoking commit SIL callback for replace on defcont:deftest3 (deftest3) Enter EDIT-2 callback ------PHASE:commit;EDITOP:replace newval deftest3 P:[0x7faf8800b220] : deftest3 { defc4 true defc5 false } child Q of simple childs: defc4='true' child Q of simple childs: defc5='false' curval deftest3 P:[0x7faf88004100] : deftest3 { defc4 true defc5 false } child Q of simple childs: defc4='true' child Q of simple childs: defc5='false' Finished invoking user callback on defcont:deftest3 edit-transaction 1472344: on session 9 by restconf@::1 time: 2021-09-14T18:06:53Z message-id: -- trace-id: -- datastore: running operation: replace target: /defcont:deftest0/defcont:deftest1/defcont:deftest2[defcont:profile-name="first-list-name"] comment: none Complete commit OK of transaction 1472344 on running database
To summarize the above log and the <edit-config> results, 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 } } ] } } }
Now lets replace a leaf node inside a list entry by using 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 the above operation the server will produce the following output:
***** start commit phase on running for session 7, transaction 1472349 ***** Start full commit of transaction 1472349: 1 edit on running config Start invoking commit SIL callback for merge on defcont:deftest2 (deftest2) Enter EDIT-2 callback ------PHASE:commit;EDITOP:merge newval deftest2 P:[0x7fba4800bd80] : deftest2 first-list-name { profile-name first-list-name defc3 false deftest3 { defc4 true defc5 false } } child Q of simple childs: profile-name='first-list-name' child Q of simple childs: defc3='false' curval deftest2 P:[0x7fba48003e30] : deftest2 first-list-name { profile-name first-list-name defc3 false deftest3 { defc4 true defc5 false } } child Q of simple childs: profile-name='first-list-name' child Q of simple childs: defc3='false' Merge list: child_edit = 0x7fba48009630 child_edit->newnode = P:[0x7fba4800bef0] child_edit->curnode = P:[0x7fba48003ff0] defc3: editop=merge newval=false curval=true Finished invoking user callback on defcont:deftest2 edit-transaction 1472349: on session 7 by restconf@::1 time: 2021-09-14T18:14:59Z message-id: -- trace-id: -- datastore: running operation: replace target: /defcont:deftest0/defcont:deftest1/defcont:deftest2[defcont:profile-name="first-list-name"]/defcont:defc3 comment: none Complete commit OK of transaction 1472349 on running database
To summarize the above log and the <edit-config> results, the server invokes the following callbacks:
- SIL callback for Merge on deftest2
Rollback with Replace operation
The Rollback procedure will be the same as for any other operation. If the server applies any edits during Apply Phase and for some reason one of the callbacks fails during Commit Phase the server will run Reverse Edits in order to Reverse all the edits that were done during the Apply Phase.
For more details refer to the YumaPro Dev Manual.
Also, refer to:
How do I replace the entire contents of the Datastore resource (PUT on datastore)?