1

I need to write an ansible module using bash (since I do not know python). This is the shell module I used in my playbook that worked:

   - name: Finding out what web server it uses
     shell: "lsof -i :80 | grep LISTEN | cut -d ' ' -f 1"
     register: result
   - name: output the result of what web server it uses
     debug: msg="{{ result.stdout_lines|first }}"

And this is the wbsrv.sh bash script located where ansible.cfg wants it.

 #!/bin/bash
lsof -i :80 | grep LISTEN | cut -d ' ' -f 1
if [ $? == 0 ]; then
  printf '{"changed": true, "rc": 0}'
else
  printf '{"failed": true, "msg": "Something went wrong", "rc": 1}'
fi

And so I changed my playbook to this

 - name: Finding out what web server it uses
     wbsrv:
     register: result
 - name: output the result of what web server it uses
   debug: msg="{{ result.stdout_lines|first }}"

When I run the playbook the error happens at "TASK [output the result of what web server it uses]":

fatal: [vm2]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout_lines'\n\nThe error appears to have been in '/home/ansible/wbsrvtest.yml': line 19, column 6, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n     register: result\n   - name: output the result of what web server it uses\n     ^ here\n\nexception type: <class 'ansible.errors.AnsibleUndefinedVariable'>\nexception: 'dict object' has no attribute 'stdout_lines'"}

I tried removing the conditionals in the bash script. I tried putting echo instead of printf. I also tried setting RESULT variable to equal the line of bash code in the script and then echoing that in the if statement but all of that returned a similar error.

5
  • 1
    Try debugging the result variable to see what is stored inside it. Because you are handling it as it was the output of the shell module, but it's not. It's saving the output of your wbsrv module. I think that is the problem. Commented Jul 31, 2019 at 15:09
  • In addition to @guzmonne's comment, you may want to store the result of lsof -i :80 | grep LISTEN | cut -d ' ' -f 1 inside a variable, then include this variable in msg: key of the dict you printf, so that you register a correctly syntaxed result. Commented Jul 31, 2019 at 15:18
  • But shouldn't the wbsrv module that I made have the same output as the shell module since essentially it's the same command that's in the wbsrv.sh? ANd I don't know how to debug "result". Commented Jul 31, 2019 at 15:21
  • Debugging means outputting in this context. You have written this code, "debug: msg={{ result.stdout_lines|first }}" - thus you can replace it with debug: msg="{{ result }}" and walk from there. Commented Jul 31, 2019 at 15:25
  • @czipo, the fact that your module is in bash doesn't mean that its output is going to be the same as the shell module. Remember that the shell module is written in python. It takes a shell command, runs it, parses the result, and returns a custom json object with the parsed result, just as you do it with your custom module. Commented Jul 31, 2019 at 15:43

1 Answer 1

1

So it looks like you have a couple of things going on here. Calling the bash script doesn't need to be as complicated as creating a new module. If you want to make a module like that, you usually have to write it in python code.

https://docs.ansible.com/ansible/2.3/dev_guide/developing_modules_general.html

But it doesn't need to be that hard, you can just use ansibles pre-written modules to run your bash script for you. Create your bash script, and if you aren't running it against localhost only, use the copy module to place it on your remote host, and then just call it with the shell module, and that will give you the output that you are looking for. Also, I don't know if this was just a paste error, but your indentation in your example doesn't look right. Ansible is SUPER picky about indentation, so the module name isn't indented further than the 'name' designator. So you could try something like this:

- name: Place shell script
  copy:
    src: < source file path >/wbsrv.sh 
    dest: < desired file location >/wbsrv.sh
    owner: < desired owner >
    group: < desired group >
    mode: < desired permissions >

- name: Finding out what web server it uses
  shell: < desired file location >/wbsrv.sh
  register: result

- name: output the result of what web server it uses
  debug: msg="{{ result.stdout }}"

And if you don't want to leave artifacts just run another shell command module deleting the shell script that you placed. Also, if you are going to have your shell script only output a single line, you don't need to do the stdout_lines and cut it down. And if you run the playbook with the verbose flag, you can actually see the output of the shell command right in the output removing the need for the debug statement and the register (but it won't be as pretty).

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.