Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate E2E features #15931

Merged
merged 3 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion datadog_checks_dev/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

***Changed***:

* Migrate E2E features ([#15931](https://github.com/DataDog/integrations-core/pull/15931))

## 26.0.1 / 2023-10-11

***Fixed***:
Expand Down Expand Up @@ -36,7 +40,7 @@
* Added overview examples to the readme file ([#15817](https://github.com/DataDog/integrations-core/pull/15817))
* Added required classifier tag examples to template ([#15828](https://github.com/DataDog/integrations-core/pull/15828))
* Prepare E2E tooling for better message passing ([#15843](https://github.com/DataDog/integrations-core/pull/15843))

## 25.0.0 / 2023-09-13

***Changed***:
Expand Down
2 changes: 1 addition & 1 deletion datadog_checks_dev/datadog_checks/dev/_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
E2E_ENV_VAR_PREFIX = '{}_ENV_'.format(E2E_PREFIX)
E2E_SET_UP = '{}_UP'.format(E2E_PREFIX)
E2E_TEAR_DOWN = '{}_DOWN'.format(E2E_PREFIX)
E2E_PARENT_PYTHON = '{}_PYTHON_PATH'.format(E2E_PREFIX)
E2E_PARENT_PYTHON = '{}_PARENT_PYTHON'.format(E2E_PREFIX)
E2E_RESULT_FILE = '{}_RESULT_FILE'.format(E2E_PREFIX)

E2E_FIXTURE_NAME = 'dd_environment'
Expand Down
38 changes: 22 additions & 16 deletions datadog_checks_dev/datadog_checks/dev/plugin/pytest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@
import warnings
from base64 import urlsafe_b64encode
from collections import namedtuple # Not using dataclasses for Py2 compatibility
from io import open
from typing import Dict, List, Optional, Tuple # noqa: F401

import pytest
from six import PY2
from six import PY2, ensure_text

from .._env import (
E2E_FIXTURE_NAME,
Expand Down Expand Up @@ -104,31 +105,29 @@ def dd_environment_runner(request):
if isinstance(config, tuple):
config, possible_metadata = config

# Support only defining the env_type for ease-of-use
# Support only defining the agent_type for ease-of-use
if isinstance(possible_metadata, str):
metadata['env_type'] = possible_metadata
metadata['agent_type'] = possible_metadata
else:
metadata.update(possible_metadata)

# Default to Docker as that is the most common
metadata.setdefault('env_type', 'docker')

# Save any environment variables
metadata.setdefault('env_vars', {})
metadata['env_vars'].update(get_env_vars(raw=True))

# Inject any log configuration
logs_config = get_state('logs_config', [])
if logs_config:
config = format_config(config)
config['logs'] = logs_config

agent_type = metadata.get('agent_type')

# Mount any volumes for Docker
if metadata['env_type'] == 'docker':
if agent_type == 'docker':
docker_volumes = get_state('docker_volumes', [])
if docker_volumes:
metadata.setdefault('docker_volumes', []).extend(docker_volumes)

# Save any environment variables
metadata['e2e_env_vars'] = get_env_vars(raw=True)

data = {'config': config, 'metadata': metadata}

message_template = 'DDEV_E2E_START_MESSAGE {} DDEV_E2E_END_MESSAGE'
Expand All @@ -139,7 +138,7 @@ def dd_environment_runner(request):
# Exit testing and pass data back up to command
if E2E_RESULT_FILE in os.environ:
with open(os.environ[E2E_RESULT_FILE], 'w', encoding='utf-8') as f:
f.write(json.dumps(data))
f.write(ensure_text(json.dumps(data)))

# Rather than exiting we skip every test to avoid the following output:
# !!!!!!!!!! _pytest.outcomes.Exit: !!!!!!!!!!
Expand All @@ -160,7 +159,8 @@ def pytest_report_teststatus(report, config):
"""
# Skipping every test displays an `s` for each even when using
# the minimum verbosity so we force zero output
return 'skipped', '', ''
if report.skipped:
return 'skipped', '', ''


@pytest.fixture
Expand All @@ -187,8 +187,7 @@ def run_check(config=None, **kwargs):
python_path = os.environ[E2E_PARENT_PYTHON]
env = os.environ['HATCH_ENV_ACTIVE']

# TODO: switch to `ddev` when the old CLI is gone
check_command = [python_path, '-m', 'datadog_checks.dev', 'env', 'check', check, env, '--json']
check_command = [python_path, '-m', 'ddev', 'env', 'agent', check, env, 'check', '--json']
FlorentClarret marked this conversation as resolved.
Show resolved Hide resolved

if config:
config = format_config(config)
Expand All @@ -197,7 +196,14 @@ def run_check(config=None, **kwargs):
with open(config_file, 'wb') as f:
output = json.dumps(config).encode('utf-8')
f.write(output)
check_command.extend(['--config', config_file])
check_command.extend(['--config-file', config_file])

# TODO: remove these legacy flags when all usage of this fixture is migrated
if 'rate' in kwargs:
kwargs['check_rate'] = kwargs.pop('rate')

if 'times' in kwargs:
kwargs['check_times'] = kwargs.pop('times')

for key, value in kwargs.items():
if value is not False:
Expand Down
2 changes: 1 addition & 1 deletion datadog_checks_dev/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def mock_e2e_config():

@pytest.fixture(scope='session')
def mock_e2e_metadata():
return {'env_type': 'vagrant', 'future': 'now', 'env_vars': {}}
return {'agent_type': 'vagrant', 'e2e_env_vars': {}, 'future': 'now', 'env_vars': {}}


@pytest.fixture(scope='session')
Expand Down
4 changes: 4 additions & 0 deletions ddev/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

***Added***:

* Migrate E2E features ([#15931](https://github.com/DataDog/integrations-core/pull/15931))

## 5.1.1 / 2023-09-29

***Fixed***:
Expand Down
2 changes: 1 addition & 1 deletion ddev/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ classifiers = [
dependencies = [
"click~=8.1.6",
"coverage",
"datadog-checks-dev[cli]~=25.0",
"datadog-checks-dev[cli]>=25.1.2,<26",
FlorentClarret marked this conversation as resolved.
Show resolved Hide resolved
"hatch>=1.6.3",
"httpx",
"jsonpointer",
Expand Down
11 changes: 9 additions & 2 deletions ddev/src/ddev/cli/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
from __future__ import annotations

import os
from functools import cached_property
from typing import cast

from ddev.cli.terminal import Terminal
from ddev.config.constants import AppEnvVars, VerbosityLevels
from ddev.config.constants import AppEnvVars, ConfigEnvVars, VerbosityLevels
from ddev.config.file import ConfigFile, RootConfig
from ddev.repo.core import Repository
from ddev.utils.fs import Path
Expand All @@ -18,7 +19,7 @@
class Application(Terminal):
def __init__(self, exit_func, *args, **kwargs):
super().__init__(*args, **kwargs)
self.platform = Platform(self.display_raw)
self.platform = Platform(self.output)
self.__exit_func = exit_func

self.config_file = ConfigFile()
Expand All @@ -40,6 +41,12 @@ def config(self) -> RootConfig:
def repo(self) -> Repository:
return self.__repo

@cached_property
def data_dir(self) -> Path:
from platformdirs import user_data_dir

return Path(os.getenv(ConfigEnvVars.DATA) or user_data_dir('ddev', appauthor=False)).expand()

@property
def github(self) -> GitHubManager:
return self.__github
Expand Down
4 changes: 2 additions & 2 deletions ddev/src/ddev/cli/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def show(app, all_keys):
from rich.syntax import Syntax

text = app.config_file.read() if all_keys else app.config_file.read_scrubbed()
app.display_raw(Syntax(text.rstrip(), 'toml', background_color='default'))
app.output(Syntax(text.rstrip(), 'toml', background_color='default'))


@config.command(short_help='Update the config file with any new fields')
Expand Down Expand Up @@ -146,4 +146,4 @@ def set_value(app, key, value):
from rich.syntax import Syntax

app.display_success('New setting:')
app.display_raw(Syntax(rendered_changed, 'toml', background_color='default'))
app.output(Syntax(rendered_changed, 'toml', background_color='default'))
31 changes: 16 additions & 15 deletions ddev/src/ddev/cli/env/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
import click
from datadog_checks.dev.tooling.commands.env.check import check_run
from datadog_checks.dev.tooling.commands.env.edit import edit
from datadog_checks.dev.tooling.commands.env.ls import ls
from datadog_checks.dev.tooling.commands.env.prune import prune
from datadog_checks.dev.tooling.commands.env.reload import reload_env
from datadog_checks.dev.tooling.commands.env.shell import shell
from datadog_checks.dev.tooling.commands.env.start import start
from datadog_checks.dev.tooling.commands.env.stop import stop
from datadog_checks.dev.tooling.commands.env.test import test

from ddev.cli.env.agent import agent
from ddev.cli.env.check import check
from ddev.cli.env.config import config
from ddev.cli.env.reload import reload_command
from ddev.cli.env.shell import shell
from ddev.cli.env.show import show
from ddev.cli.env.start import start
from ddev.cli.env.stop import stop
from ddev.cli.env.test import test_command
Comment on lines +6 to +14
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉



@click.group(short_help='Manage environments')
Expand All @@ -20,12 +21,12 @@ def env():
"""


env.add_command(check_run)
env.add_command(edit)
env.add_command(ls)
env.add_command(prune)
env.add_command(reload_env)
env.add_command(agent)
env.add_command(check)
env.add_command(config)
env.add_command(reload_command)
env.add_command(shell)
env.add_command(show)
env.add_command(start)
env.add_command(stop)
env.add_command(test)
env.add_command(test_command)
80 changes: 80 additions & 0 deletions ddev/src/ddev/cli/env/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# (C) Datadog, Inc. 2023-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from __future__ import annotations

from typing import TYPE_CHECKING

import click

if TYPE_CHECKING:
from ddev.cli.application import Application


@click.command(
short_help='Invoke the Agent', context_settings={'help_option_names': [], 'ignore_unknown_options': True}
)
@click.argument('intg_name', metavar='INTEGRATION')
@click.argument('environment')
@click.argument('args', required=True, nargs=-1)
@click.option('--config-file', hidden=True)
@click.pass_obj
def agent(app: Application, *, intg_name: str, environment: str, args: tuple[str, ...], config_file: str | None):
"""
Invoke the Agent.
"""
import subprocess

from ddev.e2e.agent import get_agent_interface
from ddev.e2e.config import EnvDataStorage
from ddev.e2e.constants import DEFAULT_AGENT_TYPE, E2EMetadata
from ddev.utils.fs import Path

integration = app.repo.integrations.get(intg_name)
env_data = EnvDataStorage(app.data_dir).get(integration.name, environment)

if not env_data.exists():
app.abort(f'Environment `{environment}` for integration `{integration.name}` is not running')

metadata = env_data.read_metadata()
agent_type = metadata.get(E2EMetadata.ENV_VARS, DEFAULT_AGENT_TYPE)
agent = get_agent_interface(agent_type)(app.platform, integration, environment, metadata, env_data.config_file)

full_args = list(args)
trigger_run = False
if full_args[0] == 'check':
trigger_run = True

# TODO: remove this when all invocations migrate to the actual command
if len(full_args) > 2 and full_args[1] == '--jmx-list':
full_args = ['jmx', 'list', full_args[2]]
# Automatically inject the integration name if not passed
elif len(full_args) == 1 or full_args[1].startswith('-'):
full_args.insert(1, intg_name)

if config_file is None or not trigger_run:
try:
agent.invoke(full_args)
except subprocess.CalledProcessError as e:
app.abort(code=e.returncode)

return

import json

config = json.loads(Path(config_file).read_text())

if not env_data.config_file.is_file():
try:
env_data.write_config(config)
agent.invoke(full_args)
finally:
env_data.config_file.unlink()
else:
temp_config_file = env_data.config_file.parent / f'{env_data.config_file.name}.bak.example'
env_data.config_file.replace(temp_config_file)
try:
env_data.write_config(config)
agent.invoke(full_args)
finally:
temp_config_file.replace(env_data.config_file)
18 changes: 18 additions & 0 deletions ddev/src/ddev/cli/env/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# (C) Datadog, Inc. 2023-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from __future__ import annotations

import click


@click.command(context_settings={'ignore_unknown_options': True}, hidden=True)
@click.argument('intg_name')
@click.argument('environment')
@click.argument('args', nargs=-1)
@click.option('--config')
@click.pass_context
def check(ctx: click.Context, *, intg_name: str, environment: str, args: tuple[str, ...], config: str | None):
from ddev.cli.env.agent import agent

ctx.invoke(agent, intg_name=intg_name, environment=environment, args=('check', *args), config_file=config)
Loading