2
votes

Jenkins version: 2.7.4
Ansible/Playbook version: 2.1.1.0

Ansible playbook file: [ vagrant@/tmp ] $ ls -l pb.yml

-rw-rw-r--. 1 vagrant vagrant 189 Nov  2 05:39 pb.yml

[ vagrant@/tmp ] $ cat $_

---
#- hosts: "{{ host }}"
- hosts: all
  gather_facts: False

#  vars:
#   - host: "all"

  tasks:
    - name: Hello
      shell: "echo hello"
      tags:
         - hello

    - name: Bye
      shell: "echo bye"
      tags:
         - bye

When I run the following command on ansible/host machine at command line, it's working if I'm passing only one or more host(s), with or without a space after "," character between hosts values:

$ /usr/bin/ansible-playbook tasks/pb.yml -i "app-server1" -f 5 --private-key /tmp/ssh738232337886876255.key -u ubuntu

if I pass more than one hosts (cmd line), it still works (PS: even if I have , as a suffix or not for the list of inventory hosts):

$ /usr/bin/ansible-playbook tasks/pb.yml -i "app-server1,web-server2" -f 5 --private-key /tmp/ssh738232337886876255.key -u ubuntu
$ /usr/bin/ansible-playbook tasks/pb.yml -i "app-server1,web-server2," -f 5 --private-key /tmp/ssh738232337886876255.key -u ubuntu

But, with a space character passed in -i option's value, I'm seeing it works for a server entry where space is not there and fails for the same host with space suffixed/prefixed (at least as per what's displayed on the stdout console).

For example running "-m setup" (gather facts) with ansible command, NOTICE the space character in the output below before proxy-server3 | UNREACHABLE! line.

If I run -m setup (ansible command) -or- even if I run the same playbook(ansible-playbook command), I see similar error UNREACHABLE as shown below:

$ /usr/bin/ansible all -m setup -i "app-server1, proxy-server3," -f 5 --private-key /tmp/ssh738232337886876255.key -u ubuntu

 proxy-server3 | UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh.",
    "unreachable": true
}
app-server1 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "10.124.12.101"
        ],
        ...more...json...stuff..here
        ...

Now, I'm Invoking Ansible Playbook in Jenkins's build step. In Jenkins I have a parameterized job parameter named hosts, which I'm using within "Invoke Ansible Playbook" plugin's build step as an "inline content" radio button for its inventory section.

When I'm passing only "app-server1" and launching the job, Jenkins is successfully running the job and running the ansible-playbook .yml file as expected.

But, when I'm giving hosts variable with multiple comma separated values, it's erroring out.

If hosts parameter in Jenkins is set to more than one host i.e.:
app-server1,web-server2
OR
app-server1,app-server1 (without any space next to "," character)
OR
app-server1,web-server2, (PS: here , is suffixed to the value).

I'm getting the following error:

23:48:00 PLAY [all] *********************************************************************
23:48:00 
23:48:00 TASK [hello] ******************************************************
23:48:01 fatal: [app-server1,web-server2]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh.", "unreachable": true}
23:48:01 
23:48:01 PLAY RECAP *********************************************************************
23:48:01 app-server1,web-server2 : ok=0    changed=0    unreachable=1    failed=0   
23:48:01 
23:48:01 FATAL: command execution failed
23:48:01 hudson.AbortException: Ansible playbook execution failed
23:48:01    at org.jenkinsci.plugins.ansible.AnsiblePlaybookBuilder.perform(AnsiblePlaybookBuilder.java:227)
23:48:01    at org.jenkinsci.plugins.ansible.AnsiblePlaybookBuilder.perform(AnsiblePlaybookBuilder.java:200)
23:48:01    at hudson.tasks.BuildStepCompatibilityLayer.perform(BuildStepCompatibilityLayer.java:78)
23:48:01    at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
23:48:01    at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:779)
23:48:01    at hudson.model.Build$BuildExecution.build(Build.java:205)
23:48:01    at hudson.model.Build$BuildExecution.doRun(Build.java:162)
23:48:01    at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:534)
23:48:01    at hudson.model.Run.execute(Run.java:1741)
23:48:01    at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
23:48:01    at hudson.model.ResourceController.execute(ResourceController.java:98)
23:48:01    at hudson.model.Executor.run(Executor.java:410)
23:48:01 ERROR: Ansible playbook execution failed
23:48:01 Finished: FAILURE

OR
(when , is used as suffix in the value of hosts parameter)


23:48:01 fatal: [app-server1,web-server2,]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh.", "unreachable": true}
23:48:01 
23:48:01 PLAY RECAP *********************************************************************
23:48:01 app-server1,web-server2, : ok=0    changed=0    unreachable=1    failed=0   
23:48:01 
23:48:01 FATAL: command execution failed

OR
If I give a space between two hosts values (irrespective of the suffixed , character at the end), I get a different error message.

Example: I passed the following value to parameter hosts:
app-server1, web-server2
or
app-server1,web-server2, proxy-server3,

Error example:

23:49:53 ERROR! /tmp/inventory5444675088910579622.ini:1: Expected key=value host variable assignment, got: app-server1,
23:49:53 FATAL: command execution failed
23:49:53 hudson.AbortException: Ansible playbook execution failed
23:49:53    at org.jenkinsci.plugins.ansible.AnsiblePlaybookBuilder.perform(AnsiblePlaybookBuilder.java:227)
23:49:53    at org.jenkinsci.plugins.ansible.AnsiblePlaybookBuilder.perform(AnsiblePlaybookBuilder.java:200)
23:49:53    at hudson.tasks.BuildStepCompatibilityLayer.perform(BuildStepCompatibilityLayer.java:78)
23:49:53    at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20)
23:49:53    at hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:779)
23:49:53    at hudson.model.Build$BuildExecution.build(Build.java:205)
23:49:53    at hudson.model.Build$BuildExecution.doRun(Build.java:162)
23:49:53    at hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:534)
23:49:53    at hudson.model.Run.execute(Run.java:1741)
23:49:53    at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:43)
23:49:53    at hudson.model.ResourceController.execute(ResourceController.java:98)
23:49:53    at hudson.model.Executor.run(Executor.java:410)
23:49:53 ERROR: Ansible playbook execution failed

Questions:

  1. Why space is not getting removed automatically when I'm giving that in ansible command or ansible-playbook command for -i option's value? How can I get rid of the situation if hosts are passed with a space character around comma "," character within double quotes for -i option. I know I can use sed beforehand but -i option should ignore any spaces next to "," character by default (whether space(s) is/are prefixed/suffixed next to a comma character).

  2. How come (when I'm not giving any space in the parameter's value) in my Jenkins job, it's erroring out when the value has ",", while it succeeds at command line?

  3. Giving -i "app-server1" (at command line) is not working. But, it works when I give -i "app-server1," (see , at the end within quotes).
    The same is totally behaving opposite in Jenkins using a parameter(string type) and using Invoke Ansible Playbook build step; there, if I give hosts parameter the value of "app-server1" it WORKS, but giving "app-server1," (suffixing comma character) does NOT.

1

1 Answers

1
votes

Found the issue and solution in Jenkins at least.

This seems like a BUG or requires an Enhancement/feature request in "Ansible Plugin" available in Jenkins (or may be I'm incorrect about what the term inline means) but when INVENTORY method is selected for "inline content" (a radio button) and if we use a variable ($hosts / etc) which contains comma separated and/or comma+space separated list of hostname/IPs etc, then Ansible is not working in running the playbook.

Opened a request against this plugin in Jenkins JIRA: https://issues.jenkins-ci.org/browse/JENKINS-39611

The workaround of creating a inventory file, using "File" radio button / method within "Invoke Ansible Playbook" actually worked here but I was trying to use just a plain "${variable}" and my assumption was, the plugin should treat that exactly like we pass -i option at command line.

So, an enhancement of having a 3rd radio button would help a lot.

For ex: Third radio button (Comma separated list/variable) and a user can just specify "${myHosts}" and be done with it (instead of creating a FILE and using File radio button or writing a proper INLINE inventory file when "inline content" method is used).

My assumption is it should work if I want to pass host(s) info as a comma separated / comma cum space separated list (as per --help documentation) and mimicking the same within this plugin, see --help below for ansible / ansible-playbook -i option.

I guess for command line issue, commas/spaces have to solved using sed or tr similar commands.

ansible or ansible-playbook documentation says that -i option specifies the inventory (host info) to be used for Ansible to work on, we can define it as a relative/absolute path and it defaults to /etc/ansible/hosts OR a comma separated host list:

ansible --help || ansible-playbook --help

  -i INVENTORY, --inventory-file=INVENTORY
                        specify inventory host path
                        (default=/etc/ansible/hosts) or comma separated host
                        list.

Anyways, my issue was around comma separated host list as it was NOT working in Jenkins within Ansible Invoke Playbook plugin's build step .

I was using $hosts or similar variable (as per the screenshot below) as "inline content" for inventory (radio button) method.

What I did to resolve:
I created a temporary (aka mktemp) file and filtering out the one liner host(s) info list containing space or comma into this temporary file and using this temporary file as "File" (Radio button) method for passing the inventory information (about the hosts) in "Invoke Ansible Playbook" build step.

Now, I'm not getting the above error messages in Jenkins. After the Ansible part is complete, I'm removing these temporary files (don't have to as they all sit in /tmp location, if you want them in your Jenkins workspace location then mktemp -p . can be used to create a temporary file in current working directory).

enter image description here