[YANGTOOLS-911] Nodes in augmentations do not inherit config statement from augmented parent Created: 17/Oct/18  Updated: 22/Oct/18  Resolved: 22/Oct/18

Status: Resolved
Project: yangtools
Component/s: parser
Affects Version/s: None
Fix Version/s: None

Type: Bug Priority: Medium
Reporter: Miroslav Kovac Assignee: Robert Varga
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Yangtools parser doesn t inherit parent config statement if it comes from augmentations. Meaning if we are augmenting container that is "config false;" all the nodes in that augmentation should be config false too without need of setting them to config false; but they are not if they are not explicitly set to config false inside of augmentation statement.

The following code:

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.ServiceLoader;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.Revision;
import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.parser.api.YangParser;
import org.opendaylight.yangtools.yang.model.parser.api.YangParserException;
import org.opendaylight.yangtools.yang.model.parser.api.YangParserFactory;
import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
import org.slf4j.LoggerFactory;

public class Main {

    private static final YangParserFactory PARSER_FACTORY;
    private static final Logger LOG = (Logger) LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME);


    static {
        LOG.setLevel(Level.INFO);
        final Iterator<YangParserFactory> it = ServiceLoader.load(YangParserFactory.class).iterator();
        if (!it.hasNext()) {
            throw new IllegalStateException("No YangParserFactory found");
        }
        PARSER_FACTORY = it.next();
    }

    public static void main(final String[] args) throws IOException, YangParserException {
        final YangParser parser = PARSER_FACTORY.createParser();

        // add sources with its dependents
        parser.addSource(YangTextSchemaSource.forFile(new File("<path_to_file>/ietf-ipv4-unicast-routing@2018-03-13.yang")));
        parser.addLibSource(YangTextSchemaSource.forFile(new File("<path_to_file>/ietf-routing@2018-03-13.yang")));
        parser.addLibSource(YangTextSchemaSource.forFile(new File("<path_to_file>/ietf-interfaces@2018-02-20.yang")));
        parser.addLibSource(YangTextSchemaSource.forFile(new File("<path_to_file>/ietf-yang-types@2013-07-15.yang")));
        parser.addLibSource(YangTextSchemaSource.forFile(new File("<path_to_file>/ietf-inet-types@2013-07-15.yang")));

        // build schema context
        final SchemaContext schemaContext = parser.buildSchemaContext();
        // get module
        final Module module = schemaContext.findModule("ietf-ipv4-unicast-routing", Revision.of("2018-03-13")).get();
        // iterate through all the augmentations
        for(final AugmentationSchemaNode augNode : module.getAugmentations()) {
            // build augmentation path
            final StringBuilder pathBuilder = new StringBuilder();
            for (QName qname : augNode.getTargetPath().getPathFromRoot()) {
                pathBuilder.append('/')
                        .append(qname.getLocalName());
            }
            LOG.info("augmentation path: " + pathBuilder.toString());
            // iterate through nodes in each augmentation
            for(DataSchemaNode node :augNode.getChildNodes()){
                final String name = node.getQName().getLocalName();
                final boolean isConfig = node.isConfiguration();
                LOG.info("node " + name + " isConfig " + isConfig);
            }
        }
    }
}

Please change <path_to_file> to wherever your file is. you can find these files in this github repo.

So this code returns output like this.

12:59:16.253 [main] INFO ROOT - augmentation path: /routing/ribs/rib/routes/route
12:59:16.263 [main] INFO ROOT - node destination-prefix isConfig true
12:59:16.263 [main] INFO ROOT - augmentation path: /routing/ribs/rib/routes/route/next-hop/next-hop-options/simple-next-hop
12:59:16.263 [main] INFO ROOT - node next-hop-address isConfig true
12:59:16.263 [main] INFO ROOT - augmentation path: /routing/ribs/rib/routes/route/next-hop/next-hop-options/next-hop-list/next-hop-list/next-hop
12:59:16.263 [main] INFO ROOT - node address isConfig true

but already in first augmentation we can see that /routing/ribs/rib/routes/route
is following in yang.

container routes {
          config false;
          description
            "Current contents of the RIB.";
          list route {
            description
              "A RIB route entry.  This data node MUST be augmented
               with information specific to routes of each address
               family.";

Right on the second line container routes is of config false; which means that list route must be config false too and everything in it even if we augmenting. but our node in that augmentation is node destination-prefix and its isConfig is set to true.



 Comments   
Comment by Robert Varga [ 22/Oct/18 ]

This is the duality of available augmentations vs. instantiated types. Instantiated nodes within the target have the correct type, while the nodes within the copied augmentation have configuration set to the logical value of the augmentation – i.e. inherited from parent, which is root, which is config=true.

Comment by Robert Varga [ 22/Oct/18 ]

There is nothing to fix here: the nodes available through ContainerSchemaNode.findDataTreeChild() return the correct configuration value.

Generated at Wed Feb 07 20:54:39 UTC 2024 using Jira 8.20.10#820010-sha1:ace47f9899e9ee25d7157d59aa17ab06aee30d3d.