Search code examples
shellcurlansibleambari

Execute curl command in ansible


I am trying to pass this curl command in ansible playbook :

shell: 'curl -k -u {{ AMBARI_USER }}:{{ AMBARI_PASSWORD }} -H 'X-Requested-By: ambari' -X POST -d '[{"Event": {"specs": [{"principal_type": "users", "sync_type": "all"}, {"principal_type": "groups", "sync_type": "all"}]}}]' https://{{AMBARI_SERVER_HOST}}:8083/api/v1/ldap_sync_events

here's my ansible playbook :

- hosts: adm
  tasks:
    - name: sync ldap
      shell: "curl -k -u {{ AMBARI_USER }}:{{ AMBARI_PASSWORD }} -H 'X-Requested-By: ambari' -X POST -d '[{"Event": {"specs": [{"principal_type": "users", "sync_type": "all"}, {"principal_type": "groups", "sync_type": "all"}]}}]' https://{{AMBARI_SERVER_HOST}}:8083/api/v1/ldap_sync_events"

The thing is that this command has multiple double and simple cotes, so it's not wrking, is there anyway to pass it here or i should create a shell script for it ? Thanks


Solution

  • Is there a reason you're using plain shell commands instead of the uri module? A general best practice is to prefer Ansible modules. They already fit to Ansible (e.g. change detection, error handling), save you work and may care about security if needed.

    For example, in your case it avoids struggeling with multiple nested quotes, since it abstracts the parameters instead of having a large call. Raw shell commands should only be used in special cases, when the Ansible module doesn't work for the use case.

    Something like this should fit for the base request using the uri module:

    - name: Make an API call
      uri:
        method: POST
        url: "https://{{ AMBARI_SERVER_HOST }}:8083/api/v1/ldap_sync_events"
        url_username: "{{ AMBARI_USER }}"
        url_password: "{{ AMBARI_PASSWORD }}"
        body_format: json
        headers:
          'X-Requested-By': 'ambari'
    

    Several ways exists to pass the JSON body:

    • As string, which would be possible here since you don't need additional quotes as you needed for the curl call. Something like this could be used:

      body: '[{"Event": ...'
      
    • A Ansible data structure like an array. Ansible would automatically convert it to JSON, as long as body_format is set to the corresponding type as the case in my example above

    • From a file. I'd prefer this if the JSON is larger, because you can directly paste the object there and have proper formatting, without messing the Ansible part. Just use lookup like this:

      body: "{{ lookup('file','api-body.json') }}"
      

    Just add the desired body property to uri. For example, If you want to have a json file, like this:

    - name: Make an API call
      uri:
        method: POST
        url: "https://{{ AMBARI_SERVER_HOST }}:8083/api/v1/ldap_sync_events"
        url_username: "{{ AMBARI_USER }}"
        url_password: "{{ AMBARI_PASSWORD }}"
        body: "{{ lookup('file','api-body.json') }}"
        body_format: json
        headers:
          'X-Requested-By': 'ambari'
        # If you're interested in the response
        return_content: yes
      register: api_result