Copy remote file to local using ansible - filename is variable - jenkins

I'm trying to fetch some files from a remote server, however, the file name is generate by a variable date.
$(date --date="$(date +%Y-%m-15) -1 month" +'%Y-%m')
- hosts: remote_server
tasks:
fetch:
src: /tmp/$(date --date="$(date +%Y-%m-15) -1 month" +'%Y-%m')
dst: /tmp/$(date --date="$(date +%Y-%m-15) -1 month" +'%Y-%m')

Declare the date command output as an ansible variable and use it in the task
- hosts: remote_server
vars:
dt: "{{ lookup('pipe', 'date --date="$(date +%Y-%m-15) -1 month" + "%Y-%m"') }}"
tasks:
fetch:
src: "/tmp/{{ dt }}"
dest: "/tmp/{{ dt }}"
Note that the value of dt will be dependant on the date of the control node.

Related

How to pass variable with type MAP in github actions

Is there is the way to pass variable with "map type" ?
For example is it possible to do something like below:
jobs:
docker_build_and_push:
uses: test/test/.github/workflows/matrixDocker.yml#main
with:
# Docker image name
service_name: nesso
tags: {"nginx":"new", "api":"old"} <<<<<< ????
Unfortunately, this is not possible yet. As I wrote in a previous answer, the only supported input types for actions are string | number | boolean (schema: with ref: definitions/env).
So the workaround would be either you pass multiple arguments to your action, or you pass them as a JSON string then you parse it with jq (if your action uses shell/bash).
And here are these example workarounds:
Specify more options as inputs to your action
Simply add more inputs to your action instead of one input of type map:
name: 'Hello World'
description: 'Greet someone'
inputs:
greeting-word:
description: What to say
required: false
default: Hello
who-to-greet:
description: 'Who to greet'
required: true
something-else:
description: Something else to say
required: false
default: ""
runs:
using: "composite"
steps:
- name: Greet!
shell: bash
run: echo "${{ inputs.greeting-word }} ${{ inputs.who-to-greet }} ${{ inputs.something-else }}"
Then just pass them form your workflow file
- name: Greet
uses: ./.github/actions/my-action
with:
greeting-word: Hallo
who-to-greet: Bob
Pass arguments as a JSON string
Workflow file:
- name: Greet
uses: ./.github/actions/my-action
with:
greeting-args: '{"greeting-word": "Hello", "who-to-greet": "Bob"}'
The action
name: 'Hello World'
description: 'Greet someone'
inputs:
greeting-args:
required: true
description: Greeting arguments
runs:
using: "composite"
steps:
- name: Greet!
shell: bash
run: |
MY_INPUT='${{ inputs.greeting-args }}'
GREETING_WORD=$(echo $MY_INPUT | jq -r '."greeting-word"')
WHO_TO_GREET=$(echo $MY_INPUT | jq -r '."who-to-greet"')
echo "${GREETING_WORD} ${WHO_TO_GREET}"
Or you can pass it as a multi-line string
This approach is used by actions like actions/upload-artifact
- uses: actions/upload-artifact#v3
with:
name: my-artifact
path: |
path/output/bin/
path/output/test-results
!path/**/*.tmp
And google-github-actions/get-secretmanager-secrets
- id: 'secrets'
uses: 'google-github-actions/get-secretmanager-secrets#v1'
with:
secrets: |-
token:my-project/docker-registry-token
anotherOne:my-project/a-secret
anotherOneToo:my-project/another-secret
i.e you just need to read these lines and split your map's key/values

Ansible: How to debug mutiple tasks, commands or iterations?

In a YAML playbook, I need to run multiple commands through each element in an array. I am using with_items to iterate, but I am getting syntax errors when I try to blend debug into the tasks.
Everything works when I remove the debug module, but than I can't see whats happening. Example provided below.
Produces Syntax Error:
- name: Iterate through array and display results
shell: "run command 1 on {{ item }}"
register: command1
debug:
msg: "Command 1 || {{ command1.stdout_lines}}"
shell: "run command 2 on {{ item }}"
register: command2
debug:
msg: "Command 2 || {{ command2.stdout_lines}}"
with_items: "{{ array_name }}"
Everything seems to be working fine when I remove the debugs, but I need to see what each command produces because it has important info.
Is there some way to print/debug the results while keeping it inside the with_items iterations?
Edit:
I also tried a few more things but they also gave me a syntax error
Also Tried 1:
- name: Iterate through array and display results
- shell: "run command 1 on {{ item }}"
register: command1
- debug:
msg: "Command 1 || {{ command1.stdout_lines}}"
- shell: "run command 2 on {{ item }}"
register: command2
- debug:
msg: "Command 2 || {{ command2.stdout_lines}}"
with_items: "{{ array_name }}"
Also Tried 2:
- name: Iterate through array and display results
- shell: "run command 1 on {{ item }}"
register: command1
- debug:
msg: "Command 1 || {{ command1.stdout_lines}}"
- shell: "run command 2 on {{ item }}"
register: command2
- debug:
msg: "Command 2 || {{ command2.stdout_lines}}"
with_items: "{{ array_name }}"
As the comments of β.εηοιτ.βε already stated
In Ansible, you can only have one module per item in the list (tasks is a list of tasks, each being an Ansible module) ... you have to have a new item in the list (a dash -), in front of all the debug and shell tasks.
This means,
integrate debug into iterations
I try to blend debug into the tasks
you can't do debugging in that way since the debug_module is for
Print statements during execution
only. However, according your question
Is there some way to print/debug the results while keeping it inside the with_items iterations?
it seems for me that you are more interested in Debugging tasks, play, role or block itself. So for this
Ansible offers a task debugger so you can fix errors during execution instead of editing your playbook and running it again to see if your change worked.
For usage you have to Enabling the debugger with the debugger keyword and may have a look into the Examples, Resolving errors in the debugger and Available debug commands.
Further questions here on SO are
How to debug Ansible issues?
Does Ansible have any feature to allow for debugging/pausing?
I was able to solve the issue, Ansible does not allow iterations through multiple tasks. I had to put the tasks in a separate yml playbook and use include_tasks: to call the playbook.

Pass Multi-Line Text Parameter in Jenkins to Ansible Playbook

I have a text parameter in Jenkins that looks like so:
text(
defaultValue: '''
- 'evn-111'
- 'evn-423'
- 'evn-414'
''',
description: 'Add list of devices to create lab',
name: 'DEVICES',
)
I want to take this list of devices and pass it as a string into an ansible playbook.
However, when I pass this string into the ansible playbook like so:
extra_args = "-e devices=${ params.DEVICES }"
sh "ansible-playbook $extra_args deploy_lab.yml"
My output in Jenkins is:
ansible-playbook -e devices=
Followed by recommendations on what arguments I need to pass. Can anyone provide suggestions on how I can accomplish passing a multiline parameter to Ansible? Once I get the variable in the Ansible file, I have a template that creates another yml file using the multi-line text string passed from Jenkins.
My Ansible file looks like this:
---
- hosts: all
gather_facts: true
vars:
devices: ""
tasks:
- name: 'Create device file'
template:
src: devices.j2
dest: "host_vars/devices.yml"
mode: '0600'
delegate_to: localhost
My Template file devices.j2 looks like this:
---
devices_from_jenkins_param:
"{{ devices }}"
In the end, I want there to be a file host_vars/devices.yml that looks like this:
---
devices_from_jenkins_param:
- 'evn-111'
- 'evn-423'
- 'evn-414'

Ansible reading Jenkins boolean parameter

I have boolean parameter input from Jenkins. My Ansible then reads this boolean as 'when' condition to execute the tasks. However, this boolean parameter seems not working properly. My playbook looks like this:
- hosts: localhost
var:
my_boolean: {{lookup('env','boolean_parameter1')}}
- name: print msg1
debug:
msg: "msg1 is {{lookup('env','boolean_parameter1')}}."
- name: print msg2
debug:
msg: "msg2 is {{my_boolean}}."
- name: execute tasks if my_boolean is 'true'
shell: ls -l
when:
- "{{my_boolean}}"=="true"
Output:
msg1 is true.
msg2 is .
<<<<execution of tasks skipped>>>>
Why does msg2 output my_boolean as blank? Should this be 'true' as well?
In your play, the comparison in when: is matching the string "true". Whereas the variable my_boolean is a boolean, so it doesn't match and skips the task. And in the debug: task it is the other way around - the message is trying to display Boolean true, and so it is blank.
The below tasks should do the job:
# Here we need the string equivalent of boolean, i.e. the text 'true'
- name: print msg2
debug:
msg: "msg2 is {{ my_boolean | string }}."
# But here we need to compare the boolean value
- name: execute tasks if my_boolean is 'true'
shell: ls -l
when: my_boolean
It is worth noting that as of Ansible 2.10 onwards referencing bare variables in when: conditionals will be deprecated. It would be a good idea to use: when: my_boolean | bool.
Try casting my_boolean to bool during initialization. This allows to just check if value of my_boolean is True.
Playing with your code, the following worked for me:
- name: Test
hosts: all
vars:
my_boolean: "{{lookup('env','boolean_parameter1')|bool}}"
tasks:
- name: print msg1
debug:
msg: "msg1 is {{lookup('env','boolean_parameter1')}}."
- name: print msg2
debug:
msg: "msg2 is {{my_boolean}}."
- name: execute tasks if my_boolean is 'true'
shell: ls -l
when:
- my_boolean
Inventory:
[hosts]
localhost ansible_connection=local

Commit all changes after executing playbook

I made an Ansible play book that loops through a .yaml file and adds descriptions to interfaces. The problem is after every set command Ansible commits, waits for the commit then configures the next interface. If I run this on a VC with 10 members it will take for ever. Any one know how to make the playbook commit only after all changes have been made?
---
- name: Change configuration using junos_config module
hosts: test
connection: local
gather_facts: no
tasks:
- include_vars: /home/ansible/interfaces.yaml
- name: Change description on interfaces based on a list of variable
junos_config:
lines:
- "set interfaces {{ item.name }} description \"{{ item.description }}\""
comment: "Update description of interface {{ item.name }}"
with_items: "{{ interfaces }}"
register: result
- debug: var=result
I changed the play book which now looks like this:
---
- name: Change configuration using junos_config module
hosts: test
connection: local
gather_facts: no
tasks:
- include_vars: /home/ansible/playbook-core/interfaces.yaml
- name: Change description on interfaces based on a list of variable
junos_config:
lines:
- "{{ lines_template }}"
- "set interfaces {{ item.name }} description \"{{ item.description }}\""
comment: "Update description of port"
vars:
lines_template: "[ {% for interface in interfaces %}'set interfaces {{ item.name }} description \"{{ item.description }}\"',{% endfor %} ]"
with_items: "{{ interfaces }}"
register: result
- debug: var=result
And when I run it I get an error:
An exception occurred during task execution. To see the full traceback, use -
vvv. The error was: TypeError: sequence item 0: expected string, list found
failed: [10.63.255.71] (item={u'name': u'ge-0/0/1', u'description': u'Set by
ansible'}) => {"changed": false, "item": {"description": "Set by ansible",
"name": "ge-0/0/1"}, "module_stderr": "Traceback (most recent ca
ll last):\n File \"/tmp/ansible_wVNymo/ansible_module_junos_config.py\",
line 402, in <module>\n main()\n File
\"/tmp/ansible_wVNymo/ansible_module_junos_config.py\", line 371, in main\n
diff = configure_device(module, warnings, candidate)\n File
\"/tmp/ansible_wVNymo/ansible_module_junos_config.py\", line 293, in
configure_device\nreturn load_config(module, candidate, warnings, **kwargs)\n
File \"/tmp/ansible_wVNy
mo/ansible_modlib.zip/ansible/module_utils/junos.py\", line 199, in
load_config\nTypeError: sequence item 0: expected string, list found\n",
"module_stdout": "", "msg": "MODULE FAILURE", "rc": 0}
Move the loop logic to Jinja2 template:
- name: Change description on interfaces based on a list of variable
junos_config:
lines: "{{ lines_template }}"
- "set interfaces {{ item.name }} description \"{{ item.description }}\""
comment: "Update description of interfaces"
vars:
lines_template: "[ {% for interface in interfaces %}'set interfaces {{ interface.name }} description \"{{ interface.description }}\"',{% endfor %} ]"
Last , could be skipped, but it seems Ansible makes up for that.
The above code is not tested with Juniper, but it should produce what you wanted.

Resources