Hello my friend,
Thanks to my friends I have a chance to take part in a project, where we are heavily using Ansible for various tasks in real network. When there are several people working on a joint project, some rules are needed in order playbooks are consistent. We have taken Ansible roles as rules. And I realized that I should have used them for my examples from the very beginning.
1 2 3 4 5 | No part of this blogpost could be reproduced, stored in a<br> retrieval system, or transmitted in any form or by any<br> means, electronic, mechanical or photocopying, recording,<br> or otherwise, for commercial purposes without the<br> prior permission of the author.<br> |
Brief description
What are roles? Frankly speaking, for me it was not clear from the very beginning, what it is. I was thanking, probably roles refer to a user type or something similar, like role of the user in configuration of the device based on the privilege level. Well, it was my network background speaking. In reality roles is just a decomposition of the playbook to certain pieces, and structuring them in different folders with certain name conventions. In the official documentations the following info is provided:
– If roles/x/tasks/main.yml exists, tasks listed therein will be added to the play. – If roles/x/handlers/main.yml exists, handlers listed therein will be added to the play. – If roles/x/vars/main.yml exists, variables listed therein will be added to the play. – If roles/x/defaults/main.yml exists, variables listed therein will be added to the play. – If roles/x/meta/main.yml exists, any role dependencies listed therein will be added to the list of roles (1.3 and later). – Any copy, script, template or include tasks (in the role) can reference files in roles/x/{files,templates,tasks}/ (dir depends on task) without having to path them relatively or absolutely. |
Let’s see how we can use this information to improve our automation scripts
What we are going to test?
We will rebuild the playbook from the article about Ansible as VNF-M to utilise role. If it is possible, some modifications will be done to make usage of those playbooks more usefull.
Software version
The following components are used for the current lab:
- CentOS 7 with python 2.7.
- Ansible 2.4.2
- Nokia (Alcatel-Lucent) SR OS 15.0.R7
- Cisco IOS XRv
See the previous article to get details how to build the lab
Topology
There is no particular topology necessary for this lab, so we will use the same topology as we did in Ansible as VNF-M article:
As we are using Ansible to deploy virtual Nokia (Alcatel-Lucent) VSR and Cisco IOS XRv routers, there are no particular initial configuration files.
Utilizing roles to create playbook
Read the previous article about Ansible as VNF-M to get understanding, what the scope of the activities is.
What we are going to do in the present article is to combine in the single playbook possibility to deploy/undeploy both Nokia (Alcatel-Lucent) VSR and Cisco IOS XRv by adding corresponding keys. So the playbook is to be capable to understand keyword and act properly. Here we go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | $ cat 108_lab.yml<br> ---<br> - hosts: linux<br> connection: local<br> tags: cisco_on<br> roles:<br> - { role: linux/108_lab, var_vendor: cisco, var_operation: deploy }<br> - hosts: linux<br> connection: local<br> tags: nokia_on<br> roles:<br> - { role: linux/108_lab, var_vendor: nokia, var_operation: deploy }<br> - hosts: linux<br> connection: local<br> tags: cisco_off<br> roles:<br> - { role: linux/108_lab, var_vendor: cisco, var_operation: undeploy }<br> - hosts: linux<br> connection: local<br> tags: nokia_off<br> roles:<br> - { role: linux/108_lab, var_vendor: nokia, var_operation: undeploy }<br> ...<br> |
We have in this playbook four roles, which performs the following operations:
- Deploy Nokia (Alcatel-Lucent) VSR
- Deploy Cisco IOS XRv
- Deploy Nokia (Alcatel-Lucent) VSR
- Deploy Cisco IOS XRv
If you don’t mention keyword by the launch, all the tasks will be performed sequentially resulting in zero result, as all VMs are deployed and undeployed. To make use of this playbook, we launch it with certain tag:
1 | $ ansible-playbook 108_lab.yml --tags nokia_on |
Then it matched against tag field, within each entry and will launch only corresponding entry. You see, our role is located in folder “linux/108_lab”, which is located in “roles”. Besides launching the playbook, we also push some variables to it (var_vendor, var_operation), which are used further for launching proper tasks and opening proper files.
Let’s review the structure of the folders:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <br> $ ls -lR roles/linux/108_lab/<br> roles/linux/108_lab/:<br> total 0<br> drwxrwxr-x. 2 aaa aaa 27 Mar 11 18:31 files<br> drwxrwxr-x. 2 aaa aaa 51 Mar 12 07:58 tasks<br> drwxrwxr-x. 2 aaa aaa 80 Mar 11 15:13 templates<br> drwxrwxr-x. 2 aaa aaa 56 Mar 11 18:25 vars<br> roles/linux/108_lab/files:<br> total 4<br> -rwxr-xr-x. 1 aaa aaa 178 Mar 11 18:31 magic_wand.py<br> roles/linux/108_lab/tasks:<br> total 12<br> -rw-rw-r--. 1 aaa aaa 301 Mar 12 07:58 main.yml<br> -rw-rw-r--. 1 aaa aaa 912 Mar 11 22:14 off.yml<br> -rw-rw-r--. 1 aaa aaa 2758 Mar 11 22:14 on.yml<br> roles/linux/108_lab/templates:<br> total 8<br> -rwxrwxrwx. 1 aaa aaa 2949 Mar 11 15:12 template-cisco-iosxr-6.1.2.j2<br> -rwxrwxrwx. 1 aaa aaa 2640 Mar 11 15:13 template-nokia-sros-15.0R7.j2<br> roles/linux/108_lab/vars:<br> total 8<br> -rwxrwxrwx. 1 aaa aaa 1087 Mar 11 18:20 new_vnf_cisco.yml<br> -rwxrwxrwx. 1 aaa aaa 1399 Mar 11 15:18 new_vnf_nokia.ym<br> |
Following guidelines form official Ansible documentation (link), we create 4 folders in our role folder:
- “files” to handle all files, we utilize additionally in our script
- “tasks” to store all tasks, including default
- “templates” to store all templates we use in this playbook
- “vars” contain all values, we need to import for our tasks
Let’s review them!
#1. Tasks
Let’s start straight with the task file, which are loaded by default, which is “main.yml”:
1 2 3 4 5 6 7 8 9 10 11 12 | <br> $ cat roles/linux/108_lab/tasks/main.yml<br> - name: READING VNF DATA // {{ var_vendor }}<br> include_vars:<br> file: new_vnf_{{ var_vendor }}.yml<br> name: VM1<br> - name: PERFORMING ONBOARDING<br> include_tasks: on.yml<br> when: var_operation == "deploy"<br> - name: PERFORMING UNDEPLOYING<br> include_tasks: off.yml<br> when: var_operation == "undeploy"<br> |
The first activity in the tasks imports vendor-dependent variables, by calling file that contains value of “{{ var_vendor }}” value, which is usual operation for parametrisation.
Point out, you don’t need to include absolute or relative path to file. That works for files with variables from “vars” folder in case of roles.
Then depending on operation type, whether we want to deploy or undeploy VM with Nokia (Alcatel-Lucent) VSR or Cisco ISO XRv, we add appropriate tasks. Those files are modifications of “transformer_on.yml” and “transformer_off,yml” we had previously.
For onboarding of VNFs the additional file looks like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | <br> $ cat roles/linux/108_lab/tasks/on.yml<br> - name: COPYING VM IMAGE TO PROPER DIRECTORY<br> copy:<br> src: "{{ VM1.nfvo.vnfd.vdu.image_path.source }}/default-image-{{ VM1.nfvo.vnfd.vendor }}-{{ VM1.nfvo.vnfd.os }}-{{ VM1.nfvo.vnfd.version }}.qcow2"<br> dest: "{{ VM1.nfvo.vnfd.vdu.image_path.destination }}/{{ VM1.nfvo.vnfd.vdu.image_name }}"<br> become: yes<br> - name: DEFINE VM IN KVM // {{ var_vendor }}<br> virt:<br> name: "{{ VM1.nfvo.vnfd.hostname }}"<br> command: define<br> xml: "{{ lookup('template', 'template-cisco-iosxr-6.1.2.j2') }}"<br> become: yes<br> when: var_vendor == "cisco"<br> - name: DEFINE VM IN KVM // {{ var_vendor }}<br> virt:<br> name: "{{ VM1.nfvo.vnfd.hostname }}"<br> command: define<br> xml: "{{ lookup('template', 'template-nokia-sros-15.0R7.j2') }}"<br> become: yes<br> when: var_vendor == "nokia"<br> - name: LAUNCHING {{ VM1.nfvo.vnfd.hostname }} ON KVM<br> virt:<br> name: "{{ VM1.nfvo.vnfd.hostname }}"<br> state: running<br> become: yes<br> - name: UPDATING ANSIBLE HOSTS FOR {{ VM1.nfvo.vnfd.hostname }}<br> lineinfile:<br> path: /etc/ansible/hosts<br> regexp: '{{ VM1.nfvo.vnfd.hostname }}'<br> line: '{{ VM1.nfvo.vnfd.hostname }}'<br> insertafter: '^\[{{ VM1.nfvo.vnfd.vendor }}\]'<br> become: yes<br> - name: UPDATING LINUX HOSTS FOR {{ VM1.nfvo.vnfd.hostname }}<br> lineinfile:<br> path: /etc/hosts<br> regexp: '{% for iface in VM1.nfvo.vnfd.vdu.interfaces %}{% if iface.connection_point == "br0" %}{{ iface.address }}{% endif %}{% endfor %}'<br> line: '{% for iface in VM1.nfvo.vnfd.vdu.interfaces %}{% if iface.connection_point == "br0" %}{{ iface.address }}{% endif %}{% endfor %} {{ VM1.nfvo.vnfd.hostname }}'<br> become: yes<br> - name: WAITING FOR {{ VM1.nfvo.vnfd.hostname }} TO BOOT<br> pause:<br> seconds: "{{ VM1.nfvo.vnfd.vdu.bootup_time }}"<br> - name: ONLY FOR {{ VM1.nfvo.vnfd.vendor }} // MAKING ROUTER REACHABLE ON CLI<br> script: magic_wand.py<br> when: ( VM1.nfvo.vnfd.vendor == "cisco" and VM1.nfvo.vnfd.os == "iosxr" )<br> - name: ONLY FOR {{ VM1.nfvo.vnfd.vendor }} // CONFIGURING OOB INTERFACE<br> telnet:<br> host: "{{ VM1.nfvo.vnfd.vdu.console.address }}"<br> port: 3517<br> user: cisco<br> password: cisco<br> pause: 1<br> login_prompt: "Username: "<br> prompts:<br> - "[>|#]"<br> command:<br> - configure terminal<br> - ssh server v2<br> - ssh server vrf MGMT<br> - ssh server netconf vrf MGMT<br> - netconf-yang agent<br> - ssh<br> - vrf MGMT<br> - address-family ipv4 unicast<br> - interface MgmtEth0/0/CPU0/0<br> - ipv4 address {% for iface in VM1.nfvo.vnfd.vdu.interfaces %}{% if iface.connection_point == "br0" %}{{ iface.address }}/{{ iface.netmask }}{% endif %}{% endfor %}<br> - no shutdown<br> - vrf MGMT<br> - control-plane<br> - management-plane<br> - out-of-band<br> - vrf MGMT<br> - interface MgmtEth0/0/CPU0/0<br> - allow SSH<br> - allow NETCONF<br> - commit<br> - clear<br> - exit<br> when: ( VM1.nfvo.vnfd.vendor == "cisco" and VM1.nfvo.vnfd.os == "iosxr" )<br> |
Comparing to previous version, we utilize template for VNF definition in much more elegant way without converting it to YAML. We do it on a cost of creation of two tasks for defining VNF, which compare “var_vendor” value coming from initial call.
One additional change you might spot in the last task (and in the task for updating hosts), where management IPv4 address of VNF is defined through more complex construction than it was previously. In the next sub chapter you will see the difference in variables. The rest of the playbook is the same
Alternatively we can make comparison against “VM1.nfvo.vnfd.vendor” variable.
For dismantling the VNFs we have:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <br> $ cat roles/linux/108_lab/tasks/off.yml<br> - name: DESTROYING {{ VM1.nfvo.vnfd.hostname }} IN KVM<br> virt:<br> name: "{{ VM1.nfvo.vnfd.hostname }}"<br> command: destroy<br> become: yes<br> - name: UNDEFINING {{ VM1.nfvo.vnfd.hostname }} IN KVM<br> virt:<br> name: "{{ VM1.nfvo.vnfd.hostname }}"<br> command: undefine<br> become: yes<br> - name: DELETING {{ VM1.nfvo.vnfd.hostname }} IMAGE FROM LIBRARY<br> file:<br> path: "{{ VM1.nfvo.vnfd.vdu.image_path.destination }}/{{ VM1.nfvo.vnfd.vdu.image_name }}"<br> state: absent<br> become: yes<br> - name: REMOVING {{ VM1.nfvo.vnfd.hostname }} FROM ANSIBLE HOSTS<br> lineinfile:<br> path: /etc/ansible/hosts<br> regexp: '{{ VM1.nfvo.vnfd.hostname }}'<br> state: absent<br> become: yes<br> - name: REMOVING {{ VM1.nfvo.vnfd.hostname }} FROM LINUX HOSTS<br> lineinfile:<br> path: /etc/hosts<br> regexp: '{% for iface in VM1.nfvo.vnfd.vdu.interfaces %}{% if iface.connection_point == "br0" %}{{ iface.address }}{% endif %}{% endfor %} {{ VM1.nfvo.vnfd.hostname }}'<br> state: absent<br> become: yes<br> |
There is no changes at all comparing to initial Ansible-playbook, besides changes in the hosts file update.
#2. Vars
As you see in the output of the folder listing previously, we have here our VNF description files, which are used for VNF definition. Here is the output of Nokia (Alcatel-Lucent) VSR definition:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | <br> $ cat roles/linux/108_lab/vars/new_vnf_nokia.yml<br> ---<br> nfvo:<br> vnfd:<br> hostname: VSR7<br> vendor: nokia<br> os: sros<br> version: 15.0R7<br> vdu:<br> vcpus: 4<br> memory_b: 4194304<br> disk_size_gb: 1<br> image_name: VSR7-nokia-sros-15.0R7.qcow2<br> image_path:<br> source: ~/temp<br> destination: /var/lib/libvirt/images<br> bootup_time: 180<br> license:<br> file: sros15.lic<br> path: 192.168.1.1<br> username: nokia<br> password: nokianokia<br> chassis:<br> type: VSR-I<br> slot:<br> id: 0<br> type: A<br> card:<br> id: 0<br> type: cpm-v<br> mda1:<br> id: 1<br> type: m20-v<br> mda2:<br> id: 2<br> type: isa-tunnel-v<br> interfaces:<br> - id: 0<br> physical_interface: vnet0<br> network_name: Management<br> connection_point: br0<br> mac: 00:A1:00:15:07:00<br> address: 192.168.1.107<br> netmask: 24<br> vnic_type: virtio<br> - id: 1<br> physical_interface: vnet1<br> network_name: Data1<br> connection_point: br1<br> mac: 00:A1:00:15:07:01<br> vnic_type: virtio<br> - id: 2<br> physical_interface: vnet2<br> network_name: Data2<br> connection_point: br2<br> mac: 00:A1:00:15:07:02<br> vnic_type: virtio<br> console:<br> address: 0.0.0.0<br> port: 2517<br> |
You see that description of interfaces looks different now. Such model is called dictionary in Ansible and is actively used for templates, where same set of fields have different values many times. Just in the next sub chapter will see the advantage of such model.
For Cisco, refer to the original article. The changes regarding interfaces are the same
#3. Templates
Here we have templates that are used for definition of VNFs. That’s actually the same XML files we created in the article about Ansible as VNF-M last time, with updates for interface creation part and IP address definition for BOF. Besides those changes we also have changed the extension from “.xml” to “.j2”:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | $ cat roles/linux/108_lab/templates/template-nokia-sros-15.0R7.j2<br> <domain type='kvm'><br> <name>{{ VM1.nfvo.vnfd.hostname }}</name><br> <uuid></uuid><br> <memory>{{ VM1.nfvo.vnfd.vdu.memory_b }}</memory><br> <currentMemory>4194304</currentMemory><br> <cpu mode='custom' match='minimum'><br> <model>SandyBridge</model><br> <vendor>Intel</vendor><br> <feature policy='require' name='x2apic'/><br> </cpu><br> <vcpu current='4'>{{ VM1.nfvo.vnfd.vdu.vcpus }}</vcpu><br> <os><br> <type arch='x86_64' machine='rhel6.0.0'>hvm</type><br> <smbios mode='sysinfo'/><br> </os><br> <sysinfo type='smbios'><br> <system><br> <entry name='product'>TIMOS:address={% for iface in VM1.nfvo.vnfd.vdu.interfaces %}{% if iface.connection_point == "br0" %}{{ iface.address }}/{{ iface.netmask }}{% endif %}{% endfor %}@active license-file=ftp://{{ VM1.nfvo.vnfd.vdu.license.username }}:{{ VM1.nfvo.vnfd.vdu.license.password }}@{{ VM1.nfvo.vnfd.vdu.license.path }}/{{ VM1.nfvo.vnfd.vdu.license.file }} slot={{ VM1.nfvo.vnfd.vdu.chassis.slot.type }} chassis={{ VM1.nfvo.vnfd.vdu.chassis.type }} card={{ VM1.nfvo.vnfd.vdu.chassis.slot.card.type }} mda/1={{ VM1.nfvo.vnfd.vdu.chassis.slot.card.mda1.type }} mda/2={{ VM1.nfvo.vnfd.vdu.chassis.slot.card.mda2.type }}</entry><br> </system><br> </sysinfo><br> <clock offset='utc'><br> <timer name='pit' tickpolicy='delay'/><br> <timer name='rtc' tickpolicy='delay'/><br> </clock><br> <devices><br> <emulator>/usr/libexec/qemu-kvm</emulator><br> <disk type='file' device='disk'><br> <driver name='qemu' type='qcow2' cache='none'/><br> <source file='{{ VM1.nfvo.vnfd.vdu.image_path.destination }}/{{ VM1.nfvo.vnfd.vdu.image_name }}'/><br> <target dev='hda' bus='virtio'/><br> </disk><br> {% for iface in VM1.nfvo.vnfd.vdu.interfaces %}<br> <interface type='bridge'><br> <mac address='{{ iface.mac}}'/><br> <source bridge='{{ iface.connection_point}}'/><br> <model type='{{ iface.vnic_type}}'/><br> </interface><br> {% endfor %}<br> <console type='tcp'><br> <source mode='bind' host='{{ VM1.nfvo.vnfd.vdu.console.address}}' service='{{ VM1.nfvo.vnfd.vdu.console.port}}'/><br> <protocol type='{{ VM1.nfvo.vnfd.vdu.console.protocol}}'/><br> <target type='virtio' port='0'/><br> </console><br> </devices><br> </domain><br> |
The construct for definition of the interfaces is the traditional “for” cycle from programming, which is very wide distributed for repetitive actions. So we do not need to define explicitly in template the number of interfaces, rather they will be automatically replicated to the number defined in VNF description module.
#4. Files
Here we have just one file, which is used to make Cisco IOS XRv router reachable on console.
Read article about Ansible as VNF-M.
Verification
As all our examples were about Nokia (Alcatel-Lucent) VSR, here we’ll provide example for Cisco IOS XRv. So we deploy it as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <br> $ ansible-playbook 108_lab.yml --tags cisco_on<br> PLAY [linux] ********************************************<br> TASK [Gathering Facts] **********************************<br> ok: [localhost]<br> TASK [linux/108_lab : READING VNF DATA // cisco] ********<br> ok: [localhost]<br> TASK [linux/108_lab : PERFORMING ONBOARDING] ************<br> included: /home/aaa/ansible/roles/linux/108_lab/tasks/on.yml for localhost<br> TASK [linux/108_lab : COPYING VM IMAGE TO PROPER DIRECTORY] **************<br> changed: [localhost]<br> TASK [linux/108_lab : DEFINE VM IN KVM // cisco] ********<br> changed: [localhost]<br> TASK [linux/108_lab : DEFINE VM IN KVM // cisco] ********<br> skipping: [localhost]<br> TASK [linux/108_lab : LAUNCHING XR7 ON KVM] *************<br> changed: [localhost]<br> TASK [linux/108_lab : UPDATING ANSIBLE HOSTS FOR XR7] ***<br> changed: [localhost]<br> TASK [linux/108_lab : UPDATING LINUX HOSTS FOR XR7] *****<br> changed: [localhost]<br> TASK [linux/108_lab : WAITING FOR XR7 TO BOOT] **********<br> Pausing for 330 seconds<br> (ctrl+C then 'C' = continue early, ctrl+C then 'A' = abort)<br> ok: [localhost]<br> TASK [linux/108_lab : ONLY FOR cisco // MAKING ROUTER REACHABLE ON CLI] ***********<br> changed: [localhost]<br> TASK [linux/108_lab : ONLY FOR cisco // CONFIGURING OOB INTERFACE] *************<br> changed: [localhost]<br> TASK [linux/108_lab : PERFORMING UNDEPLOYING] ***********<br> skipping: [localhost]<br> PLAY [linux] ********************************************<br> TASK [Gathering Facts] **********************************<br> ok: [localhost]<br> PLAY [linux] ********************************************<br> TASK [Gathering Facts] **********************************<br> ok: [localhost]<br> PLAY [linux] ********************************************<br> TASK [Gathering Facts] **********************************<br> ok: [localhost]<br> PLAY RECAP **********************************************<br> localhost : ok=14 changed=7 unreachable=0 failed=0<br> |
After this Ansible playbook is played we can connect to the newly deployed Cisco IOS XRv:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <br> $ ssh cisco@XR7<br> .<br> IMPORTANT: READ CAREFULLY<br> Welcome to the Demo Version of Cisco IOS XRv (the "Software").<br> The Software is subject to and governed by the terms and conditions<br> of the End User License Agreement and the Supplemental End User<br> License Agreement accompanying the product, made available at the<br> time of your order, or posted on the Cisco website at<br> www.cisco.com/go/terms (collectively, the "Agreement").<br> As set forth more fully in the Agreement, use of the Software is<br> strictly limited to internal use in a non-production environment<br> solely for demonstration and evaluation purposes. Downloading,<br> installing, or using the Software constitutes acceptance of the<br> Agreement, and you are binding yourself and the business entity<br> that you represent to the Agreement. If you do not agree to all<br> of the terms of the Agreement, then Cisco is unwilling to license<br> the Software to you and (a) you may not download, install or use the<br> Software, and (b) you may return the Software as more fully set forth<br> in the Agreement.<br> .<br> Please login with any configured user/password, or cisco/cisco<br> .<br> cisco@xr7's password:<br> .<br> RP/0/0/CPU0:ios#<br> |
When we don’t need this VNF anymore, we just easily remove it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <br> $ ansible-playbook 108_lab.yml --tags cisco_off<br> PLAY [linux] ********************************************<br> TASK [Gathering Facts] **********************************<br> ok: [localhost]<br> PLAY [linux] ********************************************<br> TASK [Gathering Facts] **********************************<br> ok: [localhost]<br> PLAY [linux] ********************************************<br> TASK [Gathering Facts] **********************************<br> ok: [localhost]<br> TASK [linux/108_lab : READING VNF DATA // cisco] ********<br> ok: [localhost]<br> TASK [linux/108_lab : PERFORMING ONBOARDING] ************<br> skipping: [localhost]<br> TASK [linux/108_lab : PERFORMING UNDEPLOYING] ***********<br> included: /home/aaa/ansible/roles/linux/108_lab/tasks/off.yml for localhost<br> TASK [linux/108_lab : DESTROYING XR7 IN KVM] ************<br> ok: [localhost]<br> TASK [linux/108_lab : UNDEFINING XR7 IN KVM] ************<br> ok: [localhost]<br> TASK [linux/108_lab : DELETING XR7 IMAGE FROM LIBRARY] **<br> changed: [localhost]<br> TASK [linux/108_lab : REMOVING XR7 FROM ANSIBLE HOSTS] **<br> changed: [localhost]<br> TASK [linux/108_lab : REMOVING XR7 FROM LINUX HOSTS] ****<br> changed: [localhost]<br> PLAY [linux] ********************************************<br> TASK [Gathering Facts] **********************************<br> ok: [localhost]<br> PLAY RECAP **********************************************<br> localhost : ok=11 changed=3 unreachable=0 failed=0<br> |
That’s it! Now we have more convenient script.
Here are the corresponding Ansbile playbooks: 112_lab.tar
Lessons learned
Never step learning, improving your skills and growing further. Each new thing I’ve learned in Ansible helps to create the automation better, easier and therefore useful. Many thanks to @Nikola.Arnoldi for inviting me to the project, where we do cool stuff using Ansbile and I have possibility to master my skills.
And as previously, many thanks to @Nikita.Makaranka on consulting me for json_query and guiding to proper docs.
Guys, you rock!
Conclusion
Once I was asked by one of my colleagues, why do I use the Ansible automation. He tried to use my playbook, but it was not properly documented, so he needed some my assistance. Well, question is fair enough. Each automation is as good as you can use it, so it must be convenient, easy to understand and reliable. On top it must be good documents, so that someone else besides you (or me) can use it. Usage of roles and group_vars allows to create Ansible playbooks more friendly in terms of portability and therefore usability. Jinja2 templates add flexibility and allow the whole structure (VNF in my case) be defined solely by var files. So… Now I think, this VNF manager is more user friendly, but for sure, there is further room for the improvement. Take care and good bye!
P.S.
If you have further questions or you need help with your networks, I’m happy to assist you, just send me message (https://karneliuk.com/contact/). Also don’t forget to share the article on your social media, if you like it.
Support us
BR,
Anton Karneliuk
Hello and thank you for the amazing automation articles.
I’m trying to implement it in my lab and later in production.
I’m using Juniper vRR and want to do deploy and Zero Touch Provisioning using Ansible.
But i’m stuck with configuring management interface via ansible telnet module:
“`
– name: Configure management interface via telnet
telnet:
port: 3517
user: root
pause: 1
login_prompt: ‘login: ‘
prompts:
– “[>|#]”
command:
– cli
– edit
– set system services ssh
– set system root-authentication plain-text-password
– Juniper
– Juniper
– set system services netconf rfc-compliant ssh port 830
– set intermface em0 unit 0 familt inet address 192.168.0.111/24
– commit
“`
I’m getting this error
“`
The full traceback is:
Traceback (most recent call last):
File “/usr/local/lib/python3.6/dist-packages/ansible/executor/task_executor.py”, line 138, in run
res = self._execute()
File “/usr/local/lib/python3.6/dist-packages/ansible/executor/task_executor.py”, line 576, in _execute
result = self._handler.run(task_vars=variables)
File “/usr/local/lib/python3.6/dist-packages/ansible/plugins/action/telnet.py”, line 58, in run
tn.read_until(login_prompt)
File “/usr/lib/python3.6/telnetlib.py”, line 302, in read_until
i = self.cookedq.find(match)
TypeError: a bytes-like object is required, not ‘AnsibleUnicode’
fatal: [192.168.0.95]: FAILED! => {
“msg”: “Unexpected failure during module execution.”,
“stdout”: “”
}
“`
And can’t figure out how to fix it.
Ansible 2.6.0
Python 3.6.5
Ubuntu 18.04
Hi Kirill,
thanks for kind feedback. Have you used also magic_wand.py in advance? As I’ve written in article, when you connect to emulation of serial part “0.0.0.0:3517”, the device expects you press enter, before it shows you login prompt.
BR,
Anton
Yes, I did use magic_wand.py but for some reason the script module didn’t work for me. It just tried to find magic_wand.py in ansible tmp directory which doesn’t exist. So I used a combination of copy and command modules.
Telnet module seems not working with Python3 so for now i removed play with this module and rewrite magic_wand.py:
“`
#!/bin/env python3
import telnetlib
from time import sleep
host = ‘0.0.0.0’
port = 3517
timeout = 10
tn = telnetlib.Telnet(host, port, timeout)
try:
tn.write(‘\r\n’.encode(‘ascii’))
sleep(0.5)
tn.write(‘root\n’.encode(‘ascii’))
sleep(0.5)
tn.write(‘cli\n’.encode(‘ascii’))
sleep(0.5)
tn.write(‘edit\n’.encode(‘ascii’))
sleep(0.5)
tn.write(‘set system services ssh\n’.encode(‘ascii’))
sleep(0.5)
tn.write(‘set system root-authentication plain-text-password\n’.encode(‘ascii’))
sleep(0.5)
tn.write(‘Juniper\n’.encode(‘ascii’))
sleep(0.5)
tn.write(‘Juniper\n’.encode(‘ascii’))
sleep(0.5)
tn.write(‘set system services netconf rfc-compliant ssh port 830\n’.encode(‘ascii’))
sleep(0.5)
tn.write(‘set interface em0 unit 0 family inet address 192.168.0.111/24\n’.encode(‘ascii’))
sleep(0.5)
tn.write(‘commit\n’.encode(‘ascii’))
sleep(0.5)
print(tn.read_very_eager().decode(‘ascii’))
except EOFError:
pass
“`
This works but not so conveniently as your examples.
If you tried this with new ansible which works with Python3 please let me know how did you make it work?
Hi Kirill,
Nope, I have used telnet module with Python 2.7. Have you tried to find something on github on telnet module problem with Python 3?
Well, what you are doing is directly putting commands in Python, what definitely works 🙂
BR,
Anton
I’ll try to use ansible in virtualenv with Python2.7. We’ll see how will it go.
There was an issue on GitHub already https://github.com/ansible/ansible/issues/36199. So I just add a commentary. But nobody checks I guess.
I opened an issue for script module https://github.com/ansible/ansible/issues/43216
And for include_vars module https://github.com/ansible/ansible/issues/43272
With Ansible 2.5.0 and Python 2.7 combo include_vars and telnet seems working now but I run into an issue I can’t fix.
VM is deployed perfectly fine and then the problem part of playbook is:
“`
– name: Copy magic_wand script to host
copy:
src: magic_wand.py
dest: “/home/{{ lookup(‘env’, ‘USER’) }}/”
become: no
– name: Making router reachable via CLI
command: python “/home/{{ lookup(‘env’, ‘USER’) }}/magic_wand.py”
– name: Configure management interface via telnet
telnet:
port: 3517
user: root
pause: 0.5
login_prompt: ‘login: ‘
prompts:
– “[>|#]”
command:
– cli
– edit
– set system services ssh
– set system root-authentication plain-text-password
– Juniper
– Juniper
– set system services netconf rfc-compliant ssh port 830
– set interface em0 unit 0 family inet address 192.168.0.111/24
– commit
“`
magic_wand.py is copied and executed but telnet can’t do it’s work. It just stuck (very long output):
“`
PLAYBOOK: playbook1_deploy.yml *****************************************************************************************************************************
2 plays in playbook1_deploy.yml
PLAY [192.168.0.95] ****************************************************************************************************************************************
META: ran handlers
TASK [kvm : Include vars] **********************************************************************************************************************************
task path: /home/horseinthesky/netprog/Ansible/05_deploy_JunOS_vRR/roles/kvm/tasks/main.yml:1
ok: [192.168.0.95] => {
“ansible_facts”: {
“kvm”: {
“console”: {
“host”: “0.0.0.0”,
“port”: 3517,
“protocol”: “telnet”
},
“cpu”: 4,
“interfaces”: {
“em0”: {
“bridge”: “vrr-ext”,
“type”: “virtio”
}
},
“memory”: 8388608,
“name”: “ansible_vrr”,
“product”: “VRR”,
“vendor”: “Juniper”,
“version”: 16.2
}
},
“ansible_included_var_files”: [
“/home/horseinthesky/netprog/Ansible/05_deploy_JunOS_vRR/roles/kvm/vars/kvm.yml”
],
“changed”: false
}
TASK [kvm : PERFORMING ONBOARDING] *************************************************************************************************************************
task path: /home/horseinthesky/netprog/Ansible/05_deploy_JunOS_vRR/roles/kvm/tasks/main.yml:5
included: /home/horseinthesky/netprog/Ansible/05_deploy_JunOS_vRR/roles/kvm/tasks/on.yml for 192.168.0.95
TASK [kvm : Copy magic_wand script to host] ****************************************************************************************************************
task path: /home/horseinthesky/netprog/Ansible/05_deploy_JunOS_vRR/roles/kvm/tasks/on.yml:26
ESTABLISH SSH CONNECTION FOR USER: horseinthesky
SSH: EXEC sshpass -d10 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 192.168.0.95 ‘/bin/sh -c ‘”‘”‘echo ~horseinthesky && sleep 0′”‘””
(0, ‘/home/horseinthesky\n’, ”)
ESTABLISH SSH CONNECTION FOR USER: horseinthesky
SSH: EXEC sshpass -d10 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 192.168.0.95 ‘/bin/sh -c ‘”‘”‘( umask 77 && mkdir -p “` echo /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962 `” && echo ansible-tmp-1532667583.34-205278060753962=”` echo /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962 `” ) && sleep 0′”‘””
(0, ‘ansible-tmp-1532667583.34-205278060753962=/home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962\n’, ”)
Using module file /home/horseinthesky/venv/py2/local/lib/python2.7/site-packages/ansible/modules/files/stat.py
PUT /home/horseinthesky/.ansible/tmp/ansible-local-2810rliHQ2/tmp6uflqo TO /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962/stat.py
SSH: EXEC sshpass -d10 sftp -o BatchMode=no -b – -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 ‘[192.168.0.95]’
(0, ‘sftp> put /home/horseinthesky/.ansible/tmp/ansible-local-2810rliHQ2/tmp6uflqo /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962/stat.py\n’, ”)
ESTABLISH SSH CONNECTION FOR USER: horseinthesky
SSH: EXEC sshpass -d10 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 192.168.0.95 ‘/bin/sh -c ‘”‘”‘chmod u+x /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962/ /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962/stat.py && sleep 0′”‘””
(0, ”, ”)
ESTABLISH SSH CONNECTION FOR USER: horseinthesky
SSH: EXEC sshpass -d10 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 -tt 192.168.0.95 ‘/bin/sh -c ‘”‘”‘/usr/bin/python /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962/stat.py && sleep 0′”‘””
(0, ‘\r\n{“invocation”: {“module_args”: {“checksum_algorithm”: “sha1”, “get_checksum”: true, “follow”: false, “checksum_algo”: “sha1”, “path”: “/home/horseinthesky/magic_wand.py”, “get_md5”: null, “get_mime”: true, “get_attributes”: true}}, “stat”: {“charset”: “us-ascii”, “uid”: 1000, “exists”: true, “attr_flags”: “e”, “woth”: false, “isreg”: true, “device_type”: 0, “mtime”: 1532667203.275627, “block_size”: 4096, “inode”: 132506, “isgid”: false, “size”: 176, “executable”: false, “isuid”: false, “readable”: true, “version”: “18446744072840967349”, “pw_name”: “horseinthesky”, “gid”: 1000, “ischr”: false, “wusr”: true, “writeable”: true, “mimetype”: “text/plain”, “blocks”: 8, “xoth”: false, “islnk”: false, “nlink”: 1, “issock”: false, “rgrp”: true, “gr_name”: “horseinthesky”, “path”: “/home/horseinthesky/magic_wand.py”, “xusr”: false, “atime”: 1532667203.9316387, “isdir”: false, “ctime”: 1532667203.5236313, “isblk”: false, “wgrp”: true, “checksum”: “b0efca8ecc30ce9f3bbcb486f854d888efefd8f8”, “dev”: 64768, “roth”: true, “isfifo”: false, “mode”: “0664”, “xgrp”: false, “rusr”: true, “attributes”: [“extents”]}, “changed”: false}\r\n’, ‘Shared connection to 192.168.0.95 closed.\r\n’)
Using module file /home/horseinthesky/venv/py2/local/lib/python2.7/site-packages/ansible/modules/files/file.py
PUT /home/horseinthesky/.ansible/tmp/ansible-local-2810rliHQ2/tmprxNSSr TO /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962/file.py
SSH: EXEC sshpass -d10 sftp -o BatchMode=no -b – -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 ‘[192.168.0.95]’
(0, ‘sftp> put /home/horseinthesky/.ansible/tmp/ansible-local-2810rliHQ2/tmprxNSSr /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962/file.py\n’, ”)
ESTABLISH SSH CONNECTION FOR USER: horseinthesky
SSH: EXEC sshpass -d10 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 192.168.0.95 ‘/bin/sh -c ‘”‘”‘chmod u+x /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962/ /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962/file.py && sleep 0′”‘””
(0, ”, ”)
ESTABLISH SSH CONNECTION FOR USER: horseinthesky
SSH: EXEC sshpass -d10 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 -tt 192.168.0.95 ‘/bin/sh -c ‘”‘”‘/usr/bin/python /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962/file.py && sleep 0′”‘””
(0, ‘\r\n{“group”: “horseinthesky”, “uid”: 1000, “changed”: false, “owner”: “horseinthesky”, “state”: “file”, “gid”: 1000, “mode”: “0664”, “path”: “/home/horseinthesky/magic_wand.py”, “invocation”: {“module_args”: {“directory_mode”: null, “force”: false, “remote_src”: null, “_original_basename”: “magic_wand.py”, “path”: “/home/horseinthesky/magic_wand.py”, “owner”: null, “follow”: true, “group”: null, “unsafe_writes”: null, “state”: “file”, “content”: null, “serole”: null, “setype”: null, “dest”: “/home/horseinthesky/”, “selevel”: null, “regexp”: null, “src”: null, “seuser”: null, “recurse”: false, “_diff_peek”: null, “delimiter”: null, “mode”: null, “attributes”: null, “backup”: null}}, “diff”: {“after”: {“path”: “/home/horseinthesky/magic_wand.py”}, “before”: {“path”: “/home/horseinthesky/magic_wand.py”}}, “size”: 176}\r\n’, ‘Shared connection to 192.168.0.95 closed.\r\n’)
ESTABLISH SSH CONNECTION FOR USER: horseinthesky
SSH: EXEC sshpass -d10 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 192.168.0.95 ‘/bin/sh -c ‘”‘”‘rm -f -r /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667583.34-205278060753962/ > /dev/null 2>&1 && sleep 0′”‘””
(0, ”, ”)
ok: [192.168.0.95] => {
“changed”: false,
“checksum”: “b0efca8ecc30ce9f3bbcb486f854d888efefd8f8”,
“dest”: “/home/horseinthesky/magic_wand.py”,
“diff”: {
“after”: {
“path”: “/home/horseinthesky/magic_wand.py”
},
“before”: {
“path”: “/home/horseinthesky/magic_wand.py”
}
},
“gid”: 1000,
“group”: “horseinthesky”,
“invocation”: {
“module_args”: {
“_diff_peek”: null,
“_original_basename”: “magic_wand.py”,
“attributes”: null,
“backup”: null,
“content”: null,
“delimiter”: null,
“dest”: “/home/horseinthesky/”,
“directory_mode”: null,
“follow”: true,
“force”: false,
“group”: null,
“mode”: null,
“owner”: null,
“path”: “/home/horseinthesky/magic_wand.py”,
“recurse”: false,
“regexp”: null,
“remote_src”: null,
“selevel”: null,
“serole”: null,
“setype”: null,
“seuser”: null,
“src”: null,
“state”: “file”,
“unsafe_writes”: null
}
},
“mode”: “0664”,
“owner”: “horseinthesky”,
“path”: “/home/horseinthesky/magic_wand.py”,
“size”: 176,
“state”: “file”,
“uid”: 1000
}
TASK [kvm : Making router reachable via CLI] ***************************************************************************************************************
task path: /home/horseinthesky/netprog/Ansible/05_deploy_JunOS_vRR/roles/kvm/tasks/on.yml:32
ESTABLISH SSH CONNECTION FOR USER: horseinthesky
SSH: EXEC sshpass -d10 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 192.168.0.95 ‘/bin/sh -c ‘”‘”‘echo ~horseinthesky && sleep 0′”‘””
(0, ‘/home/horseinthesky\n’, ”)
ESTABLISH SSH CONNECTION FOR USER: horseinthesky
SSH: EXEC sshpass -d10 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 192.168.0.95 ‘/bin/sh -c ‘”‘”‘( umask 77 && mkdir -p “` echo /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667584.21-187334804190948 `” && echo ansible-tmp-1532667584.21-187334804190948=”` echo /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667584.21-187334804190948 `” ) && sleep 0′”‘””
(0, ‘ansible-tmp-1532667584.21-187334804190948=/home/horseinthesky/.ansible/tmp/ansible-tmp-1532667584.21-187334804190948\n’, ”)
Using module file /home/horseinthesky/venv/py2/local/lib/python2.7/site-packages/ansible/modules/commands/command.py
PUT /home/horseinthesky/.ansible/tmp/ansible-local-2810rliHQ2/tmpqTH0wT TO /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667584.21-187334804190948/command.py
SSH: EXEC sshpass -d10 sftp -o BatchMode=no -b – -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 ‘[192.168.0.95]’
(0, ‘sftp> put /home/horseinthesky/.ansible/tmp/ansible-local-2810rliHQ2/tmpqTH0wT /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667584.21-187334804190948/command.py\n’, ”)
ESTABLISH SSH CONNECTION FOR USER: horseinthesky
SSH: EXEC sshpass -d10 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 192.168.0.95 ‘/bin/sh -c ‘”‘”‘chmod u+x /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667584.21-187334804190948/ /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667584.21-187334804190948/command.py && sleep 0′”‘””
(0, ”, ”)
ESTABLISH SSH CONNECTION FOR USER: horseinthesky
SSH: EXEC sshpass -d10 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 -tt 192.168.0.95 ‘/bin/sh -c ‘”‘”‘sudo -H -S -p “[sudo via ansible, key=jvttixlvptnqhlfrcusmiwxhmevshnww] password: ” -u root /bin/sh -c ‘”‘”‘”‘”‘”‘”‘”‘”‘echo BECOME-SUCCESS-jvttixlvptnqhlfrcusmiwxhmevshnww; /usr/bin/python /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667584.21-187334804190948/command.py'”‘”‘”‘”‘”‘”‘”‘”‘ && sleep 0′”‘””
Escalation succeeded
(0, ‘\r\n\r\n{“changed”: true, “end”: “2018-07-27 07:59:44.500158”, “stdout”: “”, “cmd”: [“python”, “/home/horseinthesky/magic_wand.py”], “rc”: 0, “start”: “2018-07-27 07:59:44.486317”, “stderr”: “”, “delta”: “0:00:00.013841”, “invocation”: {“module_args”: {“warn”: true, “executable”: null, “_uses_shell”: false, “_raw_params”: “python \\”/home/horseinthesky/magic_wand.py\\””, “removes”: null, “argv”: null, “creates”: null, “chdir”: null, “stdin”: null}}}\r\n’, ‘Shared connection to 192.168.0.95 closed.\r\n’)
ESTABLISH SSH CONNECTION FOR USER: horseinthesky
SSH: EXEC sshpass -d10 ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o User=horseinthesky -o ConnectTimeout=10 -o ControlPath=/home/horseinthesky/.ansible/cp/1b79b08566 192.168.0.95 ‘/bin/sh -c ‘”‘”‘rm -f -r /home/horseinthesky/.ansible/tmp/ansible-tmp-1532667584.21-187334804190948/ > /dev/null 2>&1 && sleep 0′”‘””
(0, ”, ”)
changed: [192.168.0.95] => {
“changed”: true,
“cmd”: [
“python”,
“/home/horseinthesky/magic_wand.py”
],
“delta”: “0:00:00.013841”,
“end”: “2018-07-27 07:59:44.500158”,
“invocation”: {
“module_args”: {
“_raw_params”: “python \”/home/horseinthesky/magic_wand.py\””,
“_uses_shell”: false,
“argv”: null,
“chdir”: null,
“creates”: null,
“executable”: null,
“removes”: null,
“stdin”: null,
“warn”: true
}
},
“rc”: 0,
“start”: “2018-07-27 07:59:44.486317”,
“stderr”: “”,
“stderr_lines”: [],
“stdout”: “”,
“stdout_lines”: []
}
TASK [kvm : Configure management interface via telnet] *****************************************************************************************************
task path: /home/horseinthesky/netprog/Ansible/05_deploy_JunOS_vRR/roles/kvm/tasks/on.yml:38
“`
If i try connect to VM manually i would not be succeded. Port is in use untul i Ctrl+C playbook.
“`
horseinthesky@ubuntu:~$ telnet 0.0.0.0 3517
Trying 0.0.0.0…
Connected to 0.0.0.0.
Escape character is ‘^]’.
“`
I guess it do not see login prompt and is waiting for another “Enter”. Do you have any ideas why?
Hi Kirill,
you can try to change “\r\n” for another kind of enter, like “\n” or “\r”.
BR,
Anton