From cafad049e063d4ae90f53aa9ec5c1c1c090d0d2a Mon Sep 17 00:00:00 2001 From: James Eichelbaum Date: Fri, 13 Sep 2024 12:27:05 -0400 Subject: [PATCH] add agent_check template for publishing platform integrations --- .../dev/tooling/commands/create.py | 32 +++++-- .../datadog_checks/dev/tooling/constants.py | 11 +++ .../datadog_checks/dev/tooling/create.py | 30 +++++- .../{check_name}/changelog.d/1.added | 1 + .../{check_name}/datadog_checks/__init__.py | 2 + .../datadog_checks/{check_name}/__about__.py | 2 + .../datadog_checks/{check_name}/__init__.py | 5 + .../datadog_checks/{check_name}/check.py | 96 +++++++++++++++++++ .../{check_name}/config_models/__init__.py | 19 ++++ .../{check_name}/config_models/defaults.py | 10 ++ .../{check_name}/config_models/instance.py | 45 +++++++++ .../{check_name}/config_models/shared.py | 42 ++++++++ .../{check_name}/config_models/validators.py | 11 +++ .../{check_name}/data/conf.yaml.example | 44 +++++++++ .../check_only/{check_name}/hatch.toml | 4 + .../check_only/{check_name}/pyproject.toml | 60 ++++++++++++ .../check_only/{check_name}/tests/__init__.py | 1 + .../check_only/{check_name}/tests/conftest.py | 12 +++ .../{check_name}/tests/test_unit.py | 24 +++++ docs/developer/setup.md | 2 +- 20 files changed, 442 insertions(+), 11 deletions(-) create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/changelog.d/1.added create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/__init__.py create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/__about__.py create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/__init__.py create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/check.py create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/__init__.py create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/defaults.py create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/instance.py create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/shared.py create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/validators.py create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/data/conf.yaml.example create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/hatch.toml create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/pyproject.toml create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/tests/__init__.py create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/tests/conftest.py create mode 100644 datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/tests/test_unit.py diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/commands/create.py b/datadog_checks_dev/datadog_checks/dev/tooling/commands/create.py index 031bc849798ecd..6ccd3818a1da19 100644 --- a/datadog_checks_dev/datadog_checks/dev/tooling/commands/create.py +++ b/datadog_checks_dev/datadog_checks/dev/tooling/commands/create.py @@ -9,7 +9,12 @@ from ...fs import resolve_path from ..constants import get_root -from ..create import construct_template_fields, create_template_files, get_valid_templates +from ..create import ( + construct_template_fields, + create_template_files, + get_valid_templates, + prefill_template_fields_for_check_only, +) from ..utils import kebab_case_name, normalize_package_name from .console import CONTEXT_SETTINGS, abort, echo_info, echo_success, echo_warning @@ -171,26 +176,35 @@ def create(ctx, name, integration_type, location, non_interactive, quiet, dry_ru if integration_type == 'snmp_tile': integration_dir_name = 'snmp_' + integration_dir_name integration_dir = os.path.join(root, integration_dir_name) - if os.path.exists(integration_dir): - abort(f'Path `{integration_dir}` already exists!') + # check-only is designed to already have content in it + if integration_type == 'check_only': + if not os.path.exists(os.path.join(integration_dir, "manifest.json")): + abort(f"Expected {integration_dir}/manifest.json to exist") + else: + if os.path.exists(integration_dir): + abort(f'Path `{integration_dir}` already exists!') template_fields = {'manifest_version': '1.0.0', "today": date.today()} + if integration_type == 'check_only': + template_fields.update(prefill_template_fields_for_check_only(integration_dir_name)) if non_interactive and repo_choice != 'core': abort(f'Cannot use non-interactive mode with repo_choice: {repo_choice}') if not non_interactive and not dry_run: if repo_choice not in ['core', 'integrations-internal-core']: - support_email = click.prompt('Email used for support requests') - template_fields['email'] = support_email + prompt_and_update_if_missing(template_fields, 'email', 'Email used for support requests') + support_email = template_fields['email'] template_fields['email_packages'] = template_fields['email'] if repo_choice == 'extras': template_fields['author'] = click.prompt('Your name') if repo_choice == 'marketplace': - author_name = click.prompt('Your Company Name') - homepage = click.prompt('The product or company homepage') - sales_email = click.prompt('Email used for subscription notifications') - + prompt_and_update_if_missing(template_fields, 'author_name', 'Your Company Name') + prompt_and_update_if_missing(template_fields, 'homepage', 'The product or company homepage') + prompt_and_update_if_missing(template_fields, 'sales_email', 'Email used for subscription notifications') + author_name = template_fields['author_name'] + sales_email = template_fields['sales_email'] + homepage = template_fields['homepage'] template_fields['author'] = author_name eula = 'assets/eula.pdf' diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/constants.py b/datadog_checks_dev/datadog_checks/dev/tooling/constants.py index babc6d87f93f58..0bfe18f1c7686a 100644 --- a/datadog_checks_dev/datadog_checks/dev/tooling/constants.py +++ b/datadog_checks_dev/datadog_checks/dev/tooling/constants.py @@ -97,6 +97,16 @@ [9]: https://docs.datadoghq.com/help/ """ +CHECK_ONLY_LINKS = """\ +[1]: **LINK_TO_INTEGRATION_SITE** +[2]: https://app.datadoghq.com/account/settings/agent/latest +[3]: https://docs.datadoghq.com/agent/kubernetes/integrations/ +[4]: https://github.com/DataDog/{repository}/blob/master/{name}/datadog_checks/{name}/data/conf.yaml.example +[5]: https://docs.datadoghq.com/agent/guide/agent-commands/#start-stop-and-restart-the-agent +[6]: https://docs.datadoghq.com/agent/guide/agent-commands/#agent-status-and-information +[9]: https://docs.datadoghq.com/help/ +""" + LOGS_LINKS = """\ [1]: https://docs.datadoghq.com/help/ [2]: https://app.datadoghq.com/account/settings/agent/latest @@ -132,6 +142,7 @@ integration_type_links = { 'check': CHECK_LINKS, + 'check_only': CHECK_ONLY_LINKS, 'logs': LOGS_LINKS, 'jmx': JMX_LINKS, 'snmp_tile': SNMP_TILE_LINKS, diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/create.py b/datadog_checks_dev/datadog_checks/dev/tooling/create.py index e5aeb95b97353d..6ceed63206b87f 100644 --- a/datadog_checks_dev/datadog_checks/dev/tooling/create.py +++ b/datadog_checks_dev/datadog_checks/dev/tooling/create.py @@ -1,6 +1,7 @@ # (C) Datadog, Inc. 2018-present # All rights reserved # Licensed under a 3-clause BSD style license (see LICENSE) +import json import os from datetime import datetime from operator import attrgetter @@ -52,6 +53,23 @@ def get_valid_templates(): return sorted(templates, key=attrgetter('name')) +def prefill_template_fields_for_check_only(normalized_integration_name: str) -> dict: + manifest_dict = {} + manifest_path = os.path.join(normalized_integration_name, 'manifest.json') + if not os.path.exists(manifest_path): + raise ValueError(f"Expected manifest to exist at {manifest_path}") + with open(manifest_path, 'r') as manifest: + manifest_dict = json.loads(manifest.read()) + author = manifest_dict.get("author", {}).get("name") + return { + 'author_name': author, + 'check_name': normalize_package_name(f"{author}_{normalized_integration_name}"), + 'email': manifest_dict.get("author", {}).get("support_email"), + 'homepage': manifest_dict.get("author", {}).get("homepage"), + 'sales_email': manifest_dict.get("author", {}).get("sales_email"), + } + + def construct_template_fields(integration_name, repo_choice, integration_type, **kwargs): normalized_integration_name = normalize_package_name(integration_name) check_name_kebab = kebab_case_name(integration_name) @@ -71,7 +89,17 @@ def construct_template_fields(integration_name, repo_choice, integration_type, * 4. Upload the build artifact to any host with an Agent and run `datadog-agent integration install -w path/to/{normalized_integration_name}/dist/.whl`.""" - + if integration_type == 'check_only': + # check_name, author, email come from kwargs due to prefill + check_name = '' + author = '' + email = '' + email_packages = '' + install_info = third_party_install_info + # Static fields + license_header = '' + support_type = 'partner' + integration_links = '' if repo_choice == 'core': check_name = normalized_integration_name author = 'Datadog' diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/changelog.d/1.added b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/changelog.d/1.added new file mode 100644 index 00000000000000..aa949b47b7b419 --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/changelog.d/1.added @@ -0,0 +1 @@ +Initial Release \ No newline at end of file diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/__init__.py b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/__init__.py new file mode 100644 index 00000000000000..a551efb893219a --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/__init__.py @@ -0,0 +1,2 @@ +{license_header} +__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/__about__.py b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/__about__.py new file mode 100644 index 00000000000000..52da1138aed946 --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/__about__.py @@ -0,0 +1,2 @@ +{license_header} +__version__ = '{starting_version}' diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/__init__.py b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/__init__.py new file mode 100644 index 00000000000000..6e1e729d61695c --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/__init__.py @@ -0,0 +1,5 @@ +{license_header} +from .__about__ import __version__ +from .check import {check_class} + +__all__ = ['__version__', '{check_class}'] diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/check.py b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/check.py new file mode 100644 index 00000000000000..fc1e471ee1487d --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/check.py @@ -0,0 +1,96 @@ +{license_header} +from typing import Any # noqa: F401 + +from datadog_checks.base import AgentCheck # noqa: F401 + +# from datadog_checks.base.utils.db import QueryManager +# from requests.exceptions import ConnectionError, HTTPError, InvalidURL, Timeout +# from json import JSONDecodeError + + +class {check_class}(AgentCheck): + + # This will be the prefix of every metric and service check the integration sends + __NAMESPACE__ = '{check_name}' + + def __init__(self, name, init_config, instances): + super({check_class}, self).__init__(name, init_config, instances) + + # Use self.instance to read the check configuration + # self.url = self.instance.get("url") + + # If the check is going to perform SQL queries you should define a query manager here. + # More info at + # https://datadoghq.dev/integrations-core/base/databases/#datadog_checks.base.utils.db.core.QueryManager + # sample_query = {{ + # "name": "sample", + # "query": "SELECT * FROM sample_table", + # "columns": [ + # {{"name": "metric", "type": "gauge"}} + # ], + # }} + # self._query_manager = QueryManager(self, self.execute_query, queries=[sample_query]) + # self.check_initializations.append(self._query_manager.compile_queries) + + def check(self, _): + # type: (Any) -> None + # The following are useful bits of code to help new users get started. + + # Perform HTTP Requests with our HTTP wrapper. + # More info at https://datadoghq.dev/integrations-core/base/http/ + # try: + # response = self.http.get(self.url) + # response.raise_for_status() + # response_json = response.json() + + # except Timeout as e: + # self.service_check( + # "can_connect", + # AgentCheck.CRITICAL, + # message="Request timeout: {{}}, {{}}".format(self.url, e), + # ) + # raise + + # except (HTTPError, InvalidURL, ConnectionError) as e: + # self.service_check( + # "can_connect", + # AgentCheck.CRITICAL, + # message="Request failed: {{}}, {{}}".format(self.url, e), + # ) + # raise + + # except JSONDecodeError as e: + # self.service_check( + # "can_connect", + # AgentCheck.CRITICAL, + # message="JSON Parse failed: {{}}, {{}}".format(self.url, e), + # ) + # raise + + # except ValueError as e: + # self.service_check( + # "can_connect", AgentCheck.CRITICAL, message=str(e) + # ) + # raise + + # This is how you submit metrics + # There are different types of metrics that you can submit (gauge, event). + # More info at https://datadoghq.dev/integrations-core/base/api/#datadog_checks.base.checks.base.AgentCheck + # self.gauge("test", 1.23, tags=['foo:bar']) + + # Perform database queries using the Query Manager + # self._query_manager.execute() + + # This is how you use the persistent cache. This cache file based and persists across agent restarts. + # If you need an in-memory cache that is persisted across runs + # You can define a dictionary in the __init__ method. + # self.write_persistent_cache("key", "value") + # value = self.read_persistent_cache("key") + + # If your check ran successfully, you can send the status. + # More info at + # https://datadoghq.dev/integrations-core/base/api/#datadog_checks.base.checks.base.AgentCheck.service_check + # self.service_check("can_connect", AgentCheck.OK) + + # If it didn't then it should send a critical service check + self.service_check("can_connect", AgentCheck.CRITICAL) diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/__init__.py b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/__init__.py new file mode 100644 index 00000000000000..1b6cb5a013ad35 --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/__init__.py @@ -0,0 +1,19 @@ +{license_header} + +{documentation} + +from .instance import InstanceConfig +from .shared import SharedConfig + + +class ConfigMixin: + _config_model_instance: InstanceConfig + _config_model_shared: SharedConfig + + @property + def config(self) -> InstanceConfig: + return self._config_model_instance + + @property + def shared_config(self) -> SharedConfig: + return self._config_model_shared diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/defaults.py b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/defaults.py new file mode 100644 index 00000000000000..54022a83625654 --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/defaults.py @@ -0,0 +1,10 @@ +{license_header} + +{documentation} + +def instance_empty_default_hostname(): + return False + + +def instance_min_collection_interval(): + return 15 diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/instance.py b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/instance.py new file mode 100644 index 00000000000000..c1f54484fe1a79 --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/instance.py @@ -0,0 +1,45 @@ +{license_header} + +{documentation} + +from __future__ import annotations + +from typing import Optional + +from pydantic import BaseModel, ConfigDict, field_validator, model_validator + +from datadog_checks.base.utils.functions import identity +from datadog_checks.base.utils.models import validation + +from . import defaults, validators + + +class InstanceConfig(BaseModel): + model_config = ConfigDict( + validate_default=True, + arbitrary_types_allowed=True, + frozen=True, + ) + empty_default_hostname: Optional[bool] = None + min_collection_interval: Optional[float] = None + service: Optional[str] = None + tags: Optional[tuple[str, ...]] = None + + @model_validator(mode='before') + def _initial_validation(cls, values): + return validation.core.initialize_config(getattr(validators, 'initialize_instance', identity)(values)) + + @field_validator('*', mode='before') + def _validate(cls, value, info): + field = cls.model_fields[info.field_name] + field_name = field.alias or info.field_name + if field_name in info.context['configured_fields']: + value = getattr(validators, f'instance_{{info.field_name}}', identity)(value, field=field) + else: + value = getattr(defaults, f'instance_{{info.field_name}}', lambda: value)() + + return validation.utils.make_immutable(value) + + @model_validator(mode='after') + def _final_validation(cls, model): + return validation.core.check_model(getattr(validators, 'check_instance', identity)(model)) diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/shared.py b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/shared.py new file mode 100644 index 00000000000000..dd76a1c12fa518 --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/shared.py @@ -0,0 +1,42 @@ +{license_header} + +{documentation} + +from __future__ import annotations + +from typing import Optional + +from pydantic import BaseModel, ConfigDict, field_validator, model_validator + +from datadog_checks.base.utils.functions import identity +from datadog_checks.base.utils.models import validation + +from . import defaults, validators + + +class SharedConfig(BaseModel): + model_config = ConfigDict( + validate_default=True, + arbitrary_types_allowed=True, + frozen=True, + ) + service: Optional[str] = None + + @model_validator(mode='before') + def _initial_validation(cls, values): + return validation.core.initialize_config(getattr(validators, 'initialize_shared', identity)(values)) + + @field_validator('*', mode='before') + def _validate(cls, value, info): + field = cls.model_fields[info.field_name] + field_name = field.alias or info.field_name + if field_name in info.context['configured_fields']: + value = getattr(validators, f'shared_{{info.field_name}}', identity)(value, field=field) + else: + value = getattr(defaults, f'shared_{{info.field_name}}', lambda: value)() + + return validation.utils.make_immutable(value) + + @model_validator(mode='after') + def _final_validation(cls, model): + return validation.core.check_model(getattr(validators, 'check_shared', identity)(model)) diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/validators.py b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/validators.py new file mode 100644 index 00000000000000..31b99cc318f2d1 --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/config_models/validators.py @@ -0,0 +1,11 @@ +{license_header} + +# Here you can include additional config validators or transformers +# +# def initialize_instance(values, **kwargs): +# if 'my_option' not in values and 'my_legacy_option' in values: +# values['my_option'] = values['my_legacy_option'] +# if values.get('my_number') > 10: +# raise ValueError('my_number max value is 10, got %s' % str(values.get('my_number'))) +# +# return values diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/data/conf.yaml.example b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/data/conf.yaml.example new file mode 100644 index 00000000000000..8ee633b1335fc5 --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/datadog_checks/{check_name}/data/conf.yaml.example @@ -0,0 +1,44 @@ +## All options defined here are available to all instances. +# +init_config: + + ## @param service - string - optional + ## Attach the tag `service:` to every metric, event, and service check emitted by this integration. + ## + ## Additionally, this sets the default `service` for every log source. + # + # service: + +## Every instance is scheduled independently of the others. +# +instances: + + - + ## @param tags - list of strings - optional + ## A list of tags to attach to every metric and service check emitted by this instance. + ## + ## Learn more about tagging at https://docs.datadoghq.com/tagging + # + # tags: + # - : + # - : + + ## @param service - string - optional + ## Attach the tag `service:` to every metric, event, and service check emitted by this integration. + ## + ## Overrides any `service` defined in the `init_config` section. + # + # service: + + ## @param min_collection_interval - number - optional - default: 15 + ## This changes the collection interval of the check. For more information, see: + ## https://docs.datadoghq.com/developers/write_agent_check/#collection-interval + # + # min_collection_interval: 15 + + ## @param empty_default_hostname - boolean - optional - default: false + ## This forces the check to send metrics with no hostname. + ## + ## This is useful for cluster-level checks. + # + # empty_default_hostname: false diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/hatch.toml b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/hatch.toml new file mode 100644 index 00000000000000..001e43ce254144 --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/hatch.toml @@ -0,0 +1,4 @@ +[env.collectors.datadog-checks] + +[[envs.default.matrix]] +python = ["3.11"] diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/pyproject.toml b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/pyproject.toml new file mode 100644 index 00000000000000..1a1a0d5b43ba51 --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/pyproject.toml @@ -0,0 +1,60 @@ +[build-system] +requires = [ + "hatchling>=0.13.0", +] +build-backend = "hatchling.build" + +[project] +name = "datadog-{project_name}" +description = "The {integration_name} check" +readme = "README.md" +license = "BSD-3-Clause" +requires-python = ">=3.11" +keywords = [ + "datadog", + "datadog agent", + "datadog check", + "{check_name}", +] +authors = [ + {{ name = "{author}", email = "{email_packages}" }}, +] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: System Administrators", + "License :: OSI Approved :: BSD License", + "Private :: Do Not Upload", + "Programming Language :: Python :: 3.11", + "Topic :: System :: Monitoring", +] +dependencies = [ + "datadog-checks-base>=32.6.0", +] +dynamic = [ + "version", +] + +[project.optional-dependencies] +deps = [] + +[project.urls] +Source = "https://github.com/DataDog/{repo_name}" + +[tool.hatch.version] +path = "datadog_checks/{check_name}/__about__.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/datadog_checks", + "/tests", + "/manifest.json", +] + +[tool.hatch.build.targets.wheel] +include = [ + "/datadog_checks/{check_name}", +] +dev-mode-dirs = [ + ".", +] diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/tests/__init__.py b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/tests/__init__.py new file mode 100644 index 00000000000000..4ad5a0451cb353 --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/tests/__init__.py @@ -0,0 +1 @@ +{license_header} diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/tests/conftest.py b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/tests/conftest.py new file mode 100644 index 00000000000000..62ffe7303083c4 --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/tests/conftest.py @@ -0,0 +1,12 @@ +{license_header} +import pytest + + +@pytest.fixture(scope='session') +def dd_environment(): + yield + + +@pytest.fixture +def instance(): + return {{}} diff --git a/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/tests/test_unit.py b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/tests/test_unit.py new file mode 100644 index 00000000000000..d4dfcaa940e37b --- /dev/null +++ b/datadog_checks_dev/datadog_checks/dev/tooling/templates/integration/check_only/{check_name}/tests/test_unit.py @@ -0,0 +1,24 @@ +{license_header} + +from typing import Any, Callable, Dict # noqa: F401 + +from datadog_checks.base import AgentCheck # noqa: F401 +from datadog_checks.base.stubs.aggregator import AggregatorStub # noqa: F401 +from datadog_checks.dev.utils import get_metadata_metrics +from datadog_checks.{check_name} import {check_class} + + +def test_check(dd_run_check, aggregator, instance): + # type: (Callable[[AgentCheck, bool], None], AggregatorStub, Dict[str, Any]) -> None + check = {check_class}('{check_name}', {{}}, [instance]) + dd_run_check(check) + + aggregator.assert_all_metrics_covered() + aggregator.assert_metrics_using_metadata(get_metadata_metrics()) + + +def test_emits_critical_service_check_when_service_is_down(dd_run_check, aggregator, instance): + # type: (Callable[[AgentCheck, bool], None], AggregatorStub, Dict[str, Any]) -> None + check = {check_class}('{check_name}', {{}}, [instance]) + dd_run_check(check) + aggregator.assert_service_check('{check_name}.can_connect', {check_class}.CRITICAL) diff --git a/docs/developer/setup.md b/docs/developer/setup.md index 14c89b383d8ac3..5bc144b9e31f59 100644 --- a/docs/developer/setup.md +++ b/docs/developer/setup.md @@ -282,7 +282,7 @@ pipx upgrade ddev Also be aware that this method does not get any changes from `datadog_checks_dev`, so if you have unreleased changes from `datadog_checks_dev` that may affect `ddev`, you will need to run the following to get the most recent changes from `datadog_checks_dev` to your `ddev`: ``` - pipx inject ddev -e "/path/to/datadog_checks_dev" + pipx inject -e ddev "/path/to/datadog_checks_dev" ``` ### Configuration