Candidate datastore

The candidate datastore is described in the NETCONF standard RFC 6241 under section 8.3.

The candidate datastore is used to store configuration prior to committing it to the running datastore. This helps users edit and validate large amounts of configuration without impacting the running database and therefore without impacting the system.

For the candidate datastore to be enabled, the NETCONF server has to support the :candidate capability.

In ConfD, the candidate datastore is enabled by default. To control where the candidate database resides, you can specify this explicitly in confd.conf.
Example:

<!-- The 'candidate' is a shared, named alternative configuration
     database which can be modified without impacting the running
     configuration.  Changes in the candidate can be commit to running,
     or discarded.
     Enable this if you want your users to use this feature from
     NETCONF, CLI or WebGUI, or other agents.
-->
<candidate>
  <enabled>true</enabled>
  <!-- By default, confd implements the candidate configuration
       without impacting the application.  But if your system
       already implements the candidate itself, set 'implementation' to
       'external'.
  -->
  <!--implementation>external</implementation-->
  <implementation>confd</implementation>
  <storage>auto</storage>
  <filename>./confd_candidate.db</filename>
</candidate>

You can also configure your system to use an external database as the candidate datastore by setting the implementation field to “external”.

In order to enable the candidate capability for NETCONF, use the capability configuration in confd.conf:

<capabilities>
  <!-- enable only if /confdConfig/datastores/candidate is enabled -->
  <candidate>
    <enabled>true</enabled>
  </candidate>
 ...

Once the candidate capability is enabled, you can send NETCONF edit-config RPC requests toward the candidate and it won’t take effect till you send the commit RPC; Data will be stored in a candidate datastore file and will persist till a commit is received by the server to write the candidate content to the running datastore.

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>

Can I enable the candidate store and still have the running writeable ?

I have a snmp.yang, which writes data internally to SNMP mib yangs through transformation hooks. Is there a better solution to the problem ?

Yes you can! But it’s not recommended.
Transformation hooks can write to the candidate store instead.

I recommend disabling the writable-running. You can still keep if you are being careful not to modify it when a Northbound user tries to commit a candidate.
This means you have to handle locking the running, copying the running to candidate, then committing and unlocking.

I don’t think you need to change much if you make running writable through candidate. The transformation hooks you have are using MAAPI and you attach to the user initiated transaction right?
If the transaction is initiated towards the candidate then your callbacks will deal with the candidate.

If on the other hand you asynchronously write to running using MAAPI, then you would need to change one call, maapi_start_trans(), by setting the dbname to CONFD_CANDIDATE.

Can you disable the writable-running and test your hooks?

Hi @nabil,

Is there any corresponding command for “candidateReset()” to copy the running db to candidate db ?

Thanks,
Bani

See RFC 6241 - Network Configuration Protocol (NETCONF) and
maapi_candidate_reset(). If you are asking about a CLI command, see revert to copy the configuration from running when you have the candidate enabled in your confd.conf.