solnlib 8.2.0b1__tar.gz → 8.2.1b1__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 (39) hide show
  1. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/PKG-INFO +1 -1
  2. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/pyproject.toml +1 -1
  3. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/__init__.py +1 -1
  4. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/observability.py +30 -18
  5. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/splunkenv.py +62 -0
  6. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/LICENSE +0 -0
  7. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/_observability_flush.py +0 -0
  8. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/_settings.py +0 -0
  9. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/_utils.py +0 -0
  10. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/acl.py +0 -0
  11. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/alerts_rest_client.py +0 -0
  12. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/bulletin_rest_client.py +0 -0
  13. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/concurrent/concurrent_executor.py +0 -0
  14. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/concurrent/process_pool.py +0 -0
  15. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/concurrent/thread_pool.py +0 -0
  16. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/conf_manager.py +0 -0
  17. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/credentials.py +0 -0
  18. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/file_monitor.py +0 -0
  19. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/hec_config.py +0 -0
  20. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/log.py +0 -0
  21. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/modular_input/__init__.py +0 -0
  22. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/modular_input/checkpointer.py +0 -0
  23. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/modular_input/event.py +0 -0
  24. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/modular_input/event_writer.py +0 -0
  25. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/modular_input/modinput.py +0 -0
  26. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/modular_input/modular_input.py +0 -0
  27. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/net_utils.py +0 -0
  28. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/orphan_process_monitor.py +0 -0
  29. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/pattern.py +0 -0
  30. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/rest.py +0 -0
  31. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/schedule/job.py +0 -0
  32. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/schedule/scheduler.py +0 -0
  33. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/server_info.py +0 -0
  34. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/soln_exceptions.py +0 -0
  35. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/splunk_rest_client.py +0 -0
  36. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/time_parser.py +0 -0
  37. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/timer_queue.py +0 -0
  38. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/user_access.py +0 -0
  39. {solnlib-8.2.0b1 → solnlib-8.2.1b1}/solnlib/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: solnlib
3
- Version: 8.2.0b1
3
+ Version: 8.2.1b1
4
4
  Summary: The Splunk Software Development Kit for Splunk Solutions
5
5
  License: Apache-2.0
6
6
  License-File: LICENSE
@@ -16,7 +16,7 @@
16
16
 
17
17
  [tool.poetry]
18
18
  name = "solnlib"
19
- version = "8.2.0-beta.1"
19
+ version = "8.2.1-beta.1"
20
20
  description = "The Splunk Software Development Kit for Splunk Solutions"
21
21
  authors = ["Splunk <addonfactory@splunk.com>"]
22
22
  license = "Apache-2.0"
@@ -55,4 +55,4 @@ __all__ = [
55
55
  "utils",
56
56
  ]
57
57
 
58
- __version__ = "8.2.0-beta.1"
58
+ __version__ = "8.2.1-beta.1"
@@ -53,7 +53,7 @@ import threading
53
53
  import urllib.request
54
54
  from typing import Callable, ClassVar, Optional, Union
55
55
  from ._observability_flush import _register_controller
56
- from .splunkenv import get_conf_stanzas
56
+ from .splunkenv import _get_running_app_name, get_conf_stanzas
57
57
  from opentelemetry.metrics import Instrument, Meter
58
58
  from opentelemetry.sdk.metrics import MeterProvider, Counter, Histogram
59
59
  from opentelemetry.sdk.metrics.export import (
@@ -392,12 +392,14 @@ class ObservabilityService:
392
392
  logger: Python logger (or ``LoggerAdapter``) for all diagnostic
393
393
  output. Typically the caller's own module-level logger.
394
394
  ta_name: Add-on identifier, e.g. ``"Splunk_TA_myapp"``. When
395
- *None* the value is read from the ``[id]`` stanza of
396
- ``app.conf`` via :func:`~solnlib.splunkenv.get_conf_stanzas`.
397
- Pass it explicitly when the add-on runs outside a full Splunk
398
- environment or to avoid the ``app.conf`` lookup.
395
+ *None* the value is read from the ``[id]`` stanza of the
396
+ ``app.conf`` of the running app (detected from the main
397
+ script's path, then solnlib's own path; falling back to the
398
+ app directory name).
399
+ Pass it explicitly when the add-on runs outside a standard
400
+ ``etc/apps/<app>`` layout or to avoid the ``app.conf`` lookup.
399
401
  ta_version: Add-on version string, e.g. ``"3.1.0"``. When *None*
400
- the value is read from the ``[launcher]`` stanza of
402
+ the value is read from the ``[launcher]`` stanza of the same
401
403
  ``app.conf``. Falls back to ``"unknown"`` if it cannot be
402
404
  determined.
403
405
  extra_exporters: Optional list of additional
@@ -433,8 +435,8 @@ class ObservabilityService:
433
435
 
434
436
  if not ta_name:
435
437
  raise ValueError(
436
- "ta_name could not be determined: pass it explicitly or ensure "
437
- "app.conf is readable via btool"
438
+ "ta_name could not be determined: pass it explicitly or run "
439
+ "the add-on from etc/apps/<app>"
438
440
  )
439
441
 
440
442
  resource = Resource(
@@ -504,19 +506,29 @@ class ObservabilityService:
504
506
  )
505
507
 
506
508
  def _read_ta_info(self) -> tuple[Optional[str], Optional[str]]:
507
- """Read the add-on name and version from ``app.conf``.
509
+ """Read the add-on name and version from the owning app's ``app.conf``.
508
510
 
509
- Returns a ``(ta_name, ta_version)`` tuple. Either value is
510
- ``None`` when the corresponding key is missing or when
511
- ``app.conf`` cannot be read (e.g. outside a Splunk environment).
511
+ The owning app is the one whose script is running
512
+ (``etc/apps/<app>/bin/...``), or failing that the one that bundles
513
+ solnlib. The lookup is always scoped to that app: an unscoped
514
+ ``app.conf`` merge can return another installed add-on's ``[id]``
515
+ stanza.
516
+
517
+ Returns a ``(ta_name, ta_version)`` tuple. Both are ``None`` when the
518
+ owning app cannot be detected or ``app.conf`` cannot be read; the
519
+ version alone is ``None`` when ``[launcher] version`` is missing.
512
520
  """
513
521
  try:
514
- stanzas = get_conf_stanzas("app")
515
- ta_name = stanzas.get("id", {}).get("name") or None
516
- scoped_stanzas = (
517
- get_conf_stanzas("app", app_name=ta_name) if ta_name else stanzas
518
- )
519
- ta_version = scoped_stanzas.get("launcher", {}).get("version") or None
522
+ app_name = _get_running_app_name()
523
+ if not app_name:
524
+ self._logger.info(
525
+ "Could not determine the running add-on from the script "
526
+ "or solnlib path; app.conf not read"
527
+ )
528
+ return None, None
529
+ stanzas = get_conf_stanzas("app", app_name=app_name)
530
+ ta_name = stanzas.get("id", {}).get("name") or app_name
531
+ ta_version = stanzas.get("launcher", {}).get("version") or None
520
532
  return ta_name, ta_version
521
533
  except Exception as error:
522
534
  self._logger.info(
@@ -19,9 +19,11 @@ import os
19
19
  import os.path as op
20
20
  import socket
21
21
  import subprocess
22
+ import sys
22
23
  import json
23
24
  from configparser import ConfigParser
24
25
  from io import StringIO
26
+ from pathlib import Path
25
27
  from typing import Optional, Union
26
28
  import __main__
27
29
  from solnlib._settings import use_btool
@@ -66,6 +68,7 @@ __all__ = [
66
68
  ETC_LEAF = "etc"
67
69
  APP_SYSTEM = "system"
68
70
  APP_HEC = "splunk_httpinput"
71
+ _APPS_DIRS = ("apps", "peer-apps", "slave-apps")
69
72
 
70
73
 
71
74
  class SessionKeyNotFound(Exception):
@@ -92,6 +95,65 @@ def make_splunkhome_path(parts: Union[list, tuple]) -> str:
92
95
  return msp(parts)
93
96
 
94
97
 
98
+ def _is_splunk_etc_dir(path: Path) -> bool:
99
+ if op.normcase(path.name) == ETC_LEAF:
100
+ return True
101
+ splunk_etc = os.environ.get("SPLUNK_ETC")
102
+ return bool(splunk_etc) and op.normcase(op.realpath(splunk_etc)) == op.normcase(
103
+ op.realpath(path)
104
+ )
105
+
106
+
107
+ def _get_app_name_from_path(path: str) -> Optional[str]:
108
+ """Return the name of the Splunk app that contains `path`.
109
+
110
+ The app is the directory directly under ``$SPLUNK_ETC/apps`` (or
111
+ ``peer-apps`` / ``slave-apps`` on indexer cluster peers). For example,
112
+ ``$SPLUNK_HOME/etc/apps/Splunk_TA_test/bin/input.py`` resolves to
113
+ ``"Splunk_TA_test"``.
114
+
115
+ Arguments:
116
+ path: File system path to inspect.
117
+
118
+ Returns:
119
+ App name, or None if `path` is not inside a Splunk apps directory.
120
+ """
121
+ # Not utils.get_appname_from_path: that one returns "-", ignores
122
+ # SPLUNK_ETC and slave-apps, and is public, so its behaviour is kept.
123
+ try:
124
+ # abspath, not resolve(): apps symlinked into etc/apps keep their name.
125
+ absolute = Path(op.abspath(path))
126
+ # Outermost match first: Splunk's etc/apps sits above anything an app
127
+ # vendors that happens to contain etc/apps.
128
+ for candidate in reversed((absolute, *absolute.parents)):
129
+ parent = candidate.parent
130
+ if op.normcase(parent.name) in _APPS_DIRS and _is_splunk_etc_dir(
131
+ parent.parent
132
+ ):
133
+ return candidate.name
134
+ except (OSError, ValueError):
135
+ pass
136
+ return None
137
+
138
+
139
+ def _get_running_app_name() -> Optional[str]:
140
+ """Return the name of the Splunk app whose script is running.
141
+
142
+ Tries the main script first (modular inputs, alert actions and search
143
+ commands run from ``etc/apps/<app>/bin``; this path also keeps
144
+ symlinked app directories intact), then falls back to the app that
145
+ bundles solnlib.
146
+
147
+ Returns:
148
+ App name, or None if neither path is inside a Splunk apps directory.
149
+ """
150
+ argv = getattr(sys, "argv", None)
151
+ main_path = getattr(__main__, "__file__", None) or (argv[0] if argv else None)
152
+ return (main_path and _get_app_name_from_path(main_path)) or (
153
+ _get_app_name_from_path(__file__)
154
+ )
155
+
156
+
95
157
  def get_splunk_host_info(session_key: Optional[str] = None) -> tuple:
96
158
  """Get splunk host info.
97
159
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes