Creating Custom Targets using the NetBeez API

An essential part of automating your NetBeez configuration is the ability to add targets to your monitoring setup programmatically. I can think of two ways where this can be used for.

First, by setting up automation scripts that add or remove targets automatically, as you are adding and removing resources to your network/hybrid-cloud/cloud environments. For example, your application team is adding new servers to the application stack, and you need those resources to be automatically monitored. A script can be triggered every time a resource is added, that would add a new target for your agents to monitor.

Second, by setting up configuration scripts that configure your whole monitoring apparatus on NetBeez from scratch, or as a convergence loop that makes sure that the NetBeez configuration is in sync with your dev ops configuration management setup.

You can compose any type of Custom Target consisting of the following components:

  • any number of Ping, DNS, HTTP, Traceroute or Path Analysis test templates (which instantiate on a per agent basis. You can also assign alert detectors on a per test template basis.
  • assign the target to any Agent, or Agent Group.
  • configure the target to monitor tests on the Wired and/or the Wireless interfaces of a Network Agent (i.e. NetBeez provisioned wireless agents).
  • assign monitoring conditions, which dictate the conditions under which Remote Worker Agents should perform the tests defined within this target.

Endpoint and JSON-API data format

The endpoint we are using for this is a POST request to /targets. The full details of this endpoint can be found here. This endpoint accepts data in JSON-API format. Here is an example of a target that has 3 test templates (1x Ping, 1x DNS, 1x HTTP):

{
    "data": {
        "type": "target",
        "attributes": {
            "name": "API Target",
            "description": "",
            "wired_test": false,
            "wifi_test": true,
            "smtp_notify": true
        },
        "relationships": {
            "agents": {
                "data": [
                    {
                        "id": 122,
                        "type": "agent"
                    }
                ]
            },
            "agent_groups": {
                "data": [
                    {
                        "id": 1,
                        "type": "agent_group"
                    }
                ]
            },
            "contacts": {
                "data": [
                    {
                        "attributes": {
                            "email": "panickos@gmail.com"
                        },
                        "type": "contact"
                    }
                ]
            },
            "test_templates": {
                "data": [
                    {
                        "type": "test_template",
                        "attributes": {
                            "count": 0,
                            "interval": 5,
                            "timeout": 5,
                            "target": "api.netbeez.net",
                            "data_size": 56,
                            "dont_fragment": false,
                            "ping_type": 2,
                            "port": null,
                            "jitter_mos": false,
                            "force_ipv6": false
                        },
                        "relationships": {
                            "test_type": {
                                "data": {
                                    "id": 1,
                                    "type": "test_type"
                                }
                            },
                            "alert_detectors": {
                                "data": [
                                    {
                                        "id": 1,
                                        "type": "alert_detector"
                                    },
                                    {
                                        "id": 5,
                                        "type": "alert_detector"
                                    }
                                ]
                            }
                        }
                    },
                    {
                        "type": "test_template",
                        "attributes": {
                            "count": 0,
                            "interval": 30,
                            "timeout": 5,
                            "target": "api.netbeez.net",
                            "dns_server": "",
                            "dns_type": 1
                        },
                        "relationships": {
                            "test_type": {
                                "data": {
                                    "id": 2,
                                    "type": "test_type"
                                }
                            },
                            "alert_detectors": {
                                "data": [
                                    {
                                        "id": 2,
                                        "type": "alert_detector"
                                    },
                                    {
                                        "id": 6,
                                        "type": "alert_detector"
                                    }
                                ]
                            }
                        }
                    },
                    {
                        "type": "test_template",
                        "attributes": {
                            "count": 0,
                            "interval": 60,
                            "timeout": 5,
                            "target": "https://api.netbeez.net",
                            "http_method": "GET"
                        },
                        "relationships": {
                            "test_type": {
                                "data": {
                                    "id": 3,
                                    "type": "test_type"
                                }
                            },
                            "alert_detectors": {
                                "data": [
                                    {
                                        "id": 3,
                                        "type": "alert_detector"
                                    },
                                    {
                                        "id": 7,
                                        "type": "alert_detector"
                                    }
                                ]
                            }
                        }
                    }
                ]
            },
            "monitoring_condition": {
                "data": {
                    "id": 2,
                    "type": "monitoring_condition"
                }
            }
        }
    }
}

The JSON data above includes 5 main areas of interest:

  1. Target attributes (name/description and WiFi agent interfaces).
  2. Agents and Agent Group associations, by ID.
  3. SMTP notifications, by email addresses.
  4. List of Test Templates (each test type has its own attributes). Each test template defines its own alert_detectors to trigger the desired alerts.
  5. Monitoring Conditions.

Script to automate the creation of targets

The script would work on the CLI using the following command:

BEEZKEEPER_HOSTNAME=my-beezkeeper.example.com API_KEY="Xyz_123" TARGET_NAME="Test target" TARGET_FQDN=test.example.com create_target.py --template-file=target.json

The script would use the environment variables, and replace the target name and target FQDN in the JSON-API template, like the one from above. The agent group is going to be hardcoded in the template as well as the agent detector ids.

import os
import json
import argparse
import requests

def main():
    # Parse the arguments
    parser = argparse.ArgumentParser(description="Create a target using a JSON template")
    parser.add_argument('--template-file', required=True, help='Path to the JSON template file')
    args = parser.parse_args()

    # Get environment variables
    BEEZKEEPER_HOSTNAME = os.getenv('BEEZKEEPER_HOSTNAME')
    API_KEY = os.getenv('API_KEY')
    TARGET_NAME = os.getenv('TARGET_NAME')
    TARGET_FQDN = os.getenv('TARGET_FQDN')

    if not all([BEEZKEEPER_HOSTNAME, API_KEY, TARGET_NAME, TARGET_FQDN]):
        raise EnvironmentError("Missing one or more required environment variables.")

    # Read the JSON template file
    with open(args.template_file, 'r') as file:
        template = json.load(file)

    # Replace target name and FQDN in the template
    template['data']['attributes']['name'] = TARGET_NAME
    for test_template in template['data']['relationships']['test_templates']['data']:
        test_template['attributes']['target'] = TARGET_FQDN

    # Print the modified template for debugging
    print(json.dumps(template, indent=2))

    # Define the endpoint URL
    url = f"https://{BEEZKEEPER_HOSTNAME}/targets"

    # Define the headers for the request
    headers = {
        'Authorization': f'Bearer {API_KEY}',
        'Content-Type': 'application/json'
    }

    # Make the POST request to create the target
    response = requests.post(url, headers=headers, json=template, verify=False)

    # Check the response
    if response.status_code == 201:
        print("Target created successfully.")
    else:
        print(f"Failed to create target. Status code: {response.status_code}")
        print("Response:", response.json())

if __name__ == "__main__":
    main()

The script opens and reads the JSON template file specified by the --template-file argument. Modifies the JSON template by setting the name attribute of the target to the value of TARGET_NAME and the target attribute in each test template to the value of TARGET_FQDN.

It then makes a POST request to the NetBeez server to create the target.

Once the script is run you should notice the new target on your dashboard with the right agents attached to it.

I hope this post helps with planning your automation strategy in your organization. If these use-cases spark any ideas or scenarios that apply in your environment, please share them in comments!

1 Like