dt-extensions-sdk 1.2.13__tar.gz → 1.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/PKG-INFO +2 -3
  2. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/guides/extension_structure.rst +24 -2
  3. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/index.rst +1 -0
  4. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/__about__.py +1 -1
  5. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/create/extension_template/.gitignore.template +3 -0
  6. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/create/extension_template/activation.json.template +1 -1
  7. dt_extensions_sdk-1.3.0/dynatrace_extension/cli/create/extension_template/secrets.json.template +3 -0
  8. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/main.py +11 -1
  9. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/communication.py +17 -1
  10. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/extension.py +3 -1
  11. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/sdk/test_extension.py +1 -5
  12. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/.github/workflows/gh-pages-docs.yml +0 -0
  13. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/.github/workflows/publish.yml +0 -0
  14. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/.gitignore +0 -0
  15. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/LICENSE.txt +0 -0
  16. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/README.md +0 -0
  17. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/_static/dt-sdk-header.png +0 -0
  18. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/_static/dt-sdk-logo.png +0 -0
  19. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/_static/favicon.ico +0 -0
  20. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/_static/img/migrate-01-new-extension.png +0 -0
  21. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/_static/img/migrate-02-type.png +0 -0
  22. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/_static/img/migrate-03-import.png +0 -0
  23. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/_static/img/migrate-04-import-remote.png +0 -0
  24. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/_static/img/migrate-05-activation.png +0 -0
  25. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/_static/img/migrate-06-activation-config.png +0 -0
  26. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/api/events/event_severity.rst +0 -0
  27. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/api/events/event_type.rst +0 -0
  28. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/api/events/index.rst +0 -0
  29. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/api/extension.rst +0 -0
  30. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/api/metrics/index.rst +0 -0
  31. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/api/metrics/metric.rst +0 -0
  32. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/api/metrics/metric_type.rst +0 -0
  33. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/cli/assemble.rst +0 -0
  34. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/cli/build.rst +0 -0
  35. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/cli/create.rst +0 -0
  36. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/cli/gencerts.rst +0 -0
  37. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/cli/help.rst +0 -0
  38. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/cli/run.rst +0 -0
  39. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/cli/sign.rst +0 -0
  40. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/cli/upload.rst +0 -0
  41. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/cli/wheel.rst +0 -0
  42. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/conf.py +0 -0
  43. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/guides/building.rst +0 -0
  44. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/guides/installation.rst +0 -0
  45. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/guides/migration.rst +0 -0
  46. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/docs/requirements.txt +0 -0
  47. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/__init__.py +0 -0
  48. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/__init__.py +0 -0
  49. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/create/__init__.py +0 -0
  50. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/create/create.py +0 -0
  51. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/create/extension_template/README.md.template +0 -0
  52. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/create/extension_template/extension/activationSchema.json.template +0 -0
  53. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/create/extension_template/extension/extension.yaml.template +0 -0
  54. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/create/extension_template/extension_name/__init__.py.template +0 -0
  55. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/create/extension_template/extension_name/__main__.py.template +0 -0
  56. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/create/extension_template/setup.py.template +0 -0
  57. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/cli/schema.py +0 -0
  58. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/__init__.py +0 -0
  59. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/activation.py +0 -0
  60. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/callback.py +0 -0
  61. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/event.py +0 -0
  62. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/helper.py +0 -0
  63. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/metric.py +0 -0
  64. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/runtime.py +0 -0
  65. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/snapshot.py +0 -0
  66. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/vendor/__init__.py +0 -0
  67. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/vendor/mureq/LICENSE +0 -0
  68. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/vendor/mureq/__init__.py +0 -0
  69. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/dynatrace_extension/sdk/vendor/mureq/mureq.py +0 -0
  70. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/pyproject.toml +0 -0
  71. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/__init__.py +0 -0
  72. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/cli/__init__.py +0 -0
  73. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/cli/test_dt_sdk.py +0 -0
  74. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/cli/test_templates.py +0 -0
  75. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/cli/test_types.py +0 -0
  76. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/data/snapshot.json +0 -0
  77. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/sdk/__init__.py +0 -0
  78. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/sdk/test_activation.py +0 -0
  79. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/sdk/test_callback.py +0 -0
  80. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/sdk/test_communication.py +0 -0
  81. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/sdk/test_metric.py +0 -0
  82. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/sdk/test_runtime_properties.py +0 -0
  83. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/sdk/test_snapshot.py +0 -0
  84. {dt_extensions_sdk-1.2.13 → dt_extensions_sdk-1.3.0}/tests/sdk/test_status.py +0 -0
@@ -1,12 +1,11 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dt-extensions-sdk
3
- Version: 1.2.13
3
+ Version: 1.3.0
4
4
  Project-URL: Documentation, https://github.com/dynatrace-extensions/dt-extensions-python-sdk#readme
5
5
  Project-URL: Issues, https://github.com/dynatrace-extensions/dt-extensions-python-sdk/issues
6
6
  Project-URL: Source, https://github.com/dynatrace-extensions/dt-extensions-python-sdk
7
7
  Author-email: dlopes7 <davidribeirolopes@gmail.com>
8
- License-Expression: MIT
9
- License-File: LICENSE.txt
8
+ License: MIT
10
9
  Classifier: Development Status :: 4 - Beta
11
10
  Classifier: Programming Language :: Python
12
11
  Classifier: Programming Language :: Python :: 3.10
@@ -14,6 +14,7 @@ The basic bare-bone structure of an extension is as follows:
14
14
  ├── my_extension
15
15
  │ ├── __init__.py
16
16
  │ └── __main__.py
17
+ ├── secrets.json
17
18
  └── setup.py
18
19
 
19
20
  This structure can be generated by running the :doc:`/cli/create` command
@@ -195,7 +196,8 @@ Activation Config
195
196
 
196
197
  This is a config file that can be used for local testing, when extension instance
197
198
  is launched using the :doc:`/cli/run` command. It must contain all of the mandatory
198
- fields as defined in the `Activation Schema`_.
199
+ fields as defined in the `Activation Schema`_. This file also supports using secrets
200
+ from the ``secrets.json`` file.
199
201
 
200
202
  When extension is deployed to the Dynatrace environment and monitoring configuration
201
203
  is created, then the environment provides an individual activation config for each
@@ -215,12 +217,32 @@ Here is what a sample activation config looks like:
215
217
  {
216
218
  "url": "http://127.0.0.1:15672",
217
219
  "user": "guest",
218
- "password": "guest"
220
+ "password": "{{myPassword}}"
219
221
  }
220
222
  ]
221
223
  }
222
224
  }
223
225
 
226
+
227
+ Secrets
228
+ -----------------
229
+
230
+ ``secrets.json``
231
+
232
+ This file defines the secrets that can be used in ``activation.json``. Specify
233
+ each secret as key-value pair and then use ``{{key}}`` in the activation config
234
+ file to use the corresponding secret's value. Only secrets of type ``string``
235
+ are supported.
236
+
237
+ This file is by default in ``.gitignore``.
238
+
239
+ .. code:: json
240
+
241
+ {
242
+ "myPassword": "secretPassword"
243
+ }
244
+
245
+
224
246
  Setup.py
225
247
  --------
226
248
 
@@ -78,6 +78,7 @@ structure:
78
78
  ├── my_extension
79
79
  │ ├── __init__.py
80
80
  │ └── __main__.py
81
+ ├── secrets.json
81
82
  └── setup.py
82
83
 
83
84
  .. admonition:: What do these files mean?
@@ -3,4 +3,4 @@
3
3
  # SPDX-License-Identifier: MIT
4
4
 
5
5
 
6
- __version__ = "1.2.13"
6
+ __version__ = "1.3.0"
@@ -158,3 +158,6 @@ cython_debug/
158
158
  # and can be added to the global gitignore or merged into this file. For a more nuclear
159
159
  # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160
160
  #.idea/
161
+
162
+ # Secrets
163
+ secrets.json
@@ -8,7 +8,7 @@
8
8
  {
9
9
  "url": "http://127.0.0.1:15672",
10
10
  "user": "guest",
11
- "password": "guest"
11
+ "password": "{{myPassword}}"
12
12
  }
13
13
  ]
14
14
  }
@@ -40,6 +40,7 @@ def version():
40
40
  def run(
41
41
  extension_dir: Path = typer.Argument("."),
42
42
  activation_config: str = "activation.json",
43
+ secrets: str = "secrets.json",
43
44
  fast_check: bool = typer.Option(False, "--fastcheck"),
44
45
  local_ingest: bool = typer.Option(False, "--local-ingest"),
45
46
  local_ingest_port: int = typer.Option(14499, "--local-ingest-port"),
@@ -50,6 +51,7 @@ def run(
50
51
 
51
52
  :param extension_dir: The directory of the extension, by default this is the current directory
52
53
  :param activation_config: The activation config file, by default this is activation.json
54
+ :param secrets: The secrets file to be used to enrich the activation config, by default this is secrets.json
53
55
  :param fast_check: If true, run a fastcheck and exits
54
56
  :param local_ingest: If true, send metrics to localhost:14499 on top of printing them
55
57
  :param local_ingest_port: The port to send metrics to, by default this is 14499
@@ -59,7 +61,15 @@ def run(
59
61
  # This parses the yaml, which validates it before running
60
62
  extension_yaml = ExtensionYaml(extension_dir / "extension/extension.yaml")
61
63
  try:
62
- command = [sys.executable, "-m", extension_yaml.python.runtime.module, "--activationconfig", activation_config]
64
+ command = [
65
+ sys.executable,
66
+ "-m",
67
+ extension_yaml.python.runtime.module,
68
+ "--activationconfig",
69
+ activation_config,
70
+ "--secrets",
71
+ secrets,
72
+ ]
63
73
  if fast_check:
64
74
  command.append("--fastcheck")
65
75
  if local_ingest:
@@ -324,14 +324,24 @@ class DebugClient(CommunicationClient):
324
324
  activation_config_path: str,
325
325
  extension_config_path: str,
326
326
  logger: logging.Logger,
327
+ secrets_path: str = "secrets.json",
327
328
  local_ingest: bool = False,
328
329
  local_ingest_port: int = 14499,
329
330
  print_metrics: bool = True,
330
331
  ):
332
+
333
+ self.secrets = {}
334
+ if secrets_path and Path(secrets_path).exists():
335
+ with open(secrets_path) as f:
336
+ self.secrets = json.load(f)
337
+
331
338
  self.activation_config = {}
332
339
  if activation_config_path and Path(activation_config_path).exists():
333
340
  with open(activation_config_path) as f:
334
- self.activation_config = json.load(f)
341
+ raw_activation_config = f.read()
342
+ self.activation_config = json.loads(
343
+ self.replace_secrets_in_activation_config(self.secrets, raw_activation_config)
344
+ )
335
345
 
336
346
  self.extension_config = ""
337
347
  if not extension_config_path:
@@ -430,6 +440,12 @@ class DebugClient(CommunicationClient):
430
440
  def get_cluster_time_diff(self) -> int:
431
441
  return 0
432
442
 
443
+ def replace_secrets_in_activation_config(self, secrets: dict, activation_config_string: str) -> str:
444
+ for secret_name, secret_value in secrets.items():
445
+ activation_config_string = activation_config_string.replace(f"{{{{{secret_name}}}}}", str(secret_value))
446
+
447
+ return activation_config_string
448
+
433
449
 
434
450
  def divide_into_batches(
435
451
  items: Sequence[dict | str], max_size_bytes: int, join_with: str | None = None
@@ -715,6 +715,7 @@ class Extension:
715
715
  # Debug parameters, these are used when running the extension locally
716
716
  parser.add_argument("--extensionconfig", required=False, default=None)
717
717
  parser.add_argument("--activationconfig", required=False, default="activation.json")
718
+ parser.add_argument("--secrets", required=False, default="secrets.json")
718
719
  parser.add_argument("--no-print-metrics", required=False, action="store_true")
719
720
 
720
721
  args, unknown = parser.parse_known_args()
@@ -727,6 +728,7 @@ class Extension:
727
728
  activation_config_path=args.activationconfig,
728
729
  extension_config_path=args.extensionconfig,
729
730
  logger=api_logger,
731
+ secrets_path=args.secrets,
730
732
  local_ingest=args.local_ingest,
731
733
  local_ingest_port=args.local_ingest_port,
732
734
  print_metrics=print_metrics,
@@ -748,6 +750,7 @@ class Extension:
748
750
 
749
751
  if not self._is_fastcheck:
750
752
  try:
753
+ self._heartbeat_iteration()
751
754
  self.initialize()
752
755
  if not self.is_helper:
753
756
  self.schedule(self.query, timedelta(minutes=1))
@@ -813,7 +816,6 @@ class Extension:
813
816
  # These were scheduled before the extension started, schedule them now
814
817
  for callback in self._scheduled_callbacks_before_run:
815
818
  self._schedule_callback(callback)
816
- self._heartbeat_iteration()
817
819
  self._metrics_iteration()
818
820
  self._sfm_metrics_iteration()
819
821
  self._timediff_iteration()
@@ -29,7 +29,7 @@ class TestExtension(unittest.TestCase):
29
29
  extension._running_in_sim = True
30
30
  extension._next_heartbeat = datetime.now()
31
31
  extension._heartbeat_iteration()
32
- extension._heartbeat.assert_called_once()
32
+ extension._heartbeat.assert_called()
33
33
 
34
34
  def test_loglevel(self):
35
35
  pass
@@ -121,10 +121,6 @@ class TestExtension(unittest.TestCase):
121
121
  time.sleep(0.1)
122
122
  extension._metrics_iteration()
123
123
 
124
- # assert metrics sent
125
- arguments = extension._client.send_metrics.call_args.args[0]
126
- self.assertEqual(len(arguments), 200)
127
-
128
124
  def test_callback_from_init(self):
129
125
  class MyExt(Extension):
130
126
  def callback(self):