07 November 2014


I has been asked be our network operation department to help with mass configuration changes of the Mikrotik routers. I should provide shell scripts for some specific tasks as

  • generating configuration from template
  • apply generated configruarion
  • run specific command

Instead of writting scripts in my favorite language I decided to use ansible.

Some notes

If you are familiar with the ansible and mikrotik just skip this section. You will find here my


Ansible is able to generate configuration files based on the templates and the variables associated with the manages device. This is really common usage of the ansible.

The only problem is that there is no moduel able to handle [miktortik] routers. Even the raw module is not working, it requires shell.

[node-test] => {"rc": 127}
stderr: /bin/sh: /file: No such file or directory



You need a paid license to get this working. Trial Mode or Free Demo show reminder banner and it need additional Enter to get shell.

In our environment the ssh is running on non standard port, the admin user is not admin and all other services, like telnet or ftp are disabled.

Howto put it together


  • device configuration must contain at least one user with the assigned ssh key
  • loaded the private part of the ssh key in ssh-agent

Reason for this is module command and local ssh and scp commands. In this setup the ansible -k switch is not functional as I do not known how to pass it to the command.

Ansible hosts

The management server is able to access the devices only by the IP so we need to use host variables to define it’s IP. For this purpose I used ansible_ssh_host. As the ssh port is not 22 I defined the port in variable ansible_ssh_portand the admin user in ansible_ssh_user.

Finally my hosts file looks like

node_ansible_001 ansible_ssh_port=2022 ansible_ssh_user=ansible ansible_ssh_host=
node_ansible_002 ansible_ssh_port=2022 ansible_ssh_user=ansible ansible_ssh_host=

Ansible playbook

I will write only the playbook for the configuration part while there are all other use cases.

- hosts: all
  connection: local
  gather_facts: no

    template: "name of the template file"

  - name: "generate script from template"
    action: template src=templates/{{ template }}.j2 dest=template_configs/{{ inventory_hostname }}_{{ template }}.rsc backup=no
    tags: generate

  - name: "copy script on device"
    action: command scp -P {{ ansible_ssh_port }} template_configs/{{ inventory_hostname }}_{{ template }}.rsc {{ ansible_ssh_user }}@{{ ansible_ssh_host }}:ansible_{{ template }}.rsc
    tags: import

  - name: "import script on device"
    action: command ssh -p {{ ansible_ssh_port }} {{ ansible_ssh_user }}@{{ ansible_ssh_host }} "/import verbose=yes ansible_{{ template }}.rsc"
    tags: import
    register: import_result

  - name: "import script on device failed"
    action: fail msg="importing script ansible_{{ template }}.rsc on {{ inventory_hostname }} failed"
    tags: import
    when: "'failure:' in import_result.stdout"

  - name: "remove script from device"
    action: command ssh -p {{ ansible_ssh_port }} {{ ansible_ssh_user }}@{{ ansible_ssh_host }} "/file remove ansible_{{ template }}.rsc"
    tags: cleanup

  - name: "remove script from  configs directory"
    action: file path=template_configs/{{ inventory_hostname }}_{{ template }}.rsc state=absent
    tags: cleanup

Some notes

As you can see all task are local and I user the ansible_ssh_ variables as parameters to ssh and scp command. Of course you can use any variables passed in group or host configuration files instead of these predefined one.

I was trying to setup remote_port and remote_user in ansible.cfg as defaults but I was not able to pass them as parameters in tasks.