Ansible run a task based on something in output - ansible

I'm new in Ansible and I try to do some practice playbook. I write a playbook to deploy a Docker container as follows. I write a task in the block section if an error happened, run a task in the rescue section based on Failed message content. For example, I want to run a specific task to delete an existing container if the Failed message is something like this:
failed: [192.168.1.140] (item=stderr_lines) => {"changed": true, "cmd": ["docker", "run", "-itd", "--name", "h1", "-p", "80:80", "httpd"], "delta": "0:00:00.016385", "end": "2021-01-04 03:00:55.403364", "failed_when_result": true, "item": "stderr_lines", "msg": "non-zero return code", "rc": 125, "start": "2021-01-04 03:00:55.386979", "stderr": "/usr/bin/docker-current: Error response from daemon: Conflict. The container name "/h1" is already in use by container bc5cc803a5f4321358992d06097ce271f3a63b8eba19900cfc0d23e321a4e243. You have to remove (or rename) that container to be able to reuse that name..\nSee '/usr/bin/docker-current run --help'.", "stderr_lines": ["/usr/bin/docker-current: Error response from daemon: Conflict. The container name "/h1" is already in use by container bc5cc803a5f4321358992d06097ce271f3a63b8eba19900cfc0d23e321a4e243. You have to remove (or rename) that container to be able to reuse that name..", "See '/usr/bin/docker-current run --help'."], "stdout": "", "stdout_lines": []}"
My playbook is as follows but it didn't work correctly. Sometimes an error in reading dictionary or "Unexpected templating type error occurred on". Can somebody guide me on what should I write?
- name: run a container
vars:
- run_container: docker run -itd --name h1 -p 80:80 httpd
- rm_container: docker stop h1 && docker rm h1
hosts: 192.168.x.x
tasks:
- name: check docker container
block:
- name: run a container httpd
command: "{{run_container}}"
register: rss
with_items:
- "stderr_lines"
failed_when: "'Error' in rss.stderr"
rescue:
- name: iterate over list
debug:
msg: "{{item.value}}"
loop: "{{rss | dict2items}}"
- name: remove the exited container
command: "{{rm_container}}"
register: rs
with_items:
- "{{rss | dict2items}}"
when: item.value is search("The container name .* is already in use")

Related

How to properly use when condition in Ansible

---
- name: test
hosts: localhost
tasks:
- name: Checking project list
shell: |
argocd proj list | grep xcore
register: argoProj
- debug: var=argoProj.stdout
- name: create a project if not exits
shell: |
argocd proj create xcore
# when: argoProj.stdout != "xcore"
when: argoProj.stdout.find('xcore')!=-1
Error:
''
TASK [create a project if not exits] *****************************************************************************************
fatal: [localhost]: FAILED! => {"changed": true, "cmd": "argocd proj create xcore\n \n# when: argoProj.stdout != \"xcore\"\n", "delta": "0:00:00.807940", "end": "2021-02-04 09:11:24.257123", "msg": "non-zero return code", "rc": 20, "start": "2021-02-04 09:11:23.449183", "stderr": "time=\"2021-02-04T09:11:24Z\" level=fatal msg=\"rpc error: code = InvalidArgument desc = existing project spec is different, use upsert flag to force update\"", "stderr_lines": ["time=\"2021-02-04T09:11:24Z\" level=fatal msg=\"rpc error: code = InvalidArgument desc = existing project spec is different, use upsert flag to force update\""], "stdout": "EE: 0/[]", "stdout_lines": ["EE: 0/[]"]}
NOTE: I want to skip the last task when an xcore project is already created. The last task needs to execute when there is no project with same name.
Actual output of the shell command:
#argocd proj list | grep xcore
xcore gke_ec2nf-256816_us-central1_gke-devops,production <none> <none> <none> <none> disabled
---
- name: test
hosts: localhost
tasks:
- name: Checking project list
shell: argocd proj list | grep xcore
register: argoProj
- debug: var=argoProj.stdout
- name: create a project if not exits
shell: argocd proj create xcore
when: "'xcore' not in argoProj.stdout"

Why register is registering even if the module when condition is false?

I was having a task file which will get container name which has particular volume mounted. The result is stored in container_id variable. This task file need to be executed in linux as well windows. So i added conditional execution but the 'register' variable is behaving weird.
- name: Get the container ID for volume "{{vol}}" mounted
shell: "docker ps -a -q --filter volume={{vol}}"
register: container_id
when: ansible_os_family != "Windows"
- name: Get the container ID for volume "{{vol}}" mounted
win_shell: "docker ps -a -q --filter volume={{vol}}"
register: container_id
when: ansible_os_family == "Windows"
- debug:
var: container_id
When i run this in linux node , i thought it will get all the container name in container_id variable. But to my surprise the output is
ok: [remotenode] => {
"container_id": {
"changed": false,
"skip_reason": "Conditional result was False",
"skipped": true
}
}
which means the skipped output from windows module is registered into container_id variable.
Then i placed the debug below linux module as below , which ensured that register at that point of time has proper value
- name: Get the container ID for volume "{{vol}}" mounted
shell: "docker ps -a -q --filter volume={{vol}}"
register: container_id
when: ansible_os_family != "Windows"
- debug:
var: container_id
- name: Get the container ID for volume "{{vol}}" mounted
win_shell: "docker ps -a -q --filter volume={{vol}}"
register: container_id
when: ansible_os_family == "Windows"
The output is as below
ok: [remotenode] => {
"container_id": {
"changed": true,
"cmd": "docker ps -a -q --filter volume=origvolfd48c6",
"delta": "0:00:00.036279",
"end": "2019-07-30 02:32:13.203036",
"failed": false,
"rc": 0,
"start": "2019-07-30 02:32:13.166757",
"stderr": "",
"stderr_lines": [],
"stdout": "fb81938cdbbe",
"stdout_lines": [
"fb81938cdbbe"
]
}
}
So the register is having value even if the module is skipped. Why it behaves this way. Is there any workaround?
If you take a look at the "Using variables" section of Ansible's Docs you'll see this note:
If a task fails or is skipped, the variable still is registered with a failure or skipped status, the only way to avoid registering a variable is using tags.
So what is happening to you is Ansible's default behaviour. You could modify your playbook to use tags like this:
- name: Get the container ID for volume "{{vol}}" mounted
shell: "docker ps -a -q --filter volume={{vol}}"
register: container_id
tags:
- linux
- name: Get the container ID for volume "{{vol}}" mounted
win_shell: "docker ps -a -q --filter volume={{vol}}"
register: container_id
tags:
- windows
- debug:
var: container_id
Then you can run it using the --tags or --skip-tags options.

Ansible fatal error while trying to print the state of firewalld

Here, i am trying to print the status of the firewall-cmd --state command , but a fatal error is being thrown.
name: Check firewall status
hosts: st
tasks:
- name: Check status of firewall
command: firewall-cmd --state
register: status
- name: Print version
debug:
msg: "Status = {{ status.stdout }}"
State is "not running" in the remote host. But am not getting the result.
I get the following output
fatal: [borexample.com]: FAILED! => {"changed": true, "cmd": ["firewall-cmd", "--state"], "delta": "0:00:00.189023", "end": "2018-09-16 11:40:17.319482", "msg": "non-zero return code", "rc": 252, "start": "2018-09-16 11:40:17.130459", "stderr": "", "stderr_lines": [], "stdout": "\u001b[91mnot running\u001b[00m", "stdout_lines": ["\u001b[91mnot running\u001b[00m"]}
How should i modify the code so that i get only the state ?
I prefer using failed_when: to control your output rc. More info at Ansible Documentation. But you can also use ìgnore_errors: true
Check error codes in the Firewall-cmd Documentation to see which codes adding to your playbook.
In your scenario could be good doing:
- name: Check status of firewall
command: firewall-cmd --state
register: status
failed_when:
- status.rc != 0
- status.rc != 252
Even you can go further and use failed_when: false to avoid the command failing.
The ignore_errors suggested by Baptiste Mille-Mathias would allow you to continue, but then you would like to "debug" {{ status.stderr }}, as in that ase stdout would be empty.

Unable to download golang repository by using ansible

I am trying to download a golang package from github. This is how my playbook looks like
- name: Fetch latest gogs repository
shell: "go get -u github.com/gogits/gogs"
become: true
become_user: git
It is throwing me following error:
{
"changed": true,
"cmd": "go get -u github.com/gogits/gogs",
"delta": "0:00:00.002695",
"end": "2017-08-22 10:50:02.984669",
"failed": true,
"invocation": {
"module_args": {
"_raw_params": "go get -u github.com/gogits/gogs",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
}
},
"rc": 127,
"start": "2017-08-22 10:50:02.981974",
"stderr": "/bin/sh: go: command not found",
"stderr_lines": [
"/bin/sh: go: command not found"
],
"stdout": "",
"stdout_lines": []
}
When I am trying this
- name: Fetch latest gogs repository
shell: "go get -u {{ gogs_repo }}"
environment:
- PATH: $PATH:/usr/local/go/bin:/usr/bin
- GOPATH: "{{gogs_home}}/{{ gogs_project_directory }}/src"
- GOBIN: "{{gogs_home}}/{{ gogs_project_directory }}/bin"
become: true
become_user: git
I got this error
fatal: [atul-ec2]: FAILED! => {
"changed": false,
"failed": true,
"module_stderr": "Shared connection to ec2-13-126-203-235.ap-south-1.compute.amazonaws.com closed.\r\n",
"module_stdout": "Traceback (most recent call last):\r\n File \"/tmp/ansible_gntmXa/ansible_module_command.py\", line 220, in <module>\r\n main()\r\n File \"/tmp/ansible_gntmXa/ansible_module_command.py\", line 163, in main\r\n os.chdir(chdir)\r\nOSError: [Errno 13] Permission denied: '/home/ec2-user/goprojects/src/src/github.com/gogits/gogs'\r\n",
"msg": "MODULE FAILURE",
"rc": 1
}
Here my variables are
---
go_version: go1.7.linux-amd64.tar.gz
go_url: https://storage.googleapis.com/golang/{{ go_version }}
go_hash: sha256:702ad90f705365227e902b42d91dd1a40e48ca7f67a2f4b2fd052aaa4295cd95
go_project_dir: goprojects
go_home: "{{ ansible_env.HOME }}"
gogs_home: "/home/git"
gogs_project_directory: "git.varadev.com"
gogs_repo: github.com/gogits/gogs
But when i am using following command on my server
which go
I got this
/usr/local/go/bin/go
and when I try manually go get -u github.com/gogits/gogs, it is working fine.
Hope this can help you as a start point:
---
- hosts: all
connection: local
tasks:
- name: check go version
command: go version
register: result
changed_when: no
ignore_errors: true
- set_fact:
go_path: "{{ lookup('env', 'GOPATH') | default(ansible_env.HOME+'/go', true) }}"
when: not result|failed
- name: go get gogs
shell: go get -u github.com/gogits/gogs
environment:
GOPATH: "{{ go_path }}"
register: gogs
when: not result|failed
- debug: var=gogs
Try to run this on your remote server by typing:
ansible-playbook gogs.yml -i localhost,
If that works then just later try remotely.
Normally you don't want to do this since you want to execute this remotely over ssh, but since you had tried so far and are getting some errors, probably by trying locally connection: local could help to debug more in details this issue.
I know this post is too old, but maybe this may help someone.
Ths issue /bin/sh: go: command not found it is because you are missing some configuration when Ansible runs, and probably you need to source the bash profile like this:
- name: Install gogs
shell: "source ~/.bash_profile && github.com/gogits/gogs"
args:
chdir: /home/{{ owner }}
become_user: '{{ owner }}'
That worked for me.

How to make changed_when work in Ansible?

I am trying to run a script using the command module on a Jenkins server. The script is written in such a way that it should return 0 if not making any configuration changes and the Ansible task should not be changed.
Here is the code:
- name: Script to run
command: java -jar /var/cache/jenkins/war/WEB-INF/jenkins-cli.jar -s http://localhost:8080 groovy "{{ jenkins_home }}/userContent/script.groovy"
register: return_code
changed_when: return_code.stdout != 0
But the above code behaves is always showing as changed.
The Ansible output:
TASK [jenkins : Script to run] ********************************
changed: [test] => {"changed": true, "cmd": ["java", "-jar", "/var/cache/jenkins/war/WEB-INF/jenkins-cli.jar", "-s", "http://localhost:8080", "groovy", "/var/lib/jenkins/userContent/script.groovy"], "delta": "0:00:01.547098", "end": "2017-02-06 15:31:05.989134", "rc": 0, "start": "2017-02-06 15:31:04.442036", "stderr": "[WARN] Failed to authenticate with your SSH keys. Proceeding as anonymous", "stdout": "0", "stdout_lines": ["0"], "warnings": []}
You need to compare the stdout value with a string instead of an integer:
- name: Script to run
command: java -jar /var/cache/jenkins/war/WEB-INF/jenkins-cli.jar -s http://localhost:8080 groovy "{{ jenkins_home }}/userContent/script.groovy"
register: script_call
changed_when: script_call.stdout != "0"

Resources