While most of the vendors and their platforms (including DellEMC) are having Ansible modules published, but there are instances where functionality you’re trying to use isn’t covered in the available module or simply modules aren’t available at all.
In such situations you’ve no choice than using Ansible URI module. It allows you to interact with HTTP and HTTPS web services, in this particular example REST API endpoints to be precise. There are several benefits of using URI module with REST API, including but not limited to
- Perform automation if there’s no Ansible module available
- Use functionality that hasn’t been implemented in Ansible modules
- Easier to redeploy your workflow to another automation tool
While I was using the URI module I came across issue of data parsing for REST API response payload. In case of Dell EMC platforms response payload is in JSON and based on the API endpoint response can be 1000s of lines. It’s very difficult to make sense of this data and also process the same in ansible to extract required information. In this blog post I am trying to list down the process I’ve followed to parse the JSON data and extract the required information.
Below is the sample playbook having uri module. In this example we’re talking about GET call for sample URI endpoint – which is getting device details of the existing server (BMaaS use case).
tasks:
- name: listdevices
uri:
url: https://api.sample.com/base/version/endpoint
method: GET
validate_certs: no
headers:
X-Auth-Token: "{{ api_key }}"
status_code: 200
register: output
- name: printoutput
ansible.builtin.debug:
var: output
In this playbook there are multiple parameters used under uri task. More on using uri module with REST API coming in another blog post.
In above example you can see that we’ve registering the output and then printing the same. Problem with this is there could be 100s of lines which probably doesn’t make sense. So for parsing this data we will need
Below is the sample of the GET call JSON response.
[
{
"id": "2b12858454174f03aece5a71bb382318",
"name": "Drive_0_0_11",
"extra_details": {
"firmware_version": "GPJ99E5Q",
"drive_type": "NVMe_SSD",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_Level_1",
"size": 3840755982336
}
},
{
"id": "2dd2c43f2582415585a9ce0bbb961a4f",
"name": "Drive_0_0_0",
"extra_details": {
"firmware_version": "GPJ99E5Q",
"drive_type": "NVMe_SSD",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_Level_1",
"size": 3840755982336
}
},
{
"id": "325e5abc34ed4be398715285cf2e2826",
"name": "Drive_0_0_8",
"extra_details": {
"firmware_version": "GPJ99E5Q",
"drive_type": "NVMe_SSD",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_None",
"size": 3840755982336
}
},
{
"id": "3c9449f55ade4c04a801e804f3872eff",
"name": "Drive_0_0_5",
"extra_details": {
"firmware_version": "GPJ99E5Q",
"drive_type": "NVMe_SSD",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_None",
"size": 3840755982336
}
},
{
"id": "426d706ef7d443a887a450e6ac4abed5",
"name": "Drive_0_0_23",
"extra_details": {
"firmware_version": "3.0.45.6",
"drive_type": "NVMe_NVRAM",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_None",
"size": 8484552704
}
},
{
"id": "42f2145cc5ef4a5f86ec1dfe8bdc5ca3",
"name": "Drive_0_0_24",
"extra_details": {
"firmware_version": "3.0.45.6",
"drive_type": "NVMe_NVRAM",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_None",
"size": 8484552704
}
},
{
"id": "4ed0b8b74eff4113ad85ded6f342ab34",
"name": "Drive_0_0_6",
"extra_details": {
"firmware_version": "GPJ99E5Q",
"drive_type": "NVMe_SSD",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_None",
"size": 3840755982336
}
},
{
"id": "5bca4db416c342ebab6d3b795c604963",
"name": "Drive_0_0_2",
"extra_details": {
"firmware_version": "GPJ99E5Q",
"drive_type": "NVMe_SSD",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_None",
"size": 3840755982336
}
},
{
"id": "6eb66e909f4b414193922e4de63cfa9f",
"name": "Drive_0_0_1",
"extra_details": {
"firmware_version": "GPJ99E5Q",
"drive_type": "NVMe_SSD",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_None",
"size": 3840755982336
}
},
{
"id": "b413b5e98e6245b58134c0d5a8d001e1",
"name": "Drive_0_0_7",
"extra_details": {
"firmware_version": "GPJ99E5Q",
"drive_type": "NVMe_SSD",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_None",
"size": 3840755982336
}
},
{
"id": "bae7ed28120e43a8b322b8d8b2fedc0d",
"name": "Drive_0_0_10",
"extra_details": {
"firmware_version": "GPJ99E5Q",
"drive_type": "NVMe_SSD",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_None",
"size": 3840755982336
}
},
{
"id": "bea9d084e49248359e3191d8f648a37c",
"name": "Drive_0_0_3",
"extra_details": {
"firmware_version": "GPJ99E5Q",
"drive_type": "NVMe_SSD",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_None",
"size": 3840755982336
}
},
{
"id": "f3af5ea2e84d4181a9068c6e85c4b750",
"name": "Drive_0_0_4",
"extra_details": {
"firmware_version": "GPJ99E5Q",
"drive_type": "NVMe_SSD",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_None",
"size": 3840755982336
}
},
{
"id": "fca0678677cf48f5a51c28ea1e47b514",
"name": "Drive_0_0_9",
"extra_details": {
"firmware_version": "GPJ99E5Q",
"drive_type": "NVMe_SSD",
"encryption_status": "Supported_Locked_Cluster_PIN",
"fips_status": "FIPS_Compliance_None",
"size": 3840755982336
}
}
]
In above JSON example if I have to extract only name and id from the JSON, then we will need to parse the data in playbook as a separate task. Sample task is as mentioned below.
- name: devicenames
set_fact:
devicenames: "{{ devices | json_query(jmesquery) }}"
vars:
jmesquery: '*.devices[*].[name, id]'
So, overall the playbook will look like below
---
- hosts: localhost
gather_facts: no
tasks:
- name: getdevices
uri:
url: https://<target_api_server>/v1/definition/endpoint
method: GET
#body_format: json
validate_certs: no
headers:
X-Auth-Token: "{{ api_key }}"
#body:
#- [ name, your_username ]
#- [ password, your_password ]
#- [ enter, Sign in ]
status_code: 200
register: devices
#- name: save the json as variable
# set_fact:
# jsondata: "{{ devices.stdout | from_json }}"
- name: devicenames
set_fact:
devicenames: "{{ devices | json_query(jmesquery) }}"
vars:
jmesquery: '*.devices[*].[hostname, id]'
- name: print devicenames
debug:
msg: "{{ item }}"
with_items:
- "{{ devicenames }}"
In this example I’ve printed the captured device value. But in real life scenario it can be captured as a variable and use as input for subsequent tasks.