The recommended approach to enabling the candidate datastore in ConfD is to disable the writable-running capability in NETCONF through confd.conf as follows:
<netconf>
<capabilities>
…
<candidate>
<enabled>true</enabled>
</candidate>
<writable-running>
<enabled>false</enabled>
</writable-running>
…
</capabilities>
</netconf>
The running datastore should then be configured as writable-through-candidate in confd.conf as follows:
<datastores>
<startup>
<enabled>false</enabled>
</startup>
<candidate>
<enabled>true</enabled>
<implementation>confd</implementation>
<storage>auto</storage>
<filename>./confd_candidate.db</filename>
</candidate>
<running>
<access>writable-through-candidate</access>
</running>
</datastores>
The above setting indicates that the running datastore can’t be written to directly through the edit-config rpc request. The running datastore can only be written to through changes made to the candidate datastore using the commit operation. This recommended configuration allows ConfD to implement the candidate datastore simply as a diff against the running datastore which is a lot more efficient. It avoids having to require the NETCONF client to perform a NETCONF copy-config operation to copy the configuration from running to candidate first before performing any edit operations on the candidate datastore if both the candidate and running datastores are configured as writable.
Unless you truly intend for the edit-config operation towards candidate to be a in a shared mode with other ConfD Northbound clients such as the CLI or other NETCONF clients in which multiple users can be modifying the candidate datastore at the same time, a NETCONF lock operation on the candidate datastore should first be performed before performing any edit-config operations.
An example series of NETCONF operations to perform an edit-config rpc request using the above configuration against the 1-2-3 intro example is as follows:
$ netconf-console --interactive
* Enter a NETCONF operation, end with an empty line
<lock>
<target>
<candidate/>
</target>
</lock>
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="2">
<ok/>
</rpc-reply>
* Enter a NETCONF operation, end with an empty line
<edit-config>
<target>
<candidate/>
</target>
<config>
<dhcp xmlns="http://tail-f.com/ns/example/dhcpd"
xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0">
<defaultLeaseTime nc:operation="replace">
PT70M
</defaultLeaseTime>
</dhcp>
</config>
</edit-config>
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="2">
<ok/>
</rpc-reply>
* Enter a NETCONF operation, end with an empty line
<commit/>
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="2">
<ok/>
</rpc-reply>
* Enter a NETCONF operation, end with an empty line
<unlock>
<target>
<candidate/>
</target>
</unlock>
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="2">
<ok/>
</rpc-reply>
The commit operation will commit changes made to candidate to running. The resulting running datastore will look like the following:
* Enter a NETCONF operation, end with an empty line
<get-config>
<source>
<running/>
</source>
<filter xmlns="http://tail-f.com/ns/example/dhcpd">
<dhcp/>
</filter>
</get-config>
<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="2">
<data>
<dhcp xmlns="http://tail-f.com/ns/example/dhcpd">
<defaultLeaseTime>PT70M</defaultLeaseTime>
</dhcp>
</data>
</rpc-reply>