BUG: Creating timeperiods with the REST-API fails for midnight

CMK version: 2.1.0p14
OS version: SLES 15.1

Hi. I’m struggeling with the REST-API and time periods. I’d like to create a time period “At night” from 20:00 to 07:00. With checkmk 1.6 I had to put it like this:

20:00-24:00 AND 00:00-07:00

in the GUI and it worked. (20:00-07:00 doesn’t work because “the from time must not be later then the until time”.)

Now with checkmk 2.1 I wanted to use the REST-API to create this time period instead of manipulating the file ~/etc/check_mk/conf.d/wato/timeperiods.mk. But the REST-API rejects the 24:00 and even the sample script from the docs fails. If I try 20:00-00:00, the REST-API doesn’t complain but I don’t think it really works because the GUI won’t let me enter these values.

The snippet:

resp = session.post(
    f"{API_URL}/domain-types/time_period/collections/all",
    headers={ "Content-Type": 'application/json', },
    json={
        'name': 'first',
        'alias': 'alias',
        'active_time_ranges': [{
            'day': 'all',
            'time_ranges': [
                { 'start': '20:00', 'end': '24:00' },
            ]
        }],
        'exceptions': [],
        'exclude': []
    },
)

Fails with an exception:

Traceback (most recent call last):
  File "./tp.py", line 41, in <module>
    raise RuntimeError(pprint.pformat(resp.json()))
  File "/usr/lib/python3/dist-packages/requests/models.py", line 897, in json
    return complexjson.loads(self.text, **kwargs)
  File "/usr/lib/python3/dist-packages/simplejson/__init__.py", line 518, in loads
    return _default_decoder.decode(s)
  File "/usr/lib/python3/dist-packages/simplejson/decoder.py", line 370, in decode
    obj, end = self.raw_decode(s)
  File "/usr/lib/python3/dist-packages/simplejson/decoder.py", line 400, in raw_decode
    return self.scan_once(s, idx=_w(s, idx).end())
simplejson.errors.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

So the problem is: 20:00-24:00 doesn’t work with the REST-API and 20:00-00:00 doesn’t work with the GUI.

Is this a known bug?

HI :slight_smile:

This seems indeed like a bug to me. If not anything else, you should get a better Error Message than a non-descriptive JSONDecodeError.

Could you give me your whole script? I don’t see line 41 in it, and it is the point where the error is originating from.

I’ll create a ticket for at least the error message and will talk to the other devs regarding the differences between the UI and the REST API.

But as I can understand it, you are able to use the REST API, it’s just that you have to use a different time span format for the REST API?

Kind regards
Philipp

1 Like

Hi Philipp!

Here is the complete script that runs into an exception.

Script create-timeperiod.py
#!/usr/bin/env python3
# -*- mode: Python; encoding: utf-8; indent-offset: 4; autowrap: nil -*-

import sys
import pprint
import requests


############################################################
#
############################################################
def main():

    HOST_NAME = "localhost"
    SITE_NAME = "testsite"
    API_URL = f"http://{HOST_NAME}/{SITE_NAME}/check_mk/api/1.0"

    USERNAME = "automation"
    PASSWORD = "test123"

    session = requests.session()
    session.headers['Authorization'] = f"Bearer {USERNAME} {PASSWORD}"
    session.headers['Accept'] = 'application/json'

    resp = session.post(
        f"{API_URL}/domain-types/time_period/collections/all",
        headers={
            "Content-Type": 'application/json',
        },
        json={
            'name': 'first',
            'alias': 'alias',
            'active_time_ranges': [{
                'day': 'all',
                'time_ranges': [{
                    'start': '20:00',
                    'end': '24:00'
                }]
            }],
            'exceptions': [],
            'exclude': []
        },
    )
    if resp.status_code == 200:
        pprint.pprint(resp.json())
    elif resp.status_code == 204:
        print("Done")
    else:
        raise RuntimeError(pprint.pformat(resp.json()))

    return 0


############################################################
#
############################################################
if __name__ == '__main__':
    sys.exit(main())

These are my observations:

  • If I create a time period 20:00-00:00 with the REST-API, it is not rejected but I don’t know if it really works and whether checkmk interprets this as the four hours after 20:00.

  • If I create a time period with the REST-API, no activation is needed. If I do the same in the GUI there is a pending change that requires activation.

  • If I query the timeperiods (GET /domain-types/time_period/collections/all) it returns the titles (aka aliases) of the time periods, but not their IDs. So it is impossible to first query the timeperiods and then show their details because that requires their IDs. To try this out, replace the session.post() call in the above script with this call:

resp = session.get(f"{API_URL}/domain-types/time_period/collections/all")

It will return something similar to this:

{'domainType': 'time_period',
 'id': 'timeperiod',
 'links': [{'domainType': 'link',
            'href': 'http://localhost/testsite/check_mk/api/1.0/domain-types/time_period/collections/all',
            'method': 'GET',
            'rel': 'self',
            'type': 'application/json'}],
 'value': [{'domainType': 'dict', 'title': 'some alias'},
           {'domainType': 'dict', 'title': 'Always'}]}

There are no time period IDs in that response. Just the aliases – which are now called title, btw. If you have further question, please feel free to contact me.

Regards
Dirk

Hi Philipp/Dirk,

Not sure if this has been written up as a bug yet but we also came across this and it comes down to DateTime module not considering 24:00 as a valid time, it is called in the File "/omd/sites/gw_dev/lib/python3/marshmallow/utils.py", line 177, in from_iso_time".

The UI must utilize another method as there is no issue setting 24:00 from the UI.
Stack trace came from prior cmk version 2.1, but i would say its the same root cause for 2.1.0p14

"title": "Internal Server Error",
  "status": 500,
  "detail": "hour must be in 0..23",
  "crash_id": "",
  "crash_report": {
	"href": ""
    "method": "get",
    "rel": "cmk/crash-report",
    "type": "text/html"
  },
  "stack_trace": [
    "Traceback (most recent call last):",
    "  File \"/omd/sites/dev/lib/python3/cmk/gui/wsgi/applications/rest_api.py\", line 403, in _wsgi_app",
    "    return wsgi_app(environ, start_response)",
    "  File \"/omd/sites/dev/lib/python3/cmk/gui/wsgi/applications/rest_api.py\", line 207, in __call__",
    "    wsgi_app = self.func(ParameterDict(path_args))",
    "  File \"/omd/sites/dev/lib/python3/cmk/gui/plugins/openapi/restful_objects/decorators.py\", line 610, in _wrapper",
    "    response = func(param)",
    "  File \"/omd/sites/dev/lib/python3/cmk/gui/plugins/openapi/restful_objects/decorators.py\", line 541, in _validating_wrapper",
    "    response = self.func(param)",
    "  File \"/omd/sites/dev/lib/python3/cmk/gui/plugins/openapi/endpoints/time_period.py\", line 80, in update_timeperiod",
    "    time_period = _to_api_format(time_period, internal_format=True)",
    "  File \"/omd/sites/dev/lib/python3/cmk/gui/plugins/openapi/endpoints/time_period.py\", line 197, in _to_api_format",
    "    active_time_ranges = _convert_to_dt(active_time_ranges)",
    "  File \"/omd/sites/dev/lib/python3/cmk/gui/plugins/openapi/endpoints/time_period.py\", line 272, in _convert_to_dt",
    "    period[\"time_ranges\"] = [convert_to_dt(entry) for entry in exception['time_ranges']]",
    "  File \"/omd/sites/dev/lib/python3/cmk/gui/plugins/openapi/endpoints/time_period.py\", line 272, in <listcomp>",
    "    period[\"time_ranges\"] = [convert_to_dt(entry) for entry in exception['time_ranges']]",
    "  File \"/omd/sites/dev/lib/python3/cmk/gui/plugins/openapi/endpoints/time_period.py\", line 268, in convert_to_dt",
    "    return {k: from_iso_time(v) for k, v in time_range.items()}",
    "  File \"/omd/sites/dev/lib/python3/cmk/gui/plugins/openapi/endpoints/time_period.py\", line 268, in <dictcomp>",
    "    return {k: from_iso_time(v) for k, v in time_range.items()}",
    "  File \"/omd/sites/dev/lib/python3/marshmallow/utils.py\", line 177, in from_iso_time",
    "    return dt.time(**kw)",
    "ValueError: hour must be in 0..23",

1 Like

I think this issue was fixed in Checkmk.
Can someone confirm, that that is the case in a recent Checkmk version?

Maybe it’s fixed in 2.2 but in 2.1.0p30 the behaviour still persists:

Behaviour in the GUI:
20:00 - 24:00: No complaint.
20:00 - 0:00 : red box “Invalid time format ‘0:00’, please use 24:00 format.”
20:00 - 00:00: red box “The from time must not be later then the until time.”

Behaviour when using the REST API:
20:00 - 24:00: RuntimeError (Invalid time format, 24:00 is not a valid time format)
20:00 - 0:00 : Seems to work (no complaint)
20:00 - 00:00: Seems to work (no complaint)

Still open in 2.1 and 2.2 (no new werk with “time period” topic in both branches).

Werk #15820: REST API now accepts ‘24:00’ as a time in time ranges. Version 2.2.0p8

I’m now working with 2.2.0p17 and I can confirm that “24:00” can be set via RestAPI.

1 Like

I can confirm that I tested against the wrong 2.2 version (2.2.0p7). :-} And I used the “wrong” search term. But I’m a little bit disappointed that the search function was not fuzzy enough to find the correct werk.

Does not work in 2.1, but in 2.2.0p8+.

1 Like