Git Product home page Git Product logo

netbox-plugin-prometheus-sd's Introduction

netbox-plugin-prometheus-sd

License: MIT CI PyPI

"Buy Me A Coffee"

Provide Prometheus http_sd compatible API Endpoint with data from Netbox.

HTTP SD is a feature since Prometheus 2.28.0 that allows hosts to be found via a URL instead of just files. This plugin implements API endpoints in Netbox to make devices, services, IPs and virtual machines available to Prometheus.

Compatibility

We aim to support the latest major versions of Netbox. For now we support Netbox >= 3.3 including bugfix versions.

Check the .github/workflows/ci.yml pipeline for the current tested builds. Other versions may work, but we do not test them explicitly. All relevant target versions are tested in CI.

Installation

The plugin is available as a Python package in pypi and can be installed with pip

pip install netbox-plugin-prometheus-sd

Enable the plugin in /opt/netbox/netbox/netbox/configuration.py:

    PLUGINS = ['netbox_prometheus_sd']

The plugin has not further plugin configuration.

Usage

The plugin only provides a new API endpoint on the Netbox API. There is no further action required after installation.

API

The plugin reuses Netbox API view sets with new serializers for Prometheus. This means that all filters that can be used on the Netbox API can also be used to filter Prometheus targets. Paging is disabled because Prometheus does not support paged results.

The plugin also reuses the Netbox authentication and permission model. Depending on the Netbox configuration, a token with valid object permissions must be passed to Netbox.

GET        /api/plugins/prometheus-sd/devices/              Get a list of devices in a prometheus compatible format
GET        /api/plugins/prometheus-sd/virtual-machines/     Get a list of vms in a prometheus compatible format
GET        /api/plugins/prometheus-sd/services/             Get a list of services in a prometheus compatible format
GET        /api/plugins/prometheus-sd/ip-addresses/         Get a list of ip in a prometheus compatible format

Extended services filters

Apart from standard Netbox filters, services endpoint also supports tenant=<slug> or tenant_id=<id> parameters. The lookup is only executed against the tenant attribute of the object associated with the service.

Config context

The plugin can also discover extra config to inject in the HTTP SD JSON from the config context of the devices/virtual machines. If you have a prometheus-plugin-prometheus-sd entry in your config context with the following schema it will be automatically picked up:

prometheus-plugin-prometheus-sd:
  - metrics_path: /not/metrics
    port: 4242
    scheme: https
  - port: 4243

This allow you to configure those values directly into netbox instead of doing that inside the Prometheus config and filtering each scenario by a specific tag for instance.

If there is only one entry you can also use this form:

prometheus-plugin-prometheus-sd:
  metrics_path: /not/metrics
  port: 4242
  scheme: https

Example

A working example on how to use this plugin with Prometheus is located at the example folder. Netbox content is created by using Netbox docker initializers.

The demo data doesn't make sense, but they are good enough for demonstrating how to configure Prometheus and get demo data to Prometheus service discovery.

Go to the example folder and run docker-compose up. Prometheus should get available on http://localhost:9090.

Push some example devices and objects to Netbox using the initializers:

docker-compose exec  netbox /opt/netbox/netbox/manage.py load_initializer_data --path /opt/netbox/initializers

Netbox content should then be available in the service discovery tab.

Development

We use Poetry for dependency management and invoke as task runner. As Netbox plugins cannot be tested standalone, we need invoke to start all code embedded in Netbox Docker containers.

All code to run in docker is located under develop. To start a virtual env managed by poetry run poetry shell. All following commands are started inside this environment.

In order to run tests invoke the test steps

# Build Docker images
invoke build

# Execute all tests
invoke tests

# Execute unit tests only
invoke unittest

Features should be covered by a unit test, but some times it's easier to develop on an running system.

# Start a local Netbox with docker
invoke start

# Create an user named `admin`
invoke create-user

Visit http://localhost:8000 and log in with the new user. You can now define Netbox entities and test around.

API endpoints for testing can be found at http://localhost:8000/api/plugins/prometheus-sd/

Conventional Commits

This repository follows the Conventional Commits specification for versioning and changelog generation. Conventional Commits provide a standardized way of writing commit messages to convey semantic meaning about the changes made. Each commit message follows a defined format that includes a type, an optional scope, and a message. The types typically include features, fixes, documentation, and more. By adhering to this convention, we ensure clear and automated versioning, release notes, and changelog generation.

netbox-plugin-prometheus-sd's People

Contributors

candlerb avatar dependabot[bot] avatar feuri avatar flxpeters avatar geg347 avatar jeffbaier avatar jkrcma avatar johanfleury avatar jsenecal avatar k0ste avatar llamafilm avatar mrfreezeex avatar oijkn avatar ryanmerolle avatar stephrdev avatar steve-nscale avatar streaming-pete avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

netbox-plugin-prometheus-sd's Issues

Pass down prometheus scraping information in the config context

Hello,

We would like to use this plugin in some kind of "self service manner" netbox wise. Meaning that we would essentially use one http_sd_config (technically two for vms and server in our case) with something like: /api/plugins/prometheus-sd/devices/?tags=prom-autoconfig and then use config context to configure metrics_path, ports etc.

The idea is to have something similar as what we used to configure Kubernetes (essentially before or if prometheus-operator is not used) with annotation on pods like: prometheus.io/scheme, prometheus.io/path, prometheus.io/port.

I propose to put something like that in the config context:

prometheus-plugin-prometheus-sd:
  - metrics_path: /not/metrics
    port: 4242
    scheme: https
  - port: 4243

And then the plugin would discover this and use it for the http sd json essentially. Of course I am happy to work on the implementation, in case that's something that could be included!

Prometheus Reader failure

Before I start, thank you for this work and I fully admit this could be me. No experience with Prometheus at all here.
prometheus-2.42.0.linux-amd64
netbox 3.4.5

API seems to return good data, validly formatted. Ran output through json lint and looks valid. All elements are strings excep for the id.

          "__meta_netbox_id": 81,

Prometheus never shows the target at all and logs this error:

Feb 23 08:35:13 prometheus.netfortris.com prometheus[11055]: ts=2023-02-23T16:35:13.317Z caller=refresh.go:99 level=error component="discovery manager scrape" discovery=http config=http_sd_devices msg="Unable to refresh target groups" err="json: cannot unmarshal number into Go struct field .labels of type model.LabelValue"

Prometheus config:

  - job_name: "http_sd_devices"
#    metrics_path: /netbox
    scheme: https
#    static_configs:
#      - targets: ["localhost:9090"]
    http_sd_configs:
    - url: https://netbox.netfortris.net/api/plugins/prometheus-sd/devices/?has_primary_ip=true&name=atl-bdr1
      refresh_interval: 15s
      authorization:
        type: "Token"
        credentials: "blahblahblahforthelength of the token."

Validated with curl that the data is returned properly from the url with the proper api key. I get different issues if I try to use the metrics_path so I let it default with the other job into /metrics.

Add support for Netbox 3.6

In Netbox 3.6, "device_role" has been renamed to "role". This gives the following exception:

Internal Server Error: /api/plugins/prometheus-sd/devices/

ValueError at /api/plugins/prometheus-sd/devices/
'device_role' does not resolve to an item that supports prefetching - this is an invalid parameter to prefetch_related().

Request Method: GET
Request URL: https://netbox.example.net/api/plugins/prometheus-sd/devices/?tag=prom_snmp&status=active
Django Version: 4.2.4
Python Executable: /opt/netbox/venv/bin/python3.8
Python Version: 3.8.10
Python Path: ['/opt/netbox/netbox', '/opt/netbox', '/opt/netbox/venv/bin', '/usr/lib/python38.zip', '/usr/lib/python3.8', '/usr/lib/python3.8/lib-dynload', '/opt/netbox/venv/lib/python3.8/site-packages']
Server time: Thu, 31 Aug 2023 10:08:31 +0000
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.humanize',
 'corsheaders',
 'debug_toolbar',
 'graphiql_debug_toolbar',
 'django_filters',
 'django_tables2',
 'django_prometheus',
 'graphene_django',
 'mptt',
 'rest_framework',
 'social_django',
 'taggit',
 'timezone_field',
 'core',
 'account',
 'circuits',
 'dcim',
 'ipam',
 'extras',
 'tenancy',
 'users',
 'utilities',
 'virtualization',
 'wireless',
 'django_rq',
 'drf_spectacular',
 'drf_spectacular_sidecar',
 'netbox_prometheus_sd.PrometheusSD']
Installed Middleware:
['graphiql_debug_toolbar.middleware.DebugToolbarMiddleware',
 'django_prometheus.middleware.PrometheusBeforeMiddleware',
 'corsheaders.middleware.CorsMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware',
 'django.middleware.security.SecurityMiddleware',
 'netbox.middleware.RemoteUserMiddleware',
 'netbox.middleware.CoreMiddleware',
 'netbox.middleware.MaintenanceModeMiddleware',
 'django_prometheus.middleware.PrometheusAfterMiddleware']


Traceback (most recent call last):
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
    return view_func(*args, **kwargs)
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "/opt/netbox/netbox/netbox/api/viewsets/__init__.py", line 91, in dispatch
    return super().dispatch(request, *args, **kwargs)
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
    raise exc
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "/opt/netbox/netbox/netbox/api/viewsets/mixins.py", line 95, in list
    return super().list(request, *args, **kwargs)
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/mixins.py", line 46, in list
    return Response(serializer.data)
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/serializers.py", line 768, in data
    ret = super().data
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/serializers.py", line 253, in data
    self._data = self.to_representation(self.instance)
  File "/opt/netbox/venv/lib/python3.8/site-packages/rest_framework/serializers.py", line 686, in to_representation
    return [
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/db/models/query.py", line 398, in __iter__
    self._fetch_all()
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/db/models/query.py", line 1883, in _fetch_all
    self._prefetch_related_objects()
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/db/models/query.py", line 1273, in _prefetch_related_objects
    prefetch_related_objects(self._result_cache, *self._prefetch_related_lookups)
  File "/opt/netbox/venv/lib/python3.8/site-packages/django/db/models/query.py", line 2310, in prefetch_related_objects
    raise ValueError(

Exception Type: ValueError at /api/plugins/prometheus-sd/devices/
Exception Value: 'device_role' does not resolve to an item that supports prefetching - this is an invalid parameter to prefetch_related().
Raised during: netbox_prometheus_sd.api.views.DeviceViewSet
Request information:
USER: admin

GET:
tag = 'prom_snmp'
status = 'active'

POST: No POST data

FILES: No FILES data

Expose Top Level location.

Hi all, Firstly GREAT project :D

With netbox having the ability to build hierarchies of Locations, and then racks living in a location.

Eg

Site Location Location Rack
DataCenter 1 Data Suite 1 Row - A Rack 1

Currently the prom_sd exporter returns the rack and the location on the next level up, so using the above example, you can get the rack and the racks first level parent and the site.

What you cant get is the top level parent of the rack.

i have had a look in the code, but I am unable to work out the best way to get that data, I think we are going to have to make another call to pull in the parent of the first level parent.

Any suggestions on how this might be implemented, im happy to take a stab at it, but im struggling to work out the best way forward.

Add support for Netbox webhooks

Hello,

Currently the sd plugin creates an api call for each job following the configured refresh_interval under the http_sd_config in prometheus (http_sd_config).

This might create some load if you have quite some jobs for different device types running over different prometheus instances.
It would be nice to let this plugin do the initial scrape on prometheus request and subscribe to changes through Netbox webhooks and dynamically update the sd result for prometheus based on the received changes from the Netbox webhook.

This creates a kind of cache for netbox limiting the amount of database calls happening.

I am unsure how in scope this is but it would be nice to have it as a feature that can be enabled on request (giving both options between in memory cache or not)

django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.

Hi,
I am testing using netbox v4.0.5 on docker got error :

example-netbox-1 | โณ Waiting on DB... (15s / 30s)
example-netbox-1 | ๐Ÿงฌ loaded config '/etc/netbox/config/configuration.py'
example-netbox-1 | ๐Ÿงฌ loaded config '/etc/netbox/config/extra.py'
example-netbox-1 | ๐Ÿงฌ loaded config '/etc/netbox/config/logging.py'
example-netbox-1 | ๐Ÿงฌ loaded config '/etc/netbox/config/plugins.py'
example-netbox-1 | Traceback (most recent call last):
example-netbox-1 | File "/opt/netbox/netbox/./manage.py", line 10, in
example-netbox-1 | execute_from_command_line(sys.argv)
example-netbox-1 | File "/opt/netbox/venv/lib/python3.11/site-packages/django/core/management/init.py", line 442, in execute_from_command_line
example-netbox-1 | utility.execute()
example-netbox-1 | File "/opt/netbox/venv/lib/python3.11/site-packages/django/core/management/init.py", line 436, in execute
example-netbox-1 | self.fetch_command(subcommand).run_from_argv(self.argv)
example-netbox-1 | File "/opt/netbox/venv/lib/python3.11/site-packages/django/core/management/base.py", line 413, in run_from_argv
example-netbox-1 | self.execute(*args, **cmd_options)
example-netbox-1 | File "/opt/netbox/venv/lib/python3.11/site-packages/django/core/management/base.py", line 454, in execute
example-netbox-1 | self.check()
example-netbox-1 | File "/opt/netbox/venv/lib/python3.11/site-packages/django/core/management/base.py", line 486, in check
example-netbox-1 | all_issues = checks.run_checks(
example-netbox-1 | ^^^^^^^^^^^^^^^^^^
example-netbox-1 | File "/opt/netbox/venv/lib/python3.11/site-packages/django/core/checks/registry.py", line 88, in run_checks
example-netbox-1 | new_errors = check(app_configs=app_configs, databases=databases)
example-netbox-1 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
example-netbox-1 | File "/opt/netbox/venv/lib/python3.11/site-packages/django/core/checks/model_checks.py", line 18, in check_all_models
example-netbox-1 | models = apps.get_models()
example-netbox-1 | ^^^^^^^^^^^^^^^^^
example-netbox-1 | File "/opt/netbox/venv/lib/python3.11/site-packages/django/apps/registry.py", line 181, in get_models
example-netbox-1 | self.check_models_ready()
example-netbox-1 | File "/opt/netbox/venv/lib/python3.11/site-packages/django/apps/registry.py", line 143, in check_models_ready
example-netbox-1 | raise AppRegistryNotReady("Models aren't loaded yet.")
example-netbox-1 | django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.
example-netbox-1 | โณ Waiting on DB... (18s / 30s)

Thank you

Update needed for Netbox 4.0

Hi,

There are some breaking changes in Netbox 4.0, including the following:

from extras.plugins import PluginConfig should be replaced by from netbox.plugins import PluginConfig.

I'm not sure what else needs to be changed, but is an update planned to be compatible with Netbox 4.0 ? Thanks :)

P.S.: Here are the changes from Netbox Doc.

Bug: unmarshal error for devices. Must have been a structure change recently

I'm not positive when this broke, but noticed it this morning, so possibly related to netbox 4.0.9 changes but will need to look.

            "__meta_netbox_rack_u_position": 31.0,

This causes:

ts=2024-08-16T14:25:05.851Z caller=refresh.go:90 level=error component="discovery manager scrape" discovery=http config=nb_snmp msg="Unable to refresh target groups" err="json: cannot unmarshal number into Go struct field .labels of type model.LabelValue"

Easy fix in utils to force it back to a string. PR to come.

Slow performance and excessive SQL queries

While this plugin works great with a small number of devices, it becomes very slow at scale. For example, with 1158 devices on my test, the following query takes 23 seconds.

This instance is running v3.7.0 on EC2 m5.2xlarge (8 vCPU and 32GB memory), connected to Postgres 15 in RDS Aurora.

/api/plugins/prometheus-sd/devices/?status=active&cf_prometheus_blackbox_module__n=null

I did a little investigation and found that 99% of that time is spent querying the database. The HTTP download is only 10ms. Postgres log shows that this one API call causes 6157 SELECT statements, about 2/3 of which return 0 rows. You can see this log here: prometheus-sd-query.psql.zip

To easily replicate this issue, you can launch a fresh instance of netbox-docker and run the following code in nbshell. This way it's a bit faster, taking 13 seconds, perhaps because the database is local.

# >>> exec(open('/etc/netbox/config/scripts/init-dummy-data.py').read())

import ipaddress
from django.db import transaction

s = Site(name='Dummy Site', slug='dummy-site')
s.full_clean()
s.save()

m = Manufacturer(name='Generic', slug='generic')
m.full_clean()
m.save()

dt = DeviceType(model='Generic Device', manufacturer_id=1, slug='generic-device')
dt.full_clean()
dt.save()

it = InterfaceTemplate(name='eth0', type='virtual', device_type_id=1)
it.full_clean()
it.save()

dr = DeviceRole(name='Generic Role', slug='generic-role')
dr.full_clean()
dr.save()

print(f"Created Dummy Site, Manufacturer, Device Type, and Device Role")
print("Creating {num_hosts} dummy devices...")

hosts = list(ipaddress.IPv4Network('127.0.0.0/16'))
num_hosts= 2000
for i in range(num_hosts):
    # if any nested atomic transactions fail then device will not be created
    with transaction.atomic():
        # create device (and interface)
        d = Device(
            site=s,
            name = f'Dummy Device {i:03}',
            device_type=dt, 
            role=dr
        )
        d.full_clean()
        d.save()
        
        # create IP and assign to interface
        ip = IPAddress(address=f"{hosts[i]}/32")
        ip.assigned_object = d.interfaces.first()
        with transaction.atomic():
            ip.full_clean()
            ip.save()
        
        # assign device primary IP
        d.primary_ip4 = ip
        with transaction.atomic():
            d.full_clean()
            d.save()

print(f"Done!")

Exclude devices/VMs via a config context setting

Hello,
Would it be possible to exclude devices/VMs being shown in the api/plugins/prometheus-sd/devices/ API endpoint please?
For context - we're looking at making a low weight config context with something like

{
    "prometheus-plugin-prometheus-sd": {
        "monitor": "false"
    }
}

in it. Then a higher weight one that we can apply to certain roles, sites etc. that has more useful information:

{
    "prometheus-plugin-prometheus-sd": {
        "monitor": "true",
        "metrics_path": "/metrics",
        "port": 9100,
        "scheme": "http"
    }
}

This would then allow us to get just the devices we'd like to monitor, without having to filter by roles in the API and setting the correct config context for roles inside Netbox for instance. Effectively, by only changing config contexts in Netbox your list of devices to monitor is automatically updated without you needing to change any Prometheus config at all!

e.g. you wouldn't need to do api/plugins/prometheus-sd/devices/?role=x&role=y any more because you can do it all via Netbox.
What do you think?
Thanks!

Include Site and Region as __meta labels

The current list of __meta_netbox labels is good, but I think it would be helpful to include Site and Region.

Forgive me if I have just missed them or if there is a good reason not to include them.

Issues with custom field multiple selection list

Version

# /opt/netbox/venv/bin/pip freeze | grep prometheus-sd
netbox-plugin-prometheus-sd @ git+https://github.com/FlxPeters/netbox-plugin-prometheus-sd@686cb3ba3cd726a163659f2303aad822414bb6a7

running under Netbox 3.7.4

Issues

I have a couple of problems with labels from a custom field, where the value it contains is a list. The example here is a custom field called "snmp_module" of type "multiple selection", linked to a choice set with strings.

Problem 1: the label value returned is a Python-style repr().

# curl -sS -H "Authorization: Token $TOKEN" "$NETBOX/api/plugins/prometheus-sd/devices/?cf_snmp_module__ic=i" | jq .
...
      "__meta_netbox_custom_field_snmp_module": "['hrDevice', 'hrStorage', 'if_mib', 'mikrotik']",

In order to get this into a simple comma-separated list (as required by snmp_exporter with multiple modules) I have to use a very ugly rewrite:

      - source_labels: [__meta_netbox_custom_field_snmp_module]
        target_label: __param_module
      # Ugh: multiselect is of form ['foo', 'bar'] and we need foo,bar. There is no gsub.
      - source_labels: [__param_module]
        regex: "\\['(.*)'\\]"
        target_label: __param_module
      - source_labels: [__param_module]
        regex: "(.*)', *'(.*)"
        replacement: "$1,$2"
        target_label: __param_module
      - source_labels: [__param_module]
        regex: "(.*)', *'(.*)"
        replacement: "$1,$2"
        target_label: __param_module
      - source_labels: [__param_module]
        regex: "(.*)', *'(.*)"
        replacement: "$1,$2"
        target_label: __param_module

... and this only works up to a fixed maximum number of values (4 here), as there's no "gsub" in prometheus rewriting.

Problem 2: when the custom field is unset the label gets the string value "None", whereas I would expect either empty string or the entire label to be omitted.

...
      "__meta_netbox_custom_field_snmp_module": "None",

(This is minor: I could always match this value explicitly in a rewrite rule, and I'm unlikely to use "None" as a genuine choice value)

Proposal

For values of a multiple selection type, I'd like to see such a list returned as a plain comma-separated list of strings.

What about other types of custom field that might return a list? I can only see two that might make a difference:

  • JSON fields. These can stay as is. JSON is JSON, after all.
  • Multiple Object Selection. I haven't tested what these do today. Maybe simplest is to generate a comma-separated list of the str(...) representation of each object, so you get whatever the default display is. (I suppose it could also be a comma-separated list of object ID, or of slug for object classes which have slugs, but there's no obvious one-size-fits-all)

The question is whether the prometheus-sd plugin would have to dig into the definition of a custom field to determine whether it's JSON or not.

References

Relates to #34, #65

Include location label

Is there a way to include Netbox location field as a label to Prometheus? I organize devices using a site > room hierarchy, so I'm using location to mean the room. Site represents a physical building here.

Intended use / Add more usage examples

I can't seem to wrap my head around how this works in general. Netbox api call (with slight mod to change id to string from other thread) returns a boatload of items out of my netbox.

Those 758 objects all show as "down" because prometheus then tries to contact each of them on port 80 (of which most do not respond). I assume that I should be adding something to the netbox side so that prometheus then knows what to look for in an object? i.e. use snmp, snmp community, address to use instead of the name?

plugin not working under netbox v3.2

I tried to install this plugin under netbox v3.2 that was released a few days ago. Unfortunately the plugin fails with:

netbox-worker_1        | Traceback (most recent call last):
netbox-worker_1        |   File "/opt/netbox/netbox/manage.py", line 10, in <module>
netbox-worker_1        |     execute_from_command_line(sys.argv)
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
netbox-worker_1        |     utility.execute()
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/core/management/__init__.py", line 440, in execute
netbox-worker_1        |     self.fetch_command(subcommand).run_from_argv(self.argv)
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/core/management/base.py", line 414, in run_from_argv
netbox-worker_1        |     self.execute(*args, **cmd_options)
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/core/management/base.py", line 455, in execute
netbox-worker_1        |     self.check()
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/core/management/base.py", line 487, in check
netbox-worker_1        |     all_issues = checks.run_checks(
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/core/checks/registry.py", line 88, in run_checks
netbox-worker_1        |     new_errors = check(app_configs=app_configs, databases=databases)
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/core/checks/urls.py", line 14, in check_url_config
netbox-worker_1        |     return check_resolver(resolver)
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/core/checks/urls.py", line 24, in check_resolver
netbox-worker_1        |     return check_method()
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/urls/resolvers.py", line 480, in check
netbox-worker_1        |     for pattern in self.url_patterns:
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/utils/functional.py", line 49, in __get__
netbox-worker_1        |     res = instance.__dict__[self.name] = self.func(instance)
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/urls/resolvers.py", line 696, in url_patterns
netbox-worker_1        |     patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/utils/functional.py", line 49, in __get__
netbox-worker_1        |     res = instance.__dict__[self.name] = self.func(instance)
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/django/urls/resolvers.py", line 689, in urlconf_module
netbox-worker_1        |     return import_module(self.urlconf_name)
netbox-worker_1        |   File "/usr/lib/python3.9/importlib/__init__.py", line 127, in import_module
netbox-worker_1        |     return _bootstrap._gcd_import(name[level:], package, level)
netbox-worker_1        |   File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
netbox-worker_1        |   File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
netbox-worker_1        |   File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
netbox-worker_1        |   File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
netbox-worker_1        |   File "<frozen importlib._bootstrap_external>", line 855, in exec_module
netbox-worker_1        |   File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
netbox-worker_1        |   File "/opt/netbox/netbox/netbox/urls.py", line 9, in <module>
netbox-worker_1        |     from extras.plugins.urls import plugin_admin_patterns, plugin_patterns, plugin_api_patterns
netbox-worker_1        |   File "/opt/netbox/netbox/extras/plugins/urls.py", line 35, in <module>
netbox-worker_1        |     urlpatterns = import_object(f"{plugin_path}.api.urls.urlpatterns")
netbox-worker_1        |   File "/opt/netbox/netbox/extras/plugins/utils.py", line 31, in import_object
netbox-worker_1        |     spec.loader.exec_module(module)
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/netbox_prometheus_sd/api/urls.py", line 2, in <module>
netbox-worker_1        |     from .views import VirtualMachineViewSet, DeviceViewSet, IPAddressViewSet
netbox-worker_1        |   File "/opt/netbox/venv/lib/python3.9/site-packages/netbox_prometheus_sd/api/views.py", line 4, in <module>
netbox-worker_1        |     from extras.api.views import CustomFieldModelViewSet
netbox-worker_1        | ImportError: cannot import name 'CustomFieldModelViewSet' from 'extras.api.views' (/opt/netbox/netbox/extras/api/views.py)

It seems some changes are needed to make it compatible with newer netbox.

There seems to be a ticket with changes that were made to the plugin framework.

Feat: Add custom fields to enable prometheus for IP and specify port

Dear @FlxPeters,

thank you very much for bringing this plugin to life!

For our usage, it would be beneficial if the following two features were available:

  1. Read a custom field boolean prometheus-sd_enable and only show the entry if the box is ticked (default: true).
  2. Read a custom field integer prometheus-sd_port that will specify the exporter's port for this entry (default: 9100).

Personally, I'd leave it up to the users to decide wether they want to add the custom fields by hand. As both fields have sane defaults, existing installations should not face any issues.

What do you think? Would these be helpful additions to the plugin? :)

Best, phpfs

Query is basically slow

curl -Li ${NETBOX_URL}/api/plugins/prometheus-sd/devices?role=server&status=active&limit=100 -H "Authorization: Token $NETBOX_TOKEN" -H "Content-Type: application/json; indent=4" -o /dev/null
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 47924 100 47924 0 0 873 0 0:00:54 0:00:54 --:--:-- 10523

real 0m54.860s
user 0m0.078s
sys 0m0.015s
root@instance-20240429-121233:~/netbox-docker#

I have ca 50 devices listed, netbox version is 4.0.5

[Feature] - Add iregex filter for devices model and return custom_fields as labels

Hi, below is the Netbox API return from /api/dcim/devices/?name=router-01.example.com and I would like to know if you could implement in your API a filter on the model or model slug (using the model__iregex) that will return all devices matching this model as well as an option to return all custom_fields as labels, please.

{
    "count": 1,
    "next": null,
    "previous": null,
    "results": [
        {
            "id": 8,
            "url": "https://netbox.example.com/api/dcim/devices/8/",
            "display": "router-01.example.com",
            "name": "router-01.example.com",
            "device_type": {
                "id": 61,
                "url": "https://netbox.example.com/api/dcim/device-types/61/",
                "display": "Dlink xSeries",
                "manufacturer": {
                    "id": 12,
                    "url": "https://netbox.example.com/api/dcim/manufacturers/12/",
                    "display": "DLINK",
                    "name": "DLINK",
                    "slug": "dlink"
                },
                "model": "Dlink xSeries",
                "slug": "dlink-xseries"
            },
            "device_role": {
                "id": 5,
                "url": "https://netbox.example.com/api/dcim/device-roles/5/",
                "display": "ROUTER",
                "name": "ROUTER",
                "slug": "ROUTER"
            },
            "tenant": {
                "id": 1,
                "url": "https://netbox.example.com/api/tenancy/tenants/1/",
                "display": "HOME",
                "name": "HOME",
                "slug": "home"
            },
            "platform": null,
            "serial": "01234567890",
            "asset_tag": null,
            "site": {
                "id": 1,
                "url": "https://netbox.example.com/api/dcim/sites/1/",
                "display": "Malakoff",
                "name": "Paris",
                "slug": "paris"
            },
            "location": null,
            "rack": {
                "id": 8,
                "url": "https://netbox.example.com/api/dcim/racks/8/",
                "display": "RACK 11",
                "name": "RACK 11"
            },
            "position": 6,
            "face": {
                "value": "front",
                "label": "Front"
            },
            "parent_device": null,
            "status": {
                "value": "active",
                "label": "Active"
            },
            "airflow": {
                "value": "side-to-rear",
                "label": "Side to rear"
            },
            "primary_ip": null,
            "primary_ip4": null,
            "primary_ip6": null,
            "cluster": null,
            "virtual_chassis": null,
            "vc_position": null,
            "vc_priority": null,
            "comments": "",
            "local_context_data": null,
            "tags": [],
            "custom_fields": {
                "IP": "10.1.1.10",
                "snmp_communaute": "read",
                "snmp_communaute_alternate": null,
                "snmp_version": "2c",
                "snmp_port": "161",
                "ping_frequence": "60",
                "snmp_frequence": "60",
                "client": null,
                "exploitant": "Operator",
                "partenaire": null
            },
            "config_context": {},
            "created": "2022-07-12T12:21:22.461170Z",
            "last_updated": "2022-07-12T12:23:18.688284Z"
        }
    ]
}

Thank you in advance.

multiple exporters on target

is it possible to scrape multiple exporters on one target?
i.e. node_exporter on port 2000, mariadb_exporter on port 2001

how can i define exporter port?

PyPi still at version 0.3.1

Hey Felix,

are you pushing the latest version up onto PyPi? I've noticed the build there is not the current version in git. 0.4?

Many Thanks.
Pete

Adding Rack label in Device target

Hello,

First thank you for this project, it is very useful!

I needed to add the Rack label when requesting a Device as Prometheus target.

But by looking the code I saw 2 possibilities of implementing this.
So I forked the project and created 2 branches here :

Also I tried to blindly implement Unit test but I was not able to try it.

Can you tell me if we can implement this, please? If yes which one of the 2 possibilities seem the best (I will create the PR based on the best branch)?
Feel free to ask for any improvements.

Thanks and have a great day!
geg347

Netbox 3.4.0 - Prometheus-sd plugin doesn't work

Hi everybody,
I'm trying Netbox 3.4.0 with netbox-plugin-prometheus-sd and I can't see any device using the /api/plugins/prometheus-sd/devices API even if I have at least 1 device.

This is the request:

GET http://netbox.local:8000/api/plugins/prometheus-sd/devices/

and this is the answer:

`
HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

[]
`

But I have at least 1 device (Dell R630 in state Active)

export custom fields as labels

Hey @FlxPeters.

I got this up and running and solved a few problems in testing. Ace work!

I was just testing this out and noticed that the custom fields are not coming out where the netbox-prometheus-sd does pull them out and turn the fields into labels. (I'd patched a bug there with label txt). I think it would be nice to export them as I'd based some functionality around it based on the other tool and it allows people to pass some params outbound for things like escalation ownership etc.

from the other closed issue about this - I'm just testing using tags etc, services looks like a right pain and not a fast way to turn it on.

I'll have a look at the code and see if I can figure out something and use your logic from the other application. might look at a url option for customlablels=true to turn them on and off etc.

happy to bounce a few things about.

Single endpoint with union of devices and virtual-machines?

How hard would it be to make a single endpoint which exposes both devices and virtual-machines?

Reason: AFAICS, currently every Prometheus scrape job needs to be duplicated, since prometheus http-sd can only scrape a single URL. If you've got a lot of rewriting rules, that can be painful.

A union endpoint would solve this, and __meta_netbox_model can be used to distinguish between the objects if necessary.

However, I can see there is much Django ORM queryset and serializer magic going on, so it may not be easy. Maybe this is relevant.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.