ansible-collections / community.general

Ansible Community General Collection
https://galaxy.ansible.com/ui/repo/published/community/general/
GNU General Public License v3.0
824 stars 1.52k forks source link

uptimerobot module error #7190

Open NathanQ opened 1 year ago

NathanQ commented 1 year ago

Summary

Using the uptimerobot module fails with AttributeError: 'NoneType' object has no attribute 'read'.

Issue Type

Bug Report

Component Name

uptimerobot

Ansible Version

ansible [core 2.11.12]

Community.general Version

Collection        Version
----------------- -------
community.general 3.8.3

Configuration

DEFAULT_STDOUT_CALLBACK = debug
DEFAULT_TRANSPORT = ssh
RETRY_FILES_ENABLED = False

OS / Environment

Ubuntu 16.04.7 LTS

Steps to Reproduce

---
- hosts: localhost
  vars:
    uptime_robot_api_key: <my_api_key>
    client_uptime_robot_monitor_id: <my_monitor_id>

  tasks:
    - name: Make sure that community.general.uptimerobot is available
      assert:
        that:
          - >
            'community.general.uptimerobot' is community.general.a_module

    - name: Pause Uptime Robot client monitor
      community.general.uptimerobot:
        monitorid: "{{ client_uptime_robot_monitor_id }}"
        apikey: "{{ uptime_robot_api_key }}"
        state: paused

    - name: timeout to check uptime
      ansible.builtin.pause:
        minutes: 2

    - name: Start Uptime Robot client monitor
      community.general.uptimerobot:
        monitorid: "{{ client_uptime_robot_monitor_id }}"
        apikey: "{{ uptime_robot_api_key }}"
        state: started

Expected Results

ok

Actual Results


MODULE_STDERR:

Traceback (most recent call last):
  File "/home/user/.ansible/tmp/ansible-tmp-1693433157.6933353-23327-236850561577025/AnsiballZ_uptimerobot.py", line 100, in <module>
    _ansiballz_main()
  File "/home/user/.ansible/tmp/ansible-tmp-1693433157.6933353-23327-236850561577025/AnsiballZ_uptimerobot.py", line 92, in _ansiballz_main
    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)
  File "/home/user/.ansible/tmp/ansible-tmp-1693433157.6933353-23327-236850561577025/AnsiballZ_uptimerobot.py", line 41, in invoke_module
run_name='__main__', alter_sys=True)
  File "/home/user/pyenv/versions/3.7.3/lib/python3.7/runpy.py", line 205, in run_module
    return _run_module_code(code, init_globals, run_name, mod_spec)
  File "/home/user/pyenv/versions/3.7.3/lib/python3.7/runpy.py", line 96, in _run_module_code
    mod_name, mod_spec, pkg_name, script_name)
  File "/home/user/pyenv/versions/3.7.3/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/tmp/ansible_community.general.uptimerobot_payload_69cspvlw/ansible_community.general.uptimerobot_payload.zip/ansible_collections/community/general/plugins/modules/uptimerobot.py", line 157, in <module>
  File "/tmp/ansible_community.general.uptimerobot_payload_69cspvlw/ansible_community.general.uptimerobot_payload.zip/ansible_collections/community/general/plugins/modules/uptimerobot.py", line 137, in main
  File "/tmp/ansible_community.general.uptimerobot_payload_69cspvlw/ansible_community.general.uptimerobot_payload.zip/ansible_collections/community/general/plugins/modules/uptimerobot.py", line 88, in checkID
AttributeError: 'NoneType' object has no attribute 'read'

Code of Conduct

ansibullbot commented 1 year ago

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

ansibullbot commented 1 year ago

cc @nate-kingsley click here for bot help

felixfontein commented 1 year ago

The module should definitely handle this better. In any case, this happens if some kind of error happens during the HTTP request. The return value info['status'] should be checked whether the HTTP status is acceptable, and if not the module should abort with at least telling the user the HTTP status code.

goetzk commented 1 year ago

Glad its not just me!

This caused me to look deeper and I think its because the API endpoint the module is using no longer exists.

~/.ansible/collections/ansible_collections/community/general/plugins/modules/monitoring/uptimerobot.py

API_BASE = "https://api.uptimerobot.com/"

API_ACTIONS = dict(
    status='getMonitors?',
    editMonitor='editMonitor?'
)

API_FORMAT = 'json'
API_NOJSONCALLBACK = 1
CHANGED_STATE = False
SUPPORTS_CHECK_MODE = False

def checkID(module, params):

    data = urlencode(params)
    full_uri = API_BASE + API_ACTIONS['status'] + data
    req, info = fetch_url(module, full_uri)
    result = to_text(req.read())
    jsonresult = json.loads(result)
    req.close()
    return jsonresult

Manually assembling full_uri we end up with https://api.uptimerobot.com/getMonitors, but the current API is suffixed by v2 (https://uptimerobot.com/api/)

$ vso -L https://api.uptimerobot.com/getMonitors 2>&1 |grep HTTP
* using HTTP/2
> GET /getMonitors HTTP/2
< HTTP/2 404 

vs

$ vso -L https://api.uptimerobot.com/v2/getMonitors 2>&1 |grep HTTP
* using HTTP/2
> GET /v2/getMonitors HTTP/2
< HTTP/2 200 

The V1 API was replaced in 2017 but I suppose its possible they finally deprecated an old endpoint and stopped handling its traffic - breaking us here.

goetzk commented 1 year ago

FTR the following idiom can be used in the mean time, flip status=1 to start the monitor again

    - name: Pause UptimeRobot monitoring                                                                                                                      
      delegate_to: localhost                                                                                                                                  
      run_once: true
      uri:
        body: "api_key={{ ur_api_main_key }}&format=json&id={{ item.id }}&status=0"                                                                           
        body_format: 'form-urlencoded'                                                                                                                        
        method: 'POST'
        url: "{{ ur_api_url_base + 'editMonitor' }}"                                                                                                          
      with_items: "{{ ur_monitors_list.json.monitors }}" 
goetzk commented 1 year ago

I spoke to uptime robot last night.

They confirmed a change in their infra probably caused the change in behaviour for that API endpoint but stressed v1 was fully retired two years ago.