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.
Related
Please I'm trying to run some steps in the CircleCI Pipeline with conditions happened in the previous step. I tried a lot of tricks like exposing the value from Step 1 to global vars and pickup it in Step 2, I can see and print the variables in Step 2 but using WHEN BLOCK forever evaluated with Empty. I searched a lot and I knew that logical conditions already evaluated before running the jobs, Please I need alternative way to execute steps in second job in case a condition happened in Step 1?
I pasted here the example that I'm trying to fix
version: 2.1
orbs:
workflows:
test-and-deploy:
jobs:
- set-data:
context: my-context
- read-data:
context: my-context
requires:
- set-data
definitions:
node_image: &node-image
docker:
- image: cimg/node:14.15.5
executors:
base-12-14-0:
description: |
Single Docker container with Node 12.14.0 and Cypress dependencies
see https://github.com/cypress-io/cypress-docker-images/tree/master/base.
Use example: `executor: cypress/base-12-14-0`.
docker:
- image: cypress/base:12.14.0
jobs:
set-data:
<<: *node-image
description: Sets the data
steps:
- run: echo "VAR=app" > global-vars
- persist_to_workspace:
root: .
paths:
- global-vars
read-data:
<<: *node-image
description: read the data
steps:
- attach_workspace:
at: .
- run: ls
- run: cat global-vars // I COULD HERE SEE THE CORRECT VAR inside global-vars
- run: cat global-vars >> $BASH_ENV
- run: echo "Test $VAR" // Successfully Printed
- when:
condition:
matches: {
pattern: "app",
value: $VAR
}
steps:
- run: echo "Condition Executed"
It's not possible to use environment variables in logic statements. The reason is that logic statements are evaluated at configuration compilation time, whereas environment variables are interpolated at run time.
The only workaround I know of is to use the CircleCI dynamic configuration functionality to set pipeline parameters' values in the "setup workflow" that you then pass to the "continuation" workflow.
And by the way, you're not using $BASH_ENV correctly (https://circleci.com/docs/env-vars#setting-an-environment-variable-in-a-shell-command). But again, even if you did, you wouldn't be able to use an environment variable in a logic statement.
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'
I have followed the guide described in Conditional steps in jobs and conditional workflows and written the below code for my CircleCI pipeline.
version: 2.1
workflows:
version: 2.1
workflowone:
when:
condition: false
jobs:
- samplejob:
workflowtwo:
when:
condition: true
jobs:
- jobone
jobs:
samplejob:
docker:
- image: buildpack-deps:stable
steps:
- run:
name: Sample Job in WF 1
command: |
echo "This job is in workflowone and the workflow should not run"
jobone:
docker:
- image: buildpack-deps:stable
steps:
- run:
name: Sample Job in WF 2
command: |
echo "This job is in workflowtwo and the workflow should run"
When I run the above code the output is not what is expected. First workflow should not run because the condition is false. Both worflows start running when the pipeline in triggered. Can anyone point out the missing piece here?
According to the CircleCI docs, workflows (specifically) does not accept the condition key:
Note: When using logic statements at the workflow level, do not
include the condition: key (the condition key is only needed for job
level logic statements).
See here logic-statement-examples (scroll to the bottom of this section to see the note)
I'm trying to send a json variable ( {{parameter_var}} ) to a Jenkins job from Ansible using a curl call. Here is the task I'm using:
- name: Call Jenkins Job
shell: curl -H "crumb:{{ response.json.crumb }}" '{{ jenkinshost }}/job/{{ jenkinsjob }}/buildWithParameters?token={{ jenkinstoken }}' --data-urlencode json='{"parameter": [{"name":"parameter", "value":\""{{ parameter_var }}"\"}]}'
The error I'm getting is:
Syntax Error while loading YAML.\n mapping values are not allowed in this context
Ansible says the issue is:
YAML thought it was looking for the start of a\nhash/dictionary and was confused to see a second "{".
It seems that instead of accepting {{ parameter_var }} as a variable, it's trying to read it as just a value of "{{ parameter_var }}". I tried a few ways of adding or escaping quotes, but can't seem to figure out what Ansible/YAML is looking for. Am I just adding my quotes wrong, or can I just not send a variable using this method?
I printed out my {{ parameter_var }}. There's nothing unusual about it, so I don't think that's the issue:
{
"msg": {
"msg": "All items completed",
"changed": false,
"results": [
{
"content_length": "142",
...
} ...
}
The goal I'm trying to accomplish is to set parameter "parameter" in Jenkins to the value of {{ parameter_var }}
Here's where I found the syntax for sending the json to Jenkins: https://wiki.jenkins.io/display/JENKINS/Remote+access+API
There are a lot of things that need addressing in your question:
you should not be shell-ing out to curl when there is a uri: module in ansible designed for that purpose
related to that, you left off --fail from your curl, so a non-200 response will cause the shell: to exit 0 which is almost certainly not what you intended
you cannot have a : character followed by whitespace in a yaml document because that's how yaml defines keys in a dict
you should not try and build up JSON using jinja2 templates, rather build up the structure in a dict or list and feed it through | to_json to ensure correct quoting
However, if you insist on that syntax specifically, you can fix it with some light editing:
- name: Call Jenkins Job
shell: >-
curl --fail -H "crumb:{{ response.json.crumb }}"
'{{ jenkinshost }}/job/{{ jenkinsjob }}/buildWithParameters?token={{ jenkinstoken }}'
--data-urlencode json={{ json_data | to_json | quote }}
vars:
json_data:
parameter:
- name: "parameter"
value: '{{ parameter_var }}'
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.