cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
2395
Views
10
Helpful
6
Replies

Create a ansible play that requires user input

Jerems
Spotlight
Spotlight

Hi dear community,

I am currently playing with Ansible and wondered if it is possible to have a play at the top of my playbook that requires a user input.

The user would need to input a device name so all the following plays will rely on that input to achieve different tasks such as :

  • Retrieving data from Netbox for that particular device
  • Parse registered data from previous task and generate some json,yaml output files
  • Render Jinja2 templates.

At the moment, the device name can be found statically at several places in my playbook and want to let the user to input the device name ony once.

Thanks in advance for your kind help, i wish you a happy end of year.

1 Accepted Solution

Accepted Solutions

Jerems
Spotlight
Spotlight

Hi,

I finaly found a solution/workaround using a python script :

 

#!/opt/homebrew/bin/python3
# -*- coding:utf-8 -*-
########################################################################################################################
# This file is a part of Jeyriku.net
#
# Created: 30.12.2022 15:27:57
# Author: Jeremie Rouzet
#
# Last Modified: 30.12.2022 15:35:42
# Modified By: Jeremie Rouzet
#
# Copyright (c) 2022 Jeyriku.net
########################################################################################################################
# Imports from Json to export datas in Json Format
import json
# Imports from Request to create REST API Call
import requests
# Imports from Jmespath to Filter Json data
import jmespath


# Define Netbox object and correct IP to build REST API Request
netbox = {
   "ip": "127.0.0.1"
}
headers = {
      "Accept" : "application/json",
      "Content-Type" : "application/json",
      "Authorization" : "Token XXXXXXXXXXXXXXXXXXXXXXXXXXX",
   }
devices_path = "/api/dcim/devices"
url = f"https://{netbox['ip']}{devices_path}"


devices = requests.get(url, headers=headers, verify=False, timeout=30).json()  # timeout:30sec
with open('./Python/devices.json', 'w', encoding='utf-8') as f:
    json.dump(devices, f, ensure_ascii=False, indent=4)
    data = jmespath.search('results[*].{Name: name, snmp_loc: custom_fields.snmp_location,IP: primary_ip.address, snmp_com: custom_fields.snmp_community, snmp_srv: custom_fields.snmp_server}', devices)

with open('./Python/results.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)

input_dev = input("Enter the Hostname of the device to be configured: \n")
print(f"Is this what you just said?\n {input_dev}")

print("Started Reading JSON file")
with open('./Python/results.json', "r" , encoding='utf-8') as check_dev:
    print("Converting JSON encoded data into Python dictionary")
    data = json.load(check_dev)

# Search data based on key and value using filter and list method
result = (list(filter(lambda x:x["Name"]== input_dev, data)))
with open("./Python/target_dev.json", "w" , encoding='utf-8') as outfile:
    json.dump(result, outfile)

 

Hope this help some others

 

View solution in original post

6 Replies 6

Claudia de Luna
Spotlight
Spotlight

Hi @Jerems 

Its been a while since I worked with Ansible but here is an example of an interactive playbook (may need "freshening up" depending on your Ansible version).  You can also provide arguments via the command line if that works, depending on how you are executing your playbook.

 

###############################################################################
# This interactive playbook queries for information and action and performs
# the selection Tenant action against the DevNet Sandbox APIC
# EXECUTION:
# ansible-playbook -i hosts aci_tenant_prompt.yml
###############################################################################

- name: ACI Playbook to Perform User Prompted Action on Tenant
  hosts: aci_sandbox
  gather_facts: no

  vars:
    avar: some_var

# Prompt for the Tenant Name and Tenant action
  vars_prompt:
    - name: "tenant_name"
      prompt: "Enter Tenant Name"
      default: "LAX_Tenant"
      private: no

    - name: "tenant_state"
      prompt: "Enter Tenant State (absent | present | query)"
      default: "query"
      private: no

Jerems
Spotlight
Spotlight

Hi @Claudia de Luna,

Thank you so much for your quick reply, let me try this between today or tomorrow and revert to you at that time.

Jerems

Hi @Claudia de Luna 

It works well thank you !

Here is the output:

 

TASK [Gathering Facts] **********************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [pause] ********************************************************************************************************************************************************************************************************************
[pause]
Enter Device Name:
jeyniper01^Mok: [localhost]

TASK [set_fact] *****************************************************************************************************************************************************************************************************************
ok: [localhost]

TASK [debug] ********************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "dev": "jeyniper01"
}

 

You can see from the screenshot below, i gather some parameters from netbox registered as "netbox_devices".

 

---
- name: Prompt for the device to configure
  hosts: localhost
  tasks:
    - pause:
        prompt: "Enter Device Name"
        echo: yes
      register: input_dev
    - set_fact:
        dev: "{{ input_dev.user_input }}"
    - debug:
        var: dev

- name: Config Junos context SNMP
  gather_facts: no
  hosts: all
  connection: local
  become: false
  vars:
    server: "https://127.0.0.1"
    endpoint1: "/api/dcim/devices/?limit=1000"
    netbox_token: "123456789"
  tasks:
    # Make a Netbox API call to retrieve devices'components
    - name: Get Device List from Netbox
      uri:
        url: "{{ server }}{{ endpoint1 }}"
        headers:
          Authorization: "Token {{ netbox_token }}"
          Accept: 'application/json'
        body_format: json
        method: GET
        status_code: [200, 201]
        timeout: 30
        validate_certs: false
        return_content: no
      register: netbox_devices
      run_once: yes

    - name: QueryDeviceName
      ansible.builtin.debug:
        msg: "{{ netbox_devices.json.results | to_json | from_json | community.general.json_query(jmesquery) }}"
      vars:
        jmesquery: "[?name== 'dev' ].{Name: name, snmp_loc: custom_fields.snmp_location, IP: primary_ip.address, snmp_com: custom_fields.snmp_community, snmp_srv: custom_fields.snmp_server}"
      register: device_name

 

I would need the input device "jeyniper01" which is stored as a variable (in var: dev from initial task) to be used and matched in the jmesquery.

I gave it a try like this :

jmesquery: "[?name== 'dev' ].

I even tried like this:

jmesquery: "[?name== {{ dev }} ].

But it doesn't as i was expecting.

Can you please advise ?

Thanks in advance,

Jerems

 

So I'm assuming this works? 

        jmesquery: "[?name=='jeyniper01' ].{Name: name, snmp_loc: custom_fields.snmp_location, IP: primary_ip.address, snmp_com: custom_fields.snmp_community, snmp_srv: custom_fields.snmp_server}"


If so, what I would try next is to build out that string explicitly so that no variable interpretation needs to be done in the query string.  Basically build out a variable called jmesquery_str or something and then pass that entire variable.  
jmesquery: {{ jmesquery_str }}

Having said that its very possible I have no idea what I'm talking about!!

Jerems
Spotlight
Spotlight

Yes this one works correctly.

        jmesquery: "[?name=='jeyniper01' ].{Name: name, snmp_loc: custom_fields.snmp_location, IP: primary_ip.address, snmp_com: custom_fields.snmp_community, snmp_srv: custom_fields.snmp_server}"

Jerems
Spotlight
Spotlight

Hi,

I finaly found a solution/workaround using a python script :

 

#!/opt/homebrew/bin/python3
# -*- coding:utf-8 -*-
########################################################################################################################
# This file is a part of Jeyriku.net
#
# Created: 30.12.2022 15:27:57
# Author: Jeremie Rouzet
#
# Last Modified: 30.12.2022 15:35:42
# Modified By: Jeremie Rouzet
#
# Copyright (c) 2022 Jeyriku.net
########################################################################################################################
# Imports from Json to export datas in Json Format
import json
# Imports from Request to create REST API Call
import requests
# Imports from Jmespath to Filter Json data
import jmespath


# Define Netbox object and correct IP to build REST API Request
netbox = {
   "ip": "127.0.0.1"
}
headers = {
      "Accept" : "application/json",
      "Content-Type" : "application/json",
      "Authorization" : "Token XXXXXXXXXXXXXXXXXXXXXXXXXXX",
   }
devices_path = "/api/dcim/devices"
url = f"https://{netbox['ip']}{devices_path}"


devices = requests.get(url, headers=headers, verify=False, timeout=30).json()  # timeout:30sec
with open('./Python/devices.json', 'w', encoding='utf-8') as f:
    json.dump(devices, f, ensure_ascii=False, indent=4)
    data = jmespath.search('results[*].{Name: name, snmp_loc: custom_fields.snmp_location,IP: primary_ip.address, snmp_com: custom_fields.snmp_community, snmp_srv: custom_fields.snmp_server}', devices)

with open('./Python/results.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=4)

input_dev = input("Enter the Hostname of the device to be configured: \n")
print(f"Is this what you just said?\n {input_dev}")

print("Started Reading JSON file")
with open('./Python/results.json', "r" , encoding='utf-8') as check_dev:
    print("Converting JSON encoded data into Python dictionary")
    data = json.load(check_dev)

# Search data based on key and value using filter and list method
result = (list(filter(lambda x:x["Name"]== input_dev, data)))
with open("./Python/target_dev.json", "w" , encoding='utf-8') as outfile:
    json.dump(result, outfile)

 

Hope this help some others