Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alternative to ansible implicit localhost host #165

Closed
dmfigol opened this issue Jul 2, 2018 · 7 comments
Closed

Alternative to ansible implicit localhost host #165

dmfigol opened this issue Jul 2, 2018 · 7 comments

Comments

@dmfigol
Copy link
Collaborator

dmfigol commented Jul 2, 2018

Ansible has implicit localhost host which you can use as a target for your tasks, or use:

delegate_to: localhost
run_once: true

Currently nornir does not have this concept (but it also does not ship the code to execute remotely) and majority of tasks work on localhost and some establish network connection.
It is a little bit confusing.
E.g., nornir-tools has an example of doing network configuration backup. It runs napalm_get and write_file on a group of networking devices.
But what does it really mean that to run the task write_file on a number of networking devices without digging a lot into doc? Does it mean I will save the file on the networking device filesystem or locally? I need to check docs or sometimes source code to be sure.
Example use-cases associated with localhost:

  • Do something strictly on localhost, like execute shell command, save file, etc.
  • Generate some config file based on variables of another group of hosts (for example, take all existing hosts with their IPs and MACs and use Jinja to generate dhcpd.conf or other file to be consumed by DNS service)
  • Do API calls
  • Modify variables for the existing hosts (mixed feelings here, could be Function, could be Task)

I don't have a good solution in mind for this. May be something like nornir_runner.local_run or nornir_runner.run(local=true) instead of nornir_runner.run? This would allow localhost directly access target's vars.
May be the Task itself must be also LocalTask which could be a subclass of Task.
I also feel that having some kind of implicit Host: localhost could be helpful to keep specific key-value pairs on the fly that don't belong to any other Host or Group

What are your thoughts about this?

@dbarrosop
Copy link
Contributor

Let's start by saying this is not ansible, so if you try to extrapolate everything from ansible without reading the docs you are doomed to be confused.

But what does it really mean that to run the task write_file on a number of networking devices without digging a lot into doc?

Well, if you don't read the docs you can only guess and maybe, only maybe, get it right. But that's why the docs are there :) Take for example the command and remote_command tasks (https://nornir.readthedocs.io/en/latest/plugins/tasks/commands.html) I think it's pretty clear what they do and is way less confusing than using delegate_to, connection_local and other crap like that. Also, it doesn't limit you to one mode as you can combine them as you please.

I need to check docs or sometimes source code to be sure.

Well, reading the docs should be a must :) Checking the source code shouldn't so if something is not clear feel free to raise an issue or a PR to improve them.

I am afraid I don't understand the problem you are describing as the "localhost" mode of ansible is how nornir works and you seem to be proposing solutions to implement exactly that. I was actually thinking in writing a plugin/task/wrapper to allow running code remotely in linux servers but that hasn't been a priority yet.

@ktbyers
Copy link
Collaborator

ktbyers commented Jul 2, 2018

Yes, I am not really seeing an issue here...in Ansible-speak everything by default for Nornir is connection: local.

@dmfigol
Copy link
Collaborator Author

dmfigol commented Jul 2, 2018

I understand your points, just two more things:
1)
https://github.com/nornir-automation/nornir-tools/blob/master/tools/network/backup/backup.py

def backup(task, path):
    r = task.run(
        task=napalm_get,
        getters=["config"],
        severity_level=logging.DEBUG,
    )
    task.run(
        task=write_file,
        filename=f"{path}/{task.host}",
        content=r.result["config"]["running"],
)

We apply this task on a group of networking devices. Don't you find confusing that the first subtask will go to the device and do something (in this case it will collect configuration), but the second task will write the files locally even though the target is a bunch of networking devices? On the first glance (again, without looking into docs), I would assume that it saves the configuration directly on the device, because this is the target.
2) David mentioned that may be at some point there will be tasks to run code remotely, let's imagine this is implemented. What kind of user-facing API would that be?

@ktbyers
Copy link
Collaborator

ktbyers commented Jul 2, 2018

I think point1 is a fair point, but I find Ansible even more confusing here (so I wouldn't want to follow patterns similar to what they do).

I would say the essential item is that the location where tasks are run is dictated by the task. So a 'napalm_' task or a 'netmiko_' task is inherently on the remote network device whereas a write_file task would be a control machine task.

So I would say the problem is how to clearly indicate where a task is being executed (and whether this indication is necessary).

@dmfigol
Copy link
Collaborator Author

dmfigol commented Jul 3, 2018

I am definitely not saying that ansible's approach is good, but I still feel that the current abstraction is not intuitive.

@dbarrosop
Copy link
Contributor

I am closing this ticket. Feel free to reopen if there is anything else to discuss but I think this is just a matter of making sure people understands all the code runs locally and properly document which connection type other tasks utilizes so they are aware when netmiko/paramiko/napalm/others are used with the implications those may have.

@dmfigol
Copy link
Collaborator Author

dmfigol commented Jul 20, 2018

@dbarrosop
On slack you mentioned that you create empty localhost in your inventory to do host-agnostic tasks. Do you think we could add implicit localhost to the inventory? Or it would be too much magic?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants