REST API: Python question: How to use variables in "json={" post in key and value?

CMK version:2.0.0p26
OS version:RHEL 8

Hello Python Experts:

I need your help to add a server via REST API by using variables for the keys and values.
In general it works but I need some help to get the right syntax for the key and value definitions by using variables.

I need the right code to post key and value which are defined by a variable:
'tag_<VARIABLE1>': '<VARIABLE1>', # how is the right syntax to use the variable at the "json={" part?

And another question from my site: is there a more dynamical way to add attributes instead of such a rigid list, especially for the labels which are dynamic?

Has somebody a solution?

Thanks a lot!
Greetings JP

here is my code example:

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

SITE = "XXX"
SERVER_ALIAS = "ALIAS"
SERVER_IP = "127.0.0.1"
ENVIRONMENT = "Test"

VARIABLE1 = "1XXXXX"
VARIABLE2 = "'tag_" + VARIABLE1 + "': '" + VARIABLE1 + "'"

    resp = session.post(
        f"{API_URL}/domain-types/host_config/collections/all",
        headers={
            "Content-Type": 'application/json', 
        },
        json={                        
            'folder':'/test/test',            
            'host_name': '%s' % HOSTNAME,
            'attributes': {               
                           "site": '%s' % SITE,                
                           'alias': '%s' % SERVER_ALIAS,
                           'ipaddress': '%s' % SERVER_IP,
                           'tag_address_family': 'ip-v4-only',
                           
                           # ---------> upper part by using the variables are ok if the variable is a value < ---------------------
                           #..... Problem.......
                           
                           'tag_<VARIABLE1>': '<VARIABLE1>',     # how is the right syntax to use the variable?
                                                      
                           #f"{VARIABLE2},"                           # not working ==> how is the right syntax to use the variable?
                           #'%s' % VARIABLE2,                         # not working ==> how is the right syntax to use the variable?
                           #'' '%s' % VARIABLE2,                         # not working ==> how is the right syntax to use the variable?
                           
                           
                           #..........
                           "tag_environment": '%s' % ENVIRONMENT                
                           },        
            },
    )
    if resp.status_code == 200:
        pprint.pprint(resp.json())
    elif resp.status_code == 204:
        print("Done")
    else:
        raise RuntimeError(pprint.pformat(resp.json()))

Hello JPH,

I usually use f-strings like this:

f'tag_{VARIABLE1}': f'{VARIABLE1}',

https://docs.python.org/3/reference/lexical_analysis.html#f-strings

The title of this topic is misleading because you are talking about the REST API not the Web API.

Command reference for the HTTP-API versus
Configuration via the Checkmk REST API

1 Like

As addition to @mimimi i would also recommend not to build the JSON manually.
It is saver to use the json.dumps()

I rewrote your example a little bit and it is working without problem.

#!/usr/bin/env python3
import requests
import json

USERNAME = "omdadmin"
PASSWORD = "omd"
HOSTNAME = "TEST"

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

SITE = "home"
SERVER_ALIAS = "ALIAS"
SERVER_IP = "127.0.0.1"
ENVIRONMENT = "Test"
API_URL = "http://<servername>/<sitename>/check_mk/api/v0"

VARIABLE1 = "demo"

DATA = {
    "folder": "/test",
    "host_name": "%s" % HOSTNAME,
    "attributes": {
        "site": "%s" % SITE,
        "alias": "%s" % SERVER_ALIAS,
        "ipaddress": "%s" % SERVER_IP,
        "tag_address_family": "ip-v4-only",
        "tag_%s" % VARIABLE1: "%s" % VARIABLE1,
    },
}
print(json.dumps(DATA))
resp = session.post(
    f"{API_URL}/domain-types/host_config/collections/all",
    headers={
        "Content-Type": "application/json",
    },
    data=json.dumps(DATA),
)

if resp.status_code == 200:
    print(resp.json())
elif resp.status_code == 204:
    print("Done")
else:
    raise RuntimeError(print(resp.json()))

1 Like

Hello Mimimi
Thanks a lot!
(I changed the head line)

Hello Andreas
That looks very good!
Thanks a lot!

It is also possible to drop the json.dumps() line and directly use the json= parameter to the post() function:

resp = session.post(
    f"{API_URL}/domain-types/host_config/collections/all",
    headers={
        "Content-Type": "application/json",
    },
    json=DATA,
)

Despite the parameter’s name, it does not expect a JSON string (like data= does) but an ordinary (Python) dictionary. See also How to POST JSON data with Python Requests? - Stack Overflow

Hello Dirk

Thanks I will try it.
But currentliy I’m struggeling with the implementation of a variable: “ICTO_IMPORT_STRING_4” as whole line:

# the variable ICTO_IMPORT_STRING_4  has such definition, defined dyn. at a previous step.
ICTO_IMPORT_STRING_4 = "'tag_cmdb_icto_number_icto_777': 'icto_777','tag_cmdb_icto_number_icto_99': 'icto_99','tag_cmdb_icto_number_icto_0': 'icto_0',"

'labels': {
                
                           'tag_application_priority': '%s' % CMDB_APPLICATION_PRIORITY,            
                           'tag_cluster_function': '%s' % CLUSTER_AND_CLUSTER_NODE,
                           # '' '%s' % ICTO_IMPORT_STRING_4,
                            f"{ICTO_IMPORT_STRING_4}",
                           'tag_department': '%s' % DEPARTMENT,
                           'tag_test': '%s' % XXXXX

The problem is now that the output is in " which is not ok:

  'labels': {"'tag_cmdb_icto_number_icto_777': 'icto_777','tag_cmdb_icto_number_icto_99': 'icto_99','tag_cmdb_icto_number_icto_0': 'icto_0',tag_department": 'IPI',
                                          'tag_application_priority': 'priority_0',
                                          'tag_cluster_function': 'cluster_no',

ICTO part an department part is not ok with the "

Further the Checkmk API accepted the input but the labels icto and department are not shown.
Has somebody a solution for it?

Please let me know.

Thanks!
Regrads
JP

Try this:

import ast

# the variable ICTO_IMPORT_STRING_4  has such definition, defined dyn. at a previous step.
ICTO_IMPORT_STRING_4 = "'tag_cmdb_icto_number_icto_777': 'icto_777','tag_cmdb_icto_number_icto_99': 'icto_99','tag_cmdb_icto_number_icto_0': 'icto_0',"

# convert string into real dict:
import_string_as_dict = ast.literal_eval("{" + ICTO_IMPORT_STRING_4 + "}")  # (1)

...
"labels": {
    'tag_application_priority': '%s' % CMDB_APPLICATION_PRIORITY,
    'tag_cluster_function': '%s' % CLUSTER_AND_CLUSTER_NODE,
    'tag_department': '%s' % DEPARTMENT,
    'tag_test': '%s' % XXXXX,
    **import_string_as_dict     # (2)
}

The line marked with (1) converts the string ICTO_IMPORT_STRING_4 into a real Python dictionary. To achieve this, it first surrounds the string with curlies {…} and then applies ast.literal_eval() to that string. For this to work you need to import the ast module.

The line marked with (2) flattens the dictionary into key/value pairs and adds them to the "labels" dictionary.

Hello Dirk

Perfect!
Thanks so much! :+1: :+1: :+1:

1 Like

Hello Dirk

How is it possible to use the import:**import_string_as_dict # (2)
more than once?

  1. at the label definition
  2. at the main attributes of the host definition

It is not possible to use it twice in my environment.

Thank
Regards

JP

The goal is better flexability:

 IMPORT_STRING_AS_DICT_1 = ast.literal_eval("{" + ICTO_IMPORT_STRING_4 + "}")  # (1)
 
 ...
 ....
 
 
       json={                      
            'folder': '/api_test',            
            'host_name': '%s' % FQDN,
            'attributes': {     
                'tag_environment': '%s' % ENVIRONMENT,            
                'labels': {
                           'tag_environment': '%s' % ENVIRONMENT,
                           **IMPORT_STRING_AS_DICT_1     # (2)
                           },                                
                **IMPORT_STRING_AS_DICT_1     # (2) ==> This is not working
                },                
            },
...
...            

But this doesn’t work, but why?

Hello Dirk and Andreas

I find out what the mistake was in my environment, the variable IMPORT_STRING_DICT_1 was filled with tag-values which aren’t in my system. I replaced it and now it works like expected.

Here is my short example how my solution (with your help) works for me:

#!/usr/bin/env python3
import requests
import json
import subprocess
import ast

USERNAME = "USER"
PASSWORD = "PWD"
HOSTNAME = "TEST"
HOST_NAME = "localhost"
FOLDER = "/api_test"

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

SITE_NAME = subprocess.getoutput('whoami')
SERVER_ALIAS = "ALIAS"
SERVER_IP = "127.0.0.1"
API_URL = f"https://{HOST_NAME}/{SITE_NAME}/check_mk/api/1.0"

CMDB_APPLICATION_1 = "sap_ca"
CMDB_APPLICATION_PRIORITY = "prio_0"
 
ICTO_IMPORT_STRING_4 = "'tag_cmdb_icto_number_icto_903': 'icto_903', 'tag_cmdb_icto_number_icto_992': 'icto_992', 'tag_cmdb_icto_number_icto_225': 'icto_225'"
IMPORT_STRING_AS_DICT = ast.literal_eval("{" + ICTO_IMPORT_STRING_4 + "}")  # (1) 

DATA = {
    'folder':  '%s' % FOLDER,            
    "host_name": "%s" % HOSTNAME,
    "attributes": {
        "site": "%s" % SITE_NAME,
        "alias": "%s" % SERVER_ALIAS,
        "ipaddress": "%s" % SERVER_IP,
        "tag_address_family": "ip-v4-only",
        'labels': {                           
                    'tag_application_priority': '%s' % CMDB_APPLICATION_PRIORITY,                     
                    **IMPORT_STRING_AS_DICT     # (2)                    
                  },
        
        'tag_cmdb_appl_1_%s' % CMDB_APPLICATION_1: '%s' % CMDB_APPLICATION_1,        
        **IMPORT_STRING_AS_DICT     # (2)
    },
}
print(json.dumps(DATA))
resp = session.post(
    f"{API_URL}/domain-types/host_config/collections/all",
    headers={
        "Content-Type": "application/json",
    },
    data=json.dumps(DATA),
)

if resp.status_code == 200:
    print(resp.json())
elif resp.status_code == 204:
    print("Done")
else:
    raise RuntimeError(print(resp.json()))

Thank you so much!

Kind regards
JP

1 Like

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed. Contact an admin if you think this should be re-opened.