Automatically labeling hosts based on specific services

Hello Checkmk community,

We are curious if anyone has found a way to automatically label hosts based on the specific services discovered during service discovery. The goal is to reduce the need to manually assign labels or rely on ‘explicit hosts’ within rules.

For example, after running service discovery, if a host has certain services like service1, service2, etc. I would like these hosts to be automatically labeled with relevant label. This way, when I create monitoring rules or dashboards, I can easily target hosts based on these labels without having to manually manage host groups or individual assignments.

When creating rules, we want to avoid using ‘explicit hosts’ and would prefer to use host groups based on labels. Labels would be assigned to hosts based on the services installed on them. For example, if service1 is installed on a host, that host should automatically be labeled with service1:yes.

There is an option to use service label rules that we tried, but you can only label services not hosts, therefore this does not fully meet our needs, as certain rules do not consider service labels for creating groups or rules.

Our goal is to automate this process so that we don’t have to manually add an explicit host to a rule every time. Instead, the rule should be automatically applied to a host based on the label it receives for the services it has.

Help or advise is appreciated, maybe someone has found some different approach to this type of problem.

We are using Checkmk Managed Services Edition 2.3.0p10.

Thank you :slight_smile:

Hi,

Maybe it could help to create the labels on the host site with a simple plugin or even cached output.

Format is:

<<<labels:sep(0)>>>
{"cpu/vendor": "zilog"}

See Creation of host labels - Format of section

Hi Michael,
thanks for pointing this out. Of course we can write a little plugin which will then add our labels.

But we thought that this is a simple straight forward request/idea, of how to automatize our config. I am sure, we havent been the first to think in such a way. I still do not believe this is not build in. Maybe i am just missing something ?

BR Miha.

Hi Miha,

maybe Roberts data2label solves your problem:

You can assign service labels based on host label filters, but not the other way around :frowning:

We use service labels quite extensively but we also use rules for service labels (and host labels) but we do not create host labels based on services (as we already have service labels)

But we create host labels based on our CMDB/IPAM so we know what kind of host it is (if this is what you are after)

I don’t think this is possible in checkmk without either writing a script, or using one already existing as @aeckstein showed.

Hello,

Thank you all for some great advice and help!

As I am really not that familiar with Python, I choose to write in Powershell (with some help of AI). For reference → REST API Host anlegen mit Label (Powershell) - #3 by Lars

# Configuration
$HOST_NAME = "hostname"
$SITE_NAME = "sitename"
$API_URL_BASE = "http://$HOST_NAME/$SITE_NAME/check_mk/api/1.0"
$USERNAME = "username"
$PASSWORD = "password"

# Prepare headers for API requests
$Credentials = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes("${USERNAME}:${PASSWORD}"))
$Headers = @{
    'Accept' = 'application/json'
    'Authorization' = "Basic $Credentials"
    'Content-Type' = 'application/json'
}

# Function to get all hosts
function Get-Hosts {
    $url = "$API_URL_BASE/domain-types/host_config/collections/all"
    $response = Invoke-RestMethod -Uri $url -Method Get -Headers $Headers
    return $response._embedded.host_config
}

# Function to get services for a host
function Get-ServicesForHost {
    param(
        [string]$HostId
    )
    $url = "$API_URL_BASE/domain-types/service_config/collections/all?host=$HostId"
    $response = Invoke-RestMethod -Uri $url -Method Get -Headers $Headers
    return $response._embedded.service_config
}

# Function to update a host with a label
function Update-HostLabel {
    param(
        [string]$HostId,
        [string]$LabelKey,
        [string]$LabelValue
    )
    $url = "$API_URL_BASE/domain-types/host_config/objects/$HostId"
    $body = @{
        "attributes" = @{
            "labels" = @{
                $LabelKey = $LabelValue
            }
        }
    } | ConvertTo-Json

    Write-Output ("Updating host " + $HostId + " with label " + $LabelKey + ": " + $LabelValue)
    Write-Output ("Request Body: " + $body)

    try {
        $response = Invoke-RestMethod -Uri $url -Method Put -Headers $Headers -Body $body
        Write-Output ("Response: " + ($response | ConvertTo-Json))
    } catch {
        Write-Output ("Error updating label: " + $_.Exception.Message)
    }
}

# Main script
$hosts = Get-Hosts

foreach ($host in $hosts) {
    $hostId = $host.id
    $services = Get-ServicesForHost -HostId $hostId

    $labels = @{}
    
    foreach ($service in $services) {
        if ($service.title -eq "Service1") {
            $labels["Service1"] = "yes"
        }
        if ($service.title -eq "Service2") {
            $labels["Service2"] = "yes"
        }
    }

    foreach ($label in $labels.GetEnumerator()) {
        Update-HostLabel -HostId $hostId -LabelKey $label.Key -LabelValue $label.Value
    }
}

Write-Output "Labels updated successfully."

As I execute the .ps1 script I only get the “Labels updated successfully.” When I check the hosts there are still no labels.

Am I missing something here?

Thank you!