diff --git a/.travis.yml b/.travis.yml index 40d5a0a083..0603f873c2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -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 diff --git a/snmpwalk/MANIFEST.in b/snmpwalk/MANIFEST.in new file mode 100644 index 0000000000..6fa1c2388a --- /dev/null +++ b/snmpwalk/MANIFEST.in @@ -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__ diff --git a/snmpwalk/README.md b/snmpwalk/README.md index 53d6b3f023..3b44c02c4c 100644 --- a/snmpwalk/README.md +++ b/snmpwalk/README.md @@ -16,10 +16,10 @@ 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/.whl`. ### Configuration @@ -27,7 +27,7 @@ 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]. @@ -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 diff --git a/snmpwalk/ci/snmpwalk.rake b/snmpwalk/ci/snmpwalk.rake deleted file mode 100644 index 22ddf9c6d1..0000000000 --- a/snmpwalk/ci/snmpwalk.rake +++ /dev/null @@ -1,68 +0,0 @@ -require 'ci/common' - -def snmpwalk_version - ENV['FLAVOR_VERSION'] || 'latest' -end - -def snmpwalk_rootdir - "#{ENV['INTEGRATIONS_DIR']}/snmpwalk_#{snmpwalk_version}" -end - -def resources_path - base = ENV['TRAVIS_BUILD_DIR'] || ENV['CI_BUILD_DIR'] - base.to_s + '/snmpwalk/ci/resources' -end - -namespace :ci do - namespace :snmpwalk do |flavor| - task before_install: ['ci:common:before_install'] - - task install: ['ci:common:install'] do - use_venv = in_venv - install_requirements('snmpwalk/requirements.txt', - "--cache-dir #{ENV['PIP_CACHE']}", - "#{ENV['VOLATILE_DIR']}/ci.log", use_venv) - sh %(docker run -d -v #{resources_path}:/etc/snmp/ \ - --name dd-test-snmpwalk -p 11111:161/udp \ - polinux/snmpd -c /etc/snmp/snmpd.conf) - sleep_for 5 - end - - task before_script: ['ci:common:before_script'] - - task script: ['ci:common:script'] do - this_provides = [ - 'snmpwalk' - ] - Rake::Task['ci:common:run_tests'].invoke(this_provides) - end - - task before_cache: ['ci:common:before_cache'] - - task cleanup: ['ci:common:cleanup'] do - sh %(docker stop dd-test-snmpwalk) - sh %(docker rm dd-test-snmpwalk) - end - - task :execute do - exception = nil - begin - %w[before_install install before_script].each do |u| - Rake::Task["#{flavor.scope.path}:#{u}"].invoke - end - Rake::Task["#{flavor.scope.path}:script"].invoke - Rake::Task["#{flavor.scope.path}:before_cache"].invoke - rescue => e - exception = e - puts "Failed task: #{e.class} #{e.message}".red - end - if ENV['SKIP_CLEANUP'] - puts 'Skipping cleanup, disposable environments are great'.yellow - else - puts 'Cleaning up' - Rake::Task["#{flavor.scope.path}:cleanup"].invoke - end - raise exception if exception - end - end -end diff --git a/snmpwalk/datadog_checks/__init__.py b/snmpwalk/datadog_checks/__init__.py new file mode 100644 index 0000000000..69e3be50da --- /dev/null +++ b/snmpwalk/datadog_checks/__init__.py @@ -0,0 +1 @@ +__path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/snmpwalk/datadog_checks/snmpwalk/__about__.py b/snmpwalk/datadog_checks/snmpwalk/__about__.py new file mode 100644 index 0000000000..b8023d8bc0 --- /dev/null +++ b/snmpwalk/datadog_checks/snmpwalk/__about__.py @@ -0,0 +1 @@ +__version__ = '0.0.1' diff --git a/snmpwalk/datadog_checks/snmpwalk/__init__.py b/snmpwalk/datadog_checks/snmpwalk/__init__.py new file mode 100644 index 0000000000..fed0884ad5 --- /dev/null +++ b/snmpwalk/datadog_checks/snmpwalk/__init__.py @@ -0,0 +1,4 @@ +from .__about__ import __version__ +from .snmpwalk import SnmpwalkCheck + +__all__ = ['__version__', 'SnmpwalkCheck'] diff --git a/snmpwalk/conf.yaml.example b/snmpwalk/datadog_checks/snmpwalk/data/conf.yaml.example similarity index 96% rename from snmpwalk/conf.yaml.example rename to snmpwalk/datadog_checks/snmpwalk/data/conf.yaml.example index cbf51cb04b..e777162a6f 100644 --- a/snmpwalk/conf.yaml.example +++ b/snmpwalk/datadog_checks/snmpwalk/data/conf.yaml.example @@ -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 diff --git a/snmpwalk/check.py b/snmpwalk/datadog_checks/snmpwalk/snmpwalk.py similarity index 80% rename from snmpwalk/check.py rename to snmpwalk/datadog_checks/snmpwalk/snmpwalk.py index d67d1c473e..9a3ce97c45 100644 --- a/snmpwalk/check.py +++ b/snmpwalk/datadog_checks/snmpwalk/snmpwalk.py @@ -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 @@ -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\w+)\.(?P\d+) = ' - r'(?P\w+): (?P.*)$') + output_re = re.compile(r'([\w\-]+)::(?P\w+)\.(?P\d+) = ' r'(?P\w+): (?P.*)$') def __init__(self, name, init_config, agentConfig, instances=None): self.binary = None @@ -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) @@ -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: @@ -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, @@ -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', []) @@ -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)] @@ -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) diff --git a/snmpwalk/requirements-dev.txt b/snmpwalk/requirements-dev.txt new file mode 100644 index 0000000000..958b51d329 --- /dev/null +++ b/snmpwalk/requirements-dev.txt @@ -0,0 +1 @@ +datadog-checks-dev diff --git a/snmpwalk/requirements.in b/snmpwalk/requirements.in new file mode 100644 index 0000000000..e69de29bb2 diff --git a/snmpwalk/requirements.txt b/snmpwalk/requirements.txt deleted file mode 100644 index f89ecf55da..0000000000 --- a/snmpwalk/requirements.txt +++ /dev/null @@ -1 +0,0 @@ -# integration pip requirements diff --git a/snmpwalk/setup.py b/snmpwalk/setup.py new file mode 100644 index 0000000000..acfcec76e8 --- /dev/null +++ b/snmpwalk/setup.py @@ -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='help@datadoghq.com', + # 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, +) diff --git a/snmpwalk/test_snmpwalk.py b/snmpwalk/test_snmpwalk.py deleted file mode 100644 index a18a344f1c..0000000000 --- a/snmpwalk/test_snmpwalk.py +++ /dev/null @@ -1,124 +0,0 @@ -# (C) Datadog, Inc. 2010-2016 -# All rights reserved -# Licensed under Simplified BSD License (see LICENSE) - -# stdlib -import os -import copy -import time - -# 3p -from nose.plugins.attrib import attr - -# project -from checks import AgentCheck -from tests.checks.common import AgentCheckTest - - -RESULTS_TIMEOUT = 10 - -@attr(requires='snmpwalk') -class TestSnmpwalk(AgentCheckTest): - """Basic Test for snmpwrap integration.""" - CHECK_NAME = 'snmpwalk' - FIXTURE_DIR = os.path.join(os.path.dirname(__file__), 'ci') - - CHECK_TAGS = ['snmp_device:localhost:11111'] - INSTANCE_CONF = { - 'ip_address': "localhost", - 'port': 11111, - 'community_string': "public", - } - CONFIG = { - 'init_config': {}, - 'instances' : [INSTANCE_CONF] - } - - TABULAR_OBJECTS = [{ - 'MIB': "IF-MIB", - 'table': "ifTable", - 'symbols': ["ifInOctets", "ifOutOctets"], - 'metric_tags': [ - { - 'tag': "interface", - 'column': "ifDescr" - }, { - 'tag': "dumbindex", - 'index': 1 - } - ] - }] - - def tearDown(self): - if self.check: - self.check.stop() - - @classmethod - def generate_instance_config(cls, metrics): - instance_config = copy.copy(cls.INSTANCE_CONF) - instance_config['metrics'] = metrics - instance_config['name'] = "localhost" - return instance_config - - def wait_for_async(self, method, attribute, count): - """ - Loop on `self.check.method` until `self.check.attribute >= count`. - - Raise after - """ - i = 0 - while i < RESULTS_TIMEOUT: - self.check._process_results() - if len(getattr(self.check, attribute)) >= count: - return getattr(self.check, method)() - time.sleep(1) - i += 1 - raise Exception("Didn't get the right count for {attribute} in time, {total}/{expected} in {seconds}s: {attr}" - .format(attribute=attribute, total=len(getattr(self.check, attribute)), expected=count, seconds=i, - attr=getattr(self.check, attribute))) - - - def test_check(self): - """ - Testing Snmpwrap check. - """ - config = { - 'instances': [self.generate_instance_config(self.TABULAR_OBJECTS)] - } - self.run_check_n(config, repeat=3, sleep=2) - self.service_checks = self.wait_for_async('get_service_checks', 'service_checks', 1) - - # Test metrics - for symbol in self.TABULAR_OBJECTS[0]['symbols']: - metric_name = '{}.{}'.format(self.CHECK_NAME, symbol) - self.assertMetric(metric_name, at_least=1) - self.assertMetricTag(metric_name, self.CHECK_TAGS[0], at_least=1) - - for mtag in self.TABULAR_OBJECTS[0]['metric_tags']: - tag = mtag['tag'] - if tag is 'dumbindex': # unsupported - self.assertMetricTagPrefix(metric_name, tag, count=0) - else: - self.assertMetricTagPrefix(metric_name, tag, at_least=1) - - # Test service check - svcchk_name = '{}.can_check'.format(self.CHECK_NAME) - self.assertServiceCheck(svcchk_name, status=AgentCheck.OK, - tags=[':'.join(self.CHECK_TAGS[0].split(':')[:-1])], count=1) - - self.coverage_report() - - def test_unavailable_binary(self): - """ - Should raise exception if binary is unavailable. - """ - config = { - 'init_config': {'binary': '/path/to/nonexistant/snmpwalk'}, - 'instances': [self.generate_instance_config(self.TABULAR_OBJECTS)] - } - - self.run_check(config) - self.assertRaises( - Exception, - lambda: self.wait_for_async('get_service_checks', 'service_checks', 1) - ) diff --git a/snmpwalk/tests/__init__.py b/snmpwalk/tests/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/snmpwalk/tests/common.py b/snmpwalk/tests/common.py new file mode 100644 index 0000000000..7a18cac8ce --- /dev/null +++ b/snmpwalk/tests/common.py @@ -0,0 +1,4 @@ +import os + +HERE = os.path.dirname(os.path.abspath(__file__)) +DOCKER_DIR = os.path.join(HERE, 'docker') diff --git a/snmpwalk/tests/conftest.py b/snmpwalk/tests/conftest.py new file mode 100644 index 0000000000..106af3fef5 --- /dev/null +++ b/snmpwalk/tests/conftest.py @@ -0,0 +1,13 @@ +import os + +import pytest + +from datadog_checks.dev.docker import docker_run + +from .common import DOCKER_DIR + + +@pytest.fixture(scope='session') +def dd_environment(): + with docker_run(os.path.join(DOCKER_DIR, 'docker-compose.yml')): + yield {'ip_address': 'localhost', 'port': 161, 'community_string': 'public'} diff --git a/snmpwalk/ci/resources/snmpd.conf b/snmpwalk/tests/docker/config/snmpd.conf similarity index 100% rename from snmpwalk/ci/resources/snmpd.conf rename to snmpwalk/tests/docker/config/snmpd.conf diff --git a/snmpwalk/tests/docker/docker-compose.yml b/snmpwalk/tests/docker/docker-compose.yml new file mode 100644 index 0000000000..45747e7a95 --- /dev/null +++ b/snmpwalk/tests/docker/docker-compose.yml @@ -0,0 +1,8 @@ +version: '3' + +services: + snmpd: + image: polinux/snmpd + volumes: + - ./config:/etc/snmp + command: -c /etc/snmp/snmpd.conf diff --git a/snmpwalk/tests/script.sh b/snmpwalk/tests/script.sh new file mode 100755 index 0000000000..eac4582be4 --- /dev/null +++ b/snmpwalk/tests/script.sh @@ -0,0 +1,2 @@ +#!/bin/bash +docker exec docker_snmpd_1 /usr/bin/snmpwalk "$@" diff --git a/snmpwalk/tests/test_snmpwalk.py b/snmpwalk/tests/test_snmpwalk.py new file mode 100644 index 0000000000..2bbf00d22a --- /dev/null +++ b/snmpwalk/tests/test_snmpwalk.py @@ -0,0 +1,76 @@ +# (C) Datadog, Inc. 2010-2016 +# All rights reserved +# Licensed under Simplified BSD License (see LICENSE) + +import os + +from datadog_checks.snmpwalk import SnmpwalkCheck + +from .common import HERE + +RESULTS_TIMEOUT = 10 + + +CHECK_NAME = 'snmpwalk' +FIXTURE_DIR = os.path.join(os.path.dirname(__file__), 'ci') + +CHECK_TAGS = ['snmp_device:localhost:161'] + +TABULAR_OBJECTS = [ + { + 'MIB': "IF-MIB", + 'table': "ifTable", + 'symbols': ["ifInOctets", "ifOutOctets"], + 'metric_tags': [{'tag': "interface", 'column': "ifDescr"}, {'tag': "dumbindex", 'index': 1}], + } +] + + +def generate_instance_config(instance_config, metrics): + instance_config['metrics'] = metrics + instance_config['name'] = 'localhost' + return instance_config + + +def test_check(aggregator, dd_environment): + """ + Testing Snmpwrap check. + """ + instance = generate_instance_config(dd_environment, TABULAR_OBJECTS) + config = {'binary': os.path.join(HERE, "script.sh")} + check = SnmpwalkCheck(CHECK_NAME, config, {}) + check.check(instance) + + # Test metrics + for symbol in TABULAR_OBJECTS[0]['symbols']: + metric_name = '{}.{}'.format(CHECK_NAME, symbol) + aggregator.assert_metric(metric_name, at_least=1) + aggregator.assert_metric_has_tag(metric_name, CHECK_TAGS[0], at_least=1) + + for mtag in TABULAR_OBJECTS[0]['metric_tags']: + tag = mtag['tag'] + if tag == 'dumbindex': # unsupported + aggregator.assert_metric_has_tag_prefix(metric_name, tag, count=0) + else: + aggregator.assert_metric_has_tag_prefix(metric_name, tag, at_least=1) + + # Test service check + svcchk_name = '{}.can_check'.format(CHECK_NAME) + aggregator.assert_service_check( + svcchk_name, status=SnmpwalkCheck.OK, tags=[':'.join(CHECK_TAGS[0].split(':')[:-1])], count=1 + ) + + aggregator.assert_all_metrics_covered() + + +def test_unavailable_binary(caplog): + """ + Should log exception if binary is unavailable. + """ + config = {'binary': '/path/to/nonexistant/snmpwalk'} + instance = generate_instance_config({}, TABULAR_OBJECTS) + + check = SnmpwalkCheck(CHECK_NAME, config, {}) + check.check(instance) + + assert 'Cannot find executable: /path/to/nonexistant/snmpwalk' in caplog.text diff --git a/snmpwalk/tox.ini b/snmpwalk/tox.ini new file mode 100644 index 0000000000..a535e6c325 --- /dev/null +++ b/snmpwalk/tox.ini @@ -0,0 +1,20 @@ +[tox] +minversion = 2.0 +skip_missing_interpreters = true +basepython = py37 +envlist = + py{27,37}-snmpwalk + +[testenv] +dd_check_style = true +usedevelop = true +platform = linux|darwin|win32 +deps = + datadog-checks-base[deps]>=6.6.0 + -rrequirements-dev.txt +passenv = + DOCKER* + COMPOSE* +commands = + pip install -r requirements.in + pytest -v {posargs}