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

New task module for configuring #33

Open
jplitza opened this issue May 21, 2021 · 8 comments
Open

New task module for configuring #33

jplitza opened this issue May 21, 2021 · 8 comments
Labels
enhancement New feature or request

Comments

@jplitza
Copy link
Contributor

jplitza commented May 21, 2021

SUMMARY

Add a new task module that makes it easier to idempotently modify RouterOS config.

ISSUE TYPE
  • Feature Idea
COMPONENT NAME
ADDITIONAL INFORMATION

Currently, it's a huge PITA to idemtpotently modify RouterOS config. My roles have RouterOS script snippets like this all over the place, to be executed via CLI:

:if ([/ip firewall filter find chain=forward action=fasttrack-connection] = "") do={/ip firewall filter add chain=forward action=fasttrack-connection connection-state=established,related ipsec-policy=out,none} else={/ip firewall filter set [find chain=forward action=fasttrack-connection] ipsec-policy=out,none}

This looks for a firewall rule in the forward chain with action "fasttrack-connection". If it finds such a rule, it sets "ipsec-policy=out,none" on it. If it doesn't find such a rule, it adds one.

Obviously it's quite impossible to catch all edge cases (especially ordering etc.), because RouterOS config is damn complex. But I'd imagine something like this:

- community.routeros.config:
    path: /ip firewall filter
    attributes:
      chain: forward
      action: fasttrack-connection
      connection-state: established,related
      ipsec-policy: out,none
    match:
      - chain
      - action

One could also think about adding more parameters, like "place-before" (ideally accepting something like [find ...]), which would obviously only be used for adding, not for updating.

Also, this would make check mode and proper change detection possible.

Or is there a more elegant way to do this?

@felixfontein
Copy link
Collaborator

Currently, it's a huge PITA to idemtpotently modify RouterOS config.

I definitely agree on that. This collection currentl only provides basic modules for talking with RouterOS devices, and nothing more fancy.

I'm not familiar with other networking collections, but I know that people did a lot of work for solving such things. So it's probably worth to investigate what other networking collections do before starting to implement something new :) AFAIK resource modules are currently a big thing. (Unfortunately I forgot the little I knew about what they are...)

@jplitza
Copy link
Contributor Author

jplitza commented May 23, 2021

I'm not familiar with other networking collections, but I know that people did a lot of work for solving such things. So it's probably worth to investigate what other networking collections do before starting to implement something new :) AFAIK resource modules are currently a big thing. (Unfortunately I forgot the little I knew about what they are...)

Okay, so I'll just dump more of my thoughts about this approach:

  • RouterOS has no commits. There is no way to queue a bunch of configuration commands and then commit/execute them. That would make it very easy to e.g. replace a whole firewall/routing filter/..., because you can simply delete the old one, insert the new one and commit. The platform would take care of minimizing the service interruption. Examples of such platforms are JunOS and EdgeOS/VyOS
  • Hence, any change should be made as precise and small as possible, to avoid service interruptions. This prohibits approaches like /ip firewall rem [find]; /ip firewall add ... and often requires the use of set
  • set is inherently difficult to diff to /export, which is another common approach: To see if the desired configuration is contained in the current configuration dump, and if not, apply it somehow.

But you are right, there are other platforms without "commit". Cisco IOS comes to my mind, and indeed they have a bunch of resource modules instead of just one. The generic ios_config modules faces some of the above problems, too (see the example "load new acl into device", where they compare a given sequence of lines to the config dump, and if it's not found they simply delete the whole acl if present and load a new one.) So then there's the ios_acls module for that use case, too, and god it's convoluted. When you look at the first example, you see a no 10 command in between, followed by something that is based on the rule that was already there. This indicates that the module parses the previously present configuration from show running-config and dynamically generates the necessary commands to merge that configuration (if desired by the user). I'm shivering while imagining to parse RouterOS config exports on that level inside Ansible modules.

So yes, having resource modules for every path in the RouterOS config would be ideal (from a user perspective). A routeros_firewall module could replace whole chains of firewall rules with the above technique (maybe with some tricks like set comment="obsolete" [find chain=...]; add ...; rem [find comment=obsolete]). And it would most closely match overall Ansible behavior, whereas my proposal is still quite close to hacking something together on the CLI.

However, I fear this would also require a ridiculous amount of work to write all these modules for this seemingly small community. Then again, maybe it's all a question of smart "templating" of these resource modules. And starting with one (e.g. routeros_firewall) might show how difficult it actually is to implement them.

@NikolayDachev
Copy link
Collaborator

Изходен текст
I have the same idea to implement scripts via api module before a long time however the limitation is in ros api and I was not sure if is even possible, will try to find a time for more research

note: set can be use via "cmd"

also check: https://galaxy.ansible.com/nikolaydachev/routeros_api
in this collection I do a bunch of examples including firewall (check firewall role README)

@felixfontein felixfontein added the enhancement New feature or request label Jul 22, 2021
@jplitza
Copy link
Contributor Author

jplitza commented Sep 8, 2021

I looked a bit more at the resource modules. They are generated/scaffolded by the resource_module_builder. There's also a cli_rm_builder, but they assume a CLI which is probably not what we want: The resource modules work by first fetching the existing configuration of some resource (like "firewall") as facts, comparing them to the wanted configuration and generate commands to migrate from "have" to "want".

This approach might work for RouterOS to some extent (e.g. interfaces, IP addresses), since the RouterOS API gives us nicely formatted JSON data for each such resource. But I haven't seen a good handling of network resources yet where order is relevant. Other network OS have numbers in such cases, like Cisco ACLs or EdgeOS firewall rules. fortios_firewall_policy also don't have explicit ordering, and they solved this via some special "move" command with internal IDs returned by earlier invocations. This could be viable for RouterOS, too, but they apparently don't use the aforementioned resource_module_builder. Also, FortiOS too uses a HTTP API instead of SSH (like iOS and others).

If I'm not mistaken, the first step would be to write a httpapi plugin, analogous to the cliconf plugin we already have. This would make using the API feel more native to Ansible, using the usual host, username and password information instead of module arguments.

But I'm also feeling like there is almost 0 code in this collection that could be reused for this whole adventure.

@jplitza
Copy link
Contributor Author

jplitza commented Jan 18, 2022

To ease the pain at hand, I wrote a role that implements an API in the spirit of what I outlined in my initial post.

@felixfontein
Copy link
Collaborator

At least some of this should be solved by #91.

@jplitza
Copy link
Contributor Author

jplitza commented May 16, 2022

Guess I'll finally have to deal with deploying certificates from a self-hosted CA to all Mikrotiks in order to use the API without transmitting the password in cleartext.

@felixfontein
Copy link
Collaborator

Fortunately Ansible can help with that (community.crypto has all tools to create the PKI, and https://docs.ansible.com/ansible/latest/collections/community/routeros/docsite/api-guide.html#installing-a-certificate-on-a-mikrotik-router shows how to install the certificate with SSH access to the router).

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

No branches or pull requests

3 participants