0

I am using Jenkins to remotely run an Ansible playbook via the Publish Over SSH command.

This command:

curl -k -v -X POST https://jenkins.myhost.com/job/Ansible_Deploy/build?token=<appToken> --user <myUser>:<userToken> --data-urlencode json='{"parameter":[{"name":"thisIsAList","value":["one","two","three"]}]}'

should trigger a post-build action to remotely execute the following command over SSH:

ansible-playbook /home/<myUser>/test/practice.yml --extra-vars "thisIsAList=$thisIsAList"

thisIsAList is a string parameter under Job Notifications, and the job is parameterized. I have successfully executed similar commands, but this one fails, assumingly because the value is a list. I have tried both "String Parameter" as well as "Multi-line String Parameter" to no avail.

Here's the stack trace:

org.kohsuke.stapler.WrongTypeException: Got type array but no lister class found for type class java.lang.String
        at org.kohsuke.stapler.RequestImpl$TypePair.convertJSON(RequestImpl.java:723)
        at org.kohsuke.stapler.RequestImpl.bindJSON(RequestImpl.java:478)
        at org.kohsuke.stapler.RequestImpl.instantiate(RequestImpl.java:777)
Caused: java.lang.IllegalArgumentException: Failed to convert the value parameter of the constructor public hudson.model.StringParameterValue(java.lang.String,java.lang.String)
        at org.kohsuke.stapler.RequestImpl.instantiate(RequestImpl.java:779)
        at org.kohsuke.stapler.RequestImpl.access$200(RequestImpl.java:83)
        at org.kohsuke.stapler.RequestImpl$TypePair.convertJSON(RequestImpl.java:678)
Caused: java.lang.IllegalArgumentException: Failed to instantiate class hudson.model.StringParameterValue from {"name":"thisIsAList","value":["one","two","three"]}
        at org.kohsuke.stapler.RequestImpl$TypePair.convertJSON(RequestImpl.java:680)
        at org.kohsuke.stapler.RequestImpl.bindJSON(RequestImpl.java:478)
        at org.kohsuke.stapler.RequestImpl.bindJSON(RequestImpl.java:474)
        at hudson.model.StringParameterDefinition.createValue(StringParameterDefinition.java:88)
        at hudson.model.ParametersDefinitionProperty._doBuild(ParametersDefinitionProperty.java:165)

Note: This may be a duplicate of How to pass an array to a jenkins parameterized job via remote access api? but it hasn't gotten a valid response.

Darrel Holt
  • 870
  • 1
  • 15
  • 39

2 Answers2

1

Since this level of nesting isn't detailed anywhere in the Jenkins or Ansible documentation I'll shed some light on the topic now that I've solved my issue.

The command:

ansible-playbook /home/<myUsr>/test/practice.yml --extra-vars "thisIsAList=$thisIsAList"

Should have declared thisIsAList to be a dictionary object. I.e.:

ansible-playbook /home/<myUsr>/test/practice.yml --extra-vars "{thisIsAList=$thisIsAList}"

Furthermore, the data in the cURL command should've been formatted differently like so:

json='{"parameter":[{"name":"thisIsAList","value":"[one,two,three]"}]}'

Note: the double-quotes are around the whole list, rather than the individual elements.

Finally, with further nested items (such as dict inside a list) you have to escape the double-quotes like so:

{"parameter":[{"name":"thisIsADictNestedInAList","value":"[{\"name\":\"numbers\",\"value\":[1s, 2s, 3s]}]"}]}

It seems, that at this level of nesting, it is no longer required to double-quote the lists; probably because the quotes one level up already lead it to be interpreted correctly.

Darrel Holt
  • 870
  • 1
  • 15
  • 39
1

This is a bit of a guess, based on a similar problem I have seen with a choice parameter. Any documentation I have found seems to be wrong about how to handle these. It shouldn't be a list. Try passing as a string with newlines separating the items.

curl -k -v -X POST https://jenkins.myhost.com/job/Ansible_Deploy/build?token=<appToken> --user <myUser>:<userToken> --data-urlencode json='{"parameter":[{"name":"thisIsAList","value":"one\ntwo\nthree"}]}'

Let me know if this works. I'm interested to find out.


Edit: (based on comments)

Would this work:

curl -k -v -X POST https://jenkins.myhost.com/job/Ansible_Deploy/build?token=<appToken> --user <myUser>:<userToken> --data-urlencode json='{"parameter":[{"name":"thisIsAList","value":"'{\"thisIsAList\": [\"one\",\"two\",\"three\"]}'"}]}'

The nested quotes get a bit ugly. If you are using pipeline or can massage the data in a shell script first, it would probably be cleaner.

Rob Hales
  • 5,123
  • 1
  • 21
  • 33
  • 1
    I re-read your question and I think I misunderstood at first. I see what you are trying to do now. The problem is not getting the data passed into Jenkins, (You can do it as a string. The problem is how to get that data out to Ansible properly. It needs to be formatted as JSON to pass a list. --extra-vars='{"test_list": [1,2,3]}' http://docs.ansible.com/ansible/latest/playbooks_variables.html#passing-variables-on-the-command-line – Rob Hales Sep 21 '17 at 16:36
  • Yeah, because POSTing to Jenkins causes the data to be sent to Ansible, I believe it gets interpreted twice. Once by TCP/IP trying to serialize it, and then again by the way Ansible wants the data structured in the `--extra-vars` option. So things have to be structured and escaped correctly. I solved the issue above though. – Darrel Holt Sep 21 '17 at 16:41
  • 1
    Ah. Yeah, I didn't notice that was your other answer. That is basically doing the same thing. – Rob Hales Sep 21 '17 at 16:44
  • Yup. Thanks for your suggestion though. I had originally tried something similar but it threw errors, yours didn't. It will probably be useful on a different part of this project, so thank you. – Darrel Holt Sep 21 '17 at 16:45