Skip to content

Commit

Permalink
Migrate to wheels (DataDog#413)
Browse files Browse the repository at this point in the history
* Migrate to wheels

* Add sample config

* Fix test environment
  • Loading branch information
therve authored Apr 15, 2019
1 parent 0c0d1fb commit cffb480
Show file tree
Hide file tree
Showing 22 changed files with 233 additions and 248 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ jobs:
env: CHECK=redis_sentinel PYTHON3=true
- stage: test
env: CHECK=riak_repl PYTHON3=true
- stage: test
env: CHECK=snmpwalk PYTHON3=true
- stage: test
env: CHECK=sortdb PYTHON3=true
- stage: test
Expand Down
10 changes: 10 additions & 0 deletions snmpwalk/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
graft datadog_checks
graft tests

include MANIFEST.in
include README.md
include requirements.in
include requirements-dev.txt
include manifest.json

global-exclude *.py[cod] __pycache__
13 changes: 7 additions & 6 deletions snmpwalk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,18 @@ The SNMP walk check is **NOT** included in the [Datadog Agent][1] package.

To install the SNMP walk check on your host:

1. [Download the Datadog Agent][1].
2. Download the [`check.py` file][2] for SNMP walk.
3. Place it in the Agent's `checks.d` directory.
4. Rename it to `snmpwalk.py`.
1. Install the [developer toolkit][3] on any machine.
2. Run `ddev release build snmpwalk` to build the package.
3. [Download the Datadog Agent][1].
4. Upload the build artifact to any host with an Agent and run `datadog-agent integration install -w path/to/snmpwalk/dist/<ARTIFACT_NAME>.whl`.

### Configuration

To configure the SNMP walk check:

1. Create a `snmpwalk.d/` folder in the `conf.d/` folder at the root of your Agent's directory.
2. Create a `conf.yaml` file in the `snmpwalk.d/` folder previously created.
3. Consult the [sample snmpwalk.yaml][2] file and copy its content in the `conf.yaml` file.
3. Consult the [sample snmpwalk.yaml][6] file and copy its content in the `conf.yaml` file.
4. Edit the `conf.yaml` file to point to your server and port, set the masters to monitor.
5. [Restart the Agent][3].

Expand All @@ -54,7 +54,8 @@ The check returns:
Need help? Contact [Datadog support][5].

[1]: https://app.datadoghq.com/account/settings#agent
[2]: https://github.com/DataDog/integrations-extras/blob/master/snmpwalk/check.py
[2]: https://docs.datadoghq.com/developers/integrations/new_check_howto/#developer-toolkit
[3]: https://docs.datadoghq.com/agent/faq/agent-commands/#start-stop-restart-the-agent
[4]: https://docs.datadoghq.com/agent/faq/agent-commands/#agent-status-and-information
[5]: http://docs.datadoghq.com/help/
[6]: https://github.com/DataDog/integrations-extras/blob/master/snmpwalk/datadog_checks/snmpwalk/data/conf.yaml.example
68 changes: 0 additions & 68 deletions snmpwalk/ci/snmpwalk.rake

This file was deleted.

1 change: 1 addition & 0 deletions snmpwalk/datadog_checks/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__path__ = __import__('pkgutil').extend_path(__path__, __name__)
1 change: 1 addition & 0 deletions snmpwalk/datadog_checks/snmpwalk/__about__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = '0.0.1'
4 changes: 4 additions & 0 deletions snmpwalk/datadog_checks/snmpwalk/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .__about__ import __version__
from .snmpwalk import SnmpwalkCheck

__all__ = ['__version__', 'SnmpwalkCheck']
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ instances:

# SNMP v1-v2 configuration
#
# - ip_address: localhost
# port: 161
# community_string: public
- ip_address: localhost
port: 161
community_string: public
# snmp_version: 2 # Only required for snmp v1, will default to 2
# timeout: 1 # second, by default
# retries: 5
Expand Down
77 changes: 31 additions & 46 deletions snmpwalk/check.py → snmpwalk/datadog_checks/snmpwalk/snmpwalk.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
# stdlib
from collections import defaultdict
from subprocess import check_output, CalledProcessError
import re
import os
import re
from collections import defaultdict

# 3rd party

# project
from checks.network_checks import NetworkCheck, Status

from datadog_checks.base.checks import NetworkCheck, Status
from datadog_checks.base.utils.subprocess_output import get_subprocess_output

EVENT_TYPE = SOURCE_TYPE_NAME = 'snmpwalk'


class BinaryUnavailable(Exception):
pass


class SnmpwalkCheck(NetworkCheck):
'''
This is a work-alike for checks.d/snmp.py that makes use of snmpwalk for
Expand All @@ -25,17 +22,16 @@ class SnmpwalkCheck(NetworkCheck):
* tags using "enum" values emit the human-readable form instead of the
integer.
'''

DEFAULT_SNMPWALK_PATH = '/usr/bin/snmpwalk'
DEFAULT_RETRIES = 2
DEFAULT_TIMEOUT = 1
COUNTER_TYPES = frozenset(('Counter32', 'Counter64', 'ZeroBasedCounter64'))
GAUGE_TYPES = frozenset(('Gauge32', 'Unsigned32', 'CounterBasedGauge64',
'INTEGER', 'Integer32'))
GAUGE_TYPES = frozenset(('Gauge32', 'Unsigned32', 'CounterBasedGauge64', 'INTEGER', 'Integer32'))
SC_NAME = '{}.can_check'.format(SOURCE_TYPE_NAME)

# regex for parsing the output of snmp walk
output_re = re.compile(r'([\w\-]+)::(?P<symbol>\w+)\.(?P<index>\d+) = '
r'(?P<type>\w+): (?P<value>.*)$')
output_re = re.compile(r'([\w\-]+)::(?P<symbol>\w+)\.(?P<index>\d+) = ' r'(?P<type>\w+): (?P<value>.*)$')

def __init__(self, name, init_config, agentConfig, instances=None):
self.binary = None
Expand All @@ -45,12 +41,13 @@ def __init__(self, name, init_config, agentConfig, instances=None):

self.mib_dirs = init_config.get('mibs_folder')

for instance in instances:
# if we don't have a name add one, but mark skip_event so that we
# don't emit the event
if 'name' not in instance:
instance['name'] = self._get_instance_addr(instance)
instance['skip_event'] = True
if instances is not None:
for instance in instances:
# if we don't have a name add one, but mark skip_event so that we
# don't emit the event
if 'name' not in instance:
instance['name'] = self._get_instance_addr(instance)
instance['skip_event'] = True

NetworkCheck.__init__(self, name, init_config, agentConfig, instances)

Expand Down Expand Up @@ -87,22 +84,20 @@ def _check(self, instance):
for metric in metrics:
mib = metric['MIB']
table = metric['table']
cmd = [self.binary, '-c{}'.format(community_string),
'-v2c', '-t', str(timeout), '-r', str(retries)]
cmd = [self.binary, '-c{}'.format(community_string), '-v2c', '-t', str(timeout), '-r', str(retries)]
if self.mib_dirs:
cmd.extend(['-M', self.mib_dirs])
cmd.extend([ip_address, '{}:{}'.format(mib, table)])

try:
output = check_output(cmd)
except CalledProcessError as e:
error = "Fail to collect metrics for {0} - {1}" \
.format(instance['name'], e)
output = get_subprocess_output(cmd, self.log)[0]
except Exception as e:
error = "Fail to collect metrics for {0} - {1}".format(instance['name'], e)
self.log.warning(error)
return [(self.SC_NAME, Status.CRITICAL, error)]

for line in output.split('\n'):
if line == '':
for line in output.splitlines():
if not line:
continue
match = self.output_re.match(line)
if match is not None:
Expand All @@ -121,13 +116,10 @@ def _check(self, instance):
data[symbol][index] = value
else:
# TODO: remove this
self.log.warning('Problem parsing output of snmp walk: %s',
line)
self.log.warning('Problem parsing output of snmp walk: %s', line)

# Get any base configured tags and add our primary tag
tags = instance.get('tags', []) + [
'snmp_device:{}'.format(ip_address),
]
tags = instance.get('tags', []) + ['snmp_device:{}'.format(ip_address)]

# It seems kind of weird, but from what I can tell the snmp check allows
# you to add symbols to a metric that were retrieved by another metric,
Expand Down Expand Up @@ -165,17 +157,15 @@ def _check(self, instance):
# It matches so we'll apply it, group(1) becomes
# the value
v = match.group(1)
dynamic_tags[i].append('{}:{}' .format(tag, v))
additional_tags = \
metric_tag.get('additional_tags', [])
dynamic_tags[i].append('{}:{}'.format(tag, v))
additional_tags = metric_tag.get('additional_tags', [])
# and we add any additional tags
dynamic_tags[i].extend(additional_tags)
else:
# This is a standard tag, just use the value
dynamic_tags[i].append('{}:{}'.format(tag, v))
else:
self.log.debug('unsupported metric_tag: {}'
.format(metric_tag))
self.log.debug('unsupported metric_tag: {}'.format(metric_tag))
continue

symbols = metric.get('symbols', [])
Expand All @@ -192,14 +182,11 @@ def _check(self, instance):

typ = types[symbol]
if typ in self.COUNTER_TYPES:
self.rate(key, value, tags + dynamic_tags[i],
hostname=hostname)
self.rate(key, value, tags + dynamic_tags[i], hostname=hostname)
elif typ in self.GAUGE_TYPES:
self.gauge(key, value, tags + dynamic_tags[i],
hostname=hostname)
self.gauge(key, value, tags + dynamic_tags[i], hostname=hostname)
else:
raise Exception('unsupported metric symbol type: {}'
.format(typ))
raise Exception('unsupported metric symbol type: {}'.format(typ))

return [(self.SC_NAME, Status.UP, None)]

Expand All @@ -209,6 +196,4 @@ def report_as_service_check(self, sc_name, status, instance, msg=None):
tags = sc_tags + custom_tags

self.log.debug('Submitting with the following tags: %s', sc_tags)
self.service_check(sc_name,
NetworkCheck.STATUS_TO_SERVICE_CHECK[status],
tags=tags, message=msg)
self.service_check(sc_name, NetworkCheck.STATUS_TO_SERVICE_CHECK[status], tags=tags, message=msg)
1 change: 1 addition & 0 deletions snmpwalk/requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
datadog-checks-dev
Empty file added snmpwalk/requirements.in
Empty file.
1 change: 0 additions & 1 deletion snmpwalk/requirements.txt

This file was deleted.

50 changes: 50 additions & 0 deletions snmpwalk/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from codecs import open # To use a consistent encoding
from os import path

from setuptools import setup

HERE = path.dirname(path.abspath(__file__))

# Get version info
ABOUT = {}
with open(path.join(HERE, 'datadog_checks', 'snmpwalk', '__about__.py')) as f:
exec(f.read(), ABOUT)

# Get the long description from the README file
with open(path.join(HERE, 'README.md'), encoding='utf-8') as f:
long_description = f.read()


CHECKS_BASE_REQ = 'datadog-checks-base>=4.2.0'


setup(
name='datadog-snmpwalk',
version=ABOUT['__version__'],
description='The Snmpwalk check',
long_description=long_description,
long_description_content_type='text/markdown',
keywords='datadog agent snmpwalk check',
# The project's main homepage.
url='https://github.com/DataDog/integrations-extras',
# Author details
author_email='[email protected]',
# License
license='BSD-3-Clause',
# See https://pypi.org/classifiers
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Intended Audience :: System Administrators',
'Topic :: System :: Monitoring',
'License :: OSI Approved :: BSD License',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3.7',
],
# The package we're going to ship
packages=['datadog_checks.snmpwalk'],
# Run-time dependencies
install_requires=[CHECKS_BASE_REQ],
# Extra files to ship with the wheel package
include_package_data=True,
)
Loading

0 comments on commit cffb480

Please sign in to comment.