--- - name: Deploy connstats (single device, linear) hosts: all gather_facts: no vars: ssh_user: "{{ ansible_user | default('root') }}" ssh_pass: "{{ ansible_password | default(ansible_ssh_pass) }}" # RabbitMQ (use controls exchange + queue_controls like the reference) rmq_host: "{{ lookup('env','RMQ_HOST') | default('10.210.12.2', true) }}" rmq_port: "{{ lookup('env','RMQ_PORT') | default('15672', true) }}" rmq_user: "{{ lookup('env','RMQ_USER') | default('admin', true) }}" rmq_pass: "{{ lookup('env','RMQ_PASS') | default('change_me', true) }}" rmq_vhost: "{{ lookup('env','RMQ_VHOST') | default('app', true) }}" rmq_exchange: "{{ lookup('env','RMQ_EXCHANGE') | default('controls', true) }}" control_queue: "{{ lookup('env','CONTROL_QUEUE') | default('queue_controls', true) }}" # Cron line we must ensure (preserve any other lines) connstats_cron_line: "*/10 * * * * /root/connstats.sh --debug --always-find-offset >/dev/null 2>&1" tasks: - block: # --- SSH reachability check --- - name: Check SSH connectivity (raw ping) raw: "echo ping" register: ping_result ignore_errors: true - block: ############ step 2 - name: Compute MD5 of local connstats.sh delegate_to: localhost command: md5sum files/connstats.sh register: md5_local_cstats changed_when: false - name: Compute MD5 of remote /root/connstats.sh raw: "md5sum /root/connstats.sh || busybox md5sum /root/connstats.sh" register: md5_remote_cstats changed_when: false failed_when: false - name: Decide if connstats.sh needs upload set_fact: upload_cstats: >- {{ (md5_remote_cstats.rc != 0) or ((md5_local_cstats.stdout.split()[0]) != (md5_remote_cstats.stdout.split()[0] if (md5_remote_cstats.stdout is defined) else '')) }} - name: Upload connstats.sh via scp (overwrite if changed) when: upload_cstats | bool delegate_to: localhost command: > sshpass -p {{ ssh_pass | quote }} scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null files/connstats.sh {{ ssh_user }}@{{ ansible_host }}:/root/connstats.sh register: scp_connstats retries: 3 delay: 2 until: scp_connstats.rc == 0 - name: Ensure /root/connstats.sh is executable and owned by root raw: | chown root:root /root/connstats.sh && chmod 0755 /root/connstats.sh ############ step 3 - name: Ensure /etc/crontabs/root exists (touch with perms) raw: | if [ ! -f /etc/crontabs/root ]; then touch /etc/crontabs/root fi chown root:root /etc/crontabs/root chmod 0644 /etc/crontabs/root - name: Check if connstats cron line already present raw: | grep -Eq '^\*/10[[:space:]]+\*[[:space:]]+\*[[:space:]]+\*[[:space:]]+\*[[:space:]]+/root/connstats\.sh[[:space:]]+--debug[[:space:]]+--always-find-offset([[:space:]]+>/dev/null[[:space:]]+2>&1)?[[:space:]]*$' /etc/crontabs/root register: cron_grep failed_when: false changed_when: false - name: Upload snippet connstats-crond-root to /tmp (only if missing) when: cron_grep.rc != 0 delegate_to: localhost command: > sshpass -p {{ ssh_pass | quote }} scp -q -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null files/connstats-crond-root {{ ssh_user }}@{{ ansible_host }}:/tmp/connstats-crond-root.snippet - name: Append snippet to /etc/crontabs/root (only if missing) when: cron_grep.rc != 0 raw: | cat /tmp/connstats-crond-root.snippet >> /etc/crontabs/root && rm -f /tmp/connstats-crond-root.snippet register: cron_append changed_when: true - name: Set result status (success deployed or no change) set_fact: result_status: "{{ 'SUCCESS_DEPLOYED' if (upload_cstats | bool) else 'SUCCESS_NO_CHANGE' }}" when: ping_result is succeeded - name: Set status fact (no ssh) when: ping_result is failed set_fact: result_status: "NO_SSH" rescue: - name: Mark result as failed set_fact: result_status: "FAILED during {{ ansible_failed_task.name }}" always: - name: Compute inscope device set_fact: inscope_device_name: "{{ ansible_hostname | default(inventory_hostname) }}" # custom field update (per your sample) - name: Publish custom-field update connstats deployed to control queue delegate_to: localhost uri: url: "http://{{ rmq_host }}:{{ rmq_port }}/api/exchanges/{{ rmq_vhost | urlencode }}/{{ rmq_exchange | urlencode }}/publish" method: POST user: "{{ rmq_user }}" password: "{{ rmq_pass }}" force_basic_auth: true status_code: 200 headers: { content-type: "application/json" } body_format: json body: properties: { content_type: "application/json" } routing_key: "{{ control_queue }}" payload: "{{ { 'inscope_device': inscope_device_name, 'task_name': 'custom_field_set', 'task_add1': 'connstats', 'task_result': 'deployed' } | to_json }}" payload_encoding: "string" register: rmq_cf changed_when: false # final wrap-up journal "connstats: ..." with actions performed - name: Build actions list set_fact: _actions_list: >- {{ [] + ((upload_cstats | default(false) | bool) | ternary(['uploaded connstats.sh'], [])) + (((cron_grep is defined) and ((cron_grep.rc | default(0)) != 0)) | ternary(['added connstats crontab entry'], [])) }} - name: Build actions string set_fact: _actions_str: "{{ ((_actions_list | default([])) | length > 0) | ternary((_actions_list | join(', ')), 'no changes needed') }}" - name: Build wrap-up journal payload delegate_to: localhost set_fact: wrap_payload: inscope_device: "{{ inscope_device_name }}" task_name: "journal_add" task_result: >- connstats: {{ 'success' if (result_status == 'SUCCESS_DEPLOYED' or result_status == 'SUCCESS_NO_CHANGE') else result_status | lower }} — actions: {{ _actions_str }} - name: Publish wrap-up journal to control queue delegate_to: localhost uri: url: "http://{{ rmq_host }}:{{ rmq_port }}/api/exchanges/{{ rmq_vhost | urlencode }}/{{ rmq_exchange | urlencode }}/publish" method: POST user: "{{ rmq_user }}" password: "{{ rmq_pass }}" force_basic_auth: true status_code: 200 headers: content-type: "application/json" body_format: json body: properties: content_type: "application/json" routing_key: "{{ control_queue }}" payload: "{{ wrap_payload | to_json }}" payload_encoding: "string" register: rmq_wrap changed_when: (rmq_wrap.json is defined) and (rmq_wrap.json.routed | default(false) | bool) # Local summary (kept for operator visibility) - name: Summary debug: msg: - "result_status: {{ result_status }}" - "we're good"