Ansible 'find' command - print only filenames - module

I am trying to use Ansible find command to delete files with a given pattern. Before executing the delete part, I want to list the files that will be deleted. I want to list only filenames including path. The default debug prints a lot of information
- name: Ansible delete old files from pathslist
find:
paths: "{{ pathslist }}"
patterns:
- "authlog.*"
- "server.log.*"
register: var_log_files_to_delete
- name : get the complete path
set_fact:
files_found_path: "{{ var_log_files_to_delete.files }}"
- debug:
var: files_found_path
This outputs like below
{
"atime": 1607759761.7751443,
"ctime": 1615192802.0948966,
"dev": 66308,
"gid": 0,
"gr_name": "root",
"inode": 158570,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0640",
"mtime": 1607675101.0750349,
"nlink": 1,
"path": "/var/log/authlog.87",
"pw_name": "root",
"rgrp": true,
"roth": false,
"rusr": true,
"size": 335501,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
I tried files_found_path: "{{ var_log_files_to_delete.files['path'] }}" but it generates an error.
How can I print only the paths?
Thank you

The Jinja2 filter map as a parameter attribute to transform a list of dict into a list of a specific attribute of each element (https://jinja.palletsprojects.com/en/2.11.x/templates/#map):
- name : get the complete path
set_fact:
files_found_path: "{{ var_log_files_to_delete.files | map(attribute='path') | list }}"
For more complex data extraction, there is the json_query filter (https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#selecting-json-data-json-queries)

Related

Ansible cisco ios, shutdown interfaces that are not connected

So here is my current playbook
---
- hosts: SWITCHES
gather_facts: no
tasks:
- name: Show Interface Status
ios_command:
commands:
- show int status
register: out
- debug: var=out.stdout_lines
I basically want to take this script, and then disable all the ports in the "notconnect" state, meaning all the ports with nothing connected to them. Is there a way I can add a "when" statement to this, so that when "show interface status" comes back, it looks at all the ports that are not connected and disables them by applying the "shutdown" command to each interface? I think a "when" statement is what I am needing to do, but not sure where to get started with it. Or is there a better way to accomplish this?
Is there a python script that could accomplish this as well?
You should use ios_facts to retrieve a dictionary containing all the interfaces. Then you can iterate over that dictionary to shutdown the interfaces that are not connected.
If you run your playbook using the -vvv switch, you will see the all the variables collected by ios_facts.
I believe in Ansible 2.9 and later, Ansible gathers the actual network device facts if you specify "gather_facts: yes". With Ansible 2.8 or older, you need to use the "ios_facts" module.
---
- hosts: SWITCHES
gather_facts: no
tasks:
- name: gather IOS facts
ios_facts:
- name: Shutdown notconnect interfaces
ios_config:
lines: shutdown
parents: "interface {{ item.key }}"
with_dict: "{{ ansible_net_interfaces }}"
when: item.value.operstatus == "down"
Here is an example from part of a collected "ansible_net_interfaces" variable:
{
"ansible_net_interfaces": {
"GigabitEthernet0/0": {
"bandwidth": 1000000,
"description": null,
"duplex": "Full",
"ipv4": [],
"lineprotocol": "down",
"macaddress": "10b3.d507.5880",
"mediatype": "RJ45",
"mtu": 1500,
"operstatus": "administratively down",
"type": "RP management port"
},
"GigabitEthernet1/0/1": {
"bandwidth": 1000000,
"description": null,
"duplex": null,
"ipv4": [],
"lineprotocol": null,
"macaddress": "10b3.d507.5881",
"mediatype": "10/100/1000BaseTX",
"mtu": 1500,
"operstatus": "down",
"type": "Gigabit Ethernet"
},
"GigabitEthernet1/0/10": {
"bandwidth": 1000000,
"description": "Telefon/PC",
"duplex": null,
"ipv4": [],
"lineprotocol": null,
"macaddress": "null,
"mediatype": "10/100/1000BaseTX",
"mtu": 1500,
"operstatus": "down",
"type": "Gigabit Ethernet"
},
"GigabitEthernet1/0/11": {
"bandwidth": 1000000,
"description": null,
"duplex": null,
"ipv4": [],
"lineprotocol": null,
"macaddress": "10b3.d507.588b",
"mediatype": "10/100/1000BaseTX",
"mtu": 1500,
"operstatus": "down",
"type": "Gigabit Ethernet"
}
}
The value of the "ansible_net_interfaces" variable is a dictionary. Each key in that dictionary is the interface name, and the value is a new dictionary containing new key/value pairs. The "operstatus" key will have a value "down" when the interface is not connected.
Using "with_dict" in the "ios_config" task loops through all top-level key/value pairs in the dictionary, and you can use the variables in each key/value pair by referring to "{{ item.key }}" or "{{ item.value }}".
Using "when" in the "ios_config" task, you set a condition for when the task is to be executed. In this case we only want it to run when "operstatus" has a value of "down".
The "parents" parameter in the "ios_config" task specifies a new section where the configuration is to be entered, in this case the section is the interface configuration mode. The interface name is returned for each interface in the "ansible_net_interfaces" using the "{{ item.key }}" variable.
Refer to Ansibles documentation for these modules to get a better understanding of them:
https://docs.ansible.com/ansible/latest/collections/cisco/ios/ios_facts_module.html
https://docs.ansible.com/ansible/latest/collections/cisco/ios/ios_config_module.html

Ansible debug module print undesired details [duplicate]

I'm trying to get a debug message from the results of a previous loop, but I can't get just the bit that I want from it. Ansible keeps giving me the entire result instead just the line I'm asking for.
Here are the 2 modules I'm using:
- name: Make the curl call
uri:
url: https://www.theurl.com
method: GET
return_content: yes
headers:
XXXX: "xxxxxxxxxx"
loop: "{{ simplelist }}"
register: this
- name: just testing
debug:
msg: "I just want to see: {{ item.json.section.test }}"
loop: "{{ this.results}}"
As you can see from the msg, I'm just trying to output that specific value, but what Ansible gives me is:
{
"ansible_loop_var": "item",
"_ansible_no_log": false,
"item": {
"content_length": "",
"cookies": {},
"via": "1.1 varnish",
"connection": "",
"vary": "Accept-Encoding",
"x_timer": "",
"access_control_allow_methods": "OPTIONS, HEAD, GET, PATCH, DELETE",
"x_cache_hits": "0",
"failed": false,
"access_control_allow_credentials": "true",
"content": blah blah blah,
"json": { the json },
"changed": false,
"msg": "I just want to see: False",
So it is setting the message, as you can see from the last line, and it is getting the correct value, but it's not outputting that message. How can I get just the message to be output? I tested and I know that I can get the value because the msg has False and I tested with doing a fail/when with that value.
What you are seeing looks like a verbose output of ansible-playbook running with the -v[vv] option. You can drop that option to decrease verbosity.
Meanwhile, even in non-verbose mode, and whatever module your are using, when going over a loop, ansible outputs a label for each iteration, roughly looking like the following (watch for the (item=....) part of the screen).
TASK [test] *******************************************************************************
ok: [localhost] => (item={'a': 1, 'b': 2}) => {
"msg": "This is the value of a: 1"
}
ok: [localhost] => (item={'a': 3, 'b': 4}) => {
"msg": "This is the value of a: 3"
}
By default, the label is a the full item your are currently looping over. But you can change this label in the loop_control parameter which can be a little too verbose for complex data structures. If you really want an empty label your can use the following example. But you will still get ok: [server1] => (item=) => prepended to each iteration output.
- name: just testing
debug:
msg: "I just want to see: {{ item.json.section.test }}"
loop: "{{ this.results }}"
loop_control:
label: ""
For more info see limiting loop output with label

Azure DevOps Server: Migrating Test Cases - Expecting end of string error

I am attempting my first migration between two different collections on Azure DevOps Server 2019.
The new collection has a custom inheritance process model.
I am trying to migrate test cases only for now. I would like to migrate test cases, test suites, and test plans.
I have added the configuration as per my understanding, but the migration keeps on failing.
Error message:
migration.exe Warning: 0 : [EXCEPTION] Microsoft.TeamFoundation.WorkItemTracking.Client.ValidationException: Expecting end of string. The error is caused by «BY».
at Microsoft.TeamFoundation.WorkItemTracking.Client.Query.Initialize(WorkItemStore store, String wiql, IDictionary context, Int32[] ids, Int32[] revs, Boolean dayPrecision)
Redacted Processor from the config file below.
Thanks!
"Processors": [
{
"ObjectType": "VstsSyncMigrator.Engine.Configuration.Processing.NodeStructuresMigrationConfig",
"PrefixProjectToNodes": false,
"Enabled": false,
"BasePaths": [
"****\\Market Regulation\\Market Surveillance - Bonds",
"****\\Trading Value Stream"
]
},
{
"ObjectType": "VstsSyncMigrator.Engine.Configuration.Processing.WorkItemMigrationConfig",
"ReplayRevisions": true,
"PrefixProjectToNodes": false,
"UpdateCreatedDate": true,
"UpdateCreatedBy": true,
"UpdateSourceReflectedId": false,
"BuildFieldTable": false,
"AppendMigrationToolSignatureFooter": false,
"QueryBit": "AND [System.AreaPath] = '****\\Market Regulation\\Market Surveillance – Bonds' AND [System.WorkItemType] = 'Test Case' ",
"OrderBit": "ORDER BY [System.Id]",
"Enabled": true,
"LinkMigration": true,
"AttachmentMigration": true,
"AttachmentWorkingPath": "c:\\temp\\WorkItemAttachmentWorkingFolder\\",
"FixHtmlAttachmentLinks": false,
"SkipToFinalRevisedWorkItemType": false,
"WorkItemCreateRetryLimit": 5,
"FilterWorkItemsThatAlreadyExistInTarget": true,
"PauseAfterEachWorkItem": false,
"AttachmentMazSize": 480000000,
"CollapseRevisions": false
}
]
I believe your "OrderBit" syntax is wrong, it should look like this:
"OrderBit": "[System.ChangedDate] desc"
Just adapt it to your situation.

Unable to assign default value to Ansible registered variable based on condition

I try to get modification date using ansible shell module command
stat /proc/1178/stat | grep Modify | cut -d' ' -f2,3
Note: the output of the shell i.e starttime.rc will always be true i.e 0 whether an output is returned or not because of pipe cut -d in the command.
I wish to display the time i.e the result of shell module if it returns output else display "Server NOT RUNNING".
Here is my playbook:
- hosts: test_test
any_errors_fatal: true
user: user1
gather_facts: false
tasks:
- shell: "stat /proc/1178/stat | grep Modify | cut -d' ' -f2,3"
register: starttime
- name: Status of Server
set_fact:
starttime: "{{ starttime | default('Server NOT RUNNING') }}"
- debug:
msg: "STARTTIME:{{ starttime }}"
Below is the verbose output where I'm not getting the expected results.
TASK [shell] ************************************************************************************************************************************************
changed: [10.9.9.111] => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"cmd": "stat /proc/1178/stat | grep Modify | cut -d' ' -f2,3",
"delta": "0:00:00.118151",
"end": "2019-11-08 10:46:28.345448",
"invocation": {
"module_args": {
"_raw_params": "stat /proc/1178/stat | grep Modify | cut -d' ' -f2,3",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"rc": 0,
"start": "2019-11-08 10:46:28.227297",
"stderr": "stat: cannot stat â/proc/1178/statâ: No such file or directory",
"stderr_lines": [
"stat: cannot stat â/proc/1178/statâ: No such file or directory"
],
"stdout": "",
"stdout_lines": []
}
TASK [Status of Server] ****************************************************************************************************************************
task path: /app/script/condition_test.yml:14
ok: [10.9.9.111] => {
"ansible_facts": {
"starttime": {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"cmd": "stat /proc/1178/stat | grep Modify | cut -d' ' -f2,3",
"delta": "0:00:00.118151",
"end": "2019-11-08 10:46:28.345448",
"failed": false,
"rc": 0,
"start": "2019-11-08 10:46:28.227297",
"stderr": "stat: cannot stat â/proc/1178/statâ: No such file or directory",
"stderr_lines": [
"stat: cannot stat â/proc/1178/statâ: No such file or directory"
],
"stdout": "",
"stdout_lines": []
}
},
"changed": false
}
TASK [debug] ************************************************************************************************************************************************
task path: /app/script/condition_test.yml:19
ok: [10.9.9.111] => {
"msg": "STARTTIME:{'stderr_lines': [u'stat: cannot stat \\u2018/proc/1178/stat\\u2019: No such file or directory'], u'changed': True, u'end': u'2019-11-08 10:46:28.345448', u'stdout': u'', u'cmd': u\"stat /proc/1178/stat | grep Modify | cut -d' ' -f2,3\", u'rc': 0, u'start': u'2019-11-08 10:46:28.227297', 'failed': False, u'stderr': u'stat: cannot stat \\u2018/proc/1178/stat\\u2019: No such file or directory', u'delta': u'0:00:00.118151', 'stdout_lines': [], 'ansible_facts': {u'discovered_interpreter_python': u'/usr/bin/python'}}"
}
META: ran handlers
META: ran handlers
PLAY RECAP **************************************************************************************************************************************************
10.9.9.111 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Can you please suggest how can I handle this ?
Note: the output of the shell i.e starttime.rc will always be true i.e 0 whether an output is returned or not because of pipe cut -d in the command.
One can easily circumvent that with set -o pipefail (which may require updating your shell: to use bash, or another "modern" shell)
- shell: "set -o pipefail; stat /proc/1178/stat | grep Modify | cut -d' ' -f2,3"
register: starttime
Another perfectly reasonable approach would be to actually test that the file exists:
- shell: |
if [ ! -e {{fn}} ]; then exit 1; fi
stat {{fn}} | grep Modify | cut -d' ' -f2,3
vars:
fn: /proc/1178/stat
register: starttime

ntc-ansible "response" and "module_args" (how access?)

I am using the networktocode ntc-ansible module in Ansible to control Cisco IOS devices (switches currently). I successfully can use ntc_show_Command to get 'show version' and 'show ip int brief' and put the result into a local file. But when I use the -vvv at the end of the ansible-playbook command, I see structured JSON output in the terminal. How do I get a access the "module_args" and the "response" from the ntc_show_command, ie. if i use "show ip int brief" and i want to know the status of int gi1/0/5. How can I access that? And then... what playbook commands would/could I use to grab the specific data I am looking for?
Here is the output I can see when I run the playbook, with -vvv, but I don't know how to access the structured data
ok: [VTgroup_SW] => {
"changed": false,
"invocation": {
"module_args": {
"command": "show ip interface brief",
"connection": "ssh",
"connection_args": {},
"delay": "1",
"file": null,
"global_delay_factor": "1",
"host": "x.x.x.x",
"index_file": "index",
"key_file": null,
"local_file": "verification/192.168.2.101.cfg",
"optional_args": {},
"password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"platform": "cisco_ios",
"port": null,
"provider": null,
"secret": null,
"template_dir": "/home/melshman/.ansible/plugins/modules/ntc-
ansible/ntc-templates/templates",
"trigger_device_list": null,
"use_keys": false,
"use_templates": true,
"username": "admin"
}
},
"response": [
{
"intf": "Vlan1",
"ipaddr": "y.y.y.y",
"proto": "down",
"status": "administratively down"
},
{
"intf": "Vlan2",
"ipaddr": "x.x.x.x",
"proto": "up",
"status": "up"
},
TRUNCATED...
Here is the output of the Show ip int brief in the local file.
Interface IP-Address OK? Method Status
Protocol
Vlan1 172.16.x.xxx YES NVRAM administratively down down
Vlan2 192.168.x.xxx YES NVRAM up up
Vlan10 10.10.yy.xxx YES NVRAM administratively down down
Here is my play...
- name: VERIFY INTERFACES
ntc_show_command:
connection: ssh
platform: "cisco_ios"
command: 'show ip interface brief'
delay: 1 # delay before performing actions / commands in seconds
global_delay_factor: 1 # delay between commands
local_file: verification/{{ ansible_host }}.cfg
host: "{{ ansible_host }}"
username: "{{ ansible_user }}"
password: "{{ ansible_ssh_pass }}"
use_templates: True
template_dir: '/home/melshman/.ansible/plugins/modules/ntc-
ansible/ntc-templates/templates'
UPDATE I updated code based on suggestions as such:
I made progress, but I seem to still be missing something important. My first debug statement (below) is outputting the full output (not shown here), which works. I can set_fact successfully to 'interfaces'. I can loop through the interfaces variable and detect a condition set with the when statement, which I changed to look for all up/up interfaces. BUT... my output (shown below doesn't show the details yours showed. Mine shows (item=None) for all and an OK on items which match the criteria, but not the details your output shows (your second code block in original answer).
UPDATED - I modified the debug var to 'item.intf' and now I get intf name, but still not all details.
**QUESTION: How can I grab an output that shows only the interfaces that meet the criteria? Can this structured data be saved to a file?
UPDATE 2:::
I was able to use the copy module to copy {{ interfaces }} to a file as structured data, but when I try to just show the interfaces, and not the rest of the data, but using {{ interfaces.intf }} I get an error. (See below)
Question: How can I get a output / file that shows only the interface names?
Question: How can I get an output / file that shows only the interfaces names that are up/up?
My second debug statement (below) is outputting this, which identifies the up/up interfaces: UPDATED.
skipping: [VTgroup_SW] => (item=None)
ok: [VTgroup_SW] => (item=None) => {
"item.intf": "Vlan2"
}
skipping: [VTgroup_SW] => (item=None)
skipping: [VTgroup_SW] => (item=None)
skipping: [VTgroup_SW] => (item=None)
ok: [VTgroup_SW] => (item=None) => {
"item.intf": "GigabitEthernet1/0/27"
Additions to playbook
UPDATE 2
- debug:
var: output
- set_fact:
interfaces: "{{ output.response }}"
# shows all the intf that are up/up
- debug:
var: item.intf
when:
- '"up" in item.proto'
- '"up" in item.status'
loop: "{{ interfaces }}"
- name: Structured Data - INTERFACES
copy:
content: "{{ interfaces }}"
dest: "verification/interfaces_{{ansible_host}}.txt"
# This causes error (see traceback)
- name: Structured Data - INTERFACES with .intf
copy:
content: "{{ interfaces.intf }}"
dest: "verification/interfaces_{{ansible_host}}.txt"
Output from play; - name: Structured Data - INTERFACES (TRUNCATED)
[{"status": "administratively down", "intf": "Vlan1", "ipaddr": "172.16.0.253", "proto": "down"}, {"status": "up", "intf": "Vlan2", "ipaddr": "192.168.2.101", "proto": "up"}, {"status": "administratively down", "intf": "Vlan10", "ipaddr": "10.10.10.1", "proto": "down"}, {"status": "administratively down", "intf": "Vlan20", "ipaddr": "10.10.20.1", "proto": "down"}, {"status": "administratively down", "intf": "Vlan51", "ipaddr": "192.168.1.1", "proto": "down"}, ---- TRUNCATED
Traceback on last play; - name: Structured Data - INTERFACES with .intf
TASK [Structured Data - INTERFACES] ************************************************************************************
task path: /home/melshman/projects/ansible/from-kbyer-ios-pb.yml:117
fatal: [VTgroup_SW]: FAILED! => {
"msg": "The task includes an option with an undefined variable. The error was: 'list object' has no attribute 'intf'\n\nThe error appears to have been in '/home/melshman/projects/ansible/from-kbyer-ios-pb.yml': line 117, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: Structured Data - INTERFACES\n ^ here\n"
You need to register the output and then start using debug and set_fact to retrieve the data structure elements that you want to retrieve:
Here I register the output and then only retrieve the 'FastEthernet4' interface.
- name: Cisco IOS Automation
hosts: pynet-rtr1
connection: local
gather_facts: no
tasks:
- name: VERIFY INTERFACES
ntc_show_command:
connection: ssh
platform: "cisco_ios"
command: 'show ip interface brief'
host: "{{ ansible_host }}"
username: "{{ ansible_user }}"
password: "{{ ansible_ssh_pass }}"
use_templates: True
template_dir: '/home/kbyers/ntc-templates/templates'
register: output
- debug:
var: output
- set_fact:
interfaces: "{{ output.response }}"
- debug:
var: item
when: '"FastEthernet4" in item.intf'
loop: "{{ interfaces }}"
Once again you could do another set_fact and save only this FastEthernet4 interface and then look at the 'proto' and 'status' fields (i.e. 'up' and 'up').
Here is what the very end of the execution looks like:
TASK [debug] *****************************************************************************************************************************************************************************
skipping: [pynet-rtr1] => (item={u'status': u'down', u'intf': u'FastEthernet0', u'ipaddr': u'unassigned', u'proto': u'down'})
skipping: [pynet-rtr1] => (item={u'status': u'down', u'intf': u'FastEthernet1', u'ipaddr': u'unassigned', u'proto': u'down'})
skipping: [pynet-rtr1] => (item={u'status': u'down', u'intf': u'FastEthernet2', u'ipaddr': u'unassigned', u'proto': u'down'})
skipping: [pynet-rtr1] => (item={u'status': u'down', u'intf': u'FastEthernet3', u'ipaddr': u'unassigned', u'proto': u'down'})
ok: [pynet-rtr1] => (item={u'status': u'up', u'intf': u'FastEthernet4', u'ipaddr': u'10.220.88.20', u'proto': u'up'}) => {
"item": {
"intf": "FastEthernet4",
"ipaddr": "10.220.88.20",
"proto": "up",
"status": "up"
}
}
skipping: [pynet-rtr1] => (item={u'status': u'down', u'intf': u'Vlan1', u'ipaddr': u'unassigned', u'proto': u'down'})
PLAY RECAP *******************************************************************************************************************************************************************************
pynet-rtr1 : ok=4 changed=0 unreachable=0 failed=0
Adding more info on the set_fact (i.e. here is how you could save a variable corresponding to only that one interface).
- set_fact:
intf_fa4: "{{ item }}"
when: '"FastEthernet4" in item.intf'
loop: "{{ interfaces }}"
- debug:
var: intf_fa4