Inheritance Problem

Hello guys,

There is something that i would like to shed some light on.
Data resolution in Nornir works by iterating recursively over all the parent groups and try to see if that parent group (or any of it’s parents) contains the data.
BUT, to me it does not seem to work as smootly as it seems.

(You do have to read the documentation, Section ’ Inheritance model ', to better understand my issue.
https://github.com/nornir-automation/nornir/blob/develop/docs/tutorial/inventory.ipynb)

Now that you read it, the problem that i have is that, for me and from what i understood

the output of :
leaf01_bma[“domain”]
should not be ‘acme.local’ but ‘global.local’.

As leaf01_bma belongs to the group ‘bma’ which in turn belongs to the groups ‘eu’ and ‘global’.

If Nornir does not find the key ‘domain’ in the hosts.yaml file, then it should go check EACH parent group.

But i lab this up and it seems that it only check one parent from the list.

For exemple here, it will only check ‘eu’ group and then go straight to the default.yaml file instead of following up on the ‘global’ group.

Let me know if you need any clarification.

(Sorry i was limited to one image, i’m a new user)

1 Like

Hello,

Just tried this and it works ok on my side. Second group get checked when data is missing from the first group. Which nornir version are you running (I’m running 3.0.0)?
Also, what happens if the data is not in your default.yaml file, do you have an error message?

Hello ,

If the data is not in the default.yaml i have this oddly :

i use nornir 3.0.0

Unless there is a mistake in the documentation or i realy miss understood something don’t you find it strange that, the comment in the documentation says that the output of leaf01_bma[“domain”] comes from global ?

leaf01_bma = nr.inventory.hosts[“leaf01.bma”]
leaf01_bma[“domain”] # comes from the group global

I actually have the same behavior than you when setting a default file. Without the default file it works as expected. I have the same understanding than you, it does not look to be the expected behavior to me.
Next step would be to open an issue on the github repo (unless somebody else has an idea?) to make sure it is a bug and have this fixed.

Great !
I freaked out when you said that it was ok for you hahaha.
i’ve looked through many topic before posting this but, nothing concerning this.

i took a quick look at gitbut earlier but couldn’t find anything neither
I will intensify the research if no one has a solution or an explanation
Thanks again lemontree

I see what you mean. If you modify some code in “nornir/plugins/inventory/simple.py” from

for n, g in groups_dict.items():
    groups[n] = _get_inventory_element(Group, g, n, defaults)

to

for n, g in groups_dict.items():
  groups[n] = _get_inventory_element(Group, g, n, Defaults())

then inheritance “appears” to work as you expected :man_shrugging:

Though that breaks test_simple_inventory.py :slight_smile:

The fix might be modifying the _resolve_data function in inventory.py

for k, v in g.items():

to

for k, v in g.data.items():

Although that breaks tests/core/test_inventory.py for some reason.

Hello,

I’ve been trying to solve this abnormal behaviours (at least to me) for the last few days, but my python knowledge aren’t that great :sweat_smile:

This does work but i believe it’s not ‘right’.

I see what you mean. If you modify some code in “nornir/plugins/inventory/simple.py” from

for n, g in groups_dict.items():
    groups[n] = _get_inventory_element(Group, g, n, defaults)

to

for n, g in groups_dict.items():
  groups[n] = _get_inventory_element(Group, g, n, Defaults())

As the variable named ‘default’ should at least contains the output of :

defaults = _get_defaults(defaults_dict)

Variable that is normaly ‘set’ when we do have a defaults.yaml file :

def load(self) -> Inventory:

        yml = ruamel.yaml.YAML(typ="safe")

        if self.defaults_file.exists():

            with open(self.defaults_file, "r") as f:

                defaults_dict = yml.load(f) or {}

            defaults = _get_defaults(defaults_dict)

        else:

            defaults = Defaults()

By updating this line :
groups[n] = _get_inventory_element(Group, g, n, defaults)
to
groups[n] = _get_inventory_element(Group, g, n, Defaults())

We nullify this line :

defaults = _get_defaults(defaults_dict)

Thanks

Yeah, modifying simple.py wasn’t much of a solution, ignore it, just a hack that appeared to work. I think modifying the _resolve_data function nornir/core/inventory.py as mentioned above is the way to go.

Here is what i did :sweat_smile:

  • pip3 uninstall nornir
  • pip3 install nornir
  • Update the inventory.py files as below :

    And i still have the same problem

Bugger. Its either a lot more complicated than I thought, or so simple I’ve missed it. If someone else beats me to it then great, otherwise, I will try again, this time not blindly bashing away without any source control. We could log a bug as suggested but this is more fun.

Okay. I think I have it now :slight_smile:

nornir/core/inventory.py

In _resolve_data function

    for g in self.groups:
        for k, v in g.data.items():
            if k not in processed:
                processed.append(k)
                result[k] = v

        for pg in g.groups:
            for k, v in pg.data.items():
                if k not in processed:
                    processed.append(k)
                    result[k] = v

In __getitem__ function

        for g in self.groups:
            try:
                r = g.data[item]
                return r
            except KeyError:
                pass

            for pg in g.groups:
                try:
                    r = pg.data[item]
                    return r
                except KeyError:
                    pass

It works, but is it correct? I’ve created an issue in github so we can get the experts involved.

All right !
I’ll have a closer look on what you’ve done and let you know if i find something.
Thanks for openning an issue on Github.

See u