Пример #1
0
def print_dict(v, module, prefix='', level=0, huff=[]):
    #huff.append(Statement(None, None , None, 'container','mqtt-netconf-bridge'))
    #module.substmts.append(huff[count])
    global count, level_memory

    if isinstance(v, dict):
        for k, v2 in v.items():
            p2 = "{}['{}']".format(prefix, k)
            print("\nDict: --- ", level, count)
            print(k, v2)
            huff.append(Statement(None, None, None, 'container', k))
            if count is 0:
                module.substmts.append(huff[level])
                level_memory[level] = count
            elif count is not 0 and level is 0:
                huff[level_memory[level]].substmts.append(huff[count])
                #level_memory[level] = count

            elif k is 'rpc':
                level = 0
                module.substmts.append(huff[count])

            else:
                print('D:', level, repr(huff[1]))
                huff[level_memory[level - 1]].substmts.append(huff[count])
                #huff[level-1].substmts.append(huff[count])
                level_memory[level] = count

            count += 1
            #if count > level:
            #	level = count-1
            print_dict(v2, module, p2, level=level + 1, huff=huff)

    elif isinstance(v, list):
        for i, v2 in enumerate(v):
            p2 = "{}[{}]".format(prefix, i)
            print("List: ---", level)
            print(i, v2)
            #
            huff.append(Statement(None, None, None, 'list', i))
            #			huff[level-1].substmts.append(huff[level])
            huff[level_memory[level - 1]].substmts.append(huff[count])
            count += 1
            print_dict(v2, module, p2, level=level + 1, huff=huff)

    else:
        print('{} = {}'.format(prefix, repr(v)))
        huff.append(Statement(None, None, None, 'leaf', v))
        #huff[level-1].substmts.append(huff[count])
        huff[level_memory[level - 1]].substmts.append(huff[count])
        level_memory[level] = count
        count += 1
Пример #2
0
    def mtype_to_statement(cls, mtype, yangname, parent=None):
        if ismodeledclass(mtype):
            return YANGContainer[mtype].to_statement(
                yangname=yangname, parent=parent)

        leaf = Statement(None, parent, None, 'leaf', yangname)
        # if member.title:
        #     description = Statement(
        #         None, leaf, None, 'description', member.title)
        #     leaf.substmts.append(description)
        type_ = Statement(None, leaf, None, 'type', TYPES[mtype])
        leaf.substmts.append(type_)
        return leaf
Пример #3
0
def test_dump():
    """
    dump should correctly print headless pyang.statements.Statement
    dump should correctly print nested pyang.statements.Statement
    """
    prefix = Statement(None, None, None, 'prefix', 'test')
    assert dump(prefix).strip() == 'prefix test;'
    namespace = Statement(None, None, None, 'namespace', 'urn:yang:test')
    module = Statement(None, None, None, 'module', 'test')
    module.substmts = [namespace, prefix]
    assert dump(module).strip() == (
        'module test {\n'
        '  namespace "urn:yang:test";\n'
        '  prefix test;\n'
        '}'
    )
Пример #4
0
def fixup_state_grouping(stmt):
    # Add config: false to every statement that doesn't already have it.

    # Recurse over groupings statements.
    if stmt.keyword in {"grouping"}:
        for s in stmt.substmts:
            fixup_state_grouping(s)

    # Fixup any data nodes that can have a status leaf.
    if stmt.keyword in {
            "container", "leaf", "leaf-list", "list", "anyxml", "anydata",
            "choice"
    }:
        has_config_true = False
        has_config_false = False
        for s in stmt.substmts:
            if s.keyword == 'config':
                if s.arg == 'true':
                    has_config_true = True
                else:
                    has_config_false = True
        if not has_config_false:
            add_substmt_canonical(
                stmt, Statement(stmt.top, stmt, stmt.pos, 'config', 'false'))
        if has_config_true:
            pass
        for s in stmt.substmts:
            fixup_state_grouping(s)
Пример #5
0
def convert_stmt(config_stmt, state_stmt):
    # Iterate the state tree
    state_substmts = grammar.sort_canonical(state_stmt.keyword,
                                            state_stmt.substmts)
    config_substmts = grammar.sort_canonical(config_stmt.keyword,
                                             config_stmt.substmts)
    for s in state_substmts:
        matching_cfg_stmts = [
            c for c in config_substmts if is_matching_stmt(c, s)
        ]
        if any(matching_cfg_stmts):
            cfg_stmt = matching_cfg_stmts[0]

            if (s.keyword in ['description', 'presence']):
                if s.arg != cfg_stmt.arg:
                    # Merge description strings.
                    cfg_stmt.arg = cfg_stmt.arg + "\n\nFROM STATE TREE (FIX ME):\n" + s.arg
            else:
                # Don't add this element (should also check type as well).
                convert_stmt(cfg_stmt, s)
        else:
            if (s.keyword != 'config'):
                # Copy the state stmt over to the config
                copied_stmt = s.copy()
                config_stmt.substmts.append(copied_stmt)
                fixup_stmt(copied_stmt)
                if copied_stmt.keyword in {
                        "container", "leaf", "leaf-list", "list", "anyxml",
                        "anydata", "choice"
                }:
                    add_substmt_canonical(
                        copied_stmt,
                        Statement(copied_stmt.top, copied_stmt,
                                  copied_stmt.pos, 'config', 'false'))
Пример #6
0
def check_namespace(parsed_module: Statement) -> bool:
    try:
        namespace = parsed_module.search('namespace')[0].arg
    except:
        return False
    if 'urn:cisco' in namespace:
        return False
    if 'urn:' in namespace:
        return True
    for ns, _ in NS_MAP:
        if ns in namespace:
                return True
    return False
Пример #7
0
def container():
    """Sample container"""
    container = Statement(None, None, None, 'container', 'outer')
    id_ = Statement(None, container, None, 'leaf', 'id')
    type_ = Statement(None, id_, None, 'type', 'int32')
    id_.substmts = [type_]
    name = Statement(None, container, None, 'leaf', 'name')
    type_ = Statement(None, name, None, 'type', 'string')
    name.substmts = [type_]
    container.substmts = [id_, name]

    return container
Пример #8
0
def module():
    """Sample container"""
    module = Statement(None, None, None, 'module', 'fixture-test')
    namespace = Statement(module, module, None, 'namespace', 'urn:yang:test')
    prefix = Statement(module, module, None, 'prefix', 'test')

    container = Statement(module, module, None, 'container', 'outer')
    id_ = Statement(module, container, None, 'leaf', 'id')
    type_ = Statement(module, id_, None, 'type', 'int32')
    id_.substmts = [type_]

    name = Statement(module, container, None, 'leaf', 'name')
    type_ = Statement(module, name, None, 'type', 'string')
    name.substmts = [type_]
    container.substmts = [id_, name]

    module.substmts = [namespace, prefix, container]

    return module
Пример #9
0
def check_dependencies(dep_type: t.Literal['import', 'include'], parsed_module: Statement,
                       directory: str, yang_models_dir: str) -> t.Tuple[t.Set[str], t.Set[str]]:
    all_modules: t.Set[str] = set()
    missing_modules: t.Set[str] = set()
    for dependency in parsed_module.search(dep_type):
        name = dependency.arg
        all_modules.add(name)
        revisions = dependency.search('revision-date')
        revision = revisions[0].arg if revisions else '*'
        pattern = '{}.yang'.format(name)
        pattern_with_revision = '{}@{}.yang'.format(name, revision)
        if not find_first_file(directory, pattern, pattern_with_revision, yang_models_dir):
            # TODO: if the matched filename doesn't include the revision, maybe we should check it?
            if revision != '*':
                missing_modules.add('{}@{}'.format(name, revision))
            else:
                missing_modules.add(name)
    return all_modules, missing_modules
Пример #10
0
def check_revision(parsed_module: Statement) -> bool:
    try:
        revision = parsed_module.search('revision')[0].arg
    except:
        return False
    revision_parts = [int(i) for i in revision.split('-')]
    try:
        date(*revision_parts)
    except:
        if revision_parts[1:] == [2, 29]:
            revision_parts[2] = 28
            try:
                date(*revision_parts)
            except:
                return False
        else:
            return False
    return True
Пример #11
0
def test_mix_builder(Y):
    """
    builder should mix with pyang standard
    """
    module = Y('module', 'test',
               Statement(None, None, None, 'namespace', 'urn:yang:test'))
    module('prefix', 'test')
    module.append(Y.from_tuple(('leaf', 'data', [('type', 'string')])))

    assert module.dump().strip() == ('module test {\n'
                                     '  namespace "urn:yang:test";\n'
                                     '  prefix test;\n'
                                     '  leaf data {\n'
                                     '    type string;\n'
                                     '  }\n'
                                     '}')

    assert module.validate()
Пример #12
0
    def to_statement(cls, yangname=None, parent=None):
        """Get YANG container as :class:`pyang.statement.Statement` instance,
           ready for feeding to a pyang output plugin.

        - If no `yangname` is given,
          a decamelized modeled class name joined by hyphens will be used.
        - Optionally binds statement to `parent` statement,
          like a module or a parent container.
        """
        container = Statement(
            None, parent, None, 'container', yangname or cls.yangname)
        # add modeled members as leafs or subcontainers to the main container
        for name, member in cls.mclass.model.members:
            yangname = name.replace('_', '-')
            statement = cls.member_to_statement(
                member, yangname=yangname, parent=container)
            container.substmts.append(statement)
        return container
Пример #13
0
 def to_statement(cls, namespace=None, prefix=None, revision=None):
     """Get YANG module as :class:`pyang.statement.Statement` instance,
        ready for feeding to a pyang output plugin.
     """
     # adapted modeled class is used as YANG module and main container
     module = Statement(None, None, None, 'module', cls.yangname)
     if not prefix:
         prefix = decamelize(cls.__name__, joiner='-')
     if namespace:
         namespace = Statement(None, module, None, 'namespace', namespace)
         module.substmts.append(namespace)
     prefix = Statement(None, module, None, 'prefix', prefix)
     module.substmts.append(prefix)
     if not revision:
         revision = str(date.today())
     revision = Statement(None, module, None, 'revision', revision)
     module.substmts.append(revision)
     container = super(YANGModuleMeta, cls).to_statement(parent=module)
     module.substmts.append(container)
     # add defined @rpc methods
     for name, obj in getmembers(cls):
         if getattr(obj, '__isnetconfrpc__', False):
             method = obj
             yangname = name.replace('_', '-')
             rpc = Statement(None, module, None, 'rpc', yangname)
             module.substmts.append(rpc)
             if method.__doc__:
                 description = Statement(None, rpc, None, 'description',
                                         method.__doc__.strip())
                 rpc.substmts.append(description)
             # if the rpc method has args then add an input statement,
             # containing a leaf statement for every arg
             argspec = getargspec(method)
             if len(argspec.args) > 1:  # ignore 'self'
                 input_ = Statement(None, rpc, None, 'input', None)
                 rpc.substmts.append(input_)
                 for name in argspec.args[1:]:
                     yangname = name.replace('_', '-')
                     mtype = method.mtypes[name]
                     statement = cls.member_to_statement(mtype,
                                                         yangname=yangname,
                                                         parent=input_)
                     input_.substmts.append(statement)
     return module
Пример #14
0
    def member_to_statement(cls, member, yangname, parent=None):
        if ismodeledclass(member.mtype):
            return YANGContainer[member.mtype].to_statement(
                yangname=yangname, parent=parent)

        if member.islist():
            list_ = Statement(None, parent, None, 'list', yangname)
            yangindexname = member.indexname.replace('_', '-')
            key = Statement(None, list_, None, 'key', yangindexname)
            list_.substmts.append(key)
            leaf = Statement(None, list_, None, 'leaf', yangindexname)
            list_.substmts.append(leaf)
            type_ = Statement(None, leaf, None, 'type', TYPES[int])
            leaf.substmts.append(type_)
            yangitemname = member.itemname.replace('_', '-')
            statement = cls.mtype_to_statement(
                member.itemtype, yangname=yangitemname, parent=list_)
            list_.substmts.append(statement)
            return list_

        if member.isdict():
            list_ = Statement(None, parent, None, 'list', yangname)
            yangkeyname = member.keyname.replace('_', '-')
            key = Statement(None, list_, None, 'key', yangkeyname)
            list_.substmts.append(key)
            leaf = Statement(None, list_, None, 'leaf', yangkeyname)
            list_.substmts.append(leaf)
            type_ = Statement(
                None, leaf, None, 'type', TYPES[member.keytype])
            leaf.substmts.append(type_)
            yangvaluename = member.valuename.replace('_', '-')
            statement = cls.mtype_to_statement(
                member.valuetype, yangname=yangvaluename, parent=list_)
            list_.substmts.append(statement)
            return list_

        return cls.mtype_to_statement(
            member.mtype, yangname=yangname, parent=parent)
Пример #15
0
def mark_stmt_deprecated(state_stmt):
    # Iterate the state tree
    def can_have_status(stmt):
        return (stmt.keyword in [
            'action', 'anydata', 'anyxml', 'augment', 'bits', 'case', 'choice',
            'container', 'enum', 'extension', 'feature', 'grouping',
            'identity', 'leaf', 'list', 'leaf-list', 'notification', 'rpc',
            'typedef', 'uses'
        ])

    if (can_have_status(state_stmt)):
        status_current = True
        for substmt in state_stmt.substmts:
            if (substmt.keyword == 'status' and substmt.arg != "current"):
                status_current = False
        if (status_current):
            add_substmt_canonical(
                state_stmt,
                Statement(state_stmt.top, state_stmt, state_stmt.pos, 'status',
                          'deprecated'))
    # Recurse down children state statements.
    for substmt in state_stmt.substmts:
        mark_stmt_deprecated(substmt)
Пример #16
0
def test_append(Y, container):
    """
    Append should accept N (mixed) arguments
    Append without copy should reuse node
    Append with copy should build a new node
    """
    other_ext = Statement(None, None, None, 'other:ext', 'other:ipsun')
    container.append(Y.description('loren ipsum'), Y('ext:loren', 'ipsun'),
                     other_ext)

    assert container.find('description')
    assert container.find('ext:loren')
    assert len(container.find(arg='ipsun', ignore_prefix=True)) == 2

    result = container.find('other:ext')[0].unwrap()
    assert id(result) == id(other_ext)

    container.append(Y.description('loren ipsum'),
                     Y('ext:loren', 'ipsun'),
                     other_ext,
                     copy=True)

    result = container.find('other:ext')[-1].unwrap()
    assert id(result) != id(other_ext)
Пример #17
0
def parse_dict(v, module):
    global mqtt_commands, my_set, device_category
    print("##############")
    huff2 = []
    count2 = 0
    if isinstance(v, dict):
        for k, v2 in v.items():
            print("# K:", k)
            if k == 'device':
                huff2.append(Statement(None, None, None, 'container', k))
                module.substmts.append(huff2[count2])
                count2 += 1
                level = count2 - 1
                for k2, v3 in v2.items():
                    print("#### K2:", k2, count2)
                    if k2 == 'description':
                        huff2.append(Statement(None, None, None, k2, v3))
                        huff2[level].substmts.append(huff2[count2])
                        count2 += 1
                    elif k2 == 'uuid':
                        huff2.append(
                            Statement(None, None, None, 'list', 'device-id'))
                        huff2[level].substmts.append(huff2[count2])
                        count2 += 1
                        level2 = count2 - 1
                        huff2.append(Statement(None, None, None, 'key', k2))
                        huff2[level2].substmts.append(huff2[count2])
                        count2 += 1
                        huff2.append(Statement(None, None, None, 'leaf', k2))
                        huff2[level2].substmts.append(huff2[count2])
                        count2 += 1
                        for k3, v4 in v3.items():
                            print("+++++++ K3:", k3, v4, count2)
                            if k3 == 'value':
                                my_set.add(
                                    v4)  #add this value to the set of UUIDs
                                print(my_set)
                            else:
                                huff2.append(
                                    Statement(None, None, None, k3, v4))
                                huff2[count2 - 1].substmts.append(
                                    huff2[count2])
                                count2 += 1

                    else:
                        huff2.append(Statement(None, None, None, 'leaf', k2))
                        huff2[level].substmts.append(huff2[count2])
                        count2 += 1
                        level2 = count2 - 1

                        for k3, v4 in v3.items():
                            print("###### K3:", k3, v4, count2)
                            if k3 == 'value':  #special rule for VALUE in 'device-category'
                                device_category = v4  #add this value to the set of UUIDs
                                print(device_category)
                            elif not isinstance(v4, dict):
                                huff2.append(
                                    Statement(None, None, None, k3, v4))
                                huff2[level2].substmts.append(huff2[count2])
                                count2 += 1
                            else:
                                #key, value = v4.popitem()
                                #print '>>>',key, value
                                huff2.append(
                                    Statement(None, None, None, k3, None))
                                huff2[count2 - 1].substmts.append(
                                    huff2[count2])
                                count2 += 1
                                for k4, v5 in v4.items():
                                    print("########x K4:", k4, v5, count2)
                                    huff2.append(
                                        Statement(None, None, None, k4, v5))
                                    huff2[count2 - 1].substmts.append(
                                        huff2[count2])
                                    count2 += 1
            if k == 'rpc':
                for k2, v3 in v2.items():
                    print("#### K2:", k2, count2)
                    huff2.append(Statement(None, None, None, 'rpc', k2))
                    module.substmts.append(huff2[count2])
                    count2 += 1
                    level = count2 - 1
                    for k3, v4 in v3.items():
                        print("###### K3:", k3, count2)
                        if not isinstance(v4, dict):
                            if k3 == 'mqtt-command':
                                mqtt_commands[
                                    k2] = v4  # add rpc-name : mqtt-command
                            else:
                                print("K3 - append", k3, v4)
                                huff2.append(
                                    Statement(None, None, None, k3, v4))
                                huff2[level].substmts.append(huff2[count2])
                                count2 += 1
                        else:
                            if k3 == 'input':
                                huff2.append(
                                    Statement(None, None, None, 'input', None))
                                huff2[level].substmts.append(huff2[count2])
                                count2 += 1

                                huff2.append(
                                    Statement(None, None, None, 'leaf',
                                              next(iter(v4))))
                                huff2[count2 - 1].substmts.append(
                                    huff2[count2])
                                level2 = count2
                                count2 += 1
                                for k4, v5 in v4.items():
                                    print("******** K4:", k4, v5, count2)
                                    if not isinstance(v4, dict):
                                        print(
                                            "!!! Fehler: sollte nicht vorkommen"
                                        )
                                        huff2.append(
                                            Statement(None, None, None, 'ooh',
                                                      k4))
                                        huff2[count2 - 1].substmts.append(
                                            huff2[count2])
                                        count2 += 1

                                    else:
                                        for k5, v6 in v5.items():
                                            print("######## K5:", k5, v6,
                                                  count2)
                                            huff2.append(
                                                Statement(
                                                    None, None, None, k5, v6))
                                            huff2[level2].substmts.append(
                                                huff2[count2])
                                            count2 += 1
Пример #18
0
def generate_yang(test, uuid_set):
    global count, level_memory
    global mqtt_commands
    global my_set
    global device_category

    my_set = uuid_set
    '''
	Generate a YANG-in-XML Tree
	- print the YANG Tree as string with SerialIO
	- build a new root-Element, called <data> with 'xmlns' Attribute
	- attach the stringified CDATA to the new Element
	- print the XML
	'''

    #python-modeled.netconf/modeled/netconf/yang/__init__.py
    module1 = Statement(None, None, None, 'module', 'mqtt-led')

    my_namespace = "http://ipv6lab.beuth-hochschule.de/led"
    my_prefix = "led"

    namespace = Statement(None, module1, None, 'namespace', my_namespace)
    module1.substmts.append(namespace)

    prefix = Statement(None, module1, None, 'prefix', my_prefix)
    module1.substmts.append(prefix)

    #http://stackoverflow.com/questions/10844064/items-in-json-object-are-out-of-order-using-json-dumps
    data = json.loads(test, object_pairs_hook=OrderedDict)
    count = 0
    level_memory = {}
    #print_dict(data, module1, count)
    parse_dict(data, module1)

    #revision = str(datetime.now())
    #revision = Statement(None, module, None, 'revision', revision)
    #module.substmts.append(revision)

    #https://github.com/mbj4668/pyang/blob/master/pyang/plugin.py
    #https://github.com/modeled/modeled.netconf/blob/master/modeled/netconf/yang/container.py
    """Serialize YANG container to the given output `format`.
			"""
    # output stream for pyang output plugin
    stream = StringIO()

    # gets filled with all availabe pyang output format plugins
    PYANG_PLUGINS = {}

    # register and initialise pyang plugin
    pyang.plugin.init([])
    for plugin in pyang.plugin.plugins:
        plugin.add_output_format(PYANG_PLUGINS)
    del plugin

    #for name in PYANG_PLUGINS:
    #    print(name)
    #...
    #dsdl
    #depend
    #name
    #omni
    #yin
    #tree
    #jstree
    #capability
    #yang
    #uml
    #jtox
    #jsonxsl
    #sample-xml-skeleton
    plugin = PYANG_PLUGINS['yang']

    # register plugin options according to pyang script
    optparser = OptionParser()
    plugin.add_opts(optparser)

    # pyang plugins also need a pyang.Context
    ctx = pyang.Context(DummyRepository())

    # which offers plugin-specific options (just take defaults)
    ctx.opts = optparser.parse_args([])[0]

    # ready to serialize
    plugin.emit(ctx, [module1], stream)

    # and return the resulting data
    stream.seek(0)
    yang = stream.getvalue()

    print('\nAusgabe: ')
    print(stream.read())
    print("")
    #return stream.read()

    #root = etree.Element("data", xmlns="urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring")
    #root.text = etree.CDATA(yang)
    #print  etree.tostring(root,  pretty_print=True)
    #return  etree.tostring(root,  pretty_print=True)

    #returns the constructed yang from json-config, a list of mqtt-commands and a set of uuids
    return (yang, mqtt_commands, my_set, device_category)
Пример #19
0
def convert_stmt(ctx, stmt, level):
    if ctx.opts.yang_remove_unused_imports and stmt.keyword == 'import':
        for p in stmt.parent.i_unused_prefixes:
            if stmt.parent.i_unused_prefixes[p] == stmt:
                return

    if util.is_prefixed(stmt.raw_keyword):
        (prefix, identifier) = stmt.raw_keyword
        keyword = prefix + ':' + identifier
    else:
        keyword = stmt.keyword

    if keyword == 'module':
        # Change the module name.
        module_name = stmt.arg
        stmt.arg = module_name + '-state'

        # Find the module prefix.
        prefix_stmt = next(x for x in stmt.substmts if x.keyword == 'prefix')

        # Rename the prefix statement.
        prefix = prefix_stmt.arg
        prefix_stmt.arg = prefix + '-s'

        # Add an import statement back to the original module.
        import_stmt = Statement(stmt.top, stmt, stmt.pos, 'import',
                                module_name)
        add_substmt_canonical(stmt, import_stmt)
        add_substmt_canonical(
            import_stmt,
            Statement(stmt.top, import_stmt, import_stmt.pos, 'prefix',
                      prefix))

    if keyword == 'submodule':
        # Change the module name.
        submodule_name = stmt.arg
        stmt.arg = submodule_name + '-state'

    if keyword == 'namespace':
        stmt.arg = stmt.arg + '-state'

    # Remove any feature statements, reference the original module feature instead.
    if keyword == 'feature':
        stmt.parent.substmts.remove(stmt)

    if keyword == 'if-feature':
        fix_references(stmt, stmt.i_module.i_features)

    # Remove any identity statements, reference the original identity instead.
    # Identity base won't matter because they are all removed.
    if keyword == 'identity':
        stmt.parent.substmts.remove(stmt)

    if keyword in ('include', 'belongs-to'):
        stmt.arg = stmt.arg + "-state"

    if keyword == "prefix" and stmt.parent.keyword == "belongs-to":
        stmt.arg = stmt.arg + "-s"

    # Remove must/when statements.
    if keyword in ('must', 'when'):
        stmt.parent.substmts.remove(stmt)
        #fix_references(stmt, stmt.i_module.i_identities)

    if keyword == 'type' and stmt.arg == 'identityref':
        base_stmt = next(x for x in stmt.substmts if x.keyword == 'base')
        fix_references(base_stmt, stmt.i_module.i_identities)

    # Remove any typedef statements, reference the original typedef instead.
    if keyword == 'typedef':
        stmt.parent.substmts.remove(stmt)

    if keyword == 'type':
        fix_references(stmt, stmt.i_module.i_typedefs)

    # Remove all config statements, only the top level config false is necessary.
    if keyword == 'config':
        stmt.parent.substmts.remove(stmt)

    if len(stmt.substmts) != 0:
        #substmts = grammar.sort_canonical(stmt.keyword, stmt.substmts)
        for s in stmt.substmts[:]:
            convert_stmt(ctx, s, level + 1)

    # Convert top level containers from "foo" to "foo-state", and mark it as config false.
    if keyword in ('container', 'list',
                   'leaf-list') and (stmt.parent.keyword == 'module'
                                     or stmt.parent.keyword == 'grouping'):
        if not stmt.arg.endswith('-state'):
            #stmt.arg = stmt.arg + '-state'
            add_substmt_canonical(
                stmt, Statement(stmt.top, stmt, stmt.pos, 'config', 'false'))