├── .github └── workflows │ ├── publish.yml │ └── tests.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── dev_helper.py ├── dynatrace ├── __init__.py ├── configuration_v1 │ ├── __init__.py │ ├── alerting_profiles.py │ ├── anomaly_detection_process_groups.py │ ├── api.py │ ├── auto_tags.py │ ├── credential_vault.py │ ├── dashboard.py │ ├── endpoint.py │ ├── extensions.py │ ├── geographic_regions.py │ ├── maintenance_windows.py │ ├── management_zones.py │ ├── metric_events.py │ ├── notifications.py │ ├── oneagent_environment_wide_configuration.py │ ├── oneagent_in_a_hostgroup.py │ ├── oneagent_on_a_host.py │ ├── plugins.py │ ├── schemas.py │ └── tile.py ├── dynatrace_object.py ├── environment_v1 │ ├── __init__.py │ ├── cluster_time.py │ ├── custom_device.py │ ├── deployment.py │ ├── event.py │ ├── oneagents.py │ ├── smartscape_hosts.py │ ├── synthetic_monitors.py │ ├── synthetic_third_party.py │ └── timeseries.py ├── environment_v2 │ ├── __init__.py │ ├── activegates.py │ ├── activegates_autoupdate_configuration.py │ ├── activegates_autoupdate_jobs.py │ ├── audit_logs.py │ ├── custom_tags.py │ ├── events.py │ ├── extensions.py │ ├── logs.py │ ├── metrics.py │ ├── monitored_entities.py │ ├── networkzones.py │ ├── problems.py │ ├── remote_configuration.py │ ├── schemas.py │ ├── service_level_objectives.py │ ├── settings.py │ ├── tokens_api.py │ └── tokens_tenant.py ├── http_client.py ├── main.py ├── pagination.py └── utils.py ├── pyproject.toml ├── test ├── __init__.py ├── configuration_v1 │ ├── __init__.py │ ├── test_alerting_profiles.py │ ├── test_anomaly_detection_metric_events.py │ ├── test_auto_tags.py │ ├── test_extensions.py │ ├── test_maintenance_windows.py │ ├── test_management_zones.py │ ├── test_notifications.py │ ├── test_oneagent_environment_wide_configuration.py │ ├── test_oneagent_in_a_hostgroup.py │ └── test_oneagent_on_a_host.py ├── conftest.py ├── environment_v1 │ ├── __init__.py │ ├── test_deployment.py │ ├── test_smartscape_hosts.py │ └── test_synthetic_monitors.py ├── environment_v2 │ ├── __init__.py │ ├── test_activegate_autoupdate_configuration.py │ ├── test_activegate_autoupdate_jobs.py │ ├── test_activegates_remote_configuration.py │ ├── test_audit_logs.py │ ├── test_customtags.py │ ├── test_entities.py │ ├── test_events_v2.py │ ├── test_extensions.py │ ├── test_metrics.py │ ├── test_networkzones.py │ ├── test_oneagents_remote_configuration.py │ ├── test_problems.py │ ├── test_service_level_objectives.py │ ├── test_settings.py │ ├── test_tokens_api.py │ └── test_tokens_tenant.py ├── mock_data │ ├── DELETE_api_v2_tags_bfb7a4f8c7f839c.json │ ├── GET_api_config_v1_alertingProfiles.json │ ├── GET_api_config_v1_alertingProfiles_b1f379d9-98b4-4efe-be38-0289609c9295.json │ ├── GET_api_config_v1_anomalyDetection_metricEvents.json │ ├── GET_api_config_v1_anomalyDetection_metricEvents_d3baaaed-3441-4931-bf24-25c4e12e137f.json │ ├── GET_api_config_v1_anomalyDetection_metricEvents_ruxit_python_rabbitmq_node_status_node_failed.json │ ├── GET_api_config_v1_autoTags_403e033b-7324-4bfe-bef1-b3f367de42f2.json │ ├── GET_api_config_v1_autoTags_76f44b03d6ff371.json │ ├── GET_api_config_v1_extensions_76f44b03d6ff371.json │ ├── GET_api_config_v1_extensions_activeGateExtensionModules.json │ ├── GET_api_config_v1_extensions_custom_python_citrixAgent.json │ ├── GET_api_config_v1_extensions_custom_python_citrixAgent_global.json │ ├── GET_api_config_v1_extensions_custom_remote_python_salesforce_eventstream_instances_5649014104314746667.json │ ├── GET_api_config_v1_extensions_custom_remote_python_salesforce_eventstream_states.json │ ├── GET_api_config_v1_hostgroups_HOST_GROUP-ABC123DEF456GHI7.json │ ├── GET_api_config_v1_hostgroups_HOST_GROUP-ABC123DEF456GHI7_autoupdate.json │ ├── GET_api_config_v1_hosts_HOST-abcd123457.json │ ├── GET_api_config_v1_hosts_HOST-abcd123457_autoupdate.json │ ├── GET_api_config_v1_hosts_HOST-abcd123457_monitoring.json │ ├── GET_api_config_v1_hosts_HOST-abcd123457_technologies.json │ ├── GET_api_config_v1_hosts_autoupdate.json │ ├── GET_api_config_v1_maintenanceWindows.json │ ├── GET_api_config_v1_maintenanceWindows_b6376a12-0b82-4069-9a41-0e55ef9a1f44.json │ ├── GET_api_config_v1_managementZones_6507829326603756920.json │ ├── GET_api_config_v1_managementZones_76f44b03d6ff371.json │ ├── GET_api_config_v1_notifications.json │ ├── GET_api_config_v1_notifications_0d06c889-4cea-4b45-aefa-a277790e784d.json │ ├── GET_api_config_v1_technologies.json │ ├── GET_api_v1_deployment_boshrelease_agent_unix_version_1_215_159_20210428-145534_checksum_fad478b86718411.json │ ├── GET_api_v1_deployment_boshrelease_versions_unix.json │ ├── GET_api_v1_deployment_installer_agent_connectioninfo_5cfedcf2b045507.json │ ├── GET_api_v1_deployment_installer_agent_unix_paas_latest_metainfo_162a156059a3150.json │ ├── GET_api_v1_deployment_installer_agent_versions_unix_paas_37c730b12310340.json │ ├── GET_api_v1_deployment_installer_gateway_connectioninfo_5e7bba15048d70e.json │ ├── GET_api_v1_deployment_installer_gateway_versions_unix.json │ ├── GET_api_v1_deployment_lambda_agent_latest.json │ ├── GET_api_v1_entity_infrastructure_hosts_2c7c3f4daf2bc97.json │ ├── GET_api_v1_entity_infrastructure_hosts_eb6d39453f5207d.json │ ├── GET_api_v1_synthetic_monitors_5a712d431f0dc23.json │ ├── GET_api_v1_synthetic_monitors_SYNTHETIC_TEST-7639A3AED66940FA.json │ ├── GET_api_v2_activeGates_-1556499193_updateJobs_5b76ac60bd217e9.json │ ├── GET_api_v2_activeGates_1513404008_autoUpdate.json │ ├── GET_api_v2_activeGates_autoUpdate.json │ ├── GET_api_v2_activeGates_remoteConfigurationManagement_2e5fcbd2c8d0e63.json │ ├── GET_api_v2_activeGates_remoteConfigurationManagement_7974003406714390819.json │ ├── GET_api_v2_activeGates_remoteConfigurationManagement_current.json │ ├── GET_api_v2_activeGates_remoteConfigurationManagement_preview_4cfaf0a9b26d2dd.json │ ├── GET_api_v2_activeGates_updateJobs_5b76ac60bd217e9.json │ ├── GET_api_v2_apiTokens_ca4f773d77d3bb7.json │ ├── GET_api_v2_auditlogs_162100314800090003.json │ ├── GET_api_v2_auditlogs_cc1c21092884f6e.json │ ├── GET_api_v2_entities_64b5e3b6872892e.json │ ├── GET_api_v2_entities_HOST-82F576674F19AC16_eeb2d99e8563a18.json │ ├── GET_api_v2_entityTypes_DISK.json │ ├── GET_api_v2_entityTypes_e0d8c23ec365525.json │ ├── GET_api_v2_eventTypes_3540f77a223c618.json │ ├── GET_api_v2_eventTypes_APPLICATION_OVERLOAD_PREVENTION.json │ ├── GET_api_v2_events_4578933396576863909_1631255744265.json │ ├── GET_api_v2_events_92a68db488c79f5.json │ ├── GET_api_v2_extensions_094e243469d892d.json │ ├── GET_api_v2_extensions_1b00aa5e4518062.json │ ├── GET_api_v2_extensions_com_dynatrace_extension_snmp-generic.json │ ├── GET_api_v2_extensions_com_dynatrace_extension_snmp-generic_0_2_5.json │ ├── GET_api_v2_extensions_ibmmq_environmentConfiguration.json │ ├── GET_api_v2_logs_export_8b3579556e13525.json │ ├── GET_api_v2_metrics_b9525a59df51eee.json │ ├── GET_api_v2_metrics_builtin_host_cpu_idle.json │ ├── GET_api_v2_metrics_c1510d03fd2e55e.json │ ├── GET_api_v2_metrics_c2452ee3448e535.json │ ├── GET_api_v2_metrics_query_0f81e686e69f013.json │ ├── GET_api_v2_metrics_query_3b31d1b7859b9a7.json │ ├── GET_api_v2_metrics_query_4fa21773411125d.json │ ├── GET_api_v2_networkZones.json │ ├── GET_api_v2_networkZones_default.json │ ├── GET_api_v2_networkZonesdefault.json │ ├── GET_api_v2_oneagents_remoteConfigurationManagement_2e5fcbd2c8d0e63.json │ ├── GET_api_v2_oneagents_remoteConfigurationManagement_7974003406714390819.json │ ├── GET_api_v2_oneagents_remoteConfigurationManagement_current.json │ ├── GET_api_v2_oneagents_remoteConfigurationManagement_preview_4cfaf0a9b26d2dd.json │ ├── GET_api_v2_problems_-1719139739592062093_1623004451641V2_8913ec9c57d7960.json │ ├── GET_api_v2_problems_-1719139739592062093_1623004451641V2_comments_-7228967546616810529_1623004451641.json │ ├── GET_api_v2_problems_-1719139739592062093_1623004451641V2_comments_0fe92b50cb1bdcb.json │ ├── GET_api_v2_problems_-1719139739592062093_1623004451641V2_comments_adba23bf24edbcc.json │ ├── GET_api_v2_problems_0d7ed4db1cd91c2.json │ ├── GET_api_v2_settings_objects_accb155250dbcbb.json │ ├── GET_api_v2_settings_objects_vu9U3hXa3q0AAAABACdidWlsdGluOmFub21hbHktZGV0ZWN0aW9uLm1ldHJpYy1ldmVudHMABnRlbmFudAAGdGVuYW50ACRiYmYzZWNhNy0zMmZmLTM2ZTEtOTFiOS05Y2QxZjE3OTc0YjC-71TeFdrerQ.json │ ├── GET_api_v2_settings_schemas.json │ ├── GET_api_v2_slo_711a4ada1bbd672.json │ ├── GET_api_v2_slo_88991da4-be17-3d57-aada-cfb3977767f4_a3b5130244d7cfb.json │ ├── GET_api_v2_tags_3d3d3b0ff3c48c2.json │ ├── GETapi_v2_-1719139739592062093_1623004451641V2_comments_adba23bf24edbcc.json │ ├── POST_api_config_v1_alertingProfiles_615cf1488e623d7.json │ ├── POST_api_config_v1_maintenanceWindows_b701f87f95f4e57.json │ ├── POST_api_config_v1_managementZones_7942f5740137a74.json │ ├── POST_api_v2_activeGates_remoteConfigurationManagement_4cfaf0a9b26d2dd.json │ ├── POST_api_v2_activeGates_remoteConfigurationManagement_validator_4cfaf0a9b26d2dd.json │ ├── POST_api_v2_events_ingest_3dfc47521cd78f3.json │ ├── POST_api_v2_metrics_ingest.json │ ├── POST_api_v2_oneagents_remoteConfigurationManagement_4cfaf0a9b26d2dd.json │ ├── POST_api_v2_oneagents_remoteConfigurationManagement_validator_4cfaf0a9b26d2dd.json │ ├── POST_api_v2_problems_-1719139739592062093_1623004451641V2_close_91e97b2b99926eb.json │ ├── POST_api_v2_settings_objects_48f5d7ab33b29d3.json │ ├── POST_api_v2_tags_4f8375bfcb42058.json │ ├── POST_api_v2_tags_fe7d869df4dac8b.json │ ├── POST_api_v2_tenantTokenRotation_cancel.json │ ├── POST_api_v2_tenantTokenRotation_finish.json │ ├── POST_api_v2_tenantTokenRotation_start.json │ └── PUT_api_v2_settings_objects_vu9U3hXa3q0AAAABACdidWlsdGluOmFub21hbHktZGV0ZWN0aW9uLm1ldHJpYy1ldmVudHMABnRlbmFudAAGdGVuYW50ACRiYmYzZWNhNy0zMmZmLTM2ZTEtOTFiOS05Y2QxZjE3OTc0YjC-71TeFdrerQ_193f82b398660c4.json └── test_logs.py └── tox.ini /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Build and publish to PyPi 2 | on: 3 | workflow_dispatch: 4 | inputs: 5 | tag: 6 | description: 'Tag to publish (v*.*.*)' 7 | required: true 8 | type: string 9 | 10 | jobs: 11 | build-n-publish: 12 | name: Build and publish to PyPi 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | ref: ${{ inputs.tag }} 18 | - uses: actions/setup-python@v5 19 | - name: Install dependencies 20 | run: | 21 | python -m pip install --upgrade poetry 22 | poetry install 23 | - name: Build 24 | run: | 25 | poetry build 26 | - name: Configure Poetry credentials 27 | run: | 28 | poetry config pypi-token.pypi ${{ secrets.PYPI_API_TOKEN }} 29 | - name: Publish 30 | run: | 31 | poetry publish 32 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | build: 7 | runs-on: ${{ matrix.platform }} 8 | strategy: 9 | max-parallel: 4 10 | matrix: 11 | # https://help.github.com/articles/virtual-environments-for-github-actions 12 | platform: 13 | - ubuntu-latest 14 | - macos-latest 15 | - windows-latest 16 | # https://raw.githubusercontent.com/actions/python-versions/main/versions-manifest.json 17 | python-version: [ '3.9', '3.10', '3.11', '3.12', '3.13' ] 18 | 19 | steps: 20 | - uses: actions/checkout@v4 21 | - name: Set up Python ${{ matrix.python-version }} 22 | uses: actions/setup-python@v5 23 | with: 24 | python-version: ${{ matrix.python-version }} 25 | - name: Install dependencies 26 | run: | 27 | python -m pip install --upgrade setuptools pip wheel pytest mock requests 28 | - name: Test with pytest 29 | run: pytest -rp 30 | 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/latest/usage/project/#working-with-version-control 110 | .pdm.toml 111 | .pdm-python 112 | .pdm-build/ 113 | 114 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 115 | __pypackages__/ 116 | 117 | # Celery stuff 118 | celerybeat-schedule 119 | celerybeat.pid 120 | 121 | # SageMath parsed files 122 | *.sage.py 123 | 124 | # Environments 125 | .env 126 | .venv 127 | env/ 128 | venv/ 129 | ENV/ 130 | env.bak/ 131 | venv.bak/ 132 | 133 | # Spyder project settings 134 | .spyderproject 135 | .spyproject 136 | 137 | # Rope project settings 138 | .ropeproject 139 | 140 | # mkdocs documentation 141 | /site 142 | 143 | # mypy 144 | .mypy_cache/ 145 | .dmypy.json 146 | dmypy.json 147 | 148 | # Pyre type checker 149 | .pyre/ 150 | 151 | # pytype static type analyzer 152 | .pytype/ 153 | 154 | # Cython debug symbols 155 | cython_debug/ 156 | 157 | # PyCharm 158 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 159 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 160 | # and can be added to the global gitignore or merged into this file. For a more nuclear 161 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 162 | #.idea/ -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor covenant code of conduct 2 | 3 | ## Our pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This code of conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project email 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at opensource@dynatrace.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce this code of conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This code of conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /dev_helper.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file can be used during development to automatically generate mock data from the API calls. 3 | Please check CONTRIBUTING.md for details 4 | """ 5 | 6 | import hashlib 7 | import json 8 | import logging 9 | import os 10 | from pathlib import Path 11 | 12 | import wrapt 13 | 14 | from dynatrace import Dynatrace 15 | from dynatrace.utils import slugify 16 | 17 | 18 | @wrapt.patch_function_wrapper("dynatrace.http_client", "HttpClient.make_request") 19 | def dump_to_json(wrapped, instance, args, kwargs): 20 | r = wrapped(*args, **kwargs) 21 | method = kwargs.get("method", "GET") 22 | params = kwargs.get("params", "") 23 | query_params = kwargs.get("query_params", "") 24 | 25 | params = f"{params}" if params else "" 26 | if query_params: 27 | params += f"{query_params}" 28 | if params: 29 | encoded = f"{params}".encode() 30 | params = f"_{hashlib.sha256(encoded).hexdigest()}"[:16] 31 | 32 | path = slugify(args[0]) 33 | file_name = f"{method}{path}{params}.json" 34 | file_path = f"test/mock_data/{file_name}" 35 | if not Path(file_path).exists(): 36 | with open(file_path, "w") as f: 37 | if r.text: 38 | print(f"Dumping response to '{file_name}'") 39 | json.dump(r.json(), f) 40 | return r 41 | 42 | 43 | def setup_log(): 44 | log = logging.getLogger(__name__) 45 | log.setLevel(logging.DEBUG) 46 | st = logging.StreamHandler() 47 | fmt = logging.Formatter("%(asctime)s - %(levelname)s - %(name)s - %(thread)d - %(filename)s:%(lineno)d - %(message)s") 48 | st.setFormatter(fmt) 49 | log.addHandler(st) 50 | return log 51 | 52 | 53 | def main(): 54 | dt = Dynatrace(os.getenv("DYNATRACE_TENANT_URL"), os.getenv("DYNATRACE_API_TOKEN"), log=setup_log()) 55 | 56 | # TODO - Code here as you add new endpoints, during development 57 | # Any requests are going to be recorded in the `test/mock` folder and can later be used to write tests. 58 | for m in dt.metrics.list(page_size=500): 59 | print(m.metric_id) 60 | 61 | 62 | if __name__ == "__main__": 63 | main() 64 | -------------------------------------------------------------------------------- /dynatrace/__init__.py: -------------------------------------------------------------------------------- 1 | from dynatrace.main import Dynatrace 2 | from dynatrace.http_client import TOO_MANY_REQUESTS_WAIT 3 | -------------------------------------------------------------------------------- /dynatrace/configuration_v1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynatrace-oss/api-client-python/9c1467b36b8a11ff74daf9d6d2c9fde25c4fd970/dynatrace/configuration_v1/__init__.py -------------------------------------------------------------------------------- /dynatrace/configuration_v1/anomaly_detection_process_groups.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | from typing import Optional, Dict, Any, Union 18 | from enum import Enum 19 | 20 | from dynatrace.dynatrace_object import DynatraceObject 21 | from dynatrace.http_client import HttpClient 22 | 23 | 24 | class Method(Enum): 25 | OFF = "OFF" 26 | MINIMUM_THRESHOLD = "MINIMUM_THRESHOLD" 27 | PROCESS_IMPACT = "PROCESS_IMPACT" 28 | 29 | 30 | class AvailabilityMonitoringPG(DynatraceObject): 31 | def _create_from_raw_data(self, raw_element: Dict[str, Any]): 32 | self.method: Method = Method(raw_element.get("method")) 33 | self.minimum_threshold: int = raw_element.get("minimumThreshold") 34 | 35 | 36 | class AnomalyDetectionPG(DynatraceObject): 37 | @staticmethod 38 | def create(method: Union[str, Method], minimum_threshold: Optional[int] = None): 39 | method = Method(method) 40 | if method == Method.MINIMUM_THRESHOLD: 41 | raw_element = {"availabilityMonitoring": {"method": method.value, "minimumThreshold": minimum_threshold}} 42 | else: 43 | raw_element = {"availabilityMonitoring": {"method": method.value}} 44 | return AnomalyDetectionPG(raw_element=raw_element) 45 | 46 | def json(self): 47 | """ 48 | Get the json representation of this process group anomaly detection config. 49 | """ 50 | if self.availability_monitoring.method == Method.MINIMUM_THRESHOLD: 51 | json = { 52 | "availabilityMonitoring": { 53 | "method": self.availability_monitoring.method.value, 54 | "minimumThreshold": self.availability_monitoring.minimum_threshold, 55 | } 56 | } 57 | else: 58 | json = {"availabilityMonitoring": {"method": self.availability_monitoring.method.value}} 59 | return json 60 | 61 | def _create_from_raw_data(self, raw_element: Dict[str, Any]): 62 | self.availability_monitoring: AvailabilityMonitoringPG = AvailabilityMonitoringPG( 63 | self._http_client, raw_element=raw_element.get("availabilityMonitoring") 64 | ) 65 | 66 | 67 | class AnomalyDetectionPGService: 68 | # TODO - Early adopter endpoint, be sure to check back in for updates 69 | def __init__(self, http_client: HttpClient): 70 | self.__http_client = http_client 71 | 72 | def get_configuration(self, id: str): 73 | """ 74 | Get the anomaly detection configuration for the specified process group. 75 | """ 76 | return AnomalyDetectionPG(self.__http_client, raw_element=self.__http_client.make_request(f"/api/config/v1/anomalyDetection/processGroups/{id}").json()) 77 | 78 | def put_configuration(self, id: str, anomaly_detection_config: AnomalyDetectionPG): 79 | """ 80 | Update the anomaly detection configuration for the specified process group. 81 | """ 82 | return self.__http_client.make_request(f"/api/config/v1/anomalyDetection/processGroups/{id}", method="PUT", params=anomaly_detection_config.json()) 83 | 84 | def delete_configuration(self, id: str): 85 | """ 86 | Deletes the anomaly detection configuration for the process group. This is the same as turning availaility monitoring off. 87 | """ 88 | return self.__http_client.make_request(f"/api/config/v1/anomalyDetection/processGroups/{id}", method="DELETE") 89 | -------------------------------------------------------------------------------- /dynatrace/configuration_v1/api.py: -------------------------------------------------------------------------------- 1 | from dynatrace.configuration_v1.geographic_regions import GeoRegionsIpAddressMappingsService 2 | from dynatrace.http_client import HttpClient 3 | 4 | 5 | class ConfigurationV1: 6 | def __init__(self, http_client: HttpClient): 7 | self._http_client = http_client 8 | 9 | self.geo_regions_ip_address_mappings = GeoRegionsIpAddressMappingsService(http_client) 10 | -------------------------------------------------------------------------------- /dynatrace/configuration_v1/credential_vault.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from base64 import b64encode 3 | from typing import List, Optional 4 | 5 | from dynatrace.dynatrace_object import DynatraceObject 6 | from dynatrace.http_client import HttpClient 7 | from dynatrace.pagination import PaginatedList 8 | 9 | 10 | class CredentialVaultService: 11 | _ENDPOINT = "/api/config/v1/credentials" 12 | 13 | def __init__(self, http_client: HttpClient): 14 | self.__http_client = http_client 15 | 16 | def list(self) -> PaginatedList["CredentialsResponseElement"]: 17 | """ 18 | Lists all sets of credentials stored in your environment 19 | 20 | Required Api-Token scope: 21 | credentialVault.read (Read credential vault entries) 22 | """ 23 | return PaginatedList(CredentialsResponseElement, self.__http_client, self._ENDPOINT, list_item="credentials") 24 | 25 | def post(self, credential: "Credentials"): 26 | response = self.__http_client.make_request(path=self._ENDPOINT, 27 | params=credential.to_json(), 28 | method="POST") 29 | 30 | return CredentialsResponseElement(raw_element=response.json()) 31 | 32 | 33 | 34 | class CredentialUsageHandler(DynatraceObject): 35 | def _create_from_raw_data(self, raw_element): 36 | self.type: str = raw_element.get("type", "") 37 | self.count: int = raw_element.get("count", 0) 38 | 39 | 40 | class CredentialsResponseElement(DynatraceObject): 41 | def _create_from_raw_data(self, raw_element): 42 | self.name: str = raw_element.get("name", "") 43 | self.id: str = raw_element.get("id", "") 44 | self.type: str = raw_element.get("type", "") 45 | self.description: str = raw_element.get("description", "") 46 | self.owner: str = raw_element.get("owner", "") 47 | self.owner_access_only = raw_element.get("ownerAccessOnly", False) 48 | self.scope: str = raw_element.get("scope", "") 49 | self.credential_usage_summary: List[CredentialUsageHandler] = [CredentialUsageHandler(raw_element=summary) for summary in raw_element.get("credentialUsageSummary", [])] 50 | 51 | 52 | class Credentials(ABC): 53 | def __init__(self, 54 | name: str, 55 | scope: str, 56 | description: Optional[str] = None, 57 | owner_access_only: Optional[bool] = False, 58 | credential_type: Optional[str] = None): 59 | self.name: str = name 60 | self.scope: str = scope 61 | self.description: Optional[str] = description 62 | self.owner_access_only: Optional[bool] = owner_access_only 63 | self.type: Optional[str] = credential_type 64 | 65 | @abstractmethod 66 | def to_json(self) -> dict: 67 | pass 68 | 69 | 70 | class PublicCertificateCredentials(Credentials): 71 | def __init__(self, 72 | name: str, 73 | scope: str, 74 | certificate: str, 75 | password: str, 76 | certificate_format: str, 77 | description: Optional[str] = None, 78 | owner_access_only: Optional[bool] = False, 79 | credential_type: Optional[str] = None): 80 | super().__init__(name, scope, description, owner_access_only, credential_type) 81 | self.certificate: str = b64encode(certificate.encode()).decode() 82 | 83 | self.password: str = password 84 | self.certificate_format: str = certificate_format 85 | 86 | def to_json(self) -> dict: 87 | return { 88 | "name": self.name, 89 | "scope": self.scope, 90 | "description": self.description, 91 | "ownerAccessOnly": self.owner_access_only, 92 | "type": self.type, 93 | "certificate": self.certificate, 94 | "password": self.password, 95 | "certificateFormat": self.certificate_format 96 | } 97 | -------------------------------------------------------------------------------- /dynatrace/configuration_v1/endpoint.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | from requests import Response 18 | from dynatrace.environment_v2.monitored_entities import EntityShortRepresentation 19 | 20 | 21 | class EndpointShortRepresentation(EntityShortRepresentation): 22 | def delete(self, plugin_id: str) -> Response: 23 | """ 24 | Deletes this endpoint 25 | """ 26 | return self._http_client.make_request(f"/api/config/v1/plugins/{plugin_id}/endpoints/{self.id}", method="DELETE") 27 | -------------------------------------------------------------------------------- /dynatrace/configuration_v1/geographic_regions.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | from dynatrace.dynatrace_object import DynatraceObject 4 | from dynatrace.http_client import HttpClient 5 | 6 | 7 | class GeoRegionsIpAddressMappingsService: 8 | ENDPOINT = "/api/config/v1/geographicRegions/ipAddressMappings" 9 | 10 | def __init__(self, http_client: HttpClient): 11 | self._http_client = http_client 12 | 13 | def list(self) -> "IPAddressMapping": 14 | """ 15 | Lists all IP address mappings of the environment 16 | """ 17 | response = self._http_client.make_request(self.ENDPOINT).json() 18 | return IPAddressMapping(self._http_client, None, response) 19 | 20 | def put(self, mappings: List["IPAddressMapping"]): 21 | """ 22 | Updates the IP address mappings of the environment 23 | """ 24 | data = [mapping.json() for mapping in mappings] 25 | body = { 26 | "ipAddressMappingRules": data 27 | } 28 | self._http_client.make_request(self.ENDPOINT, method="PUT", params=body) 29 | 30 | 31 | class IPAddressMapping(DynatraceObject): 32 | def _create_from_raw_data(self, raw_element): 33 | self.rules: List["IPAddressMappingRule"] = [ 34 | IPAddressMappingRule(raw_element=e) for e in raw_element.get("ipAddressMappingRules") 35 | ] 36 | 37 | 38 | class IPAddressMappingRule(DynatraceObject): 39 | def _create_from_raw_data(self, raw_element): 40 | self.location = IPAddressMappingLocation(raw_element=raw_element.get("location")) 41 | self.ip_range = IPAddressRange(raw_element=raw_element.get("ipRange")) 42 | 43 | @staticmethod 44 | def create(location: "IPAddressMappingLocation", ip_range: "IPAddressRange"): 45 | """ 46 | Creates a new IP address mapping rule 47 | """ 48 | return IPAddressMappingRule(raw_element={ 49 | "ipAddressMappingLocation": location.json(), 50 | "ipAddressRange": ip_range.json(), 51 | }) 52 | 53 | 54 | class IPAddressMappingLocation(DynatraceObject): 55 | def _create_from_raw_data(self, raw_element): 56 | self.country_code: str = raw_element.get("countryCode") 57 | self.city: Optional[str] = raw_element.get("city") 58 | self.region_code: Optional[str] = raw_element.get("regionCode") 59 | self.latitude: Optional[float] = raw_element.get("latitude") 60 | self.longitude: Optional[float] = raw_element.get("longitude") 61 | 62 | @staticmethod 63 | def create(country_code: str, 64 | city: Optional[str] = None, 65 | region_code: Optional[str] = None, 66 | latitude: Optional[float] = None, 67 | longitude: Optional[float] = None): 68 | return IPAddressMappingLocation( 69 | raw_element={ 70 | "countryCode": country_code, 71 | "city": city, 72 | "regionCode": region_code, 73 | "latitude": latitude, 74 | "longitude": longitude, 75 | }, 76 | ) 77 | 78 | 79 | class IPAddressRange(DynatraceObject): 80 | def _create_from_raw_data(self, raw_element): 81 | self.address: str = raw_element.get("address") 82 | self.subnet_mask: Optional[int] = raw_element.get("subnetMask") 83 | self.address_to: Optional[str] = raw_element.get("addressTo") 84 | 85 | @staticmethod 86 | def create(address: str, subnet_mask: Optional[int] = None, address_to: Optional[str] = None) -> "IPAddressRange": 87 | return IPAddressRange(raw_element={ 88 | "address": address, 89 | "subnetMask": subnet_mask, 90 | "addressTo": address_to 91 | }) 92 | -------------------------------------------------------------------------------- /dynatrace/configuration_v1/oneagent_environment_wide_configuration.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | 18 | from requests import Response 19 | from typing import Dict, Any, Optional 20 | 21 | from dynatrace.http_client import HttpClient 22 | from dynatrace.dynatrace_object import DynatraceObject 23 | from dynatrace.configuration_v1.schemas import UpdateWindowsConfig, AutoUpdateSetting, TechMonitoringList 24 | from dynatrace.environment_v2.schemas import ConfigurationMetadata 25 | 26 | 27 | class OneAgentEnvironmentWideConfigService: 28 | ENDPOINT = "/api/config/v1/hosts/autoupdate" 29 | 30 | def __init__(self, http_client: HttpClient): 31 | self.__http_client = http_client 32 | 33 | def get(self) -> "EnvironmentAutoUpdateConfig": 34 | """Gets the environment-wide configuration of OneAgents auto-update. 35 | 36 | :returns EnvironmentAutoUpdateConfig: the auto-update configuration for this environment 37 | """ 38 | response = self.__http_client.make_request(path=self.ENDPOINT).json() 39 | return EnvironmentAutoUpdateConfig(raw_element=response, http_client=self.__http_client) 40 | 41 | def get_technologies(self) -> "TechMonitoringList": 42 | """Gets the global monitoring configuration of technologies. 43 | 44 | :returns TechMonitoringList: the technologies monitoring configuration for this environment 45 | """ 46 | response = self.__http_client.make_request(path="/api/config/v1/technologies").json() 47 | return TechMonitoringList(raw_element=response) 48 | 49 | def put(self, config: "EnvironmentAutoUpdateConfig") -> "Response": 50 | """Updates the environment-wide configuration of OneAgents auto-update 51 | 52 | OneAgents are updated several minutes after the change of configuration. 53 | The process can take more time depending on number of OneAgents in the update queue. 54 | 55 | :param config: the updated global auto-update configuration object 56 | 57 | :returns Response: HTTP Response to the Request 58 | """ 59 | return config.put() 60 | 61 | def is_valid(self, config: "EnvironmentAutoUpdateConfig") -> bool: 62 | """Validates the payload for the put function 63 | 64 | :param config: a global auto-update configuration object 65 | 66 | :returns bool: True if valid, false otherwise. 67 | """ 68 | try: 69 | self.__http_client.make_request(path=f"{self.ENDPOINT}/validator", method="POST", params=config.to_json()) 70 | except Exception as e: 71 | print(e.args) 72 | return False 73 | else: 74 | return True 75 | 76 | 77 | class EnvironmentAutoUpdateConfig(DynatraceObject): 78 | def _create_from_raw_data(self, raw_element: Dict[str, Any]): 79 | self.metadata: ConfigurationMetadata = ConfigurationMetadata(raw_element=raw_element.get("metadata")) 80 | self.setting: AutoUpdateSetting = AutoUpdateSetting(raw_element.get("setting")) 81 | self.version: Optional[str] = raw_element.get("version") 82 | self.update_windows: UpdateWindowsConfig = UpdateWindowsConfig(raw_element=raw_element.get("updateWindows")) 83 | 84 | def to_json(self) -> Dict[str, Any]: 85 | return { 86 | "setting": str(self.setting), 87 | "version": self.version, 88 | "updateWindows": self.update_windows.to_json(), 89 | } 90 | 91 | def put(self) -> "Response": 92 | return self._http_client.make_request(path=OneAgentEnvironmentWideConfigService.ENDPOINT, method="PUT", params=self.to_json()) 93 | -------------------------------------------------------------------------------- /dynatrace/configuration_v1/plugins.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | from requests import Response 18 | from dynatrace.environment_v2.monitored_entities import EntityShortRepresentation 19 | from dynatrace.configuration_v1.endpoint import EndpointShortRepresentation 20 | from dynatrace.http_client import HttpClient 21 | from dynatrace.pagination import PaginatedList 22 | from dynatrace.dynatrace_object import DynatraceObject 23 | 24 | 25 | class PluginService: 26 | def __init__(self, http_client: HttpClient): 27 | self.__http_client = http_client 28 | 29 | def list(self) -> PaginatedList["PluginShortRepresentation"]: 30 | """ 31 | List all uploaded plugins 32 | """ 33 | return PaginatedList(PluginShortRepresentation, self.__http_client, "/api/config/v1/plugins", list_item="values") 34 | 35 | def list_states(self, plugin_id) -> PaginatedList["PluginState"]: 36 | """ 37 | List the states of the specified plugin 38 | """ 39 | return PaginatedList(PluginState, self.__http_client, f"/api/config/v1/plugins/{plugin_id}/states", list_item="states") 40 | 41 | def delete(self, plugin_id) -> Response: 42 | """ 43 | Deletes the ZIP file of the specified plugin 44 | :param plugin_id: The ID of the plugin to be deleted 45 | """ 46 | return self.__http_client.make_request(f"/api/config/v1/plugins/{plugin_id}/binary", method="DELETE") 47 | 48 | 49 | class PluginState(DynatraceObject): 50 | def _create_from_raw_data(self, raw_element): 51 | self.plugin_id: str = raw_element.get("pluginId") 52 | self.version: str = raw_element.get("version") 53 | self.endpoint_id: str = raw_element.get("endpointId") 54 | self.state: str = raw_element.get("state") 55 | self.state_description: str = raw_element.get("stateDescription") 56 | self.timestamp: str = raw_element.get("timestamp") 57 | self.host_id: str = raw_element.get("hostId") 58 | self.process_id: str = raw_element.get("processId") 59 | 60 | 61 | class PluginShortRepresentation(EntityShortRepresentation): 62 | def delete(self) -> Response: 63 | """ 64 | Deletes the ZIP file of this plugin 65 | """ 66 | return self._http_client.make_request(f"/api/config/v1/plugins/{self.id}/binary", method="DELETE") 67 | 68 | @property 69 | def endpoints(self) -> PaginatedList[EndpointShortRepresentation]: 70 | return PaginatedList( 71 | EndpointShortRepresentation, 72 | self._http_client, 73 | f"/api/config/v1/plugins/{self.id}/endpoints", 74 | None, 75 | list_item="values", 76 | ) 77 | 78 | @property 79 | def states(self) -> PaginatedList[PluginState]: 80 | return PaginatedList(PluginState, self._http_client, f"/api/config/v1/plugins/{self.id}/states", None, list_item="states") 81 | -------------------------------------------------------------------------------- /dynatrace/configuration_v1/tile.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | from dynatrace.dynatrace_object import DynatraceObject 18 | 19 | 20 | class Tile(DynatraceObject): 21 | def _create_from_raw_data(self, raw_element): 22 | self.name = raw_element.get("name") 23 | self.tile_type = raw_element.get("tileType") # TODO - This branches, maybe Tile is a subclass 24 | self.configured = raw_element.get("configured") 25 | self.bounds = raw_element.get("bounds") # TODO - This is a TileBounds 26 | self.tile_filter = raw_element.get("tileFilter") # TODO - This is a TileFilter 27 | -------------------------------------------------------------------------------- /dynatrace/dynatrace_object.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | import pprint 18 | from typing import Any, Dict, Optional 19 | 20 | from requests import Response 21 | 22 | from dynatrace.http_client import HttpClient 23 | 24 | 25 | class DynatraceObject: 26 | def __init__(self, 27 | http_client: Optional[HttpClient] = None, 28 | headers: Optional[Dict[str, str]] = None, 29 | raw_element: Optional[Dict[str, Any]] = None): 30 | if raw_element is None: 31 | raw_element = {} 32 | self._http_client = http_client 33 | self._headers = headers 34 | self._raw_element = raw_element 35 | self._create_from_raw_data(raw_element) 36 | 37 | def _create_from_raw_data(self, raw_element: Dict[str, Any]): 38 | pass 39 | 40 | def __repr__(self): 41 | return f"{self.__class__.__name__}({pprint.pformat(self._raw_element, width=130)})" 42 | 43 | def _make_request(self, 44 | path: str, 45 | params: Optional[Dict] = None, 46 | headers: Optional[Dict] = None, 47 | method = "GET", 48 | data = None) -> Response: 49 | return self._http_client.make_request(path, params, headers, method, data) 50 | 51 | def json(self): 52 | return self._raw_element 53 | -------------------------------------------------------------------------------- /dynatrace/environment_v1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynatrace-oss/api-client-python/9c1467b36b8a11ff74daf9d6d2c9fde25c4fd970/dynatrace/environment_v1/__init__.py -------------------------------------------------------------------------------- /dynatrace/environment_v1/cluster_time.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | from datetime import datetime 18 | 19 | from dynatrace.http_client import HttpClient 20 | 21 | 22 | class ClusterTimeService: 23 | def __init__(self, http_client: HttpClient): 24 | self.__http_client = http_client 25 | 26 | def time(self) -> datetime: 27 | return datetime.utcfromtimestamp(float(self.__http_client.make_request("/api/v1/time").text) / 1000) 28 | -------------------------------------------------------------------------------- /dynatrace/environment_v1/timeseries.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | from enum import Enum 18 | from typing import Optional, List, Union 19 | 20 | from dynatrace.dynatrace_object import DynatraceObject 21 | from dynatrace.http_client import HttpClient 22 | 23 | 24 | class Unit(Enum): 25 | BIT = "Bit(bit)" 26 | BITPERHOUR = "BitPerHour(bit/h)" 27 | BITPERMINUTE = "BitPerMinute(bit/min)" 28 | BITPERSECOND = "BitPerSecond(bit/s)" 29 | BYTE = "Byte(B)" 30 | BYTEPERHOUR = "BytePerHour(B/h)" 31 | BYTEPERMINUTE = "BytePerMinute(B/min)" 32 | BYTEPERSECOND = "BytePerSecond(B/s)" 33 | CORES = "Cores" 34 | COUNT = "Count(count)" 35 | DAY = "Day(ds)" 36 | DECIBELMILLIWATT = "DecibelMilliWatt(dBm)" 37 | G = "G" 38 | GIBIBYTE = "GibiByte(GiB)" 39 | GIGABYTE = "GigaByte(GB)" 40 | HOUR = "Hour(hs)" 41 | KIBIBYTE = "KibiByte(KiB)" 42 | KIBIBYTEPERHOUR = "KibiBytePerHour(KiB/h)" 43 | KIBIBYTEPERMINUTE = "KibiBytePerMinute(KiB/min)" 44 | KIBIBYTEPERSECOND = "KibiBytePerSecond(KiB/s)" 45 | KILOBYTE = "KiloByte(kB)" 46 | KILOBYTEPERHOUR = "KiloBytePerHour(kB/h)" 47 | KILOBYTEPERMINUTE = "KiloBytePerMinute(kB/min)" 48 | KILOBYTEPERSECOND = "KiloBytePerSecond(kB/s)" 49 | M = "M" 50 | MEBIBYTE = "MebiByte(MiB)" 51 | MEBIBYTEPERHOUR = "MebiBytePerHour(MiB/h)" 52 | MEBIBYTEPERMINUTE = "MebiBytePerMinute(MiB/min)" 53 | MEBIBYTEPERSECOND = "MebiBytePerSecond(MiB/s)" 54 | MEGABYTE = "MegaByte(MB)" 55 | MEGABYTEPERHOUR = "MegaBytePerHour(MB/h)" 56 | MEGABYTEPERMINUTE = "MegaBytePerMinute(MB/min)" 57 | MEGABYTEPERSECOND = "MegaBytePerSecond(MB/s)" 58 | MICROSECOND = "MicroSecond(µs)" 59 | MILLISECOND = "MilliSecond(ms)" 60 | MILLISECONDPERMINUTE = "MilliSecondPerMinute(ms/min)" 61 | MINUTE = "Minute(mins)" 62 | MONTH = "Month(mos)" 63 | NOT_APPLICABLE = "N/A" 64 | NANOSECOND = "NanoSecond(ns)" 65 | NANOSECONDPERMINUTE = "NanoSecondPerMinute(ns/min)" 66 | PERHOUR = "PerHour(count/h)" 67 | PERMINUTE = "PerMinute(count/min)" 68 | PERSECOND = "PerSecond(count/s)" 69 | PERCENT = "Percent(%)" 70 | PIXEL = "Pixel(px)" 71 | PROMILLE = "Promille(‰)" 72 | RATIO = "Ratio" 73 | SECOND = "Second(s)" 74 | STATE = "State" 75 | UNSPECIFIED = "Unspecified" 76 | WEEK = "Week(ws)" 77 | YEAR = "Year(ys)" 78 | K = "k" 79 | M_CORES = "mCores" 80 | 81 | 82 | class TimeSerieService: 83 | def __init__(self, http_client: HttpClient): 84 | self.__http_client = http_client 85 | 86 | def create_timeseries( 87 | self, 88 | metric_id: str, 89 | display_name: Optional[str], 90 | unit: Optional[Union[Unit, str]] = None, 91 | dimensions: Optional[List[str]] = None, 92 | technologies: Optional[List[str]] = None, 93 | ) -> "TimeseriesRegistrationMessage": 94 | 95 | unit: Unit = Unit(unit) 96 | return TimeseriesRegistrationMessage( 97 | self.__http_client, 98 | metric_id=metric_id, 99 | display_name=display_name, 100 | unit=unit.value, 101 | dimensions=dimensions, 102 | technologies=technologies, 103 | ) 104 | 105 | 106 | class TimeseriesRegistrationMessage(DynatraceObject): 107 | def __init__( 108 | self, 109 | http_client, 110 | metric_id: str, 111 | display_name: Optional[str], 112 | unit: Optional[str] = None, 113 | dimensions: Optional[List[str]] = None, 114 | technologies: Optional[List[str]] = None, 115 | ): 116 | self.metric_id = metric_id 117 | 118 | raw_element = { 119 | "displayName": display_name, 120 | "unit": unit, 121 | "dimensions": dimensions, 122 | "types": technologies, 123 | } 124 | super().__init__(http_client, None, raw_element) 125 | 126 | def put(self): 127 | return self._http_client.make_request(f"/api/v1/timeseries/{self.metric_id}", params=self._raw_element, method="PUT") 128 | -------------------------------------------------------------------------------- /dynatrace/environment_v2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynatrace-oss/api-client-python/9c1467b36b8a11ff74daf9d6d2c9fde25c4fd970/dynatrace/environment_v2/__init__.py -------------------------------------------------------------------------------- /dynatrace/environment_v2/activegates_autoupdate_configuration.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | from typing import Dict, Any 18 | 19 | from requests import Response 20 | 21 | from dynatrace.dynatrace_object import DynatraceObject 22 | from dynatrace.environment_v2.schemas import ConfigurationMetadata 23 | from dynatrace.http_client import HttpClient 24 | 25 | 26 | class ActiveGateAutoUpdateConfigurationService: 27 | def __init__(self, http_client: HttpClient): 28 | self.__http_client = http_client 29 | 30 | def get_global(self) -> "ActiveGateGlobalAutoUpdateConfig": 31 | return ActiveGateGlobalAutoUpdateConfig(raw_element=self.__http_client.make_request("/api/v2/activeGates/autoUpdate").json()) 32 | 33 | def put_global(self, setting: str) -> Response: 34 | """ 35 | Puts the global auto-update configuration of environment ActiveGates 36 | 37 | :param setting: The state of auto-updates for all ActiveGates connected to the environment or Managed cluster. ENABLED or DISABLED 38 | """ 39 | return self.__http_client.make_request("/api/v2/activeGates/autoUpdate", method="PUT", params={"globalSetting": setting}) 40 | 41 | def validate_global(self, setting: str) -> Response: 42 | return self.__http_client.make_request("/api/v2/activeGates/autoUpdate/validator", method="POST", params={"globalSetting": setting}) 43 | 44 | def get(self, activegate_id: str) -> "ActiveGateAutoUpdateConfig": 45 | return ActiveGateAutoUpdateConfig(raw_element=self.__http_client.make_request(f"/api/v2/activeGates/{activegate_id}/autoUpdate").json()) 46 | 47 | def put(self, activegate_id: str, setting: str) -> Response: 48 | return self.__http_client.make_request(f"/api/v2/activeGates/{activegate_id}/autoUpdate", method="PUT", params={"setting": setting}) 49 | 50 | def validate(self, activegate_id: str, setting: str) -> Response: 51 | return self.__http_client.make_request(f"/api/v2/activeGates/{activegate_id}/autoUpdate/validator", method="POST", params={"setting": setting}) 52 | 53 | 54 | class ActiveGateGlobalAutoUpdateConfig(DynatraceObject): 55 | def _create_from_raw_data(self, raw_element): 56 | self.global_setting: str = raw_element.get("globalSetting") 57 | self.metadata: ConfigurationMetadata = ConfigurationMetadata(raw_element=raw_element.get("metadata")) 58 | 59 | 60 | class ActiveGateAutoUpdateConfig(DynatraceObject): 61 | def _create_from_raw_data(self, raw_element: Dict[str, Any]): 62 | self.setting: str = raw_element.get("setting") 63 | self.effective_setting: str = raw_element.get("effectiveSetting") 64 | -------------------------------------------------------------------------------- /dynatrace/environment_v2/audit_logs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | from datetime import datetime 18 | from enum import Enum 19 | from typing import Optional, Union, Dict, Any, List 20 | 21 | from dynatrace.dynatrace_object import DynatraceObject 22 | from dynatrace.http_client import HttpClient 23 | from dynatrace.pagination import PaginatedList 24 | from dynatrace.utils import timestamp_to_string 25 | 26 | 27 | class AuditLogsService: 28 | 29 | # TODO - Early adopter as of May 14th 2021, check back later for changes 30 | def __init__(self, http_client: HttpClient): 31 | self.__http_client = http_client 32 | 33 | def list( 34 | self, 35 | log_filter: Optional[str] = None, 36 | time_from: Optional[Union[datetime, str]] = None, 37 | time_to: Optional[Union[datetime, str]] = None, 38 | sort: Optional[str] = None, 39 | ) -> PaginatedList["AuditLogEntry"]: 40 | params = {"filter": log_filter, "from": timestamp_to_string(time_from), "to": timestamp_to_string(time_to), "sort": sort} 41 | return PaginatedList( 42 | target_class=AuditLogEntry, http_client=self.__http_client, target_url="/api/v2/auditlogs", target_params=params, list_item="auditLogs" 43 | ) 44 | 45 | def get(self, log_id: str) -> "AuditLogEntry": 46 | response = self.__http_client.make_request(f"/api/v2/auditlogs/{log_id}").json() 47 | return AuditLogEntry(raw_element=response) 48 | 49 | 50 | class EventType(Enum): 51 | CREATE = "CREATE" 52 | DELETE = "DELETE" 53 | GENERAL = "GENERAL" 54 | GET = "GET" 55 | LOGIN = "LOGIN" 56 | LOGOUT = "LOGOUT" 57 | PATCH = "PATCH" 58 | POST = "POST" 59 | PUT = "PUT" 60 | READ = "READ" 61 | REMOTE_CONFIGURATION_MANAGEMENT = "REMOTE_CONFIGURATION_MANAGEMENT" 62 | REVOKE = "REVOKE" 63 | TAG_ADD = "TAG_ADD" 64 | TAG_REMOVE = "TAG_REMOVE" 65 | TAG_UPDATE = "TAG_UPDATE" 66 | UPDATE = "UPDATE" 67 | 68 | 69 | class Category(Enum): 70 | ACTIVEGATE_TOKEN = "ACTIVEGATE_TOKEN" 71 | CONFIG = "CONFIG" 72 | DEBUG_UI = "DEBUG_UI" 73 | MANUAL_TAGGING_SERVICE = "MANUAL_TAGGING_SERVICE" 74 | REST = "REST" 75 | TOKEN = "TOKEN" 76 | WEB_UI = "WEB_UI" 77 | 78 | 79 | class UserType(Enum): 80 | PUBLIC_TOKEN_IDENTIFIER = "PUBLIC_TOKEN_IDENTIFIER" 81 | REQUEST_ID = "REQUEST_ID" 82 | SERVICE_NAME = "SERVICE_NAME" 83 | TOKEN_HASH = "TOKEN_HASH" 84 | USER_NAME = "USER_NAME" 85 | 86 | 87 | class AuditLogEntry(DynatraceObject): 88 | def _create_from_raw_data(self, raw_element: Dict[str, Any]): 89 | self.category: Category = Category(raw_element.get("category")) 90 | self.environment_id: str = raw_element.get("environmentId") 91 | self.event_type: EventType = EventType(raw_element.get("eventType")) 92 | self.log_id: str = raw_element.get("logId") 93 | self.success: bool = raw_element.get("success") 94 | self.timestamp: datetime = datetime.utcfromtimestamp(raw_element.get("timestamp") / 1000) 95 | self.user: str = raw_element.get("user") 96 | self.user_type: UserType = UserType(raw_element.get("userType")) 97 | 98 | self.entity_id: Optional[str] = raw_element.get("entityId") 99 | self.user_origin: Optional[str] = raw_element.get("userOrigin") 100 | self.message: Optional[str] = raw_element.get("message") 101 | self.patch: Optional[List[Dict[str, Any]]] = raw_element.get("patch") 102 | -------------------------------------------------------------------------------- /dynatrace/environment_v2/logs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | from enum import Enum 17 | from typing import Dict, Any, Union, List 18 | 19 | from requests import Response 20 | from datetime import datetime 21 | from typing import Optional, Union, Dict, Any, List 22 | 23 | from dynatrace.http_client import HttpClient 24 | from dynatrace.dynatrace_object import DynatraceObject 25 | from dynatrace.pagination import PaginatedList 26 | from dynatrace.utils import timestamp_to_string 27 | 28 | 29 | class LogService: 30 | # TODO - Add search and aggregate 31 | ENDPOINT = "/api/v2/logs" 32 | 33 | def __init__(self, http_client: HttpClient): 34 | self.__http_client = http_client 35 | 36 | def export( 37 | self, 38 | query: Optional[str] = None, 39 | time_from: Optional[Union[datetime, str]] = None, 40 | time_to: Optional[Union[datetime, str]] = None, 41 | sort: Optional[str] = None, 42 | page_size: Optional[int] = None, 43 | ) -> PaginatedList["LogRecord"]: 44 | """ 45 | Gets the log records matching the provided criteria. Retrieves all records using pagination. 46 | :param query: The log search query 47 | :param page_size: Number of results per page 48 | :param time_from: Start of the requested timeframe 49 | :param time_to: End of the requested timefram 50 | :param sort: Defines the ordering of log records 51 | :return A list of log records 52 | """ 53 | params = { 54 | "query": query, 55 | "pageSize": page_size, 56 | "from": timestamp_to_string(time_from), 57 | "to": timestamp_to_string(time_to), 58 | "sort": sort, 59 | } 60 | return PaginatedList(LogRecord, self.__http_client, "/api/v2/logs/export", params, list_item="results") 61 | 62 | def ingest(self, payload: Union[Dict[str, Any], List[Dict[str, Any]]]) -> Response: 63 | """ 64 | Ingests logs into the Dynatrace log store. 65 | :param payload: A list of log entries or a single log entry, which are JSON objects (dictionaries) 66 | :return: The HTTP Response 67 | """ 68 | headers = {"Content-Type": "application/json; charset=utf-8"} 69 | return self.__http_client.make_request(f"{self.ENDPOINT}/ingest", params=payload, method="POST", headers=headers) 70 | 71 | class LogRecord(DynatraceObject): 72 | def _create_from_raw_data(self, raw_element: Dict[str, Any]): 73 | self.additional_columns: dict = raw_element.get("additionalColumns") 74 | self.event_type: EventType = EventType(raw_element.get("eventType")) 75 | self.timestamp: datetime = datetime.utcfromtimestamp(raw_element.get("timestamp") / 1000) 76 | self.content: str = raw_element.get("content") 77 | self.status: LogRecordStatus = LogRecordStatus(raw_element.get("status")) 78 | 79 | class EventType(Enum): 80 | K8S = "K8S" 81 | LOG = "LOG" 82 | SFM = "SFM" 83 | 84 | class LogRecordStatus(Enum): 85 | ERROR = "ERROR" 86 | INFO = "INFO" 87 | NONE = "NONE" 88 | NOT_APPLICABLE = "NOT_APPLICABLE" 89 | WARN = "WARN" -------------------------------------------------------------------------------- /dynatrace/environment_v2/networkzones.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | from datetime import datetime 18 | from dynatrace.dynatrace_object import DynatraceObject 19 | from typing import List, Optional, Union, Dict, Any 20 | 21 | from dynatrace.http_client import HttpClient 22 | from dynatrace.pagination import PaginatedList 23 | 24 | 25 | class NetworkZoneService: 26 | ENDPOINT = "/api/v2/networkZones" 27 | ENDPOINT_GLOBALSETTINGS = "/api/v2/networkZoneSettings" 28 | 29 | def __init__(self, http_client: HttpClient): 30 | self.__http_client = http_client 31 | 32 | def list(self) -> PaginatedList["NetworkZone"]: 33 | """Lists all network zones. No params 34 | 35 | :return: a list of Network Zones with details 36 | """ 37 | return PaginatedList(NetworkZone, self.__http_client, target_url=self.ENDPOINT, list_item="networkZones") 38 | 39 | def get(self, networkzone_id: str): 40 | """Gets parameters of specified network zone 41 | 42 | :param networkzone_id: the ID of the network zone 43 | :return: a Network Zone + details 44 | """ 45 | response = self.__http_client.make_request(f"{self.ENDPOINT}/{networkzone_id}").json() 46 | return NetworkZone(raw_element=response) 47 | 48 | def update(self, networkzone_id: str, alternate_zones: Optional[List[str]] = None, description: Optional[str] = None): 49 | """Updates an existing network zone or creates a new one 50 | 51 | :param networkzone_id: the ID of the network zone, if none exists, will create 52 | :param alternate_zones: optional list of text body of alternative network zones 53 | :param description: optional text body for short description of network zone 54 | :return: HTTP response 55 | """ 56 | params = {"alternativeZones": alternate_zones, "description": description} 57 | return self.__http_client.make_request(path=f"{self.ENDPOINT}/{networkzone_id}", params=params, method="PUT") 58 | 59 | def delete(self, networkzone_id: str): 60 | """Deletes the specified network zone 61 | 62 | :param networkzone_id: the ID of the network zone 63 | :return: HTTP response 64 | """ 65 | return self.__http_client.make_request(path=f"{self.ENDPOINT}/{networkzone_id}", method="DELETE") 66 | 67 | def getGlobalConfig(self): 68 | """Gets the global configuration of network zones. No params 69 | :return: Network Zone Global Settings object 70 | """ 71 | response = self.__http_client.make_request(path=self.ENDPOINT_GLOBALSETTINGS).json() 72 | return NetworkZoneSettings(raw_element=response) 73 | 74 | def updateGlobalConfig(self, configuration: bool): 75 | """Updates the global configuration of network zones. 76 | 77 | :param configuration: boolean setting to enable/disable NZs 78 | :return: HTTP response 79 | """ 80 | params = {"networkZonesEnabled": configuration} 81 | return self.__http_client.make_request(path=self.ENDPOINT_GLOBALSETTINGS, method="PUT", params=params) 82 | 83 | 84 | class NetworkZone(DynatraceObject): 85 | def _create_from_raw_data(self, raw_element: Dict[str, Any]): 86 | self.id: str = raw_element.get("id") 87 | self.description: str = raw_element.get("description") 88 | self.alternative_zones: List[str] = raw_element.get("alternativeZones") 89 | self.num_oneagents_using: int = raw_element.get("numOfOneAgentsUsing") 90 | self.num_oneagents_configured: int = raw_element.get("numOfConfiguredOneAgents") 91 | self.num_oneagents_from_other_zones: int = raw_element.get("numOfOneAgentsFromOtherZones") 92 | self.num_configured_activegates: int = raw_element.get("numOfConfiguredActiveGates") 93 | 94 | 95 | class NetworkZoneSettings(DynatraceObject): 96 | def _create_from_raw_data(self, raw_element: Dict[str, bool]): 97 | self.network_zones_enabled: bool = raw_element.get("networkZonesEnabled") 98 | -------------------------------------------------------------------------------- /dynatrace/environment_v2/schemas.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | from enum import Enum 18 | from typing import List, Dict, Any, Optional 19 | from dynatrace.dynatrace_object import DynatraceObject 20 | 21 | # Schemas that don't belong to a specific api tag 22 | 23 | 24 | class ConfigurationMetadata(DynatraceObject): 25 | def _create_from_raw_data(self, raw_element): 26 | self.cluster_version: str = raw_element.get("clusterVersion") 27 | self.configuration_versions: List[int] = raw_element.get("configurationVersions") 28 | self.current_configuration_versions: List[str] = raw_element.get("currentConfigurationVersions") 29 | 30 | 31 | class VersionCompareType(Enum): 32 | EQUAL = "EQUAL" 33 | GREATER = "GREATER" 34 | GREATER_EQUAL = "GREATER_EQUAL" 35 | LOWER = "LOWER" 36 | LOWER_EQUAL = "LOWER_EQUAL" 37 | 38 | def __repr__(self) -> str: 39 | return self.value 40 | 41 | def __str__(self) -> str: 42 | return self.value 43 | 44 | 45 | class ManagementZone(DynatraceObject): 46 | def _create_from_raw_data(self, raw_element: Dict[str, Any]): 47 | self.name: str = raw_element.get("name", "") 48 | self.id: str = raw_element["id"] 49 | 50 | def to_json(self) -> Dict[str, Any]: 51 | return {"name": self.name, "id": self.id} 52 | 53 | -------------------------------------------------------------------------------- /dynatrace/environment_v2/tokens_tenant.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | from typing import Dict, Any, Optional 18 | from dynatrace.dynatrace_object import DynatraceObject 19 | from dynatrace.http_client import HttpClient 20 | 21 | 22 | class TenantTokenService: 23 | def __init__(self, http_client: HttpClient): 24 | self.__http_client = http_client 25 | 26 | def cancel_rotation(self) -> "TenantTokenConfig": 27 | return TenantTokenConfig(raw_element=self.__http_client.make_request("/api/v2/tenantTokenRotation/cancel", method="POST").json()) 28 | 29 | def start_rotation(self) -> "TenantTokenConfig": 30 | return TenantTokenConfig(raw_element=self.__http_client.make_request("/api/v2/tenantTokenRotation/start", method="POST").json()) 31 | 32 | def finish_rotation(self) -> "TenantTokenConfig": 33 | return TenantTokenConfig(raw_element=self.__http_client.make_request("/api/v2/tenantTokenRotation/finish", method="POST").json()) 34 | 35 | 36 | class TenantTokenConfig(DynatraceObject): 37 | def _create_from_raw_data(self, raw_element: Dict[str, Any]): 38 | self.active: Optional[TenantToken] = TenantToken(raw_element=raw_element.get("active")) 39 | self.old: Optional[TenantToken] = TenantToken(raw_element=raw_element.get("old")) 40 | 41 | 42 | class TenantToken(DynatraceObject): 43 | def _create_from_raw_data(self, raw_element: Dict[str, Any]): 44 | self.value: str = raw_element.get("value") 45 | -------------------------------------------------------------------------------- /dynatrace/pagination.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | from typing import Generic, TypeVar, Iterator, TYPE_CHECKING 18 | 19 | from dynatrace.dynatrace_object import DynatraceObject 20 | from dynatrace.http_client import HttpClient 21 | 22 | T = TypeVar("T", bound=DynatraceObject) 23 | 24 | 25 | class PaginatedList(Generic[T]): 26 | def __init__(self, target_class, http_client, target_url, target_params=None, headers=None, list_item="result"): 27 | self.__target_class = target_class 28 | self.__http_client: HttpClient = http_client 29 | self.__target_url = target_url 30 | self.__target_params = target_params 31 | self.__headers = headers 32 | self.__list_item = list_item 33 | self._has_next_page = True 34 | self.__total_count = None 35 | self.__page_size = None 36 | 37 | self.__elements = self._get_next_page() 38 | 39 | def __getitem__(self, index): 40 | pass 41 | 42 | def __iter__(self) -> Iterator[T]: 43 | for element in self.__elements: 44 | yield element 45 | 46 | while self._has_next_page: 47 | new_elements = self._get_next_page() 48 | for element in new_elements: 49 | yield element 50 | 51 | def __len__(self): 52 | return self.__total_count or len(self.__elements) 53 | 54 | def _get_next_page(self): 55 | response = self.__http_client.make_request(self.__target_url, params=self.__target_params, headers=self.__headers) 56 | json_response = response.json() 57 | data = [] 58 | if json_response.get("nextPageKey", None): 59 | self._has_next_page = True 60 | self.__target_params = {"nextPageKey": json_response["nextPageKey"]} 61 | else: 62 | self._has_next_page = False 63 | 64 | if self.__list_item in json_response: 65 | elements = json_response[self.__list_item] 66 | self.__total_count = json_response.get("totalCount") or len(elements) 67 | 68 | data = [self.__target_class(self.__http_client, response.headers, element) for element in elements] 69 | return data 70 | 71 | 72 | class HeaderPaginatedList(Generic[T]): 73 | def __init__(self, target_class, http_client, target_url, target_params=None, headers=None): 74 | self.__elements = list() 75 | self.__target_class = target_class 76 | self.__http_client: HttpClient = http_client 77 | self.__target_url = target_url 78 | self.__target_params = target_params 79 | self.__headers = headers 80 | self._has_next_page = True 81 | self.__total_count = None 82 | self.__page_size = None 83 | 84 | def __getitem__(self, index): 85 | pass 86 | 87 | def __iter__(self) -> Iterator[T]: 88 | for element in self.__elements: 89 | yield element 90 | 91 | while self._has_next_page: 92 | new_elements = self._get_next_page() 93 | for element in new_elements: 94 | yield element 95 | 96 | def __len__(self): 97 | return self.__total_count or len(self.__elements) 98 | 99 | def _get_next_page(self): 100 | response = self.__http_client.make_request(self.__target_url, params=self.__target_params, headers=self.__headers) 101 | json_response = response.json() 102 | headers = response.headers 103 | if "next-page-key" in headers: 104 | self._has_next_page = True 105 | self.__target_params = {"nextPageKey": headers["next-page-key"]} 106 | else: 107 | self._has_next_page = False 108 | 109 | elements = json_response 110 | self.__total_count = headers.get("total-count") or len(elements) 111 | data = [self.__target_class(self.__http_client, response.headers, element) for element in elements] 112 | return data 113 | -------------------------------------------------------------------------------- /dynatrace/utils.py: -------------------------------------------------------------------------------- 1 | """ 2 | Copyright 2021 Dynatrace LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | """ 16 | 17 | import warnings 18 | import functools 19 | from datetime import datetime, timezone 20 | from typing import Union, Optional 21 | import unicodedata 22 | import re 23 | 24 | 25 | ISO_8601 = "%Y-%m-%dT%H:%M:%S.%fZ" 26 | ISO_8601_NO_MS = "%Y-%m-%dT%H:%M:%SZ" 27 | 28 | 29 | def slugify(value): 30 | value = str(value) 31 | value = unicodedata.normalize("NFKC", value) 32 | value = re.sub(r"[:.-/\s]+", "_", value) 33 | value = re.sub(r"[^\w\s-]", "", value) 34 | return value 35 | 36 | 37 | def deprecated(reason=""): 38 | def decorator(func): 39 | @functools.wraps(func) 40 | def new_func(*args, **kwargs): 41 | warnings.warn(f"'{func.__name__}' is deprecated. {reason}", category=DeprecationWarning, stacklevel=2) 42 | return func(*args, **kwargs) 43 | 44 | return new_func 45 | 46 | return decorator 47 | 48 | 49 | def timestamp_to_string(timestamp: Optional[Union[datetime, str]]) -> Optional[str]: 50 | if not isinstance(timestamp, datetime): 51 | return timestamp 52 | return timestamp.isoformat(timespec="milliseconds") 53 | 54 | 55 | def iso8601_to_datetime(timestamp: Optional[str]) -> Optional[datetime]: 56 | if isinstance(timestamp, str): 57 | try: 58 | return datetime.strptime(timestamp, ISO_8601) 59 | except ValueError: 60 | # DT API currently omitts milliseconds in response if they are 000 61 | return datetime.strptime(timestamp, ISO_8601_NO_MS) 62 | return timestamp 63 | 64 | 65 | def int64_to_datetime(timestamp: Optional[int]) -> Optional[datetime]: 66 | if timestamp is None or not timestamp: 67 | return None 68 | return datetime.fromtimestamp(timestamp / 1000, timezone.utc) 69 | 70 | 71 | def datetime_to_int64(timestamp: Optional[datetime]) -> Optional[int]: 72 | if not isinstance(timestamp, datetime): 73 | return timestamp 74 | return int(timestamp.replace(tzinfo=timezone.utc).timestamp() * 1000) 75 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "dt" 3 | version = "1.1.73" 4 | description = "Dynatrace API Python client" 5 | readme = "README.md" 6 | authors = ["David Lopes "] 7 | maintainers = [ 8 | "David Lopes ", 9 | "James Kitson ", 10 | "Vagiz Duseev " 11 | ] 12 | homepage = "https://github.com/dynatrace-oss/api-client-python" 13 | repository = "https://github.com/dynatrace-oss/api-client-python" 14 | documentation = "https://github.com/dynatrace-oss/api-client-python" 15 | packages = [ 16 | { include = "dynatrace*" } 17 | ] 18 | classifiers = [ 19 | "Development Status :: 5 - Production/Stable", 20 | "Intended Audience :: Developers", 21 | "License :: OSI Approved", 22 | "License :: OSI Approved :: Apache Software License", 23 | "Programming Language :: Python", 24 | "Programming Language :: Python :: 3", 25 | "Programming Language :: Python :: 3.6", 26 | "Programming Language :: Python :: 3.7", 27 | "Programming Language :: Python :: 3.8", 28 | "Programming Language :: Python :: 3.9", 29 | "Programming Language :: Python :: 3.10", 30 | "Programming Language :: Python :: 3.11", 31 | "Programming Language :: Python :: 3.12", 32 | "Programming Language :: Python :: 3.13", 33 | "Programming Language :: Python :: Implementation :: CPython", 34 | "Operating System :: POSIX :: Linux", 35 | "Operating System :: Microsoft :: Windows", 36 | "Operating System :: MacOS", 37 | "Topic :: Software Development", 38 | ] 39 | 40 | [tool.poetry.dependencies] 41 | python = ">=3.6" 42 | requests = ">=2.22" 43 | 44 | [tool.poetry.group.dev.dependencies] 45 | pytest = "*" 46 | mock = "*" 47 | tox = "*" 48 | wrapt = "*" 49 | 50 | [build-system] 51 | requires = ["poetry-core"] 52 | build-backend = "poetry.core.masonry.api" 53 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynatrace-oss/api-client-python/9c1467b36b8a11ff74daf9d6d2c9fde25c4fd970/test/__init__.py -------------------------------------------------------------------------------- /test/configuration_v1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynatrace-oss/api-client-python/9c1467b36b8a11ff74daf9d6d2c9fde25c4fd970/test/configuration_v1/__init__.py -------------------------------------------------------------------------------- /test/configuration_v1/test_anomaly_detection_metric_events.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | from dynatrace.configuration_v1.metric_events import ( 3 | AggregationType, 4 | DisabledReason, 5 | MetricEventAlertingScopeFilterType, 6 | MetricEventAlertingScope, 7 | MetricEventAutoAdaptiveBaselineMonitoringStrategy, 8 | MetricEventDimension, 9 | MetricEventDimensionsFilterType, 10 | MetricEventMonitoringStrategyType, 11 | MetricEventShortRepresentation, 12 | MetricEventStaticThresholdMonitoringStrategy, 13 | Severity, 14 | WarningReason, 15 | Unit, 16 | ) 17 | from dynatrace.pagination import PaginatedList 18 | 19 | from typing import List 20 | 21 | STATIC_ID = "ruxit.python.rabbitmq:node_status:node_failed" 22 | STATIC_NAME = "RabbitMQ Node failed" 23 | BASELINE_ID = "d3baaaed-3441-4931-bf24-25c4e12e137f" 24 | BASELINE_NAME = "Mint alert for static" 25 | 26 | 27 | def test_list(dt: Dynatrace): 28 | metric_events = dt.anomaly_detection_metric_events.list() 29 | assert isinstance(metric_events, PaginatedList) 30 | 31 | list_metric_events = list(metric_events) 32 | assert len(list_metric_events) == 193 33 | 34 | first = list_metric_events[0] 35 | assert isinstance(first, MetricEventShortRepresentation) 36 | 37 | assert first.id == STATIC_ID 38 | assert first.name == STATIC_NAME 39 | 40 | 41 | def test_get_full_configuration(dt: Dynatrace): 42 | metric_events = dt.anomaly_detection_metric_events.list() 43 | list_metric_events = list(metric_events) 44 | 45 | for metric_event in list_metric_events: 46 | if metric_event.id == STATIC_ID: 47 | # static 48 | full = metric_event.get_full_metric_event() 49 | 50 | # type checks 51 | assert isinstance(full.name, str) 52 | assert isinstance(full.metric_id, str) 53 | assert isinstance(full.severity, Severity) 54 | assert isinstance(full.enabled, bool) 55 | assert isinstance(full.disabled_reason, DisabledReason) 56 | assert isinstance(full.aggregation_type, AggregationType) 57 | assert isinstance(full.warning_reason, WarningReason) 58 | assert isinstance(full.alerting_scope, List) 59 | assert isinstance(full.monitoring_strategy, MetricEventStaticThresholdMonitoringStrategy) 60 | assert isinstance(full.metric_dimensions, List) 61 | assert isinstance(full.primary_dimension_key, type(None)) 62 | 63 | # value checks 64 | assert full.name == STATIC_NAME 65 | assert full.id == STATIC_ID 66 | assert full.aggregation_type == AggregationType.VALUE 67 | assert full.severity == Severity.AVAILABILITY 68 | assert full.enabled == True 69 | assert full.disabled_reason == DisabledReason.NONE 70 | assert full.monitoring_strategy.type == MetricEventMonitoringStrategyType.STATIC_THRESHOLD 71 | assert full.monitoring_strategy.unit == Unit.COUNT 72 | assert full.monitoring_strategy.violating_samples == 3 73 | assert full.metric_dimensions[0].filter_type == MetricEventDimensionsFilterType.STRING 74 | 75 | elif metric_event.id == BASELINE_ID: 76 | # static 77 | full = metric_event.get_full_metric_event() 78 | 79 | # type checks 80 | assert isinstance(full.monitoring_strategy, MetricEventAutoAdaptiveBaselineMonitoringStrategy) 81 | 82 | # value checks 83 | assert full.monitoring_strategy.type == MetricEventMonitoringStrategyType.AUTO_ADAPTIVE_BASELINE 84 | 85 | break 86 | 87 | else: 88 | continue 89 | -------------------------------------------------------------------------------- /test/configuration_v1/test_auto_tags.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from dynatrace import Dynatrace 3 | from dynatrace.configuration_v1.auto_tags import ( 4 | AutoTag, 5 | AutoTagRule, 6 | AutoTagShortRepresentation, 7 | ComparisonBasic, 8 | ComparisonBasicType, 9 | ConditionKey, 10 | ConditionKeyAttribute, 11 | EntityRuleEngineCondition, 12 | ) 13 | from dynatrace.environment_v2.schemas import ConfigurationMetadata 14 | from dynatrace.pagination import PaginatedList 15 | from dynatrace.configuration_v1.auto_tags import ConditionKeyAttribute, RuleType 16 | 17 | 18 | def test_list(dt: Dynatrace): 19 | tags = dt.auto_tags.list() 20 | assert isinstance(tags, PaginatedList) 21 | 22 | for tag in tags: 23 | assert isinstance(tag, AutoTagShortRepresentation) 24 | assert tag.id == "403e033b-7324-4bfe-bef1-b3f367de42f2" 25 | assert tag.name == "frontend" 26 | break 27 | 28 | 29 | def test_get(dt: Dynatrace): 30 | tags = dt.auto_tags.list() 31 | for tag in tags: 32 | full_tag = tag.get_full_configuration() 33 | assert isinstance(full_tag, AutoTag) 34 | assert isinstance(full_tag.metadata, ConfigurationMetadata) 35 | assert full_tag.metadata.cluster_version == "1.214.112.20210409-064503" 36 | assert full_tag.id == "403e033b-7324-4bfe-bef1-b3f367de42f2" 37 | assert full_tag.name == "frontend" 38 | assert isinstance(full_tag.rules, List) 39 | for rule in full_tag.rules: 40 | assert isinstance(rule, AutoTagRule) 41 | assert rule.type == RuleType.SERVICE 42 | assert rule.enabled == True 43 | assert rule.value_format == "" 44 | assert rule.propagation_types == [] 45 | assert isinstance(rule.conditions, List) 46 | for condition in rule.conditions: 47 | assert isinstance(condition, EntityRuleEngineCondition) 48 | assert isinstance(condition.key, ConditionKey) 49 | assert condition.key.attribute == ConditionKeyAttribute.PROCESS_GROUP_NAME 50 | assert isinstance(condition.comparison_info, ComparisonBasic) 51 | assert condition.comparison_info.type == ComparisonBasicType.STRING 52 | assert condition.comparison_info.operator == "CONTAINS" 53 | assert condition.comparison_info.value == "frontend" 54 | assert condition.comparison_info.negate == False 55 | assert condition.comparison_info.case_sensitive == False 56 | break 57 | break 58 | break 59 | -------------------------------------------------------------------------------- /test/configuration_v1/test_extensions.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from dynatrace import Dynatrace 4 | from dynatrace.configuration_v1.extensions import ( 5 | ExtensionDto, 6 | ExtensionType, 7 | Extension, 8 | ExtensionProperty, 9 | GlobalExtensionConfiguration, 10 | ExtensionState, 11 | ExtensionStateEnum, 12 | ExtensionConfigurationDto, 13 | ) 14 | from dynatrace.environment_v2.monitored_entities import EntityShortRepresentation 15 | from dynatrace.pagination import PaginatedList 16 | 17 | 18 | def test_list(dt: Dynatrace): 19 | extensions = dt.extensions.list() 20 | assert isinstance(extensions, PaginatedList) 21 | 22 | extensions_list = list(extensions) 23 | assert len(extensions_list) == 35 24 | first = extensions_list[0] 25 | 26 | assert isinstance(first, ExtensionDto) 27 | assert first.id == "custom.remote.python.certificates" 28 | assert first.name == "Certificates Plugin" 29 | assert first.type == ExtensionType.ACTIVEGATE 30 | 31 | 32 | def test_get(dt: Dynatrace): 33 | extension = dt.extensions.get("custom.python.citrixAgent") 34 | assert isinstance(extension, Extension) 35 | assert extension.id == "custom.python.citrixAgent" 36 | assert extension.name == "Citrix Virtual Apps & Virtual Desktops" 37 | assert extension.version == "2.034" 38 | assert extension.type == ExtensionType.ONEAGENT 39 | assert extension.metric_group == "tech.Citrix" 40 | assert isinstance(extension.properties, list) 41 | 42 | first_property = extension.properties[0] 43 | assert isinstance(first_property, ExtensionProperty) 44 | assert first_property.key == "openkit_verify_certificates" 45 | assert first_property.type == "BOOLEAN" 46 | 47 | 48 | def test_get_global_configuration(dt: Dynatrace): 49 | global_config = dt.extensions.get_global_configuration("custom.python.citrixAgent") 50 | assert isinstance(global_config, GlobalExtensionConfiguration) 51 | assert global_config.extension_id == "custom.python.citrixAgent" 52 | assert global_config.enabled 53 | assert not global_config.infraOnlyEnabled 54 | assert global_config.properties["log_level"] == "INFO" 55 | 56 | 57 | def test_get_state(dt: Dynatrace): 58 | states = dt.extensions.list_states("custom.remote.python.salesforce_eventstream") 59 | assert isinstance(states, PaginatedList) 60 | 61 | list_states = list(states) 62 | assert isinstance(list_states, list) 63 | 64 | first = list_states[0] 65 | assert isinstance(first, ExtensionState) 66 | assert first.extension_id == "custom.remote.python.salesforce_eventstream" 67 | assert first.version == "" 68 | assert first.endpoint_id == "5649014104314746667" 69 | assert first.state == ExtensionStateEnum.ERROR_CONFIG 70 | assert first.state_description == "Extension doesn't exist on given host" 71 | assert first.timestamp == datetime.utcfromtimestamp(1620943873929 / 1000) 72 | assert first.host_id is None 73 | assert first.process_id is None 74 | 75 | 76 | def test_get_instance_configuration(dt: Dynatrace): 77 | config = dt.extensions.get_instance_configuration("custom.remote.python.salesforce_eventstream", "5649014104314746667") 78 | assert isinstance(config, ExtensionConfigurationDto) 79 | 80 | # TODO - This is a bug on Dynatrace, watch for the fix, this is the configuration ID 81 | assert config.extension_id == "5649014104314746667" 82 | 83 | assert config.enabled 84 | assert config.active_gate.id == "-7885258652650793909" 85 | assert config.active_gate.name == "arch-david" 86 | assert config.endpoint_id == "5649014104314746667" 87 | assert config.endpoint_name == "curious-hawk" 88 | assert config.properties["openkit_application_id"] == "87eee414-9338-446b-988b-bbdbf495c4f4" 89 | 90 | 91 | def test_list_activegate_extension_modules(dt: Dynatrace): 92 | modules = dt.extensions.list_activegate_extension_modules() 93 | assert isinstance(modules, PaginatedList) 94 | 95 | list_modules = list(modules) 96 | assert isinstance(list_modules, list) 97 | 98 | first = list_modules[0] 99 | assert isinstance(first, EntityShortRepresentation) 100 | assert first.id == "-7885258652650793909" 101 | assert first.name == "arch-david" 102 | -------------------------------------------------------------------------------- /test/configuration_v1/test_maintenance_windows.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | from dynatrace.configuration_v1.maintenance_windows import ( 3 | MaintenanceWindowService, 4 | TagCombination, 5 | MonitoredEntityFilter, 6 | Scope, 7 | Recurrence, 8 | Schedule, 9 | MaintenanceWindow, 10 | MaintenanceWindowStub, 11 | ) 12 | from dynatrace.environment_v2.custom_tags import METag, TagContext 13 | from dynatrace.pagination import PaginatedList 14 | from dynatrace.environment_v2.monitored_entities import EntityShortRepresentation 15 | 16 | ID = "b6376a12-0b82-4069-9a41-0e55ef9a1f44" 17 | NAME = "Example Window" 18 | 19 | 20 | def test_list(dt: Dynatrace): 21 | mw = dt.maintenance_windows.list() 22 | assert isinstance(mw, PaginatedList) 23 | 24 | list_mw = list(mw) 25 | assert len(list_mw) == 3 26 | 27 | first = list_mw[0] 28 | assert isinstance(first, MaintenanceWindowStub) 29 | 30 | assert first.id == ID 31 | assert first.name == NAME 32 | 33 | 34 | def test_get(dt: Dynatrace): 35 | mw = dt.maintenance_windows.get(mw_id=ID) 36 | 37 | # type checks 38 | assert isinstance(mw, MaintenanceWindow) 39 | assert isinstance(mw.id, str) 40 | assert isinstance(mw.name, str) 41 | assert isinstance(mw.description, str) 42 | assert isinstance(mw.type, str) 43 | assert isinstance(mw.suppression, str) 44 | assert isinstance(mw.suppress_synthetic_monitors_execution, bool) 45 | assert isinstance(mw.scope, Scope) 46 | assert isinstance(mw.schedule, Schedule) 47 | 48 | assert all(isinstance(rule, MonitoredEntityFilter) for rule in mw.scope.matches) 49 | for rule in mw.scope.matches: 50 | assert isinstance(rule.type, str) 51 | assert isinstance(rule.mz_id, str) 52 | for t in rule.tags: 53 | assert isinstance(t, METag) 54 | assert isinstance(rule.tag_combination, TagCombination) 55 | 56 | # value checks 57 | assert mw.id == ID 58 | assert mw.name == NAME 59 | assert mw.description == "An example Maintenance window" 60 | assert mw.type == "UNPLANNED" 61 | assert mw.suppression == "DETECT_PROBLEMS_AND_ALERT" 62 | assert mw.suppress_synthetic_monitors_execution == True 63 | assert mw.scope.entities[0] == "HOST-0000000000123456" 64 | assert mw.scope.matches[0].type == "HOST" 65 | assert mw.scope.matches[0].mz_id == "-5283929364044076484" 66 | assert mw.scope.matches[0].tags[0].context == TagContext.AWS 67 | assert mw.scope.matches[0].tags[0].key == "testkey" 68 | assert mw.scope.matches[0].tags[0].value == "testvalue" 69 | assert mw.scope.matches[0].tag_combination == TagCombination.AND 70 | assert mw.schedule.recurrence_type == "ONCE" 71 | assert isinstance(mw.schedule.recurrence, Recurrence) 72 | assert mw.schedule.start_time == "2018-08-02 00:00" 73 | assert mw.schedule.end_time == "2021-02-27 00:00" 74 | assert mw.schedule.zone_id == "Europe/Vienna" 75 | 76 | 77 | def test_post(dt: Dynatrace): 78 | response = dt.maintenance_windows.post( 79 | MaintenanceWindow( 80 | raw_element={ 81 | "id": ID, 82 | "name": NAME, 83 | "description": "test_desc", 84 | "type": "PLANNED", 85 | "suppression": None, 86 | "suppressSyntheticMonitorsExecution": False, 87 | "schedule": { 88 | "end": "2031-02-27 00:00", 89 | "start": "2028-08-02 00:00", 90 | "zoneId": "Europe/Vienna", 91 | "recurrence": {"dayOfWeek": None, "dayOfMonth": None, "startTime": None, "durationMinutes": None}, 92 | "recurrenceType": "ONCE", 93 | }, 94 | "scope": { 95 | "entities": ["HOST-0000000000123456"], 96 | "matches": [ 97 | { 98 | "type": "HOST", 99 | "mzId": "-5283929364044076484", 100 | "tags": [{"context": "AWS", "key": "testkey", "value": "testvalue"}], 101 | "tagCombination": "AND", 102 | } 103 | ], 104 | }, 105 | } 106 | ) 107 | ) 108 | 109 | # type checks 110 | assert isinstance(response, EntityShortRepresentation) 111 | # value checks 112 | assert response.id == ID 113 | assert response.name == NAME 114 | -------------------------------------------------------------------------------- /test/configuration_v1/test_management_zones.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | from dynatrace import Dynatrace 3 | from dynatrace.configuration_v1.management_zones import ( 4 | ManagementZone, 5 | ManagementZoneRule, 6 | ManagementZoneShortRepresentation, 7 | ComparisonBasic, 8 | ComparisonBasicType, 9 | ConditionKey, 10 | ConditionKeyAttribute, 11 | EntityRuleEngineCondition, 12 | PropagationType, 13 | ) 14 | from dynatrace.environment_v2.schemas import ConfigurationMetadata 15 | from dynatrace.pagination import PaginatedList 16 | from dynatrace.configuration_v1.management_zones import ConditionKeyAttribute, RuleType 17 | 18 | 19 | def test_list(dt: Dynatrace): 20 | management_zones = dt.management_zones.list() 21 | assert isinstance(management_zones, PaginatedList) 22 | 23 | for management_zone in management_zones: 24 | assert isinstance(management_zone, ManagementZoneShortRepresentation) 25 | assert management_zone.id == "6507829326603756920" 26 | assert management_zone.name == "Frontend Services" 27 | break 28 | 29 | 30 | def test_get(dt: Dynatrace): 31 | management_zones = dt.management_zones.list() 32 | for management_zone in management_zones: 33 | full_management_zone = management_zone.get_full_configuration() 34 | assert isinstance(full_management_zone, ManagementZone) 35 | assert isinstance(full_management_zone.metadata, ConfigurationMetadata) 36 | assert full_management_zone.metadata.cluster_version == "1.237.130.20220311-144350" 37 | assert full_management_zone.id == "6507829326603756920" 38 | assert full_management_zone.name == "Frontend Services" 39 | assert isinstance(full_management_zone.rules, List) 40 | for rule in full_management_zone.rules: 41 | assert isinstance(rule, ManagementZoneRule) 42 | assert rule.type == RuleType.SERVICE 43 | assert rule.enabled == True 44 | assert rule.propagation_types == [PropagationType.SERVICE_TO_PROCESS_GROUP_LIKE] 45 | assert isinstance(rule.conditions, List) 46 | for condition in rule.conditions: 47 | assert isinstance(condition, EntityRuleEngineCondition) 48 | assert isinstance(condition.key, ConditionKey) 49 | assert condition.key.attribute == ConditionKeyAttribute.PROCESS_GROUP_CUSTOM_METADATA 50 | assert isinstance(condition.comparison_info, ComparisonBasic) 51 | assert condition.comparison_info.type == ComparisonBasicType.STRING 52 | assert condition.comparison_info.operator == "EQUALS" 53 | assert condition.comparison_info.value == "FRONTEND" 54 | assert condition.comparison_info.negate == False 55 | assert condition.comparison_info.case_sensitive == True 56 | break 57 | break 58 | break 59 | -------------------------------------------------------------------------------- /test/configuration_v1/test_notifications.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | from dynatrace.configuration_v1.notifications import NotificationConfigStub, NotificationType, ServiceNowNotificationConfig 3 | from dynatrace.pagination import PaginatedList 4 | 5 | ID = "0d06c889-4cea-4b45-aefa-a277790e784d" 6 | NAME = "Service Now Example" 7 | TYPE = NotificationType.SERVICE_NOW 8 | 9 | 10 | def test_list(dt: Dynatrace): 11 | notifications = dt.notifications.list() 12 | assert isinstance(notifications, PaginatedList) 13 | 14 | list_notifications = list(notifications) 15 | assert len(list_notifications) == 4 16 | 17 | first = list_notifications[0] 18 | assert isinstance(first, NotificationConfigStub) 19 | 20 | assert first.id == ID 21 | assert first.name == NAME 22 | assert first.type == TYPE 23 | 24 | 25 | def test_get_full_configuration(dt: Dynatrace): 26 | notifications = dt.notifications.list() 27 | list_notifications = list(notifications) 28 | first = list_notifications[0] 29 | 30 | full = first.get_full_configuration() 31 | 32 | # type checks 33 | assert isinstance(full, ServiceNowNotificationConfig) 34 | assert isinstance(full.name, str) 35 | assert isinstance(full.id, str) 36 | assert isinstance(full.type, NotificationType) 37 | assert isinstance(full.alerting_profile, str) 38 | assert isinstance(full.url, type(None)) 39 | assert isinstance(full.username, str) 40 | assert isinstance(full.password, type(None)) 41 | assert isinstance(full.message, str) 42 | assert isinstance(full.send_incidents, bool) 43 | assert isinstance(full.send_events, bool) 44 | 45 | # value checks 46 | assert full.id == ID 47 | assert full.name == NAME 48 | assert full.type == TYPE 49 | assert full.alerting_profile == "7693d108-fda9-3529-8ca3-55e9269b6097" 50 | assert full.active == True 51 | assert full.instance_name == "dev63549" 52 | assert full.url == None 53 | assert full.message == "{State} {ProblemID} {ProblemImpact} {ProblemSeverity}" 54 | assert full.send_incidents == True 55 | assert full.send_events == False 56 | -------------------------------------------------------------------------------- /test/configuration_v1/test_oneagent_environment_wide_configuration.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | from dynatrace.configuration_v1.oneagent_environment_wide_configuration import EnvironmentAutoUpdateConfig 3 | from dynatrace.configuration_v1.schemas import ( 4 | ConfigurationMetadata, 5 | AutoUpdateSetting, 6 | UpdateWindowsConfig, 7 | TechMonitoringList, 8 | Technology, 9 | TechnologyType, 10 | SettingScope, 11 | ) 12 | 13 | CLUSTER_VERSION = "1.222.47.20210712-162143" 14 | 15 | 16 | def test_get(dt: Dynatrace): 17 | oa_env_autoupdate_config = dt.oneagents_config_environment.get() 18 | 19 | # type checks 20 | assert isinstance(oa_env_autoupdate_config, EnvironmentAutoUpdateConfig) 21 | assert isinstance(oa_env_autoupdate_config.metadata, ConfigurationMetadata) 22 | assert isinstance(oa_env_autoupdate_config.setting, AutoUpdateSetting) 23 | assert isinstance(oa_env_autoupdate_config.version, (str, type(None))) 24 | assert isinstance(oa_env_autoupdate_config.update_windows, UpdateWindowsConfig) 25 | 26 | # value checks 27 | assert oa_env_autoupdate_config.metadata.cluster_version == CLUSTER_VERSION 28 | assert oa_env_autoupdate_config.setting == AutoUpdateSetting.DISABLED 29 | assert oa_env_autoupdate_config.version is None 30 | assert oa_env_autoupdate_config.update_windows.windows == [] 31 | 32 | 33 | def test_get_technologies(dt: Dynatrace): 34 | oa_env_technologies = dt.oneagents_config_environment.get_technologies() 35 | 36 | # type checks 37 | assert isinstance(oa_env_technologies, TechMonitoringList) 38 | assert isinstance(oa_env_technologies.metadata, ConfigurationMetadata) 39 | assert all(isinstance(t, Technology) for t in oa_env_technologies.technologies) 40 | for tech in oa_env_technologies.technologies: 41 | assert isinstance(tech.type, TechnologyType) 42 | assert isinstance(tech.monitoring_enabled, bool) 43 | assert isinstance(tech.scope, (SettingScope, type(None))) 44 | 45 | # value checks 46 | assert oa_env_technologies.metadata.cluster_version == CLUSTER_VERSION 47 | assert len(oa_env_technologies.technologies) == 4 48 | assert oa_env_technologies.technologies[0].type == TechnologyType.DOT_NET 49 | assert oa_env_technologies.technologies[0].monitoring_enabled == True 50 | assert oa_env_technologies.technologies[0].scope == SettingScope.ENVIRONMENT 51 | -------------------------------------------------------------------------------- /test/configuration_v1/test_oneagent_in_a_hostgroup.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | from dynatrace.configuration_v1.oneagent_in_a_hostgroup import OneAgentHostGroupConfig, HostGroupAutoUpdateConfig 3 | from dynatrace.configuration_v1.schemas import UpdateWindowsConfig, UpdateWindow, ConfigurationMetadata, EffectiveSetting, AutoUpdateSetting 4 | 5 | HOST_GROUP_ID = "HOST_GROUP-ABC123DEF456GHI7" 6 | CLUSTER_VERSION = "1.222.47.20210712-162143" 7 | 8 | 9 | def test_get(dt: Dynatrace): 10 | oa_hostgroup_config = dt.oneagents_config_hostgroup.get(HOST_GROUP_ID) 11 | 12 | # type checks 13 | assert isinstance(oa_hostgroup_config, OneAgentHostGroupConfig) 14 | assert isinstance(oa_hostgroup_config.id, (str, type(None))) 15 | assert isinstance(oa_hostgroup_config.auto_update_config, HostGroupAutoUpdateConfig) 16 | 17 | # value checks 18 | assert oa_hostgroup_config.id == None 19 | 20 | 21 | def test_get_audoupdate(dt: Dynatrace): 22 | oa_hostgroup_autoupdate = dt.oneagents_config_hostgroup.get_autoupdate(HOST_GROUP_ID) 23 | 24 | # type checks 25 | assert isinstance(oa_hostgroup_autoupdate, HostGroupAutoUpdateConfig) 26 | assert isinstance(oa_hostgroup_autoupdate.id, str) 27 | assert isinstance(oa_hostgroup_autoupdate.metadata, ConfigurationMetadata) 28 | assert isinstance(oa_hostgroup_autoupdate.setting, AutoUpdateSetting) 29 | assert isinstance(oa_hostgroup_autoupdate.update_windows, UpdateWindowsConfig) 30 | assert isinstance(oa_hostgroup_autoupdate.effective_setting, (EffectiveSetting, type(None))) 31 | assert isinstance(oa_hostgroup_autoupdate.version, (str, type(None))) 32 | assert isinstance(oa_hostgroup_autoupdate.effective_version, (str, type(None))) 33 | 34 | # value checks 35 | assert oa_hostgroup_autoupdate.metadata.cluster_version == CLUSTER_VERSION 36 | assert oa_hostgroup_autoupdate.id == HOST_GROUP_ID 37 | assert oa_hostgroup_autoupdate.setting == AutoUpdateSetting.DISABLED 38 | assert oa_hostgroup_autoupdate.version is None 39 | assert oa_hostgroup_autoupdate.update_windows.windows == [] 40 | assert oa_hostgroup_autoupdate.effective_setting == EffectiveSetting.DISABLED 41 | assert oa_hostgroup_autoupdate.effective_version is None 42 | -------------------------------------------------------------------------------- /test/configuration_v1/test_oneagent_on_a_host.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | from dynatrace.configuration_v1.oneagent_on_a_host import ( 3 | HostConfig, 4 | HostAutoUpdateConfig, 5 | MonitoringConfig, 6 | AutoUpdateSetting, 7 | TechMonitoringList, 8 | EffectiveSetting, 9 | MonitoringMode, 10 | ) 11 | from dynatrace.configuration_v1.schemas import UpdateWindowsConfig, UpdateWindow, ConfigurationMetadata, Technology, TechnologyType, SettingScope 12 | 13 | HOST_ID = "HOST-abcd123457" 14 | CLUSTER_VERSION = "1.222.47.20210712-162143" 15 | 16 | 17 | def test_get(dt: Dynatrace): 18 | oa_host_config = dt.oneagents_config_host.get(HOST_ID) 19 | 20 | # type checks 21 | assert isinstance(oa_host_config, HostConfig) 22 | assert isinstance(oa_host_config.id, str) 23 | assert isinstance(oa_host_config.auto_update_config, HostAutoUpdateConfig) 24 | assert isinstance(oa_host_config.monitoring_config, MonitoringConfig) 25 | assert isinstance(oa_host_config.tech_monitoring_config_list, TechMonitoringList) 26 | 27 | # value checks 28 | assert oa_host_config.id == HOST_ID 29 | 30 | 31 | def test_get_autoupdate(dt: Dynatrace): 32 | oa_autoupdate = dt.oneagents_config_host.get_autoupdate(HOST_ID) 33 | 34 | # type checks 35 | assert isinstance(oa_autoupdate, HostAutoUpdateConfig) 36 | assert isinstance(oa_autoupdate.id, str) 37 | assert isinstance(oa_autoupdate.setting, AutoUpdateSetting) 38 | assert isinstance(oa_autoupdate.version, (str, type(None))) 39 | assert isinstance(oa_autoupdate.effective_setting, EffectiveSetting) 40 | assert isinstance(oa_autoupdate.effective_version, (str, type(None))) 41 | assert isinstance(oa_autoupdate.update_windows, UpdateWindowsConfig) 42 | assert isinstance(oa_autoupdate.metadata, ConfigurationMetadata) 43 | assert all(isinstance(uw, UpdateWindow) for uw in oa_autoupdate.update_windows.windows) 44 | 45 | # value checks 46 | assert oa_autoupdate.id == HOST_ID 47 | assert oa_autoupdate.setting == AutoUpdateSetting.DISABLED 48 | assert oa_autoupdate.version is None 49 | assert oa_autoupdate.effective_setting == EffectiveSetting.DISABLED 50 | assert oa_autoupdate.effective_version is None 51 | assert oa_autoupdate.update_windows.windows == [] 52 | assert oa_autoupdate.metadata.cluster_version == CLUSTER_VERSION 53 | 54 | 55 | def test_get_monitoring(dt: Dynatrace): 56 | oa_monitoring = dt.oneagents_config_host.get_monitoring(HOST_ID) 57 | 58 | # type checks 59 | assert isinstance(oa_monitoring, MonitoringConfig) 60 | assert isinstance(oa_monitoring.id, str) 61 | assert isinstance(oa_monitoring.monitoring_enabled, bool) 62 | assert isinstance(oa_monitoring.monitoring_mode, MonitoringMode) 63 | assert isinstance(oa_monitoring.metadata, ConfigurationMetadata) 64 | 65 | # value checks 66 | assert oa_monitoring.id == HOST_ID 67 | assert oa_monitoring.monitoring_enabled == True 68 | assert oa_monitoring.monitoring_mode == MonitoringMode.FULL_STACK 69 | assert oa_monitoring.metadata.cluster_version == CLUSTER_VERSION 70 | 71 | 72 | def test_get_technologies(dt: Dynatrace): 73 | oa_technologies = dt.oneagents_config_host.get_technologies(HOST_ID) 74 | 75 | # type checks 76 | assert isinstance(oa_technologies.metadata, ConfigurationMetadata) 77 | assert isinstance(oa_technologies, TechMonitoringList) 78 | assert all(isinstance(t, Technology) for t in oa_technologies.technologies) 79 | for tech in oa_technologies.technologies: 80 | assert isinstance(tech.type, TechnologyType) 81 | assert isinstance(tech.monitoring_enabled, bool) 82 | assert isinstance(tech.scope, (SettingScope, type(None))) 83 | 84 | # value checks 85 | assert len(oa_technologies.technologies) == 4 86 | assert oa_technologies.technologies[0].type == TechnologyType.LOG_ANALYTICS 87 | assert oa_technologies.technologies[0].monitoring_enabled == True 88 | assert oa_technologies.technologies[0].scope == SettingScope.ENVIRONMENT 89 | assert oa_technologies.metadata.cluster_version == CLUSTER_VERSION 90 | -------------------------------------------------------------------------------- /test/conftest.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import os 3 | from pathlib import Path 4 | from typing import Optional, Dict 5 | from unittest import mock 6 | import json 7 | 8 | import pytest 9 | 10 | from dynatrace import Dynatrace 11 | from dynatrace.http_client import HttpClient 12 | from dynatrace.utils import slugify 13 | 14 | current_file_path = os.path.dirname(os.path.realpath(__file__)) 15 | 16 | 17 | class MockResponse: 18 | def __init__(self, json_data): 19 | self.json_data = json_data 20 | self.headers = {} 21 | self.content = json.dumps(json_data).encode() if json_data else None 22 | 23 | def json(self): 24 | return self.json_data 25 | 26 | 27 | def local_make_request( 28 | self, path: str, params: Optional[Dict] = None, headers: Optional[Dict] = None, method="GET", data=None, query_params=None, **kwargs 29 | ) -> MockResponse: 30 | 31 | params = f"{params}" if params else "" 32 | if query_params: 33 | params += f"{query_params}" 34 | if params: 35 | encoded = f"{params}".encode() 36 | params = f"_{hashlib.sha256(encoded).hexdigest()}"[:16] 37 | 38 | path = slugify(path) 39 | file_name = f"{method}{path}{params}.json" 40 | file_path = Path(current_file_path, "mock_data", file_name) 41 | with open(file_path) as f: 42 | content = f.read() 43 | json_data = json.loads(content) if content else None 44 | return MockResponse(json_data) 45 | 46 | 47 | @pytest.fixture(autouse=True) 48 | def dt(): 49 | with mock.patch.object(HttpClient, "make_request", new=local_make_request): 50 | dt = Dynatrace("mock_tenant", "mock_token") 51 | yield dt 52 | -------------------------------------------------------------------------------- /test/environment_v1/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynatrace-oss/api-client-python/9c1467b36b8a11ff74daf9d6d2c9fde25c4fd970/test/environment_v1/__init__.py -------------------------------------------------------------------------------- /test/environment_v1/test_smartscape_hosts.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | from dynatrace.environment_v1.smartscape_hosts import Host, MonitoringMode, OSArchitecture 3 | from dynatrace.pagination import HeaderPaginatedList 4 | from dynatrace.environment_v1.smartscape_hosts import Host 5 | 6 | 7 | def test_list(dt: Dynatrace): 8 | hosts = dt.smartscape_hosts.list(page_size=20) 9 | assert isinstance(hosts, HeaderPaginatedList) 10 | for host in hosts: 11 | assert isinstance(host, Host) 12 | assert host.entity_id == "HOST-7EC661999923A6B9" 13 | assert host.discovered_name == "TAG009444368559.clients.example.com" 14 | assert host.last_seen_timestamp == 1621519976487 15 | for tag in host.tags: 16 | assert tag.context == "CONTEXTLESS" 17 | assert tag.key == "APP1234567" 18 | break 19 | assert host.os_version == "Windows 10 Enterprise 20H2 2009, ver. 10.0.19042" 20 | assert host.monitoring_mode == MonitoringMode.FULL_STACK 21 | assert host.consumed_host_units == 2.0 22 | assert host.os_architecture == OSArchitecture.X_EIGHTY_SIX 23 | assert host.cpu_cores == 8 24 | break 25 | -------------------------------------------------------------------------------- /test/environment_v1/test_synthetic_monitors.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | 3 | from dynatrace.environment_v1.synthetic_monitors import CreatedFrom, ManagementZone, MonitorCollectionElement, MonitorType 4 | from dynatrace.pagination import PaginatedList 5 | 6 | 7 | def test_list_string(dt: Dynatrace): 8 | monitors = dt.synthetic_monitors.list(monitor_type="BROWSER") 9 | assert isinstance(monitors, PaginatedList) 10 | for monitor in monitors: 11 | assert isinstance(monitor, MonitorCollectionElement) 12 | assert monitor.name == "angular easytravel bounce" 13 | assert monitor.entity_id == "SYNTHETIC_TEST-7639A3AED66940FA" 14 | assert monitor.monitor_type == "BROWSER" 15 | assert monitor.enabled 16 | break 17 | 18 | 19 | def test_list_enum(dt: Dynatrace): 20 | monitors = dt.synthetic_monitors.list(monitor_type=MonitorType.BROWSER) 21 | assert isinstance(monitors, PaginatedList) 22 | for monitor in monitors: 23 | assert isinstance(monitor, MonitorCollectionElement) 24 | assert monitor.name == "angular easytravel bounce" 25 | assert monitor.entity_id == "SYNTHETIC_TEST-7639A3AED66940FA" 26 | assert monitor.monitor_type == "BROWSER" 27 | assert monitor.enabled 28 | break 29 | 30 | 31 | def test_get_full_synthetic_config(dt: Dynatrace): 32 | config = dt.synthetic_monitors.get_full_monitor_configuration(monitor_id="SYNTHETIC_TEST-7639A3AED66940FA") 33 | assert config.name == "angular easytravel bounce" 34 | assert config.frequency_min == 5 35 | assert config.enabled 36 | assert config.type == MonitorType.BROWSER 37 | assert config.created_from == CreatedFrom.API 38 | assert isinstance(config.script, dict) 39 | assert config.anomaly_detection.outage_handling.local_outage_policy.consecutive_runs == 1 40 | assert not config.anomaly_detection.loading_time_thresholds.enabled 41 | for mz in config.management_zones: 42 | assert isinstance(mz, ManagementZone) 43 | break 44 | -------------------------------------------------------------------------------- /test/environment_v2/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynatrace-oss/api-client-python/9c1467b36b8a11ff74daf9d6d2c9fde25c4fd970/test/environment_v2/__init__.py -------------------------------------------------------------------------------- /test/environment_v2/test_activegate_autoupdate_configuration.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | 3 | 4 | def test_get_global(dt: Dynatrace): 5 | alert_profiles = dt.activegates_autoupdate_configuration.get_global() 6 | assert alert_profiles.global_setting == "DISABLED" 7 | assert alert_profiles.metadata.cluster_version == "1.217.96.20210507-181038" 8 | assert alert_profiles.metadata.configuration_versions[0] == 1 9 | assert isinstance(alert_profiles.metadata.configuration_versions, list) 10 | 11 | 12 | def test_get(dt: Dynatrace): 13 | alert_profiles = dt.activegates_autoupdate_configuration.get("1513404008") 14 | assert alert_profiles.setting == "ENABLED" 15 | assert alert_profiles.effective_setting == "ENABLED" 16 | -------------------------------------------------------------------------------- /test/environment_v2/test_activegate_autoupdate_jobs.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | from datetime import datetime 3 | 4 | 5 | def test_list(dt: Dynatrace): 6 | update_jobs = list(dt.activegates_autoupdate_jobs.list()) 7 | assert isinstance(update_jobs, list) 8 | 9 | first_ag = update_jobs[0] 10 | assert first_ag.activegate_id == "-1556499193" 11 | assert len(first_ag.update_jobs) == 3 12 | 13 | first_job = first_ag.update_jobs[0] 14 | assert first_job.job_id == "-4754066816153208332" 15 | assert first_job.job_state == "SUCCEED" 16 | assert first_job.update_method == "MANUAL_INSTALLATION" 17 | assert first_job.update_type == "ACTIVE_GATE" 18 | assert not first_job.cancelable 19 | assert first_job.start_version == "1.217.89.20210506-182520" 20 | assert first_job.target_version == "1.217.96.20210507-181038" 21 | assert first_job.timestamp == datetime.utcfromtimestamp(1620419177047 / 1000) 22 | assert first_job.ag_type == "ENVIRONMENT" 23 | assert first_job.environments == ["eaa50379"] 24 | assert first_job.error is None 25 | assert first_job.duration is None 26 | 27 | 28 | def test_get(dt: Dynatrace): 29 | update_jobs_list = dt.activegates_autoupdate_jobs.get("-1556499193") 30 | 31 | assert update_jobs_list.activegate_id == "-1556499193" 32 | assert isinstance(update_jobs_list.update_jobs, list) 33 | 34 | first_job = update_jobs_list.update_jobs[0] 35 | assert first_job.job_id == "-4754066816153208332" 36 | assert first_job.job_state == "SUCCEED" 37 | assert first_job.update_method == "MANUAL_INSTALLATION" 38 | assert first_job.update_type == "ACTIVE_GATE" 39 | assert not first_job.cancelable 40 | assert first_job.start_version == "1.217.89.20210506-182520" 41 | assert first_job.target_version == "1.217.96.20210507-181038" 42 | assert first_job.timestamp == datetime.utcfromtimestamp(1620419177047 / 1000) 43 | assert first_job.ag_type == "ENVIRONMENT" 44 | assert first_job.environments == ["eaa50379"] 45 | assert first_job.error is None 46 | assert first_job.duration is None 47 | -------------------------------------------------------------------------------- /test/environment_v2/test_activegates_remote_configuration.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import List 3 | from dynatrace import Dynatrace 4 | from dynatrace.environment_v2.remote_configuration import ( 5 | RemoteConfigurationManagementOperation, 6 | RemoteConfigurationManagementOperationActiveGateRequest, 7 | AttributeType, 8 | OperationType, 9 | EntityType, 10 | RemoteConfigurationManagementJobPreview, 11 | RemoteConfigurationManagementJobSummary 12 | ) 13 | from dynatrace.pagination import PaginatedList 14 | 15 | TEST_ENTITY_ID = "0x2b7c0b02" 16 | 17 | def test_list(dt: Dynatrace): 18 | jobs = dt.activegates_remote_configuration.list() 19 | 20 | assert isinstance(jobs, PaginatedList) 21 | 22 | for job in jobs: 23 | assert isinstance(job, RemoteConfigurationManagementJobSummary) 24 | assert hasattr(job, "id") 25 | assert hasattr(job, "entity_type") 26 | assert hasattr(job, "start_time") 27 | assert isinstance(job.entity_type, EntityType) 28 | break 29 | 30 | def test_post(dt: Dynatrace): 31 | operation = RemoteConfigurationManagementOperation.build( 32 | attribute=AttributeType.NETWORK_ZONE, 33 | operation=OperationType.SET, 34 | value="test-zone", 35 | ) 36 | 37 | job = dt.activegates_remote_configuration.post(entities=[TEST_ENTITY_ID], operations=[operation]) 38 | 39 | assert job is not None 40 | assert job.id is not None 41 | assert job.entity_type == EntityType.ACTIVE_GATE 42 | assert len(job.operations) == 1 43 | assert job.operations[0].attribute == AttributeType.NETWORK_ZONE 44 | assert job.operations[0].operation == OperationType.SET 45 | assert job.operations[0].value == "test-zone" 46 | 47 | def test_get_current(dt: Dynatrace): 48 | current_job = dt.activegates_remote_configuration.get_current() 49 | 50 | if current_job is not None: 51 | assert current_job.id is not None 52 | assert hasattr(current_job, "timeout_time") 53 | assert current_job.processed_entities_count <= current_job.total_entities_count 54 | 55 | def test_post_preview(dt: Dynatrace): 56 | operation = RemoteConfigurationManagementOperation.build( 57 | attribute=AttributeType.NETWORK_ZONE, 58 | operation=OperationType.SET, 59 | value="test-zone", 60 | ) 61 | 62 | previews = dt.activegates_remote_configuration.post_preview( 63 | entities=[TEST_ENTITY_ID], 64 | operations=[operation], 65 | ) 66 | 67 | assert isinstance(previews, PaginatedList) 68 | 69 | for preview in previews: 70 | assert isinstance(preview, RemoteConfigurationManagementJobPreview) 71 | assert preview.attribute == AttributeType.NETWORK_ZONE 72 | assert preview.operation == OperationType.SET 73 | assert preview.value == "test-zone" 74 | assert isinstance(preview.already_configured_entities_count, int) 75 | assert isinstance(preview.target_entities_count, int) 76 | break 77 | 78 | def test_validate(dt: Dynatrace): 79 | operation = RemoteConfigurationManagementOperation.build( 80 | attribute=AttributeType.NETWORK_ZONE, 81 | operation=OperationType.SET, 82 | value="test-zone", 83 | ) 84 | validation_result = dt.activegates_remote_configuration.validate( 85 | entities=[TEST_ENTITY_ID], 86 | operations=[operation] 87 | ) 88 | 89 | # If validation succeeds, result should be None 90 | # If validation fails, result should contain error details 91 | if validation_result is not None: 92 | assert hasattr(validation_result, "invalid_entities") 93 | assert hasattr(validation_result, "invalid_operations") 94 | assert isinstance(validation_result.invalid_entities, list) 95 | assert isinstance(validation_result.invalid_operations, list) 96 | 97 | def test_get_job(dt: Dynatrace): 98 | ID = "7974003406714390819" 99 | job = dt.activegates_remote_configuration.get(ID) 100 | 101 | assert job is not None 102 | assert job.id == ID 103 | assert job.entity_type == EntityType.ACTIVE_GATE 104 | assert len(job.operations) == 1 105 | assert job.operations[0].attribute == AttributeType.NETWORK_ZONE 106 | assert job.operations[0].operation == OperationType.SET 107 | assert job.operations[0].value == "test-zone" -------------------------------------------------------------------------------- /test/environment_v2/test_audit_logs.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | from datetime import datetime 3 | 4 | from dynatrace.environment_v2.audit_logs import AuditLogEntry, EventType, Category, UserType 5 | from dynatrace.pagination import PaginatedList 6 | 7 | 8 | def test_list(dt: Dynatrace): 9 | audit_logs = dt.audit_logs.list() 10 | assert isinstance(audit_logs, PaginatedList) 11 | 12 | audit_logs_list = list(audit_logs) 13 | assert len(audit_logs_list) == 6 14 | 15 | first = audit_logs_list[0] 16 | assert isinstance(first, AuditLogEntry) 17 | assert first.log_id == "162100314800090003" 18 | assert first.event_type == EventType("DELETE") 19 | assert first.category == Category("CONFIG") 20 | assert first.entity_id == "builtin:alerting.profile (tenant): d89472d3-f9f4-420d-9398-768bb3351e85: test" 21 | assert first.environment_id == "eaa50379" 22 | assert first.user == "Dynatrace support user #649982176" 23 | assert first.user_type == UserType("USER_NAME") 24 | assert first.user_origin == "webui (xxx.xxx.xxx.xxx)" 25 | assert first.timestamp == datetime.utcfromtimestamp(1621003148800 / 1000) 26 | assert first.success 27 | 28 | 29 | def test_get(dt: Dynatrace): 30 | audit_log = dt.audit_logs.get("162100314800090003") 31 | assert isinstance(audit_log, AuditLogEntry) 32 | assert audit_log.log_id == "162100314800090003" 33 | assert audit_log.event_type == EventType("DELETE") 34 | assert audit_log.category == Category("CONFIG") 35 | assert audit_log.entity_id == "builtin:alerting.profile (tenant): d89472d3-f9f4-420d-9398-768bb3351e85: test" 36 | assert audit_log.environment_id == "eaa50379" 37 | assert audit_log.user == "Dynatrace support user #649982176" 38 | assert audit_log.user_type == UserType("USER_NAME") 39 | assert audit_log.user_origin == "webui (xxx.xxx.xxx.xxx)" 40 | assert audit_log.timestamp == datetime.utcfromtimestamp(1621003148800 / 1000) 41 | assert audit_log.success 42 | -------------------------------------------------------------------------------- /test/environment_v2/test_customtags.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import List, Optional, Union, Dict, Any 3 | from dynatrace import Dynatrace 4 | from dynatrace.environment_v2.custom_tags import AddEntityTags, METag 5 | from dynatrace.pagination import PaginatedList 6 | 7 | import dynatrace.environment_v2.custom_tags as customtags 8 | 9 | ENTITY_SELECTOR = "bilalhosts" 10 | 11 | 12 | def test_list(dt: Dynatrace): 13 | _tags = dt.custom_tags.list(entity_selector=ENTITY_SELECTOR) 14 | 15 | # type checks 16 | assert isinstance(_tags, PaginatedList) 17 | assert len(list(_tags)) == 2 18 | assert all(isinstance(n, METag) for n in _tags) 19 | 20 | # value checks 21 | for t in _tags: 22 | assert t.key == "mainApp" 23 | assert t.string_representation == "mainApp" 24 | assert str(t.context) == "CONTEXTLESS" 25 | break 26 | 27 | 28 | def test_post_no_value(dt: Dynatrace): 29 | tags = dt.custom_tags.post("entityId(CUSTOM_DEVICE-3B7788FE910B0F42)", [AddEntityTags("test-tag-no-value")]) 30 | for tag in tags.applied_tags: 31 | assert str(tag.context) == "CONTEXTLESS" 32 | assert tag.key == "test-tag-no-value" 33 | assert tag.value is None 34 | assert tag.string_representation == "test-tag-no-value" 35 | 36 | 37 | def test_post_value(dt: Dynatrace): 38 | tags = dt.custom_tags.post("entityId(CUSTOM_DEVICE-3B7788FE910B0F42)", [AddEntityTags("test-tag-value", "tag-value")]) 39 | for tag in tags.applied_tags: 40 | assert str(tag.context) == "CONTEXTLESS" 41 | assert tag.key == "test-tag-value" 42 | assert tag.value == "tag-value" 43 | assert tag.string_representation == "test-tag-value:tag-value" 44 | 45 | 46 | def test_delete(dt: Dynatrace): 47 | deleted_tags = dt.custom_tags.delete("test-tag-value", "entityId(CUSTOM_DEVICE-3B7788FE910B0F42)", delete_all_with_key=True) 48 | assert deleted_tags.matched_entities_count == 1 49 | -------------------------------------------------------------------------------- /test/environment_v2/test_events_v2.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from dynatrace import Dynatrace 4 | from dynatrace.pagination import PaginatedList 5 | from dynatrace.utils import int64_to_datetime 6 | from dynatrace.environment_v2.events import Event, EventProperty, EventStatus, EventType, EventSeverity 7 | from dynatrace.environment_v2.monitored_entities import EntityStub 8 | from dynatrace.environment_v2.custom_tags import METag 9 | from dynatrace.environment_v2.schemas import ManagementZone 10 | 11 | EVENT_ID = "4578933396576863909_1631255744265" 12 | EVENT_TYPE = "APPLICATION_OVERLOAD_PREVENTION" 13 | 14 | 15 | def test_list(dt: Dynatrace): 16 | events = dt.events_v2.list(page_size=100, time_from=datetime.utcfromtimestamp(1599913748), time_to="1631258989895") 17 | 18 | # type checks 19 | assert isinstance(events, PaginatedList) 20 | assert all(isinstance(e, Event) for e in events) 21 | 22 | # value checks 23 | assert len(events) == 3 24 | 25 | 26 | def test_get(dt: Dynatrace): 27 | event = dt.events_v2.get(EVENT_ID) 28 | 29 | # type checks 30 | assert isinstance(event, Event) 31 | assert isinstance(event.start_time, datetime) 32 | assert isinstance(event.end_time, datetime) 33 | assert isinstance(event.event_type, str) 34 | assert isinstance(event.title, str) 35 | assert isinstance(event.entity_id, EntityStub) 36 | assert isinstance(event.properties, list) 37 | assert all(isinstance(p, EventProperty) for p in event.properties) 38 | assert isinstance(event.status, EventStatus) 39 | assert isinstance(event.entity_tags, list) 40 | assert all(isinstance(tag, METag) for tag in event.entity_tags) 41 | assert isinstance(event.management_zones, list) 42 | assert all(isinstance(mz, ManagementZone) for mz in event.management_zones) 43 | assert isinstance(event.under_maintenance, bool) 44 | assert isinstance(event.suppress_alert, bool) 45 | assert isinstance(event.suppress_problem, bool) 46 | assert isinstance(event.frequent_event, bool) 47 | 48 | # value checks 49 | assert event.event_id == EVENT_ID 50 | assert event.start_time == int64_to_datetime(1631255744265) 51 | assert event.end_time == int64_to_datetime(1631255744265) 52 | assert event.event_type == "CUSTOM_DEPLOYMENT" 53 | assert event.title == "Deployment" 54 | assert event.properties[0].key == "dt.event.group_label" 55 | assert event.properties[0].value == "Deployment" 56 | assert event.status == EventStatus.CLOSED 57 | assert event.under_maintenance == False 58 | assert event.suppress_alert == False 59 | assert event.suppress_problem == False 60 | assert event.frequent_event == False 61 | 62 | 63 | def test_list_types(dt: Dynatrace): 64 | event_types = dt.events_v2.list_types() 65 | 66 | # type checks 67 | assert isinstance(event_types, PaginatedList) 68 | assert all(isinstance(et, EventType) for et in event_types) 69 | 70 | # value checks 71 | assert len(event_types) == 5 72 | 73 | 74 | def test_get_type(dt: Dynatrace): 75 | type_details = dt.events_v2.get_type(EVENT_TYPE) 76 | 77 | # type checks 78 | assert isinstance(type_details, EventType) 79 | assert isinstance(type_details.type, str) 80 | assert isinstance(type_details.display_name, str) 81 | assert isinstance(type_details.severity_level, EventSeverity) 82 | assert isinstance(type_details.description, str) 83 | 84 | # value checks 85 | assert type_details.type == EVENT_TYPE 86 | assert type_details.display_name == "Application overload prevention" 87 | assert type_details.severity_level == EventSeverity.INFO 88 | assert type_details.description == "Max user actions per minute exceeded" 89 | 90 | def test_ingest(dt: Dynatrace): 91 | ingest = dt.events_v2.ingest("CUSTOM_ALERT", "Dt API Test", properties={"test": "test"}, entity_selector="type(HOST)") 92 | assert isinstance(ingest, dict) 93 | assert ingest["eventIngestResults"][0]["status"] == "OK" -------------------------------------------------------------------------------- /test/environment_v2/test_extensions.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | from dynatrace.environment_v2.extensions import MinimalExtension 3 | from dynatrace.pagination import PaginatedList 4 | 5 | import dynatrace.environment_v2.extensions as extensions_v2 6 | 7 | 8 | def test_list(dt: Dynatrace): 9 | extensions = list(dt.extensions_v2.list()) 10 | 11 | assert len(extensions) == 2 12 | 13 | for extension in extensions: 14 | assert isinstance(extension, MinimalExtension) 15 | assert extension.extension_name == "com.dynatrace.extension.snmp-generic" 16 | assert extension.version == "0.2.5" 17 | break 18 | 19 | 20 | def test_list_name(dt: Dynatrace): 21 | extensions = list(dt.extensions_v2.list(name="custom")) 22 | 23 | assert len(extensions) == 1 24 | 25 | for extension in extensions: 26 | assert isinstance(extension, MinimalExtension) 27 | assert extension.extension_name == "custom:dynatrace.cisco.asa" 28 | assert extension.version == "0.1.0" 29 | break 30 | 31 | 32 | def test_list_versions(dt: Dynatrace): 33 | extensions = list(dt.extensions_v2.list_versions("com.dynatrace.extension.snmp-generic")) 34 | 35 | assert len(extensions) == 1 36 | 37 | for extension in extensions: 38 | assert isinstance(extension, MinimalExtension) 39 | assert extension.extension_name == "com.dynatrace.extension.snmp-generic" 40 | assert extension.version == "0.2.5" 41 | break 42 | 43 | 44 | def test_get(dt: Dynatrace): 45 | extension = dt.extensions_v2.get("com.dynatrace.extension.snmp-generic", "0.2.5") 46 | 47 | # type checks 48 | assert isinstance(extension, extensions_v2.Extension) 49 | assert isinstance(extension.author, extensions_v2.AuthorDTO) 50 | assert isinstance(extension.data_sources, list) 51 | assert isinstance(extension.feature_sets, list) 52 | assert isinstance(extension.variables, list) 53 | 54 | # value checks 55 | assert extension.extension_name == "com.dynatrace.extension.snmp-generic" 56 | assert extension.author.name == "Dynatrace" 57 | assert extension.version == "0.2.5" 58 | assert extension.variables[0] == "ext.activationtag" 59 | 60 | 61 | def test_get_active_extension_version(dt: Dynatrace): 62 | environemnt_config = dt.extensions_v2.get_environment_config("ibmmq") 63 | 64 | # type checks 65 | assert isinstance(environemnt_config, extensions_v2.ExtensionEnvironmentConfigurationVersion) 66 | 67 | # value checks 68 | assert environemnt_config.version == "1.2.3" 69 | -------------------------------------------------------------------------------- /test/environment_v2/test_networkzones.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from dynatrace import Dynatrace 3 | from dynatrace.pagination import PaginatedList 4 | 5 | import dynatrace.environment_v2.networkzones as nz 6 | 7 | NETWORKZONE_ID = "default" 8 | 9 | 10 | def test_list(dt: Dynatrace): 11 | network_zones = dt.network_zones.list() 12 | 13 | # type checks 14 | assert isinstance(network_zones, PaginatedList) 15 | assert len(list(network_zones)) == 2 16 | assert all(isinstance(n, nz.NetworkZone) for n in network_zones) 17 | 18 | 19 | def test_get(dt: Dynatrace): 20 | network_zone = dt.network_zones.get(networkzone_id=NETWORKZONE_ID) 21 | 22 | # type checks 23 | assert isinstance(network_zone, nz.NetworkZone) 24 | assert isinstance(network_zone.alternative_zones, list) 25 | 26 | # value checks 27 | assert ( 28 | network_zone.description 29 | == "The default network zone. This is the network zone for OneAgents or ActiveGates that do not have any network zone configured." 30 | ) 31 | assert network_zone.id == "default" 32 | assert network_zone.num_configured_activegates == 0 33 | assert network_zone.num_oneagents_configured == 141 34 | assert network_zone.num_oneagents_using == 141 35 | assert network_zone.num_oneagents_from_other_zones == 0 36 | -------------------------------------------------------------------------------- /test/environment_v2/test_oneagents_remote_configuration.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import List 3 | from dynatrace import Dynatrace 4 | from dynatrace.environment_v2.remote_configuration import ( 5 | RemoteConfigurationManagementOperation, 6 | RemoteConfigurationManagementOperationOneAgentRequest, 7 | AttributeType, 8 | OperationType, 9 | EntityType, 10 | RemoteConfigurationManagementJobPreview, 11 | RemoteConfigurationManagementJobSummary 12 | ) 13 | from dynatrace.pagination import PaginatedList 14 | 15 | TEST_ENTITY_ID = "0x2b7c0b02" 16 | 17 | def test_list(dt: Dynatrace): 18 | jobs = dt.oneagents_remote_configuration.list() 19 | 20 | assert isinstance(jobs, PaginatedList) 21 | 22 | for job in jobs: 23 | assert isinstance(job, RemoteConfigurationManagementJobSummary) 24 | assert hasattr(job, "id") 25 | assert hasattr(job, "entity_type") 26 | assert hasattr(job, "start_time") 27 | assert isinstance(job.entity_type, EntityType) 28 | break 29 | 30 | def test_post(dt: Dynatrace): 31 | operation = RemoteConfigurationManagementOperation.build( 32 | attribute=AttributeType.NETWORK_ZONE, 33 | operation=OperationType.SET, 34 | value="test-zone" 35 | ) 36 | 37 | job = dt.oneagents_remote_configuration.post( 38 | entities=[TEST_ENTITY_ID], 39 | operations=[operation] 40 | ) 41 | 42 | assert job is not None 43 | assert job.id is not None 44 | assert job.entity_type == EntityType.ONE_AGENT 45 | assert len(job.operations) == 1 46 | assert job.operations[0].attribute == AttributeType.NETWORK_ZONE 47 | assert job.operations[0].operation == OperationType.SET 48 | assert job.operations[0].value == "test-zone" 49 | 50 | def test_get_current(dt: Dynatrace): 51 | current_job = dt.oneagents_remote_configuration.get_current() 52 | 53 | if current_job is not None: 54 | assert current_job.id is not None 55 | assert hasattr(current_job, "timeout_time") 56 | assert current_job.processed_entities_count <= current_job.total_entities_count 57 | 58 | def test_post_preview(dt: Dynatrace): 59 | operation = RemoteConfigurationManagementOperation.build( 60 | attribute=AttributeType.NETWORK_ZONE, 61 | operation=OperationType.SET, 62 | value="test-zone" 63 | ) 64 | 65 | previews = dt.oneagents_remote_configuration.post_preview( 66 | entities=[TEST_ENTITY_ID], 67 | operations=[operation] 68 | ) 69 | 70 | assert isinstance(previews, PaginatedList) 71 | 72 | for preview in previews: 73 | assert isinstance(preview, RemoteConfigurationManagementJobPreview) 74 | assert preview.attribute == AttributeType.NETWORK_ZONE 75 | assert preview.operation == OperationType.SET 76 | assert preview.value == "test-zone" 77 | assert isinstance(preview.already_configured_entities_count, int) 78 | assert isinstance(preview.target_entities_count, int) 79 | break 80 | 81 | def test_validate(dt: Dynatrace): 82 | operation = RemoteConfigurationManagementOperation.build( 83 | attribute=AttributeType.NETWORK_ZONE, 84 | operation=OperationType.SET, 85 | value="test-zone", 86 | ) 87 | 88 | validation_result = dt.oneagents_remote_configuration.validate( 89 | entities=[TEST_ENTITY_ID], 90 | operations=[operation] 91 | ) 92 | 93 | # If validation succeeds, result should be None 94 | # If validation fails, result should contain error details 95 | if validation_result is not None: 96 | assert hasattr(validation_result, "invalid_entities") 97 | assert hasattr(validation_result, "invalid_operations") 98 | assert isinstance(validation_result.invalid_entities, list) 99 | assert isinstance(validation_result.invalid_operations, list) 100 | 101 | def test_get_job(dt: Dynatrace): 102 | ID = "7974003406714390819" 103 | job = dt.oneagents_remote_configuration.get(ID) 104 | 105 | assert job is not None 106 | assert job.id == ID 107 | assert job.entity_type == EntityType.ONE_AGENT 108 | assert len(job.operations) == 1 109 | assert job.operations[0].attribute == AttributeType.NETWORK_ZONE 110 | assert job.operations[0].operation == OperationType.SET 111 | assert job.operations[0].value == "test-zone" -------------------------------------------------------------------------------- /test/environment_v2/test_service_level_objectives.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | from dynatrace.environment_v2.service_level_objectives import Slo, SloStatus, SloError, SloEvaluationType 3 | from dynatrace.pagination import PaginatedList 4 | 5 | SLO_ID = "88991da4-be17-3d57-aada-cfb3977767f4" 6 | 7 | 8 | def test_list(dt: Dynatrace): 9 | slos = dt.slos.list(enabled_slos="all") 10 | 11 | assert isinstance(slos, PaginatedList) 12 | assert len(list(slos)) == 4 13 | assert all(isinstance(s, Slo) for s in slos) 14 | 15 | 16 | def test_get(dt: Dynatrace): 17 | slo = dt.slos.get(slo_id=SLO_ID) 18 | 19 | # type checks 20 | assert isinstance(slo, Slo) 21 | assert isinstance(slo.enabled, bool) 22 | assert isinstance(slo.name, str) 23 | assert isinstance(slo.custom_description, str) 24 | assert isinstance(slo.evaluated_percentage, float) 25 | assert isinstance(slo.error_budget, float) 26 | assert isinstance(slo.status, SloStatus) 27 | assert isinstance(slo.error, SloError) 28 | assert isinstance(slo.use_rate_metric, bool) 29 | assert isinstance(slo.metric_rate, str) 30 | assert isinstance(slo.metric_numerator, str) 31 | assert isinstance(slo.metric_denominator, str) 32 | assert isinstance(slo.numerator_value, (float, int)) 33 | assert isinstance(slo.denominator_value, (float, int)) 34 | assert isinstance(slo.target, float) 35 | assert isinstance(slo.warning, float) 36 | assert isinstance(slo.evaluation_type, SloEvaluationType) 37 | assert isinstance(slo.timeframe, str) 38 | assert isinstance(slo.filter, str) 39 | assert isinstance(slo.related_open_problems, int) 40 | 41 | # value checks 42 | assert slo.id == SLO_ID 43 | assert slo.enabled == True 44 | assert slo.name == "test123" 45 | assert slo.custom_description == "test" 46 | assert slo.evaluated_percentage == 100.0 47 | assert slo.error_budget == 2.0 48 | assert slo.status == SloStatus.SUCCESS 49 | assert slo.error == SloError.NONE 50 | assert slo.metric_rate == "" 51 | assert slo.metric_numerator == "" 52 | assert slo.metric_denominator == "" 53 | assert slo.numerator_value == 0.0 54 | assert slo.denominator_value == 0.0 55 | assert slo.target == 98.0 56 | assert slo.warning == 99.0 57 | assert slo.evaluation_type == SloEvaluationType.AGGREGATE 58 | assert slo.timeframe == "now-1h" 59 | assert slo.filter == "" 60 | assert slo.related_open_problems == 0 61 | -------------------------------------------------------------------------------- /test/environment_v2/test_settings.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | from dynatrace.environment_v2.settings import SettingsObject, SettingsObjectCreate, SchemaStub 4 | from dynatrace import Dynatrace 5 | from dynatrace.pagination import PaginatedList 6 | 7 | settings_dict = { 8 | "enabled": True, 9 | "summary": "DT API TEST 22", 10 | "queryDefinition": { 11 | "type": "METRIC_KEY", 12 | "metricKey": "netapp.ontap.node.fru.state", 13 | "aggregation": "AVG", 14 | "entityFilter": { 15 | "dimensionKey": "dt.entity.netapp_ontap:fru", 16 | "conditions": [], 17 | }, 18 | "dimensionFilter": [], 19 | }, 20 | "modelProperties": { 21 | "type": "STATIC_THRESHOLD", 22 | "threshold": 100.0, 23 | "alertOnNoData": False, 24 | "alertCondition": "BELOW", 25 | "violatingSamples": 3, 26 | "samples": 5, 27 | "dealertingSamples": 5, 28 | }, 29 | "eventTemplate": { 30 | "title": "OnTap {dims:type} {dims:fru_id} is in Error State", 31 | "description": "OnTap field replaceable unit (FRU) {dims:type} with id {dims:fru_id} on node {dims:node} in cluster {dims:cluster} is in an error state.\n", 32 | "eventType": "RESOURCE", 33 | "davisMerge": True, 34 | "metadata": [], 35 | }, 36 | "eventEntityDimensionKey": "dt.entity.netapp_ontap:fru", 37 | } 38 | settings_object = SettingsObjectCreate("builtin:anomaly-detection.metric-events", settings_dict, "environment") 39 | test_object_id = "vu9U3hXa3q0AAAABACdidWlsdGluOmFub21hbHktZGV0ZWN0aW9uLm1ldHJpYy1ldmVudHMABnRlbmFudAAGdGVuYW50ACRiYmYzZWNhNy0zMmZmLTM2ZTEtOTFiOS05Y2QxZjE3OTc0YjC-71TeFdrerQ" 40 | 41 | def test_list_schemas(dt: Dynatrace): 42 | schemas = dt.settings.list_schemas() 43 | assert isinstance(schemas, PaginatedList) 44 | assert len(list(schemas)) == 3 45 | assert all(isinstance(s, SchemaStub) for s in schemas) 46 | 47 | def test_list_objects(dt: Dynatrace): 48 | settings = dt.settings.list_objects(schema_id="builtin:anomaly-detection.metric-events") 49 | assert isinstance(settings, PaginatedList) 50 | assert len(list(settings)) == 2 51 | assert all(isinstance(s, SettingsObject) for s in settings) 52 | 53 | def test_get_object(dt: Dynatrace): 54 | setting = dt.settings.get_object(object_id=test_object_id) 55 | assert isinstance(setting, SettingsObject) 56 | assert setting.schema_version == "1.0.16" 57 | 58 | def test_post_object(dt: Dynatrace): 59 | response = dt.settings.create_object(body=settings_object) 60 | assert response[0].get("code") == 200 61 | 62 | def test_put_object(dt: Dynatrace): 63 | response = dt.settings.update_object(test_object_id, settings_object) 64 | print(response) 65 | -------------------------------------------------------------------------------- /test/environment_v2/test_tokens_api.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | 3 | 4 | def test_parse_multiple_date_formats(dt: Dynatrace): 5 | """ 6 | The API can currently return two different date formats. 7 | If a token is created exactly at 0, then the millisecond portion is not returned by the API. 8 | E.g., 2025-01-19T21:36:02.000Z will be returned as 2025-01-19T21:36:02Z by API. 9 | This test ensures that both are parsed correctly. 10 | """ 11 | tokens = dt.tokens.list() 12 | assert len(tokens) == 2 13 | -------------------------------------------------------------------------------- /test/environment_v2/test_tokens_tenant.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | 3 | 4 | def test_start_rotation(dt: Dynatrace): 5 | token_config = dt.tenant_tokens.start_rotation() 6 | assert token_config.active.value == "hRCnr6Yd3BFrtxaF" 7 | assert token_config.old.value == "prv0bYw93v8sU9b1" 8 | 9 | 10 | def test_cancel_rotation(dt: Dynatrace): 11 | token_config = dt.tenant_tokens.cancel_rotation() 12 | assert token_config.active.value == "prv0bYw93v8sU9b1" 13 | assert token_config.old.value is None 14 | 15 | 16 | def test_finish_rotation(dt: Dynatrace): 17 | token_config = dt.tenant_tokens.finish_rotation() 18 | assert token_config.active.value == "prv0bYw93v8sU9b1" 19 | assert token_config.old.value is None 20 | -------------------------------------------------------------------------------- /test/mock_data/DELETE_api_v2_tags_bfb7a4f8c7f839c.json: -------------------------------------------------------------------------------- 1 | {"matchedEntitiesCount": 1} -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_alertingProfiles.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | { 4 | "id": "b1f379d9-98b4-4efe-be38-0289609c9295", 5 | "name": "deployment_change_autoremediation" 6 | }, 7 | { 8 | "id": "c21f969b-5f03-333d-83e0-4f8f136e7682", 9 | "name": "Default" 10 | }, 11 | { 12 | "id": "142e6edb-280a-4e9c-85b1-e01f5d2ee829", 13 | "name": "dbslowdwon_autoremediation" 14 | }, 15 | { 16 | "id": "b68e03c2-8a28-45a1-a516-4abce33317e7", 17 | "name": "process_crash_autoremediation" 18 | }, 19 | { 20 | "id": "caa901e6-8163-413c-ac64-5de723a400ab", 21 | "name": "rguerrero" 22 | }, 23 | { 24 | "id": "ebb53f45-6cc6-4efa-a271-1a9657a433c0", 25 | "name": "Keptn" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_alertingProfiles_b1f379d9-98b4-4efe-be38-0289609c9295.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "currentConfigurationVersions": [ 4 | "7.0.2" 5 | ], 6 | "configurationVersions": [], 7 | "clusterVersion": "1.226.21.20210831-165523" 8 | }, 9 | "id": "b1f379d9-98b4-4efe-be38-0289609c9295", 10 | "displayName": "deployment_change_autoremediation", 11 | "rules": [{ 12 | "severityLevel": "PERFORMANCE", 13 | "tagFilter": { 14 | "includeMode": "INCLUDE_ANY", 15 | "tagFilters": [{ 16 | "context": "CONTEXTLESS", 17 | "key": "Application", 18 | "value": "Custom" 19 | }] 20 | }, 21 | "delayInMinutes": 25 22 | }, 23 | { 24 | "severityLevel": "AVAILABILITY", 25 | "tagFilter": { 26 | "includeMode": "NONE", 27 | "tagFilters": [] 28 | }, 29 | "delayInMinutes": 0 30 | } 31 | ], 32 | "managementZoneId": -6238974133282121422, 33 | "mzId": "-6238974133282121422", 34 | "eventTypeFilters": [{ 35 | "customEventFilter": { 36 | "customTitleFilter": { 37 | "enabled": true, 38 | "value": "ERROR", 39 | "operator": "CONTAINS", 40 | "negate": false, 41 | "caseInsensitive": false 42 | } 43 | } 44 | }, 45 | { 46 | "predefinedEventFilter": { 47 | "eventType": "OSI_HIGH_CPU", 48 | "negate": false 49 | } 50 | } 51 | ] 52 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_anomalyDetection_metricEvents_d3baaaed-3441-4931-bf24-25c4e12e137f.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata":{ 3 | "configurationVersions":[ 4 | 6 5 | ], 6 | "clusterVersion":"1.232.0.20211122-125428" 7 | }, 8 | "id":"d3baaaed-3441-4931-bf24-25c4e12e137f", 9 | "metricId":"mint.monotonic", 10 | "name":"Mint alert for static", 11 | "description":"The {metricname} value of {severity} was {alert_condition} the baseline of {baseline}.", 12 | "aggregationType":"AVG", 13 | "severity":"ERROR", 14 | "enabled":true, 15 | "disabledReason":"NONE", 16 | "warningReason":"NONE", 17 | "monitoringStrategy":{ 18 | "type":"AUTO_ADAPTIVE_BASELINE", 19 | "samples":5, 20 | "violatingSamples":3, 21 | "dealertingSamples":5, 22 | "alertCondition":"ABOVE", 23 | "alertingOnMissingData":false, 24 | "numberOfSignalFluctuations":1.0 25 | }, 26 | "primaryDimensionKey":"dt.entity.host", 27 | "eventType":"ERROR" 28 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_anomalyDetection_metricEvents_ruxit_python_rabbitmq_node_status_node_failed.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata":{ 3 | "configurationVersions":[ 4 | 6 5 | ], 6 | "clusterVersion":"1.232.0.20211122-125428" 7 | }, 8 | "id":"ruxit.python.rabbitmq:node_status:node_failed", 9 | "metricId":"builtin:tech.rabbitmq.node_status", 10 | "name":"RabbitMQ Node failed", 11 | "description":"Node {severity} for {violating_samples}.", 12 | "aggregationType":"VALUE", 13 | "severity":"AVAILABILITY", 14 | "enabled":true, 15 | "disabledReason":"NONE", 16 | "warningReason":"NONE", 17 | "metricDimensions":[ 18 | { 19 | "filterType":"STRING", 20 | "key":null, 21 | "name":"Bucket", 22 | "index":1, 23 | "textFilter":{ 24 | "value":"failed", 25 | "operator":"EQUALS" 26 | } 27 | } 28 | ], 29 | "monitoringStrategy":{ 30 | "type":"STATIC_THRESHOLD", 31 | "samples":5, 32 | "violatingSamples":3, 33 | "dealertingSamples":5, 34 | "alertCondition":"ABOVE", 35 | "alertingOnMissingData":false, 36 | "threshold":0.0, 37 | "unit":"COUNT" 38 | }, 39 | "alertCondition":"ABOVE", 40 | "samples":5, 41 | "violatingSamples":3, 42 | "dealertingSamples":5, 43 | "threshold":0.0, 44 | "unit":"COUNT", 45 | "eventType":"AVAILABILITY" 46 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_autoTags_403e033b-7324-4bfe-bef1-b3f367de42f2.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata":{ 3 | "configurationVersions":[ 4 | 7 5 | ], 6 | "clusterVersion":"1.214.112.20210409-064503" 7 | }, 8 | "id":"403e033b-7324-4bfe-bef1-b3f367de42f2", 9 | "name":"frontend", 10 | "rules":[ 11 | { 12 | "type":"SERVICE", 13 | "enabled":true, 14 | "valueFormat":"", 15 | "propagationTypes":[ 16 | 17 | ], 18 | "conditions":[ 19 | { 20 | "key":{ 21 | "attribute":"PROCESS_GROUP_NAME" 22 | }, 23 | "comparisonInfo":{ 24 | "type":"STRING", 25 | "operator":"CONTAINS", 26 | "value":"frontend", 27 | "negate":false, 28 | "caseSensitive":false 29 | } 30 | } 31 | ] 32 | } 33 | ] 34 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_autoTags_76f44b03d6ff371.json: -------------------------------------------------------------------------------- 1 | { 2 | "values":[ 3 | { 4 | "id":"403e033b-7324-4bfe-bef1-b3f367de42f2", 5 | "name":"frontend" 6 | }, 7 | { 8 | "id":"5a4d1b61-70d2-4c3a-a561-383053a291ba", 9 | "name":"[Azure]tenant:CustomerA" 10 | }, 11 | { 12 | "id":"386a9fa6-c506-4613-9929-2240311f1bed", 13 | "name":"Cloud_AWS" 14 | }, 15 | { 16 | "id":"ea16c4b8-d74d-494e-9767-f70dd67ebb8b", 17 | "name":"k8s-namespace" 18 | }, 19 | { 20 | "id":"726bc1ee-1558-4b86-87ee-6343b43f36cd", 21 | "name":"keptn_stage" 22 | }, 23 | { 24 | "id":"a5b214b8-b2c8-4e5f-87a8-aecf37a2288d", 25 | "name":"mainframe" 26 | }, 27 | { 28 | "id":"5be4cecf-56ee-4a53-9407-6f0fb3352c70", 29 | "name":"backend" 30 | }, 31 | { 32 | "id":"e7006e3f-259e-44e6-960b-44e24ecd1602", 33 | "name":"CLOUD_TYPE_EQ_AZURE" 34 | }, 35 | { 36 | "id":"a960e358-419a-4645-afed-2726deeb53d6", 37 | "name":"Kubernetes" 38 | }, 39 | { 40 | "id":"604065a2-d6f3-482f-b07e-7c3c1dd4293c", 41 | "name":"Citrix" 42 | }, 43 | { 44 | "id":"8f289697-6e38-4d1c-b37c-806db60930c3", 45 | "name":"Cloud_Azure" 46 | }, 47 | { 48 | "id":"8b5f6b33-c3ed-4a8f-8cbd-303be72991b3", 49 | "name":"BOSH-managed VM" 50 | }, 51 | { 52 | "id":"269ce931-3663-4f5a-a0e4-fae11c1ea372", 53 | "name":"CFAppID" 54 | }, 55 | { 56 | "id":"82d04c9f-75cc-4025-bb6b-65c9e0ae2671", 57 | "name":"[Kubernetes]namespace" 58 | }, 59 | { 60 | "id":"bcebbffd-1f87-43a6-9e67-7370cbd0eeb4", 61 | "name":"HostName" 62 | }, 63 | { 64 | "id":"5137a0c6-4a17-46c1-b62c-a8fdcf291f98", 65 | "name":"kubernetes-pod" 66 | }, 67 | { 68 | "id":"8ed1b53e-b4df-4b0d-9d43-7e7479435f05", 69 | "name":"Database" 70 | }, 71 | { 72 | "id":"7b335586-8888-4b8c-ae44-255317684d58", 73 | "name":"DT-ContainerBoundariesAffected" 74 | }, 75 | { 76 | "id":"d54b621d-698e-411f-b16c-246f4d1f5540", 77 | "name":"Azure" 78 | }, 79 | { 80 | "id":"506a7cf2-3051-49a1-89c2-cb84a24883b9", 81 | "name":"keptn_service" 82 | }, 83 | { 84 | "id":"8151916e-48d9-4b45-85c0-8aa55fc9818d", 85 | "name":"OpenShift" 86 | }, 87 | { 88 | "id":"47cb86ac-d7ce-4fd0-ac79-401e8ff3883f", 89 | "name":"keptn_deployment" 90 | }, 91 | { 92 | "id":"678fbc80-ca89-40b6-a385-0b77cbb25321", 93 | "name":"SAP" 94 | }, 95 | { 96 | "id":"834fa6ce-c080-4872-8b23-36ac989b31e6", 97 | "name":"kubernetes-namespace" 98 | }, 99 | { 100 | "id":"e2cd51ef-3a39-4bab-b918-23f5eaed23c0", 101 | "name":"cloudfoundry-space" 102 | }, 103 | { 104 | "id":"8b50bc39-55d9-4f1e-babf-d47e7515b0c4", 105 | "name":"Cloud_VMWare" 106 | }, 107 | { 108 | "id":"378a1a56-b16f-4fee-910a-f180103b8948", 109 | "name":"keptn_project" 110 | } 111 | ] 112 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_extensions_76f44b03d6ff371.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensions": [ 3 | { 4 | "id": "custom.remote.python.certificates", 5 | "name": "Certificates Plugin", 6 | "type": "ACTIVEGATE" 7 | }, 8 | { 9 | "id": "custom.remote.python.dbquery", 10 | "name": "Generic DB Query Plugin", 11 | "type": "ACTIVEGATE" 12 | }, 13 | { 14 | "id": "custom.remote.python.salesforce_eventstream", 15 | "name": "Salesforce EventStream", 16 | "type": "ACTIVEGATE" 17 | }, 18 | { 19 | "id": "dynatrace.jmx.Hadoop.HDFS", 20 | "name": "Apache Hadoop HDFS", 21 | "type": "JMX" 22 | }, 23 | { 24 | "id": "dynatrace.jmx.Hadoop.yarn", 25 | "name": "Apache Hadoop YARN", 26 | "type": "JMX" 27 | }, 28 | { 29 | "id": "dynatrace.jmx.activemq", 30 | "name": "ActiveMQ JMX", 31 | "type": "JMX" 32 | }, 33 | { 34 | "id": "dynatrace.jmx.appserver.jetty", 35 | "name": "Jetty JMX", 36 | "type": "JMX" 37 | }, 38 | { 39 | "id": "dynatrace.jmx.cassandra", 40 | "name": "Cassandra JMX", 41 | "type": "JMX" 42 | }, 43 | { 44 | "id": "dynatrace.jmx.hornetq", 45 | "name": "HornetQ JMX", 46 | "type": "JMX" 47 | }, 48 | { 49 | "id": "dynatrace.jmx.jboss.connectionpool", 50 | "name": "JBoss Connection Pools", 51 | "type": "JMX" 52 | }, 53 | { 54 | "id": "dynatrace.jmx.kafka", 55 | "name": "Kafka JMX", 56 | "type": "JMX" 57 | }, 58 | { 59 | "id": "dynatrace.jmx.liberty.appserver", 60 | "name": "WebSphere Liberty Appserver", 61 | "type": "JMX" 62 | }, 63 | { 64 | "id": "dynatrace.jmx.liberty.connectionpool", 65 | "name": "WebSphere Liberty Connection Pools", 66 | "type": "JMX" 67 | }, 68 | { 69 | "id": "dynatrace.jmx.netflix.servo", 70 | "name": "Netflix OSS JMX", 71 | "type": "JMX" 72 | }, 73 | { 74 | "id": "dynatrace.jmx.solr", 75 | "name": "Solr JMX", 76 | "type": "JMX" 77 | }, 78 | { 79 | "id": "dynatrace.jmx.spark", 80 | "name": "Apache Spark", 81 | "type": "JMX" 82 | }, 83 | { 84 | "id": "dynatrace.jmx.tomcat.connectionpool", 85 | "name": "Tomcat Connection Pools", 86 | "type": "JMX" 87 | }, 88 | { 89 | "id": "dynatrace.jmx.weblogic.connectionpool", 90 | "name": "WebLogic Connection Pools", 91 | "type": "JMX" 92 | }, 93 | { 94 | "id": "dynatrace.jmx.wso2-api-manager", 95 | "name": "WSO2 API Manager", 96 | "type": "JMX" 97 | }, 98 | { 99 | "id": "dynatrace.python.coredns", 100 | "name": "CoreDNS", 101 | "type": "ONEAGENT" 102 | }, 103 | { 104 | "id": "dynatrace.python.couchbase", 105 | "name": "Couchbase", 106 | "type": "ONEAGENT" 107 | }, 108 | { 109 | "id": "dynatrace.python.couchdb", 110 | "name": "CouchDB", 111 | "type": "ONEAGENT" 112 | }, 113 | { 114 | "id": "dynatrace.python.docker", 115 | "name": "Docker technology monitoring", 116 | "type": "ONEAGENT" 117 | }, 118 | { 119 | "id": "dynatrace.python.elasticsearch", 120 | "name": "Elasticsearch", 121 | "type": "ONEAGENT" 122 | }, 123 | { 124 | "id": "dynatrace.python.haproxy", 125 | "name": "HAProxy", 126 | "type": "ONEAGENT" 127 | }, 128 | { 129 | "id": "dynatrace.python.memcached", 130 | "name": "Memcached", 131 | "type": "ONEAGENT" 132 | }, 133 | { 134 | "id": "dynatrace.python.mongodb", 135 | "name": "MongoDB", 136 | "type": "ONEAGENT" 137 | }, 138 | { 139 | "id": "dynatrace.python.mssql", 140 | "name": "MS SQL", 141 | "type": "ONEAGENT" 142 | }, 143 | { 144 | "id": "dynatrace.python.mysql", 145 | "name": "MySQL", 146 | "type": "ONEAGENT" 147 | }, 148 | { 149 | "id": "dynatrace.python.ntp", 150 | "name": "NTP", 151 | "type": "ONEAGENT" 152 | }, 153 | { 154 | "id": "dynatrace.python.phpfpm", 155 | "name": "PHP-FPM", 156 | "type": "ONEAGENT" 157 | }, 158 | { 159 | "id": "dynatrace.python.postgresql", 160 | "name": "PostgreSQL", 161 | "type": "ONEAGENT" 162 | }, 163 | { 164 | "id": "dynatrace.python.rabbitmq", 165 | "name": "RabbitMQ", 166 | "type": "ONEAGENT" 167 | }, 168 | { 169 | "id": "dynatrace.python.redis", 170 | "name": "Redis", 171 | "type": "ONEAGENT" 172 | }, 173 | { 174 | "id": "dynatrace.remote.python.elasticsearch", 175 | "name": "Elasticsearch Cloud", 176 | "type": "ACTIVEGATE" 177 | } 178 | ], 179 | "totalResults": 35 180 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_extensions_activeGateExtensionModules.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | { 4 | "id": "-7885258652650793909", 5 | "name": "arch-david" 6 | }, 7 | { 8 | "id": "-7683927725266039098", 9 | "name": "windows-david" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_extensions_custom_python_citrixAgent.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "custom.python.citrixAgent", 3 | "name": "Citrix Virtual Apps & Virtual Desktops", 4 | "version": "2.034", 5 | "type": "ONEAGENT", 6 | "metricGroup": "tech.Citrix", 7 | "metadata": { 8 | "configurationVersions": [ 9 | 0 10 | ], 11 | "clusterVersion": "1.217.103.20210511-092057" 12 | }, 13 | "properties": [ 14 | { 15 | "key": "openkit_verify_certificates", 16 | "type": "BOOLEAN", 17 | "defaultValue": "" 18 | }, 19 | { 20 | "key": "openkit_use_oneagent_endpoints", 21 | "type": "BOOLEAN", 22 | "defaultValue": "false" 23 | }, 24 | { 25 | "key": "openkit_application_id", 26 | "type": "STRING", 27 | "defaultValue": "" 28 | }, 29 | { 30 | "key": "monitoring_mode", 31 | "type": "DROPDOWN", 32 | "defaultValue": "Basic", 33 | "dropdownValues": [ 34 | "Basic", 35 | "Default", 36 | "Advanced" 37 | ] 38 | }, 39 | { 40 | "key": "openkit_beacon_url", 41 | "type": "STRING", 42 | "defaultValue": "" 43 | }, 44 | { 45 | "key": "openkit_proxy_username", 46 | "type": "STRING", 47 | "defaultValue": "" 48 | }, 49 | { 50 | "key": "log_level", 51 | "type": "DROPDOWN", 52 | "defaultValue": "INFO", 53 | "dropdownValues": [ 54 | "INFO", 55 | "DEBUG" 56 | ] 57 | }, 58 | { 59 | "key": "citrixagent_run", 60 | "type": "DROPDOWN", 61 | "defaultValue": "Enabled", 62 | "dropdownValues": [ 63 | "Enabled", 64 | "Disabled" 65 | ] 66 | }, 67 | { 68 | "key": "openkit_proxy_address", 69 | "type": "STRING", 70 | "defaultValue": "" 71 | }, 72 | { 73 | "key": "openkit_proxy_password", 74 | "type": "PASSWORD", 75 | "defaultValue": "" 76 | } 77 | ] 78 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_extensions_custom_python_citrixAgent_global.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionId": "custom.python.citrixAgent", 3 | "enabled": true, 4 | "infraOnlyEnabled": false, 5 | "properties": { 6 | "openkit_verify_certificates": "", 7 | "openkit_use_oneagent_endpoints": "false", 8 | "openkit_application_id": "", 9 | "monitoring_mode": "Basic", 10 | "openkit_beacon_url": "", 11 | "openkit_proxy_username": "", 12 | "log_level": "INFO", 13 | "citrixagent_run": "Enabled", 14 | "openkit_proxy_address": "", 15 | "openkit_proxy_password": null 16 | } 17 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_extensions_custom_remote_python_salesforce_eventstream_instances_5649014104314746667.json: -------------------------------------------------------------------------------- 1 | { 2 | "extensionId": "5649014104314746667", 3 | "enabled": true, 4 | "useGlobal": null, 5 | "properties": { 6 | "salesforce_password": null, 7 | "capture_listview": "true", 8 | "max_session_age_minutes": "1440", 9 | "proxy_address": "http://192.168.15.101:3128", 10 | "proxy_username": "", 11 | "capture_uri": "true", 12 | "log_level": "INFO", 13 | "salesforce_username": "david.lopes@dynapoc.unicredit0001", 14 | "proxy_password": null, 15 | "capture_report": "true", 16 | "capture_lightning_uri": "true", 17 | "salesforce_security_token": null, 18 | "openkit_application_id": "87eee414-9338-446b-988b-bbdbf495c4f4", 19 | "openkit_beacon_url": "https://localhost:9999/mbeacon/eaa50379", 20 | "capture_api": "true", 21 | "capture_user_details": "true" 22 | }, 23 | "activeGate": { 24 | "id": "-7885258652650793909", 25 | "name": "arch-david" 26 | }, 27 | "endpointId": "5649014104314746667", 28 | "endpointName": "curious-hawk" 29 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_extensions_custom_remote_python_salesforce_eventstream_states.json: -------------------------------------------------------------------------------- 1 | { 2 | "states": [ 3 | { 4 | "extensionId": "custom.remote.python.salesforce_eventstream", 5 | "version": "", 6 | "endpointId": "5649014104314746667", 7 | "state": "ERROR_CONFIG", 8 | "stateDescription": "Extension doesn't exist on given host", 9 | "timestamp": 1620943873929, 10 | "hostId": null, 11 | "processId": null 12 | } 13 | ], 14 | "totalResults": 1 15 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_hostgroups_HOST_GROUP-ABC123DEF456GHI7.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": null, 3 | "autoUpdateConfig": { 4 | "metadata": { 5 | "configurationVersions": [ 6 | 2 7 | ], 8 | "clusterVersion": "1.222.47.20210712-162143" 9 | }, 10 | "id": "HOST_GROUP-ABC123DEF456GHI7", 11 | "setting": "DISABLED", 12 | "version": null, 13 | "updateWindows": { 14 | "windows": [] 15 | }, 16 | "effectiveSetting": "DISABLED", 17 | "effectiveVersion": null 18 | } 19 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_hostgroups_HOST_GROUP-ABC123DEF456GHI7_autoupdate.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "configurationVersions": [ 4 | 2 5 | ], 6 | "clusterVersion": "1.222.47.20210712-162143" 7 | }, 8 | "id": "HOST_GROUP-ABC123DEF456GHI7", 9 | "setting": "DISABLED", 10 | "version": null, 11 | "updateWindows": { 12 | "windows": [] 13 | }, 14 | "effectiveSetting": "DISABLED", 15 | "effectiveVersion": null 16 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_hosts_HOST-abcd123457.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "HOST-abcd123457", 3 | "monitoringConfig": { 4 | "metadata": { 5 | "configurationVersions": [ 6 | 9 7 | ], 8 | "clusterVersion": "1.222.47.20210712-162143" 9 | }, 10 | "id": "HOST-abcd123457", 11 | "monitoringEnabled": true, 12 | "monitoringMode": "FULL_STACK" 13 | }, 14 | "autoUpdateConfig": { 15 | "metadata": { 16 | "configurationVersions": [ 17 | 0 18 | ], 19 | "clusterVersion": "1.222.47.20210712-162143" 20 | }, 21 | "id": "HOST-abcd123457", 22 | "setting": "DISABLED", 23 | "version": null, 24 | "updateWindows": { 25 | "windows": [] 26 | }, 27 | "effectiveSetting": "DISABLED", 28 | "effectiveVersion": null 29 | }, 30 | "techMonitoringConfigList": { 31 | "metadata": { 32 | "configurationVersions": [ 33 | 89, 34 | 9 35 | ], 36 | "clusterVersion": "1.222.47.20210712-162143" 37 | }, 38 | "technologies": [{ 39 | "type": "LOG_ANALYTICS", 40 | "monitoringEnabled": true, 41 | "scope": "ENVIRONMENT" 42 | }, 43 | { 44 | "type": "RUBY", 45 | "monitoringEnabled": false, 46 | "scope": "ENVIRONMENT" 47 | }, 48 | { 49 | "type": "OPENTRACINGNATIVE", 50 | "monitoringEnabled": false, 51 | "scope": "ENVIRONMENT" 52 | }, 53 | { 54 | "type": "DOT_NET", 55 | "monitoringEnabled": true, 56 | "scope": "ENVIRONMENT" 57 | } 58 | ] 59 | } 60 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_hosts_HOST-abcd123457_autoupdate.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "configurationVersions": [ 4 | 0 5 | ], 6 | "clusterVersion": "1.222.47.20210712-162143" 7 | }, 8 | "id": "HOST-abcd123457", 9 | "setting": "DISABLED", 10 | "version": null, 11 | "updateWindows": { 12 | "windows": [] 13 | }, 14 | "effectiveSetting": "DISABLED", 15 | "effectiveVersion": null 16 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_hosts_HOST-abcd123457_monitoring.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "configurationVersions": [ 4 | 9 5 | ], 6 | "clusterVersion": "1.222.47.20210712-162143" 7 | }, 8 | "id": "HOST-abcd123457", 9 | "monitoringEnabled": true, 10 | "monitoringMode": "FULL_STACK" 11 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_hosts_HOST-abcd123457_technologies.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "configurationVersions": [ 4 | 89, 5 | 9 6 | ], 7 | "clusterVersion": "1.222.47.20210712-162143" 8 | }, 9 | "technologies": [{ 10 | "type": "LOG_ANALYTICS", 11 | "monitoringEnabled": true, 12 | "scope": "ENVIRONMENT" 13 | }, 14 | { 15 | "type": "RUBY", 16 | "monitoringEnabled": false, 17 | "scope": "ENVIRONMENT" 18 | }, 19 | { 20 | "type": "OPENTRACINGNATIVE", 21 | "monitoringEnabled": false, 22 | "scope": "ENVIRONMENT" 23 | }, 24 | { 25 | "type": "DOT_NET", 26 | "monitoringEnabled": true, 27 | "scope": "ENVIRONMENT" 28 | } 29 | ] 30 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_hosts_autoupdate.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "configurationVersions": [ 4 | 0 5 | ], 6 | "clusterVersion": "1.222.47.20210712-162143" 7 | }, 8 | "setting": "DISABLED", 9 | "version": null, 10 | "updateWindows": { 11 | "windows": [] 12 | } 13 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_maintenanceWindows.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | { 4 | "id": "b6376a12-0b82-4069-9a41-0e55ef9a1f44", 5 | "name": "Example Window", 6 | "description": "An example Maintenance window" 7 | }, 8 | { 9 | "id": "befa9c77-ade3-463f-ad3a-743d5a271880", 10 | "name": "Example Window", 11 | "description": "An example Maintenance window" 12 | }, 13 | { 14 | "id": "15d42c47-051c-4b4a-96b8-3af5040b8f66", 15 | "name": "Example Window", 16 | "description": "An example Maintenance window" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_maintenanceWindows_b6376a12-0b82-4069-9a41-0e55ef9a1f44.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "configurationVersions": [ 4 | 0 5 | ], 6 | "clusterVersion": "1.238.53.20220318-123456" 7 | }, 8 | "id": "b6376a12-0b82-4069-9a41-0e55ef9a1f44", 9 | "name": "Example Window", 10 | "description": "An example Maintenance window", 11 | "type": "UNPLANNED", 12 | "enabled": true, 13 | "suppression": "DETECT_PROBLEMS_AND_ALERT", 14 | "suppressSyntheticMonitorsExecution": true, 15 | "scope": { 16 | "entities": [ 17 | "HOST-0000000000123456" 18 | ], 19 | "matches": [ 20 | { 21 | "type": "HOST", 22 | "managementZoneId": -5283929364044076000, 23 | "mzId": "-5283929364044076484", 24 | "tags": [ 25 | { 26 | "context": "AWS", 27 | "key": "testkey", 28 | "value": "testvalue" 29 | } 30 | ], 31 | "tagCombination": "AND" 32 | } 33 | ] 34 | }, 35 | "schedule": { 36 | "recurrenceType": "ONCE", 37 | "start": "2018-08-02 00:00", 38 | "end": "2021-02-27 00:00", 39 | "zoneId": "Europe/Vienna" 40 | } 41 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_managementZones_6507829326603756920.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "configurationVersions": [ 4 | 0 5 | ], 6 | "clusterVersion": "1.237.130.20220311-144350" 7 | }, 8 | "id": "6507829326603756920", 9 | "name": "Frontend Services", 10 | "description": null, 11 | "rules": [ 12 | { 13 | "type": "SERVICE", 14 | "enabled": true, 15 | "propagationTypes": [ 16 | "SERVICE_TO_PROCESS_GROUP_LIKE" 17 | ], 18 | "conditions": [ 19 | { 20 | "key": { 21 | "attribute": "PROCESS_GROUP_CUSTOM_METADATA", 22 | "dynamicKey": { 23 | "source": "ENVIRONMENT", 24 | "key": "SERVICE_TYPE" 25 | }, 26 | "type": "PROCESS_CUSTOM_METADATA_KEY" 27 | }, 28 | "comparisonInfo": { 29 | "type": "STRING", 30 | "operator": "EQUALS", 31 | "value": "FRONTEND", 32 | "negate": false, 33 | "caseSensitive": true 34 | } 35 | } 36 | ] 37 | } 38 | ], 39 | "dimensionalRules": [], 40 | "entitySelectorBasedRules": [] 41 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_managementZones_76f44b03d6ff371.json: -------------------------------------------------------------------------------- 1 | { 2 | "values": [ 3 | { 4 | "id": "6507829326603756920", 5 | "name": "Frontend Services" 6 | }, 7 | { 8 | "id": "-8521824865418595254", 9 | "name": "ZEV" 10 | }, 11 | { 12 | "id": "-7409477718575261721", 13 | "name": "SQL" 14 | }, 15 | { 16 | "id": "-8688695753416735127", 17 | "name": "Architect Team" 18 | }, 19 | { 20 | "id": "-211422878468461018", 21 | "name": "test2", 22 | "description": "" 23 | }, 24 | { 25 | "id": "6841456773259382933", 26 | "name": "Env: Prod" 27 | }, 28 | { 29 | "id": "8074341982397537498", 30 | "name": "Keptn: unleash dev" 31 | } 32 | ] 33 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_notifications.json: -------------------------------------------------------------------------------- 1 | { 2 | "values":[ 3 | { 4 | "id":"0d06c889-4cea-4b45-aefa-a277790e784d", 5 | "name":"Service Now Example", 6 | "type":"SERVICE_NOW" 7 | }, 8 | { 9 | "id":"3e921ece-3e52-4392-a5f5-7d089d6a80d1", 10 | "name":"keptn remediation", 11 | "type":"WEBHOOK" 12 | }, 13 | { 14 | "id":"aaf00e30-6b5a-47c6-a760-ecc01d8c61fa", 15 | "name":"Email-2", 16 | "type":"EMAIL" 17 | }, 18 | { 19 | "id":"d748eb3d-0bc7-3741-ac9f-e30df03b12ee", 20 | "name":"Test", 21 | "type":"EMAIL" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_notifications_0d06c889-4cea-4b45-aefa-a277790e784d.json: -------------------------------------------------------------------------------- 1 | { 2 | "type":"SERVICE_NOW", 3 | "id":"0d06c889-4cea-4b45-aefa-a277790e784d", 4 | "name":"Service Now Example", 5 | "alertingProfile":"7693d108-fda9-3529-8ca3-55e9269b6097", 6 | "active":true, 7 | "instanceName":"dev63549", 8 | "url":null, 9 | "username":"admin", 10 | "password":null, 11 | "message":"{State} {ProblemID} {ProblemImpact} {ProblemSeverity}", 12 | "sendIncidents":true, 13 | "sendEvents":false 14 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_config_v1_technologies.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": { 3 | "configurationVersions": [ 4 | 89 5 | ], 6 | "clusterVersion": "1.222.47.20210712-162143" 7 | }, 8 | "technologies": [{ 9 | "type": "DOT_NET", 10 | "monitoringEnabled": true, 11 | "scope": "ENVIRONMENT" 12 | }, 13 | { 14 | "type": "GO", 15 | "monitoringEnabled": true, 16 | "scope": "ENVIRONMENT" 17 | }, 18 | { 19 | "type": "PHP_CGI", 20 | "monitoringEnabled": false, 21 | "scope": "ENVIRONMENT" 22 | }, 23 | { 24 | "type": "DOCKER_WIN", 25 | "monitoringEnabled": true, 26 | "scope": "ENVIRONMENT" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v1_deployment_boshrelease_agent_unix_version_1_215_159_20210428-145534_checksum_fad478b86718411.json: -------------------------------------------------------------------------------- 1 | { 2 | "sha256": "8747793999922D34666A26F48C2061E598B164159015D12103A5D55A4F05225C" 3 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v1_deployment_boshrelease_versions_unix.json: -------------------------------------------------------------------------------- 1 | { 2 | "availableVersions": [ 3 | "1.215.159.20210428-145534", 4 | "1.219.133.20210624-130507", 5 | "1.221.42.20210628-133019", 6 | "1.221.87.20210707-201934", 7 | "1.219.110.20210616-151105", 8 | "1.221.84.20210706-113445" 9 | ] 10 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v1_deployment_installer_agent_connectioninfo_5cfedcf2b045507.json: -------------------------------------------------------------------------------- 1 | { 2 | "tenantUUID": "abc12345", 3 | "tenantToken": "4BcD3fGh1JkLmN0p", 4 | "communicationEndpoints": [ 5 | "https://host.docker.internal:9999/communication", 6 | "https://some.activegate.domain:9999/communication", 7 | "https://192.168.0.0:9999/communication", 8 | "https://abc12345.live.dynatrace.com:443" 9 | ], 10 | "formattedCommunicationEndpoints": "{https://host.docker.internal:9999/communication;https://some.activegate.domain:9999/communication;https://192.168.0.0:9999/communication;https://abc12345.live.dynatrace.com:443}" 11 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v1_deployment_installer_agent_unix_paas_latest_metainfo_162a156059a3150.json: -------------------------------------------------------------------------------- 1 | { 2 | "latestAgentVersion": "1.215.159.20210428-145534" 3 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v1_deployment_installer_agent_versions_unix_paas_37c730b12310340.json: -------------------------------------------------------------------------------- 1 | { 2 | "availableVersions": [ 3 | "1.215.159.20210428-145534", 4 | "1.219.133.20210624-130507", 5 | "1.221.42.20210628-133019", 6 | "1.221.87.20210707-201934", 7 | "1.219.110.20210616-151105", 8 | "1.221.84.20210706-113445" 9 | ] 10 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v1_deployment_installer_gateway_connectioninfo_5e7bba15048d70e.json: -------------------------------------------------------------------------------- 1 | { 2 | "tenantUUID": "abc12345", 3 | "tenantToken": "4BcD3fGh1JkLmN0p", 4 | "communicationEndpoints": "https://sg-eu-west-1234.domain.com/communication,https://sg-eu-west-1234.domain.com/communication,https://abc12345.live.dynatrace.com:443/communication" 5 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v1_deployment_installer_gateway_versions_unix.json: -------------------------------------------------------------------------------- 1 | { 2 | "availableVersions": [ 3 | "1.215.159.20210428-145534", 4 | "1.219.133.20210624-130507", 5 | "1.221.42.20210628-133019", 6 | "1.221.87.20210707-201934", 7 | "1.219.110.20210616-151105", 8 | "1.221.84.20210706-113445" 9 | ] 10 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v1_deployment_lambda_agent_latest.json: -------------------------------------------------------------------------------- 1 | { 2 | "java": "Dynatrace_OneAgent_1_221_103_20210713-172057", 3 | "python": "Dynatrace_OneAgent_1_221_3_20210624-164237", 4 | "nodejs": "Dynatrace_OneAgent_1_221_1_20210618-040655" 5 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v1_synthetic_monitors_5a712d431f0dc23.json: -------------------------------------------------------------------------------- 1 | { 2 | "monitors":[ 3 | { 4 | "name":"angular easytravel bounce", 5 | "entityId":"SYNTHETIC_TEST-7639A3AED66940FA", 6 | "type":"BROWSER", 7 | "enabled":true 8 | }, 9 | { 10 | "name":"www.angular.easytravel.com", 11 | "entityId":"SYNTHETIC_TEST-30C72F9255ED128D", 12 | "type":"BROWSER", 13 | "enabled":true 14 | }, 15 | { 16 | "name":"Google Hipster Shop", 17 | "entityId":"SYNTHETIC_TEST-10E43FE0212A5C82", 18 | "type":"BROWSER", 19 | "enabled":true 20 | }, 21 | { 22 | "name":"angular easytravel abandon", 23 | "entityId":"SYNTHETIC_TEST-59ADE6AB7BCCF957", 24 | "type":"BROWSER", 25 | "enabled":true 26 | }, 27 | { 28 | "name":"CNN", 29 | "entityId":"SYNTHETIC_TEST-03A56B42FD5BC08F", 30 | "type":"BROWSER", 31 | "enabled":true 32 | }, 33 | { 34 | "name":"www.weather.easytravel.com", 35 | "entityId":"SYNTHETIC_TEST-0000000000005724", 36 | "type":"BROWSER", 37 | "enabled":true 38 | }, 39 | { 40 | "name":"perfwear-shop", 41 | "entityId":"SYNTHETIC_TEST-1A2CC381A76FDE68", 42 | "type":"BROWSER", 43 | "enabled":true 44 | }, 45 | { 46 | "name":"easyTravel booking", 47 | "entityId":"SYNTHETIC_TEST-0000000000005721", 48 | "type":"BROWSER", 49 | "enabled":true 50 | }, 51 | { 52 | "name":"angular easytravel booking", 53 | "entityId":"SYNTHETIC_TEST-212D2C9601E54CED", 54 | "type":"BROWSER", 55 | "enabled":true 56 | } 57 | ] 58 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v1_synthetic_monitors_SYNTHETIC_TEST-7639A3AED66940FA.json: -------------------------------------------------------------------------------- 1 | { 2 | "entityId":"SYNTHETIC_TEST-7639A3AED66940FA", 3 | "name":"angular easytravel bounce", 4 | "frequencyMin":5, 5 | "enabled":true, 6 | "type":"BROWSER", 7 | "createdFrom":"API", 8 | "script":{ 9 | "type":"clickpath", 10 | "version":"1.0", 11 | "configuration":{ 12 | "device":{ 13 | "deviceName":"Desktop", 14 | "orientation":"landscape" 15 | } 16 | }, 17 | "events":[ 18 | { 19 | "type":"navigate", 20 | "description":"Loading of \"https://easytravel-angular-demo1.internal.dynatracelabs.com/?utm_source=email&utm_medium=email&utm_campaign=spring_sale\"", 21 | "url":"https://easytravel-angular-demo1.internal.dynatracelabs.com/?utm_source=email&utm_medium=email&utm_campaign=spring_sale", 22 | "wait":{ 23 | "waitFor":"page_complete" 24 | } 25 | }, 26 | { 27 | "type":"click", 28 | "description":"click on \"header:specialoffers\"", 29 | "target":{ 30 | "locators":[ 31 | { 32 | "type":"css", 33 | "value":"#header\\:specialoffers" 34 | }, 35 | { 36 | "type":"css", 37 | "value":"a:contains(\"Special offers\")" 38 | }, 39 | { 40 | "type":"css", 41 | "value":"html body:nth-child(19) app-root app-dashboard:nth-child(2) app-main-layout div app-header header nav:nth-child(2) a" 42 | } 43 | ] 44 | }, 45 | "button":0, 46 | "wait":{ 47 | "waitFor":"network" 48 | } 49 | } 50 | ] 51 | }, 52 | "locations":[ 53 | "GEOLOCATION-E01B833216FC3598" 54 | ], 55 | "anomalyDetection":{ 56 | "outageHandling":{ 57 | "globalOutage":false, 58 | "localOutage":true, 59 | "localOutagePolicy":{ 60 | "affectedLocations":1, 61 | "consecutiveRuns":1 62 | }, 63 | "retryOnError":true 64 | }, 65 | "loadingTimeThresholds":{ 66 | "enabled":false, 67 | "thresholds":[ 68 | 69 | ] 70 | } 71 | }, 72 | "tags":[ 73 | 74 | ], 75 | "managementZones":[ 76 | { 77 | "id":"2557473151390310784", 78 | "name":"easytravel Apps" 79 | }, 80 | { 81 | "id":"-4188763185079505174", 82 | "name":"Production" 83 | } 84 | ], 85 | "automaticallyAssignedApps":[ 86 | 87 | ], 88 | "manuallyAssignedApps":[ 89 | 90 | ], 91 | "keyPerformanceMetrics":{ 92 | "loadActionKpm":"VISUALLY_COMPLETE", 93 | "xhrActionKpm":"VISUALLY_COMPLETE" 94 | }, 95 | "events":[ 96 | { 97 | "entityId":"SYNTHETIC_TEST_STEP-669BB9AF82C6F2E9", 98 | "name":"Loading of \"https://easytravel-angular-demo1.internal.dynatracelabs.com/?utm_source=email&utm_medium=email&utm_campaign=spring_sale\"", 99 | "sequenceNumber":1 100 | }, 101 | { 102 | "entityId":"SYNTHETIC_TEST_STEP-368D89D2177A87B6", 103 | "name":"click on \"header:specialoffers\"", 104 | "sequenceNumber":2 105 | } 106 | ] 107 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_activeGates_-1556499193_updateJobs_5b76ac60bd217e9.json: -------------------------------------------------------------------------------- 1 | { 2 | "agId": "-1556499193", 3 | "updateJobs": [ 4 | { 5 | "jobId": "-4754066816153208332", 6 | "jobState": "SUCCEED", 7 | "updateMethod": "MANUAL_INSTALLATION", 8 | "updateType": "ACTIVE_GATE", 9 | "cancelable": false, 10 | "startVersion": "1.217.89.20210506-182520", 11 | "targetVersion": "1.217.96.20210507-181038", 12 | "timestamp": 1620419177047, 13 | "agType": "ENVIRONMENT", 14 | "environments": [ 15 | "eaa50379" 16 | ], 17 | "error": null, 18 | "duration": null 19 | }, 20 | { 21 | "jobId": "5075770917171973084", 22 | "jobState": "SUCCEED", 23 | "updateMethod": "MANUAL_INSTALLATION", 24 | "updateType": "ACTIVE_GATE", 25 | "cancelable": false, 26 | "startVersion": "1.217.84.20210505-174021", 27 | "targetVersion": "1.217.89.20210506-182520", 28 | "timestamp": 1620332833412, 29 | "agType": "ENVIRONMENT", 30 | "environments": [ 31 | "eaa50379" 32 | ], 33 | "error": null, 34 | "duration": null 35 | }, 36 | { 37 | "jobId": "-6499213237883713862", 38 | "jobState": "SUCCEED", 39 | "updateMethod": "MANUAL_INSTALLATION", 40 | "updateType": "ACTIVE_GATE", 41 | "cancelable": false, 42 | "startVersion": "1.217.75.20210504-201049", 43 | "targetVersion": "1.217.84.20210505-174021", 44 | "timestamp": 1620245814673, 45 | "agType": "ENVIRONMENT", 46 | "environments": [ 47 | "eaa50379" 48 | ], 49 | "error": null, 50 | "duration": null 51 | } 52 | ] 53 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_activeGates_1513404008_autoUpdate.json: -------------------------------------------------------------------------------- 1 | { 2 | "setting": "ENABLED", 3 | "effectiveSetting": "ENABLED" 4 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_activeGates_autoUpdate.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalSetting": "DISABLED", 3 | "metadata": { 4 | "configurationVersions": [ 5 | 1 6 | ], 7 | "clusterVersion": "1.217.96.20210507-181038" 8 | } 9 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_activeGates_remoteConfigurationManagement_2e5fcbd2c8d0e63.json: -------------------------------------------------------------------------------- 1 | { 2 | "jobs": [ 3 | { 4 | "endTime": "2020-11-05T08:15:30.144Z", 5 | "entityType": "ACTIVE_GATE", 6 | "id": "7974003406714390819", 7 | "startTime": "2020-11-05T08:15:30.144Z" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_activeGates_remoteConfigurationManagement_7974003406714390819.json: -------------------------------------------------------------------------------- 1 | { 2 | "endTime": "2020-11-05T08:15:30.144Z", 3 | "entityType": "ACTIVE_GATE", 4 | "id": "7974003406714390819", 5 | "operations": [ 6 | { 7 | "attribute": "networkZone", 8 | "operation": "set", 9 | "value": "test-zone" 10 | } 11 | ], 12 | "processedEntitiesCount": 1, 13 | "startTime": "2020-11-05T08:15:30.144Z", 14 | "timeoutTime": "2020-11-05T08:15:30.144Z", 15 | "totalEntitiesCount": 1 16 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_activeGates_remoteConfigurationManagement_current.json: -------------------------------------------------------------------------------- 1 | { 2 | "endTime": "2020-11-05T08:15:30.144Z", 3 | "entityType": "ACTIVE_GATE", 4 | "id": "7974003406714390819", 5 | "operations": [ 6 | { 7 | "attribute": "networkZone", 8 | "operation": "set", 9 | "value": "exampleNetworkZoneName" 10 | } 11 | ], 12 | "processedEntitiesCount": 1, 13 | "startTime": "2020-11-05T08:15:30.144Z", 14 | "timeoutTime": "2020-11-05T08:15:30.144Z", 15 | "totalEntitiesCount": 1 16 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_activeGates_remoteConfigurationManagement_preview_4cfaf0a9b26d2dd.json: -------------------------------------------------------------------------------- 1 | { 2 | "previews": [ 3 | { 4 | "alreadyConfiguredEntitiesCount": 1, 5 | "attribute": "networkZone", 6 | "operation": "set", 7 | "targetEntitiesCount": 2, 8 | "value": "test-zone" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_apiTokens_ca4f773d77d3bb7.json: -------------------------------------------------------------------------------- 1 | {"totalCount": 2, "pageSize": 200, "apiTokens": [{"id": "dt0c01.34ILWD2EUD4ZYZG3LH7D2358", "name": "Without ms in timestamp", "enabled": true, "owner": "TestOwner", "creationDate": "2025-01-20T21:37:02Z"}, {"id": "dt0c01.SZQBU44KW2NIOICNL6YZ4354", "name": "With ms in timestamp", "enabled": true, "owner": "TestOwner", "creationDate": "2025-01-19T21:36:02.999Z"}]} -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_auditlogs_162100314800090003.json: -------------------------------------------------------------------------------- 1 | { 2 | "logId": "162100314800090003", 3 | "eventType": "DELETE", 4 | "category": "CONFIG", 5 | "entityId": "builtin:alerting.profile (tenant): d89472d3-f9f4-420d-9398-768bb3351e85: test", 6 | "environmentId": "eaa50379", 7 | "user": "Dynatrace support user #649982176", 8 | "userType": "USER_NAME", 9 | "userOrigin": "webui (xxx.xxx.xxx.xxx)", 10 | "timestamp": 1621003148800, 11 | "success": true, 12 | "patch": [ 13 | { 14 | "op": "replace", 15 | "path": "/", 16 | "value": null, 17 | "oldValue": { 18 | "name (Name)": "test", 19 | "severityRules": [ 20 | { 21 | "severityLevel (Problem severity level)": "PERFORMANCE", 22 | "delayInMinutes (Problem send delay in minutes)": 30, 23 | "tagFilterIncludeMode (Filter problems by tag)": "NONE", 24 | "tagFilter (Tags)": [] 25 | }, 26 | { 27 | "severityLevel (Problem severity level)": "RESOURCE_CONTENTION", 28 | "delayInMinutes (Problem send delay in minutes)": 30, 29 | "tagFilterIncludeMode (Filter problems by tag)": "NONE", 30 | "tagFilter (Tags)": [] 31 | }, 32 | { 33 | "severityLevel (Problem severity level)": "MONITORING_UNAVAILABLE", 34 | "delayInMinutes (Problem send delay in minutes)": 0, 35 | "tagFilterIncludeMode (Filter problems by tag)": "NONE", 36 | "tagFilter (Tags)": [] 37 | }, 38 | { 39 | "severityLevel (Problem severity level)": "CUSTOM_ALERT", 40 | "delayInMinutes (Problem send delay in minutes)": 0, 41 | "tagFilterIncludeMode (Filter problems by tag)": "NONE", 42 | "tagFilter (Tags)": [] 43 | }, 44 | { 45 | "severityLevel (Problem severity level)": "AVAILABILITY", 46 | "delayInMinutes (Problem send delay in minutes)": 0, 47 | "tagFilterIncludeMode (Filter problems by tag)": "NONE", 48 | "tagFilter (Tags)": [] 49 | }, 50 | { 51 | "severityLevel (Problem severity level)": "ERRORS", 52 | "delayInMinutes (Problem send delay in minutes)": 0, 53 | "tagFilterIncludeMode (Filter problems by tag)": "NONE", 54 | "tagFilter (Tags)": [] 55 | } 56 | ], 57 | "eventFilters": [] 58 | } 59 | } 60 | ] 61 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_entityTypes_DISK.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "DISK", 3 | "displayName": "Disk", 4 | "dimensionKey": "dt.entity.disk", 5 | "entityLimitExceeded": false, 6 | "properties": [{ 7 | "id": "awsNameTag", 8 | "type": "String", 9 | "displayName": "awsNameTag" 10 | }, 11 | { 12 | "id": "boshName", 13 | "type": "String", 14 | "displayName": "boshName" 15 | }, 16 | { 17 | "id": "conditionalName", 18 | "type": "String", 19 | "displayName": "conditionalName" 20 | }, 21 | { 22 | "id": "customizedName", 23 | "type": "String", 24 | "displayName": "customizedName" 25 | }, 26 | { 27 | "id": "detectedName", 28 | "type": "String", 29 | "displayName": "detectedName" 30 | }, 31 | { 32 | "id": "gcpZone", 33 | "type": "String", 34 | "displayName": "gcpZone" 35 | }, 36 | { 37 | "id": "oneAgentCustomHostName", 38 | "type": "String", 39 | "displayName": "oneAgentCustomHostName" 40 | } 41 | ], 42 | "tags": "List", 43 | "managementZones": "List", 44 | "fromRelationships": [{ 45 | "id": "isDiskOf", 46 | "toTypes": [ 47 | "HOST" 48 | ] 49 | }], 50 | "toRelationships": [{ 51 | "id": "isEbsVolumeOf", 52 | "fromTypes": [ 53 | "EBS_VOLUME" 54 | ] 55 | }] 56 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_eventTypes_3540f77a223c618.json: -------------------------------------------------------------------------------- 1 | { 2 | "totalCount": 5, 3 | "pageSize": 100, 4 | "eventTypeInfos": [{ 5 | "type": "APPLICATION_ERROR_RATE_INCREASED", 6 | "displayName": "JavaScript error rate increase", 7 | "severityLevel": "ERROR" 8 | }, 9 | { 10 | "type": "APPLICATION_JS_FRAMEWORK_DETECTED", 11 | "displayName": "JavaScript framework change", 12 | "severityLevel": "INFO" 13 | }, 14 | { 15 | "type": "APPLICATION_OVERLOAD_PREVENTION", 16 | "displayName": "Application overload prevention", 17 | "severityLevel": "INFO", 18 | "description": "Max user actions per minute exceeded" 19 | }, 20 | { 21 | "type": "APPLICATION_SLOWDOWN", 22 | "displayName": "Application slowdown", 23 | "severityLevel": "PERFORMANCE", 24 | "description": "User action duration degradation" 25 | }, 26 | { 27 | "type": "APPLICATION_UNEXPECTED_HIGH_LOAD", 28 | "displayName": "Application high traffic", 29 | "severityLevel": "RESOURCE_CONTENTION", 30 | "description": "Unexpected high traffic" 31 | } 32 | ] 33 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_eventTypes_APPLICATION_OVERLOAD_PREVENTION.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "APPLICATION_OVERLOAD_PREVENTION", 3 | "displayName": "Application overload prevention", 4 | "severityLevel": "INFO", 5 | "description": "Max user actions per minute exceeded" 6 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_events_4578933396576863909_1631255744265.json: -------------------------------------------------------------------------------- 1 | { 2 | "eventId": "4578933396576863909_1631255744265", 3 | "startTime": 1631255744265, 4 | "endTime": 1631255744265, 5 | "eventType": "CUSTOM_DEPLOYMENT", 6 | "title": "Deployment", 7 | "entityId": { 8 | "entityId": { 9 | "id": "SERVICE-596877472CDAA92E", 10 | "type": "SERVICE" 11 | }, 12 | "name": "[final] Simple-Node-Service" 13 | }, 14 | "properties": [{ 15 | "key": "dt.event.group_label", 16 | "value": "Deployment" 17 | }, 18 | { 19 | "key": "dt.event.source", 20 | "value": "Radu's Python Pipeline" 21 | } 22 | ], 23 | "status": "CLOSED", 24 | "entityTags": [{ 25 | "context": "ENVIRONMENT", 26 | "key": "Environment", 27 | "value": "final", 28 | "stringRepresentation": "[Environment]Environment:final" 29 | }, 30 | { 31 | "context": "ENVIRONMENT", 32 | "key": "Version", 33 | "value": "v2", 34 | "stringRepresentation": "[Environment]Version:v2" 35 | }, 36 | { 37 | "context": "ENVIRONMENT", 38 | "key": "Application", 39 | "value": "simple-node", 40 | "stringRepresentation": "[Environment]Application:simple-node" 41 | } 42 | ], 43 | "managementZones": [{ 44 | "id": "1953014305523637885", 45 | "name": "Test-Management-Zone" 46 | }], 47 | "underMaintenance": false, 48 | "suppressAlert": false, 49 | "suppressProblem": false, 50 | "frequentEvent": false 51 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_extensions_094e243469d892d.json: -------------------------------------------------------------------------------- 1 | {"extensions": [{"extensionName": "com.dynatrace.extension.snmp-generic", "version": "0.2.5"}, {"extensionName": "custom:dynatrace.cisco.asa", "version": "0.1.0"}], "totalCount": 2} -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_extensions_1b00aa5e4518062.json: -------------------------------------------------------------------------------- 1 | {"extensions": [{"extensionName": "custom:dynatrace.cisco.asa", "version": "0.1.0"}], "totalCount": 1} -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_extensions_com_dynatrace_extension_snmp-generic.json: -------------------------------------------------------------------------------- 1 | {"extensions": [{"extensionName": "com.dynatrace.extension.snmp-generic", "version": "0.2.5"}], "totalCount": 1} -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_extensions_com_dynatrace_extension_snmp-generic_0_2_5.json: -------------------------------------------------------------------------------- 1 | {"extensionName": "com.dynatrace.extension.snmp-generic", "version": "0.2.5", "author": {"name": "Dynatrace"}, "dataSources": ["snmp"], "variables": ["ext.activationtag"], "featureSets": [], "minDynatraceVersion": "1.218.0", "fileHash": "c6216b9b1ce837383cc84a825795a4708a0b4744dc71a76791527eefa754c3e4"} -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_extensions_ibmmq_environmentConfiguration.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.2.3" 3 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_metrics_builtin_host_cpu_idle.json: -------------------------------------------------------------------------------- 1 | { 2 | "metricId": "builtin:host.cpu.idle", 3 | "displayName": "CPU idle", 4 | "description": "", 5 | "unit": "Percent", 6 | "dduBillable": false, 7 | "created": 0, 8 | "lastWritten": 1621030565348, 9 | "entityType": [ 10 | "HOST" 11 | ], 12 | "aggregationTypes": [ 13 | "auto", 14 | "avg", 15 | "max", 16 | "min" 17 | ], 18 | "transformations": [ 19 | "filter", 20 | "fold", 21 | "limit", 22 | "merge", 23 | "names", 24 | "parents", 25 | "timeshift", 26 | "sort", 27 | "last", 28 | "splitBy", 29 | "default" 30 | ], 31 | "defaultAggregation": { 32 | "type": "avg" 33 | }, 34 | "dimensionDefinitions": [ 35 | { 36 | "key": "dt.entity.host", 37 | "name": "Host", 38 | "displayName": "Host", 39 | "index": 0, 40 | "type": "ENTITY" 41 | } 42 | ], 43 | "tags": [], 44 | "metricValueType": { 45 | "type": "score" 46 | } 47 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_metrics_query_0f81e686e69f013.json: -------------------------------------------------------------------------------- 1 | { 2 | "nextPageKey": "null", 3 | "resolution": "1h", 4 | "result": [ 5 | { 6 | "data": [ 7 | { 8 | "dimensionMap": { 9 | "dt.entity.host": "HOST-82F576674F19AC16" 10 | }, 11 | "dimensions": [ 12 | "HOST-82F576674F19AC16" 13 | ], 14 | "timestamps": [ 15 | 3151435100000, 16 | 3151438700000, 17 | 3151442300000 18 | ], 19 | "values": [ 20 | 11.1, 21 | 22.2, 22 | 33.3 23 | ] 24 | } 25 | ], 26 | "dataPointCountRatio": "0.1211", 27 | "dimensionCountRatio": "0.0322", 28 | "metricId": "builtin:host.cpu.idle" 29 | }, 30 | { 31 | "data": [], 32 | "metricId": "builtin:host.cpu.idle:filter(eq(\"dt.entityhost\",HOST-123))", 33 | "warnings": [ 34 | "The dimension key `dt.entityhost` has been referenced, but the metric has no such key." 35 | ] 36 | } 37 | ], 38 | "totalCount": 3, 39 | "warnings": [ 40 | "The dimension key `dt.entityhost` has been referenced, but the metric has no such key." 41 | ] 42 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_metrics_query_4fa21773411125d.json: -------------------------------------------------------------------------------- 1 | { 2 | "nextPageKey": null, 3 | "resolution": "1h", 4 | "result": [ 5 | { 6 | "data": [ 7 | { 8 | "dimensionMap": { 9 | "dt.entity.host": "HOST-82F576674F19AC16" 10 | }, 11 | "dimensions": [ 12 | "HOST-82F576674F19AC16" 13 | ], 14 | "timestamps": [ 15 | 3151435100000, 16 | 3151438700000, 17 | 3151442300000 18 | ], 19 | "values": [ 20 | 11.1, 21 | 22.2, 22 | 33.3 23 | ] 24 | } 25 | ], 26 | "dataPointCountRatio": "0.1211", 27 | "dimensionCountRatio": "0.0322", 28 | "metricId": "builtin:host.cpu.idle" 29 | }, 30 | { 31 | "data": [], 32 | "metricId": "builtin:host.cpu.idle:filter(eq(\"dt.entityhost\",HOST-123))", 33 | "warnings": [ 34 | "The dimension key `dt.entityhost` has been referenced, but the metric has no such key." 35 | ] 36 | } 37 | ], 38 | "totalCount": 3, 39 | "warnings": [ 40 | "The dimension key `dt.entityhost` has been referenced, but the metric has no such key." 41 | ] 42 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_networkZones.json: -------------------------------------------------------------------------------- 1 | { 2 | "networkZones": [ 3 | { 4 | "id": "default", 5 | "description": "The default network zone. This is the network zone for OneAgents or ActiveGates that do not have any network zone configured.", 6 | "alternativeZones": [], 7 | "numOfOneAgentsUsing": 141, 8 | "numOfConfiguredOneAgents": 141, 9 | "numOfOneAgentsFromOtherZones": 0, 10 | "numOfConfiguredActiveGates": 0 11 | }, 12 | { 13 | "id": "us-east1", 14 | "description": "The us east a networkzone", 15 | "alternativeZones": ["us-east2, us-east3"], 16 | "numOfOneAgentsUsing": 90, 17 | "numOfConfiguredOneAgents": 90, 18 | "numOfOneAgentsFromOtherZones": 0, 19 | "numOfConfiguredActiveGates": 12 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_networkZones_default.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "default", 3 | "description": "The default network zone. This is the network zone for OneAgents or ActiveGates that do not have any network zone configured.", 4 | "alternativeZones": [], 5 | "numOfOneAgentsUsing": 141, 6 | "numOfConfiguredOneAgents": 141, 7 | "numOfOneAgentsFromOtherZones": 0, 8 | "numOfConfiguredActiveGates": 0 9 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_networkZonesdefault.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "default", 3 | "description": "The default network zone. This is the network zone for OneAgents or ActiveGates that do not have any network zone configured.", 4 | "alternativeZones": [], 5 | "numOfOneAgentsUsing": 141, 6 | "numOfConfiguredOneAgents": 141, 7 | "numOfOneAgentsFromOtherZones": 0, 8 | "numOfConfiguredActiveGates": 0 9 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_oneagents_remoteConfigurationManagement_2e5fcbd2c8d0e63.json: -------------------------------------------------------------------------------- 1 | { 2 | "jobs": [ 3 | { 4 | "endTime": "2020-11-05T08:15:30.144Z", 5 | "entityType": "ONE_AGENT", 6 | "id": "7974003406714390819", 7 | "startTime": "2020-11-05T08:15:30.144Z" 8 | } 9 | ] 10 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_oneagents_remoteConfigurationManagement_7974003406714390819.json: -------------------------------------------------------------------------------- 1 | { 2 | "endTime": "2020-11-05T08:15:30.144Z", 3 | "entityType": "ONE_AGENT", 4 | "id": "7974003406714390819", 5 | "operations": [ 6 | { 7 | "attribute": "networkZone", 8 | "operation": "set", 9 | "value": "test-zone" 10 | } 11 | ], 12 | "processedEntitiesCount": 1, 13 | "startTime": "2020-11-05T08:15:30.144Z", 14 | "timeoutTime": "2020-11-05T08:15:30.144Z", 15 | "totalEntitiesCount": 1 16 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_oneagents_remoteConfigurationManagement_current.json: -------------------------------------------------------------------------------- 1 | { 2 | "endTime": "2020-11-05T08:15:30.144Z", 3 | "entityType": "ONE_AGENT", 4 | "id": "7974003406714390819", 5 | "operations": [ 6 | { 7 | "attribute": "networkZone", 8 | "operation": "set", 9 | "value": "test-zone" 10 | } 11 | ], 12 | "processedEntitiesCount": 1, 13 | "startTime": "2020-11-05T08:15:30.144Z", 14 | "timeoutTime": "2020-11-05T08:15:30.144Z", 15 | "totalEntitiesCount": 1 16 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_oneagents_remoteConfigurationManagement_preview_4cfaf0a9b26d2dd.json: -------------------------------------------------------------------------------- 1 | { 2 | "previews": [ 3 | { 4 | "alreadyConfiguredEntitiesCount": 1, 5 | "attribute": "networkZone", 6 | "operation": "set", 7 | "targetEntitiesCount": 2, 8 | "value": "test-zone" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_problems_-1719139739592062093_1623004451641V2_comments_-7228967546616810529_1623004451641.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "-7228967546616810529_1623004451641", 3 | "createdAtTimestamp": 1623047022173, 4 | "content": "Closing this. 1234", 5 | "authorName": "radu.stefan@dynatrace.com", 6 | "context": "dynatrace-problem-close" 7 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_problems_-1719139739592062093_1623004451641V2_comments_0fe92b50cb1bdcb.json: -------------------------------------------------------------------------------- 1 | { 2 | "authorName": "string", 3 | "content": "string", 4 | "context": "string", 5 | "createdAtTimestamp": 1, 6 | "id": "string" 7 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_problems_-1719139739592062093_1623004451641V2_comments_adba23bf24edbcc.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": [ 3 | { 4 | "authorName": "string", 5 | "content": "string", 6 | "context": "string", 7 | "createdAtTimestamp": 1, 8 | "id": "string" 9 | }, 10 | { 11 | "authorName": "string", 12 | "content": "string", 13 | "context": "string", 14 | "createdAtTimestamp": 2, 15 | "id": "string" 16 | } 17 | ], 18 | "nextPageKey": "AQAAABQBAAAABQ==", 19 | "pageSize": 1, 20 | "totalCount": 1 21 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_problems_0d7ed4db1cd91c2.json: -------------------------------------------------------------------------------- 1 | { 2 | "totalCount": 11, 3 | "pageSize": 50, 4 | "problems": [ 5 | { 6 | "problemId": "-1719139739592062093_1623004451641V2", 7 | "displayId": "P-210620", 8 | "title": "custom host disconnected error", 9 | "impactLevel": "INFRASTRUCTURE", 10 | "severityLevel": "AVAILABILITY", 11 | "status": "OPEN", 12 | "affectedEntities": [ 13 | { 14 | "entityId": { 15 | "id": "HOST-44DD554D0DA01178", 16 | "type": "HOST" 17 | }, 18 | "name": "TAG009444549397.clients.dynatrace.org" 19 | } 20 | ], 21 | "impactedEntities": [ 22 | { 23 | "entityId": { 24 | "id": "HOST-44DD554D0DA01178", 25 | "type": "HOST" 26 | }, 27 | "name": "TAG009444549397.clients.dynatrace.org" 28 | } 29 | ], 30 | "rootCauseEntity": null, 31 | "managementZones": [ 32 | { 33 | "id": "8692695975020499402", 34 | "name": "Operations Team" 35 | } 36 | ], 37 | "entityTags": [ 38 | { 39 | "context": "CONTEXTLESS", 40 | "key": "Application", 41 | "value": "EasyTravel", 42 | "stringRepresentation": "Application:EasyTravel" 43 | }, 44 | { 45 | "context": "CONTEXTLESS", 46 | "key": "Environment", 47 | "value": "UAT", 48 | "stringRepresentation": "Environment:UAT" 49 | } 50 | ], 51 | "problemFilters": [ 52 | { 53 | "id": "c21f969b-5f03-333d-83e0-4f8f136e7682", 54 | "name": "Default" 55 | }, 56 | { 57 | "id": "c48a68f0-7cab-4c00-8822-9486b98c5e4d", 58 | "name": "Keptn" 59 | }, 60 | { 61 | "id": "8bc2041d-9282-4c1d-9b21-4ae775cf00ae", 62 | "name": "123" 63 | } 64 | ], 65 | "startTime": 1623004451641, 66 | "endTime": -1 67 | }, 68 | { 69 | "problemId": "-8720840650528236841_1623003540000V2", 70 | "displayId": "P-210619", 71 | "title": "custom host disconnected error", 72 | "impactLevel": "INFRASTRUCTURE", 73 | "severityLevel": "AVAILABILITY", 74 | "status": "CLOSED", 75 | "affectedEntities": [ 76 | { 77 | "entityId": { 78 | "id": "HOST-44DD554D0DA01178", 79 | "type": "HOST" 80 | }, 81 | "name": "TAG009444549397.clients.dynatrace.org" 82 | } 83 | ], 84 | "impactedEntities": [ 85 | { 86 | "entityId": { 87 | "id": "HOST-44DD554D0DA01178", 88 | "type": "HOST" 89 | }, 90 | "name": "TAG009444549397.clients.dynatrace.org" 91 | } 92 | ], 93 | "rootCauseEntity": null, 94 | "managementZones": [ 95 | { 96 | "id": "8692695975020499402", 97 | "name": "Operations Team" 98 | } 99 | ], 100 | "entityTags": [ 101 | { 102 | "context": "CONTEXTLESS", 103 | "key": "Application", 104 | "value": "EasyTravel", 105 | "stringRepresentation": "Application:EasyTravel" 106 | }, 107 | { 108 | "context": "CONTEXTLESS", 109 | "key": "Environment", 110 | "value": "UAT", 111 | "stringRepresentation": "Environment:UAT" 112 | } 113 | ], 114 | "problemFilters": [ 115 | { 116 | "id": "c21f969b-5f03-333d-83e0-4f8f136e7682", 117 | "name": "Default" 118 | }, 119 | { 120 | "id": "c48a68f0-7cab-4c00-8822-9486b98c5e4d", 121 | "name": "Keptn" 122 | }, 123 | { 124 | "id": "8bc2041d-9282-4c1d-9b21-4ae775cf00ae", 125 | "name": "123" 126 | } 127 | ], 128 | "startTime": 1623003540000, 129 | "endTime": 1623004383324 130 | } 131 | ] 132 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_settings_objects_accb155250dbcbb.json: -------------------------------------------------------------------------------- 1 | { 2 | "items": [ 3 | { 4 | "objectId": "vu9U3hXa3q0AAAABACdidWlsdGluOmFub21hbHktZGV0ZWN0aW9uLm1ldHJpYy1ldmVudHMABnRlbmFudAAGdGVuYW50ACQ4OWNhMmY2Ny0wY2Q3LTM0MzAtYmU5Ny1kOTg4YTRmMWRiYWa-71TeFdrerQ", 5 | "value": { 6 | "enabled": true, 7 | "summary": "OnTap Node Field Replaceable Unit in Error State", 8 | "queryDefinition": { 9 | "type": "METRIC_KEY", 10 | "metricKey": "netapp.ontap.node.fru.state", 11 | "aggregation": "AVG", 12 | "entityFilter": { 13 | "dimensionKey": "dt.entity.netapp_ontap:fru", 14 | "conditions": [] 15 | }, 16 | "dimensionFilter": [] 17 | }, 18 | "modelProperties": { 19 | "type": "STATIC_THRESHOLD", 20 | "threshold": 100.0, 21 | "alertOnNoData": false, 22 | "alertCondition": "BELOW", 23 | "violatingSamples": 3, 24 | "samples": 5, 25 | "dealertingSamples": 5 26 | }, 27 | "eventTemplate": { 28 | "title": "OnTap {dims:type} {dims:fru_id} is in Error State", 29 | "description": "OnTap field replaceable unit (FRU) {dims:type} with id {dims:fru_id} on node {dims:node} in cluster {dims:cluster} is in an error state.\n", 30 | "eventType": "RESOURCE", 31 | "davisMerge": true, 32 | "metadata": [] 33 | }, 34 | "eventEntityDimensionKey": "dt.entity.netapp_ontap:fru" 35 | } 36 | }, 37 | { 38 | "objectId": "vu9U3hXa3q0AAAABACdidWlsdGluOmFub21hbHktZGV0ZWN0aW9uLm1ldHJpYy1ldmVudHMABnRlbmFudAAGdGVuYW50ACQ5MjRiNjdiYS00OGQ1LTM0NDctODg4Zi05NzUzMzg5NzcxMze-71TeFdrerQ", 39 | "value": { 40 | "enabled": false, 41 | "summary": "High outbound bandwidth utilization", 42 | "queryDefinition": { 43 | "type": "METRIC_SELECTOR", 44 | "metricSelector": "func:com.dynatrace.extension.snmp-generic-cisco-device.if.out.bandwidth" 45 | }, 46 | "modelProperties": { 47 | "type": "STATIC_THRESHOLD", 48 | "threshold": 90.0, 49 | "alertOnNoData": false, 50 | "alertCondition": "ABOVE", 51 | "violatingSamples": 3, 52 | "samples": 5, 53 | "dealertingSamples": 5 54 | }, 55 | "eventTemplate": { 56 | "title": "High outbound bandwidth utilization", 57 | "description": "The {metricname} value of {severity} was {alert_condition} your custom threshold of {threshold}.", 58 | "eventType": "CUSTOM_ALERT", 59 | "davisMerge": false, 60 | "metadata": [] 61 | }, 62 | "eventEntityDimensionKey": "dt.entity.snmp:com_dynatrace_extension_snmp_generic_cisco_network_interface", 63 | "legacyId": "E|649d5713-380b-6751-a64f-6904a2c4cd2f" 64 | } 65 | } 66 | ], 67 | "totalCount": 25, 68 | "pageSize": 100 69 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_settings_objects_vu9U3hXa3q0AAAABACdidWlsdGluOmFub21hbHktZGV0ZWN0aW9uLm1ldHJpYy1ldmVudHMABnRlbmFudAAGdGVuYW50ACRiYmYzZWNhNy0zMmZmLTM2ZTEtOTFiOS05Y2QxZjE3OTc0YjC-71TeFdrerQ.json: -------------------------------------------------------------------------------- 1 | { 2 | "objectId": "vu9U3hXa3q0AAAABACdidWlsdGluOmFub21hbHktZGV0ZWN0aW9uLm1ldHJpYy1ldmVudHMABnRlbmFudAAGdGVuYW50ACRiYmYzZWNhNy0zMmZmLTM2ZTEtOTFiOS05Y2QxZjE3OTc0YjC-71TeFdrerQ", 3 | "summary": "DT API TEST 22", 4 | "searchSummary": "DT API TEST 22", 5 | "created": 1705095249587, 6 | "modified": 1705095274757, 7 | "author": "dt0c01.EZN2OP5XE26C3I5ZA2NTHTF5", 8 | "updateToken": "vu9U3hXY3q0ATAAkYmJmM2VjYTctMzJmZi0zNmUxLTkxYjktOWNkMWYxNzk3NGIwACQ2MTFiMTM1MC1iMTkyLTExZWUtODAwMS0wMTAwMDAwMDAwMDi-71TeFdjerQ", 9 | "scope": "environment", 10 | "schemaId": "builtin:anomaly-detection.metric-events", 11 | "schemaVersion": "1.0.16", 12 | "value": { 13 | "enabled": true, 14 | "summary": "DT API TEST 22", 15 | "queryDefinition": { 16 | "type": "METRIC_KEY", 17 | "metricKey": "netapp.ontap.node.fru.state", 18 | "aggregation": "AVG", 19 | "entityFilter": { 20 | "dimensionKey": "dt.entity.netapp_ontap:fru", 21 | "conditions": [] 22 | }, 23 | "dimensionFilter": [] 24 | }, 25 | "modelProperties": { 26 | "type": "STATIC_THRESHOLD", 27 | "threshold": 100.0, 28 | "alertOnNoData": false, 29 | "alertCondition": "BELOW", 30 | "violatingSamples": 3, 31 | "samples": 5, 32 | "dealertingSamples": 5 33 | }, 34 | "eventTemplate": { 35 | "title": "OnTap {dims:type} {dims:fru_id} is in Error State", 36 | "description": "OnTap field replaceable unit (FRU) {dims:type} with id {dims:fru_id} on node {dims:node} in cluster {dims:cluster} is in an error state.\n", 37 | "eventType": "RESOURCE", 38 | "davisMerge": true, 39 | "metadata": [] 40 | }, 41 | "eventEntityDimensionKey": "dt.entity.netapp_ontap:fru" 42 | } 43 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_settings_schemas.json: -------------------------------------------------------------------------------- 1 | { 2 | "items": [ 3 | { 4 | "schemaId": "builtin:attribute-block-list", 5 | "displayName": "Blocked attributes", 6 | "latestSchemaVersion": "0.0.1" 7 | }, 8 | { 9 | "schemaId": "builtin:ua.attribute-table", 10 | "displayName": "Attribute table cards", 11 | "latestSchemaVersion": "0.10" 12 | }, 13 | { 14 | "schemaId": "builtin:span-attribute", 15 | "displayName": "Span attributes", 16 | "latestSchemaVersion": "0.0.42" 17 | } 18 | ], 19 | "totalCount": 3 20 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_slo_88991da4-be17-3d57-aada-cfb3977767f4_a3b5130244d7cfb.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "88991da4-be17-3d57-aada-cfb3977767f4", 3 | "enabled": true, 4 | "name": "test123", 5 | "description": "test", 6 | "evaluatedPercentage": 100.0, 7 | "errorBudget": 2.0, 8 | "status": "SUCCESS", 9 | "error": "NONE", 10 | "errorBudgetBurnRate": { 11 | "burnRateVisualizationEnabled": false 12 | }, 13 | "metricKey": "func:slo.test123", 14 | "burnRateMetricKey": "func:slo.errorBudgetBurnRate.test123", 15 | "errorBudgetMetricKey": "func:slo.errorBudget.test123", 16 | "normalizedErrorBudgetMetricKey": "func:slo.normalizedErrorBudget.test123", 17 | "metricExpression": "(100)*(builtin:service.errors.server.successCount:splitBy())/(builtin:service.requestCount.server:splitBy())", 18 | "target": 98.0, 19 | "warning": 99.0, 20 | "evaluationType": "AGGREGATE", 21 | "timeframe": "now-1h", 22 | "filter": "", 23 | "relatedOpenProblems": 0, 24 | "relatedTotalProblems": 0, 25 | "metricRate": "", 26 | "numeratorValue": 0.0, 27 | "denominatorValue": 0.0, 28 | "metricDenominator": "", 29 | "useRateMetric": true, 30 | "metricNumerator": "" 31 | } -------------------------------------------------------------------------------- /test/mock_data/GET_api_v2_tags_3d3d3b0ff3c48c2.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": [ 3 | { 4 | "context": "CONTEXTLESS", 5 | "key": "mainApp", 6 | "stringRepresentation": "mainApp" 7 | }, 8 | { 9 | "context": "CONTEXTLESS", 10 | "key": "bookings", 11 | "stringRepresentation": "bookings" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /test/mock_data/GETapi_v2_-1719139739592062093_1623004451641V2_comments_adba23bf24edbcc.json: -------------------------------------------------------------------------------- 1 | { 2 | "totalCount": 2, 3 | "pageSize": 20, 4 | "comments": [ 5 | { 6 | "id": "-8516688511120418342_1623004451641", 7 | "createdAtTimestamp": 1623047802052, 8 | "content": "yet another comment", 9 | "authorName": "radu.stefan@dynatrace.com" 10 | }, 11 | { 12 | "id": "-7228967546616810529_1623004451641", 13 | "createdAtTimestamp": 1623047022173, 14 | "content": "Closing this. 1234", 15 | "authorName": "radu.stefan@dynatrace.com", 16 | "context": "dynatrace-problem-close" 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /test/mock_data/POST_api_config_v1_alertingProfiles_615cf1488e623d7.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "b1f379d9-98b4-4efe-be38-0289609c9295", 3 | "name": "deployment_change_autoremediation", 4 | "description": "new_maangement_zone" 5 | } -------------------------------------------------------------------------------- /test/mock_data/POST_api_config_v1_maintenanceWindows_b701f87f95f4e57.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "b6376a12-0b82-4069-9a41-0e55ef9a1f44", 3 | "name": "Example Window", 4 | "description": "test_desc", 5 | "type": "PLANNED", 6 | "suppression": null, 7 | "suppressSyntheticMonitorsExecution": false, 8 | "schedule": { 9 | "end": "2031-02-27 00:00", 10 | "start": "2028-08-02 00:00", 11 | "zoneId": "Europe/Vienna", 12 | "recurrence": { 13 | "dayOfWeek": null, 14 | "dayOfMonth": null, 15 | "startTime": null, 16 | "durationMinutes": null 17 | }, 18 | "recurrenceType": "ONCE" 19 | }, 20 | "scope": { 21 | "entities": [ 22 | "HOST-0000000000123456" 23 | ], 24 | "matches": [ 25 | { 26 | "type": "HOST", 27 | "mzId": "-5283929364044076484", 28 | "tags": [ 29 | { 30 | "context": "AWS", 31 | "key": "testkey", 32 | "value": "testvalue" 33 | } 34 | ], 35 | "tagCombination": "AND" 36 | } 37 | ] 38 | } 39 | } -------------------------------------------------------------------------------- /test/mock_data/POST_api_config_v1_managementZones_7942f5740137a74.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Test-Management-Zone", 3 | "id": "1234567890987654321" 4 | } -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_activeGates_remoteConfigurationManagement_4cfaf0a9b26d2dd.json: -------------------------------------------------------------------------------- 1 | { 2 | "endTime": "2020-11-05T08:15:30.144Z", 3 | "entityType": "ACTIVE_GATE", 4 | "id": "7974003406714390819", 5 | "operations": [ 6 | { 7 | "attribute": "networkZone", 8 | "operation": "set", 9 | "value": "test-zone" 10 | } 11 | ], 12 | "processedEntitiesCount": 1, 13 | "startTime": "2020-11-05T08:15:30.144Z", 14 | "timeoutTime": "2020-11-05T08:15:30.144Z", 15 | "totalEntitiesCount": 1 16 | } -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_activeGates_remoteConfigurationManagement_validator_4cfaf0a9b26d2dd.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynatrace-oss/api-client-python/9c1467b36b8a11ff74daf9d6d2c9fde25c4fd970/test/mock_data/POST_api_v2_activeGates_remoteConfigurationManagement_validator_4cfaf0a9b26d2dd.json -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_events_ingest_3dfc47521cd78f3.json: -------------------------------------------------------------------------------- 1 | {"reportCount": 2, "eventIngestResults": [{"correlationId": "1ffdfaec762febda", "status": "OK"}, {"correlationId": "5b7c0bfb20c21e9a", "status": "OK"}]} -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_metrics_ingest.json: -------------------------------------------------------------------------------- 1 | { 2 | "linesOk": 1, 3 | "linesInvalid": 0, 4 | "error": null 5 | } -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_oneagents_remoteConfigurationManagement_4cfaf0a9b26d2dd.json: -------------------------------------------------------------------------------- 1 | { 2 | "endTime": "2020-11-05T08:15:30.144Z", 3 | "entityType": "ONE_AGENT", 4 | "id": "7974003406714390819", 5 | "operations": [ 6 | { 7 | "attribute": "networkZone", 8 | "operation": "set", 9 | "value": "test-zone" 10 | } 11 | ], 12 | "processedEntitiesCount": 1, 13 | "startTime": "2020-11-05T08:15:30.144Z", 14 | "timeoutTime": "2020-11-05T08:15:30.144Z", 15 | "totalEntitiesCount": 1 16 | } -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_oneagents_remoteConfigurationManagement_validator_4cfaf0a9b26d2dd.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dynatrace-oss/api-client-python/9c1467b36b8a11ff74daf9d6d2c9fde25c4fd970/test/mock_data/POST_api_v2_oneagents_remoteConfigurationManagement_validator_4cfaf0a9b26d2dd.json -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_problems_-1719139739592062093_1623004451641V2_close_91e97b2b99926eb.json: -------------------------------------------------------------------------------- 1 | { 2 | "problemId": "-1719139739592062093_1623004451641V2", 3 | "comment": { 4 | "id": "-7228967546616810529_1623004451641", 5 | "createdAtTimestamp": 1623047022173, 6 | "content": "Closing this. 1234", 7 | "authorName": "radu.stefan@dynatrace.com", 8 | "context": "dynatrace-problem-close" 9 | }, 10 | "closeTimestamp": 1623047022173, 11 | "closing": true 12 | } -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_settings_objects_48f5d7ab33b29d3.json: -------------------------------------------------------------------------------- 1 | [{"code": 200, "objectId": "vu9U3hXa3q0AAAABACdidWlsdGluOmFub21hbHktZGV0ZWN0aW9uLm1ldHJpYy1ldmVudHMABnRlbmFudAAGdGVuYW50ACQwMjA1ZjE2ZS0yMzI5LTMxMzktYmJmNS0zZTNmMTAyNzA0MjC-71TeFdrerQ"}] -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_tags_4f8375bfcb42058.json: -------------------------------------------------------------------------------- 1 | {"matchedEntitiesCount": 1, "appliedTags": [{"context": "CONTEXTLESS", "key": "test-tag-value", "value": "tag-value", "stringRepresentation": "test-tag-value:tag-value"}]} -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_tags_fe7d869df4dac8b.json: -------------------------------------------------------------------------------- 1 | {"matchedEntitiesCount": 1, "appliedTags": [{"context": "CONTEXTLESS", "key": "test-tag-no-value", "stringRepresentation": "test-tag-no-value"}]} -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_tenantTokenRotation_cancel.json: -------------------------------------------------------------------------------- 1 | { 2 | "old": { 3 | "value": null 4 | }, 5 | "active": { 6 | "value": "prv0bYw93v8sU9b1" 7 | } 8 | } -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_tenantTokenRotation_finish.json: -------------------------------------------------------------------------------- 1 | { 2 | "old": { 3 | "value": null 4 | }, 5 | "active": { 6 | "value": "prv0bYw93v8sU9b1" 7 | } 8 | } -------------------------------------------------------------------------------- /test/mock_data/POST_api_v2_tenantTokenRotation_start.json: -------------------------------------------------------------------------------- 1 | { 2 | "old": { 3 | "value": "prv0bYw93v8sU9b1" 4 | }, 5 | "active": { 6 | "value": "hRCnr6Yd3BFrtxaF" 7 | } 8 | } -------------------------------------------------------------------------------- /test/mock_data/PUT_api_v2_settings_objects_vu9U3hXa3q0AAAABACdidWlsdGluOmFub21hbHktZGV0ZWN0aW9uLm1ldHJpYy1ldmVudHMABnRlbmFudAAGdGVuYW50ACRiYmYzZWNhNy0zMmZmLTM2ZTEtOTFiOS05Y2QxZjE3OTc0YjC-71TeFdrerQ_193f82b398660c4.json: -------------------------------------------------------------------------------- 1 | {"code": 200, "objectId": "vu9U3hXa3q0AAAABACdidWlsdGluOmFub21hbHktZGV0ZWN0aW9uLm1ldHJpYy1ldmVudHMABnRlbmFudAAGdGVuYW50ACRiYmYzZWNhNy0zMmZmLTM2ZTEtOTFiOS05Y2QxZjE3OTc0YjC-71TeFdrerQ"} -------------------------------------------------------------------------------- /test/test_logs.py: -------------------------------------------------------------------------------- 1 | from dynatrace import Dynatrace 2 | from datetime import datetime 3 | 4 | from dynatrace.environment_v2.logs import LogRecord, EventType, LogRecordStatus 5 | from dynatrace.pagination import PaginatedList 6 | 7 | 8 | def test_export(dt: Dynatrace): 9 | logs = dt.logs.export(time_from="now-10m") 10 | assert isinstance(logs, PaginatedList) 11 | 12 | logs = list(logs) 13 | assert len(logs) == 18 14 | 15 | first = logs[0] 16 | assert isinstance(first, LogRecord) 17 | assert first.additional_columns['dt.extension.ds'][0] == "python" 18 | assert first.content.startswith("Failed to assign") 19 | assert first.event_type == EventType.SFM 20 | assert first.status == LogRecordStatus.ERROR 21 | assert first.timestamp == datetime.utcfromtimestamp(1683574915193 / 1000) 22 | 23 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py{36,37,38,39} 3 | 4 | [testenv] 5 | deps = 6 | pytest 7 | mock 8 | commands = 9 | pytest -rp 10 | --------------------------------------------------------------------------------