splunkctl 0.11.2__tar.gz → 0.12.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.
- {splunkctl-0.11.2 → splunkctl-0.12.0}/MANIFEST.in +1 -0
- {splunkctl-0.11.2/splunkctl.egg-info → splunkctl-0.12.0}/PKG-INFO +2 -2
- splunkctl-0.12.0/docs/guides/alerts.md +79 -0
- splunkctl-0.12.0/docs/guides/apps.md +65 -0
- splunkctl-0.12.0/docs/guides/audit.md +125 -0
- splunkctl-0.12.0/docs/guides/conf.md +84 -0
- splunkctl-0.12.0/docs/guides/configure.md +120 -0
- splunkctl-0.12.0/docs/guides/dashboards.md +17 -0
- splunkctl-0.12.0/docs/guides/datamodels.md +164 -0
- splunkctl-0.12.0/docs/guides/doctor.md +70 -0
- splunkctl-0.12.0/docs/guides/es.md +236 -0
- splunkctl-0.12.0/docs/guides/exit-codes.md +44 -0
- splunkctl-0.12.0/docs/guides/hec.md +59 -0
- splunkctl-0.12.0/docs/guides/indexes.md +76 -0
- splunkctl-0.12.0/docs/guides/inputs.md +80 -0
- splunkctl-0.12.0/docs/guides/install.md +55 -0
- splunkctl-0.12.0/docs/guides/knowledge.md +113 -0
- splunkctl-0.12.0/docs/guides/kvstore.md +125 -0
- splunkctl-0.12.0/docs/guides/lookups.md +127 -0
- splunkctl-0.12.0/docs/guides/mcp.md +173 -0
- splunkctl-0.12.0/docs/guides/parsers.md +67 -0
- splunkctl-0.12.0/docs/guides/rules.md +183 -0
- splunkctl-0.12.0/docs/guides/search.md +144 -0
- splunkctl-0.12.0/docs/guides/server.md +257 -0
- splunkctl-0.12.0/docs/guides/soar-actions.md +130 -0
- splunkctl-0.12.0/docs/guides/soar-admin.md +120 -0
- splunkctl-0.12.0/docs/guides/soar-approvals.md +99 -0
- splunkctl-0.12.0/docs/guides/soar-apps.md +56 -0
- splunkctl-0.12.0/docs/guides/soar-automation.md +132 -0
- splunkctl-0.12.0/docs/guides/soar-cases.md +178 -0
- splunkctl-0.12.0/docs/guides/soar-functions.md +94 -0
- splunkctl-0.12.0/docs/guides/soar-indicators.md +123 -0
- splunkctl-0.12.0/docs/guides/soar-ingest.md +161 -0
- splunkctl-0.12.0/docs/guides/soar-lists.md +110 -0
- splunkctl-0.12.0/docs/guides/soar-playbooks.md +267 -0
- splunkctl-0.12.0/docs/guides/soar.md +440 -0
- splunkctl-0.12.0/docs/guides/state.md +270 -0
- splunkctl-0.12.0/docs/guides/users.md +86 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/pyproject.toml +4 -1
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/__init__.py +1 -1
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/mcp_cmd.py +8 -5
- splunkctl-0.12.0/splunkctl/mcp/dynamic_server.py +132 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/prompts.py +8 -4
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/resources.py +20 -3
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/runner.py +0 -64
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/server.py +38 -59
- splunkctl-0.12.0/splunkctl/mcp/transport.py +18 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0/splunkctl.egg-info}/PKG-INFO +2 -2
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl.egg-info/SOURCES.txt +38 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl.egg-info/requires.txt +1 -1
- {splunkctl-0.11.2 → splunkctl-0.12.0}/LICENSE +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/README.md +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/setup.cfg +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/__main__.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/client.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/__init__.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/alerts.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/apps.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/audit.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/audit_parse.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/commands_meta.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/common.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/conf.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/conf_ops.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/config_cmd.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/dashboards.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/datamodels.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/docs_cmd.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/doctor.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/es.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/es_threat_intel.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/hec.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/indexes.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/info.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/inputs.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/knowledge.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/kvstore.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/lookups.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/lookups_wiring.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/parsers.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/parsers_io.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/rules.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/rules_io.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/rules_schedule.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/search.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/server.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/server_auth.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/server_deployment.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/server_tokens.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/server_topology.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/server_workloads.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/__init__.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/_client.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/_ingest_helpers.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/actions.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/admin.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/admin_roles_audit.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/admin_views.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/approvals.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/apps.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/artifacts.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/assets.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/cases.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/containers.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/containers_assign.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/containers_write.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/functions.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/indicators.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/ingest.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/lists.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/notes.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/playbook_runs.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/playbooks.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/playbooks_delete.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/search.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/system.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/vault.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/soar/workbook_templates.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state_io.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state_io_blobs.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state_io_confs.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state_io_soar.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state_io_soar_assets.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/state_types.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/commands/users.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/config.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/errors.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/guard.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/main.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/__init__.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/output_cap.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/mcp/tools.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/output.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/py.typed +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/soar/__init__.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/soar/cimcef.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/soar/client.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl/soar/web.py +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl.egg-info/dependency_links.txt +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl.egg-info/entry_points.txt +0 -0
- {splunkctl-0.11.2 → splunkctl-0.12.0}/splunkctl.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: splunkctl
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Open-source MCP server and CLI for Splunk Enterprise SIEM and Splunk SOAR.
|
|
5
5
|
Author: dannyota
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -27,7 +27,7 @@ Requires-Dist: pyyaml>=6.0
|
|
|
27
27
|
Requires-Dist: tabulate>=0.9
|
|
28
28
|
Requires-Dist: requests>=2.32
|
|
29
29
|
Requires-Dist: defusedxml>=0.7
|
|
30
|
-
Requires-Dist: mcp<2
|
|
30
|
+
Requires-Dist: mcp<3,>=2
|
|
31
31
|
Provides-Extra: dev
|
|
32
32
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
33
33
|
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Alerts
|
|
2
|
+
|
|
3
|
+
Fired alerts are the SOC's incoming work queue. During an incident, you
|
|
4
|
+
need to see what triggered, when, and at what severity. During planned
|
|
5
|
+
maintenance, you need to suppress noisy rules before they flood the
|
|
6
|
+
on-call channel. After the fact, auditors ask which alerts fired and
|
|
7
|
+
which were suppressed. These commands cover all three workflows.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
splunkctl alerts list # list fired alerts
|
|
13
|
+
splunkctl alerts get 'Alert Name' # details for one alert group
|
|
14
|
+
splunkctl alerts actions # list alert action types
|
|
15
|
+
splunkctl alerts suppress 'Alert Name' \
|
|
16
|
+
--duration 7200 --yes # suppress for 2 hours
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Triage during an incident
|
|
20
|
+
|
|
21
|
+
List all currently fired alerts to see what the environment is telling you.
|
|
22
|
+
Output includes name, trigger count, triggered time, and severity.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
splunkctl alerts list
|
|
26
|
+
splunkctl alerts get 'Brute Force Login Attempts'
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Check alert action types
|
|
30
|
+
|
|
31
|
+
See which action types (email, webhook, script, etc.) are configured on
|
|
32
|
+
the instance. Useful before creating or modifying saved searches that
|
|
33
|
+
fire alerts.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
splunkctl alerts actions
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Suppress during a maintenance window
|
|
40
|
+
|
|
41
|
+
Suppression is guarded -- dry-run by default. The first command below
|
|
42
|
+
previews the change; the second applies it. Duration is in seconds.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
splunkctl alerts suppress 'Brute Force Login Attempts' --duration 7200
|
|
46
|
+
splunkctl alerts suppress 'Brute Force Login Attempts' --duration 7200 --yes
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Suppress multiple alerts in a loop during a planned outage:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
for rule in 'Brute Force Login Attempts' 'Failed VPN Auth' 'DNS Exfil'; do
|
|
53
|
+
splunkctl alerts suppress "$rule" --duration 14400 --yes
|
|
54
|
+
done
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## JSON output for scripts and agents
|
|
58
|
+
|
|
59
|
+
Pass `--json` to get structured output suitable for piping into `jq`,
|
|
60
|
+
feeding into an LLM agent, or storing as audit evidence.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
splunkctl alerts list --json # all fired alerts
|
|
64
|
+
splunkctl alerts list --json | jq '.[] | select(.severity >= 6)'
|
|
65
|
+
splunkctl alerts get 'Brute Force Login Attempts' --json > alert_detail.json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
An LLM agent can consume the JSON directly to decide next steps --
|
|
69
|
+
for example, correlating fired alerts with a change window calendar
|
|
70
|
+
or auto-filing tickets for high-severity triggers.
|
|
71
|
+
|
|
72
|
+
## Options
|
|
73
|
+
|
|
74
|
+
| Flag | Applies to | Description |
|
|
75
|
+
|------|-----------|-------------|
|
|
76
|
+
| `--duration` | `suppress` | Suppression length in seconds (default 3600) |
|
|
77
|
+
| `--json` | all | Force JSON output regardless of TTY |
|
|
78
|
+
| `--format` | all | Output format: `table`, `json`, `csv`, `jsonl` |
|
|
79
|
+
| `--yes` | `suppress` | Apply the mutation (skip dry-run preview) |
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Apps
|
|
2
|
+
|
|
3
|
+
Splunk's detection and enrichment capabilities live in apps --
|
|
4
|
+
Technology Add-ons (TAs) for data normalization, security content packs
|
|
5
|
+
like Splunk Enterprise Security, and custom apps with org-specific
|
|
6
|
+
detections. Managing these remotely lets you deploy, update, and audit
|
|
7
|
+
apps across instances without SSH or manual Web UI clicks.
|
|
8
|
+
|
|
9
|
+
## Commands
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
splunkctl apps list # list installed apps
|
|
13
|
+
splunkctl apps get SplunkForwarder # get app details
|
|
14
|
+
splunkctl apps install --path ./app.spl --yes # install from local file
|
|
15
|
+
splunkctl apps install --path ./app.tar.gz \
|
|
16
|
+
--force --yes # force overwrite
|
|
17
|
+
splunkctl apps uninstall my_app --yes # uninstall
|
|
18
|
+
splunkctl apps update my_app --enabled \
|
|
19
|
+
--visible --yes # enable + show
|
|
20
|
+
splunkctl apps update my_app --disabled \
|
|
21
|
+
--hidden --yes # disable + hide
|
|
22
|
+
splunkctl apps reload --yes # reload all apps
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Remote install
|
|
26
|
+
|
|
27
|
+
`apps install --path` uploads a local `.spl` or `.tar.gz` package to
|
|
28
|
+
the remote Splunk instance via the Web UI handler. No SSH, no SCP, no
|
|
29
|
+
server filesystem access needed -- push from your laptop to any
|
|
30
|
+
reachable instance.
|
|
31
|
+
|
|
32
|
+
Use `--force` to overwrite an existing app of the same name.
|
|
33
|
+
|
|
34
|
+
## Practical examples
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
# Deploy a TA for Windows event log normalization
|
|
38
|
+
splunkctl apps install \
|
|
39
|
+
--path ./Splunk_TA_windows-8.9.0.spl --yes
|
|
40
|
+
|
|
41
|
+
# Upgrade a security content pack (force overwrite)
|
|
42
|
+
splunkctl apps install \
|
|
43
|
+
--path ./DA-ESS-ContentUpdate-4.29.0.spl --force --yes
|
|
44
|
+
|
|
45
|
+
# Disable an app during an incident (stop its scheduled searches)
|
|
46
|
+
splunkctl apps update SplunkEnterpriseSecuritySuite \
|
|
47
|
+
--disabled --yes
|
|
48
|
+
|
|
49
|
+
# Re-enable after the incident
|
|
50
|
+
splunkctl apps update SplunkEnterpriseSecuritySuite \
|
|
51
|
+
--enabled --yes
|
|
52
|
+
|
|
53
|
+
# Audit installed apps -- pipe JSON to jq for scripting
|
|
54
|
+
splunkctl apps list --json | jq '.[] | {name, version, disabled}'
|
|
55
|
+
|
|
56
|
+
# Reload all app configs after a bulk change
|
|
57
|
+
splunkctl apps reload --yes
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Notes
|
|
61
|
+
|
|
62
|
+
- App install may require a Splunk restart to activate new modular
|
|
63
|
+
inputs or scripted lookups. The CLI does not restart automatically.
|
|
64
|
+
- `--force` is required when reinstalling or upgrading an app that
|
|
65
|
+
already exists on the instance.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Change audit & RBAC attestation
|
|
2
|
+
|
|
3
|
+
Regulator-facing evidence for bank SOC operations: who changed what
|
|
4
|
+
(`audit changes`) and who can do what (`audit rbac`). Both commands are
|
|
5
|
+
**read-only** — no `guard`, no `--yes` needed.
|
|
6
|
+
|
|
7
|
+
## Why this matters
|
|
8
|
+
|
|
9
|
+
Banks carry regulator obligations for change-management evidence ("who
|
|
10
|
+
changed this saved search / role / index, and when") and periodic access
|
|
11
|
+
recertification ("who has which capabilities, and why"). Today an agent
|
|
12
|
+
would have to hand-write `index=_audit` SPL and know that Splunk mixes
|
|
13
|
+
**two incompatible event shapes** in that one index — this group
|
|
14
|
+
normalizes both into one schema and joins the RBAC graph so neither
|
|
15
|
+
requires bespoke SPL per engagement.
|
|
16
|
+
|
|
17
|
+
## Commands
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
splunkctl audit changes # last 24h, up to 500
|
|
21
|
+
splunkctl audit changes --since -7d --until -1d # explicit window
|
|
22
|
+
splunkctl audit changes --user jdoe # exact-match user
|
|
23
|
+
splunkctl audit changes --action edit # substring-match action
|
|
24
|
+
splunkctl audit changes --object-type saved_search # exact-match object type
|
|
25
|
+
splunkctl audit changes --limit 2000 --json # raise the display cap
|
|
26
|
+
|
|
27
|
+
splunkctl audit rbac # one row per user
|
|
28
|
+
splunkctl audit rbac --format csv --out recert-2026-07.csv # recertification export
|
|
29
|
+
splunkctl audit rbac --roles-only # one row per role
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## `audit changes`: normalized schema
|
|
33
|
+
|
|
34
|
+
Every row has exactly six keys, in this order: `time`, `user`, `action`,
|
|
35
|
+
`object`, `object_type`, `app`. Splunk's `_audit` index mixes two
|
|
36
|
+
sourcetypes and this command normalizes both:
|
|
37
|
+
|
|
38
|
+
| Sourcetype | Shape | Mapping |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `audittrail` (legacy) | `Audit:[timestamp=..., user=..., action=..., <tail>]` plain text | `user`/`action` parsed directly; `object` only when the line carries a literal `object="..."` marker (common on capability checks like `edit_user`/`edit_roles`); `object_type` is always empty — the legacy format has no per-action type field; `app` from `app="..."` or unquoted `app=...`, when present |
|
|
41
|
+
| `audittrailv2` (structured) | one JSON object per line | `user` = `actor.name`; `action` = top-level `action`; `object` = `data.name`; `object_type` = `data.type`; `app` = `data.ownership.app` or `data.attributes.app` |
|
|
42
|
+
|
|
43
|
+
`time` always comes from Splunk's own indexed `_time` (not a re-parse of
|
|
44
|
+
either embedded timestamp format) — it's present on every event
|
|
45
|
+
regardless of shape and gives one consistent, sortable value.
|
|
46
|
+
|
|
47
|
+
There is no literal `data.object`/`data.object_type` key on real
|
|
48
|
+
`audittrailv2` events; `data.name`/`data.type` are the nearest
|
|
49
|
+
equivalents and confirmed present for object/system-category events
|
|
50
|
+
(config changes). Action/authn/check-category events (ad-hoc searches,
|
|
51
|
+
logins, capability grants) carry `data.type` sometimes but rarely
|
|
52
|
+
`data.name` — `object` stays empty for those, which is correct: they
|
|
53
|
+
aren't changes to a named object.
|
|
54
|
+
|
|
55
|
+
An event matching neither shape is **never dropped** — it comes back as
|
|
56
|
+
`action: "unparsed"` with the full raw line in `object`, so evidence
|
|
57
|
+
stays complete even for audit-log formats this parser doesn't yet know.
|
|
58
|
+
|
|
59
|
+
## `audit changes`: SPL safety
|
|
60
|
+
|
|
61
|
+
The dispatched search is always the constant `search index=_audit` —
|
|
62
|
+
nothing else, ever. `--since`/`--until` go through the oneshot job's
|
|
63
|
+
`earliest_time`/`latest_time` kwargs (not string-composed), and
|
|
64
|
+
`--user`/`--action`/`--object-type` filter the already-normalized rows
|
|
65
|
+
**client-side**, after the fetch. No flag value — however adversarial —
|
|
66
|
+
reaches the SPL string. Verified live with `--debug`:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
$ splunkctl --debug audit changes --user 'x" | delete' --action 'y | outputlookup evil.csv'
|
|
70
|
+
...
|
|
71
|
+
POST .../search/v2/jobs/ (body: {'search': 'search index=_audit', ...})
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
`--limit` (default 500) applies **after** filtering, not to the raw
|
|
75
|
+
fetch — the raw fetch itself is unbounded (`count=0`) within the
|
|
76
|
+
`--since`/`--until` window, so a `--user`/`--action` filter never misses
|
|
77
|
+
a match just because it fell outside an arbitrary raw-fetch cutoff.
|
|
78
|
+
A very wide `--since` over a large `_audit` index may fetch all events in that range before limiting, which can be slow; narrow `--since` when possible.
|
|
79
|
+
`--user`/`--object-type` are case-insensitive exact match; `--action` is case-insensitive substring match.
|
|
80
|
+
|
|
81
|
+
## `audit rbac`: aggregation
|
|
82
|
+
|
|
83
|
+
One row per user by default: `user`, `email`, `roles` (direct roles,
|
|
84
|
+
semicolon-joined), `capabilities`, `srch_indexes_allowed`. The last two
|
|
85
|
+
are aggregated across the user's direct roles **and the full transitive
|
|
86
|
+
closure of their imported roles** — deduplicated, sorted, and
|
|
87
|
+
semicolon-joined. `--roles-only` flips to one row per role instead:
|
|
88
|
+
`role`, `imported_roles` (direct only), `capabilities`,
|
|
89
|
+
`srch_indexes_allowed` (both aggregated the same transitive way, rooted
|
|
90
|
+
at that role).
|
|
91
|
+
|
|
92
|
+
Example: role `soc_analyst` imports `power`, which imports `user`. A
|
|
93
|
+
`soc_analyst` user's effective `capabilities` is the union of all three
|
|
94
|
+
roles' own capabilities — this is what a role with zero capabilities of
|
|
95
|
+
its own (e.g. Splunk's built-in `splunk-system-role`, which only imports
|
|
96
|
+
`admin`) needs to show its real effective grant, not an empty cell.
|
|
97
|
+
|
|
98
|
+
## CSV round-trip safety
|
|
99
|
+
|
|
100
|
+
Multi-value fields (`roles`, `capabilities`, `srch_indexes_allowed`,
|
|
101
|
+
`imported_roles`) join with `;`, never `\n` — Splunk role/capability/index
|
|
102
|
+
names can't contain a semicolon, so this is a safe, lossless join that
|
|
103
|
+
never produces an embedded newline inside a CSV cell. `--format csv`
|
|
104
|
+
output round-trips cleanly through Python's `csv` module.
|
|
105
|
+
|
|
106
|
+
## Options
|
|
107
|
+
|
|
108
|
+
| Flag | Applies to | Description |
|
|
109
|
+
|------|-----------|--------------|
|
|
110
|
+
| `--since` | `changes` | Earliest time (default `-24h`) |
|
|
111
|
+
| `--until` | `changes` | Latest time (default `now`) |
|
|
112
|
+
| `--user` | `changes` | Filter by user, case-insensitive exact match |
|
|
113
|
+
| `--action` | `changes` | Filter by action, case-insensitive substring match |
|
|
114
|
+
| `--object-type` | `changes` | Filter by object type, case-insensitive exact match |
|
|
115
|
+
| `--limit` | `changes` | Max results after client-side filtering (default 500) |
|
|
116
|
+
| `--roles-only` | `rbac` | One row per role instead of per user |
|
|
117
|
+
|
|
118
|
+
## Implementation notes
|
|
119
|
+
|
|
120
|
+
`changes` runs over the existing oneshot-search infrastructure
|
|
121
|
+
(`svc.jobs.oneshot`); the event-shape parsers live in a sibling module,
|
|
122
|
+
`splunkctl/commands/audit_parse.py`, kept separate from the click
|
|
123
|
+
commands since they're pure functions with their own fixture-driven test
|
|
124
|
+
suite. `rbac` is SDK reads only (`svc.roles`, `svc.users`) — no oneshot
|
|
125
|
+
search involved.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Conf
|
|
2
|
+
|
|
3
|
+
Generic conf file/stanza editor over the REST `confs` API — the escape
|
|
4
|
+
hatch for any Splunk conf file that doesn't have a dedicated command
|
|
5
|
+
group yet: `macros`, `eventtypes`, `tags`, `limits`, `authorize`,
|
|
6
|
+
`server`, `web`, and everything else under `$SPLUNK_HOME/etc/*/local`.
|
|
7
|
+
|
|
8
|
+
## Why this matters
|
|
9
|
+
|
|
10
|
+
Detections depend on more than saved searches: macros expand reusable
|
|
11
|
+
SPL fragments, eventtypes classify events, tags drive CIM compliance,
|
|
12
|
+
and calculated fields live in `props.conf` alongside sourcetypes.
|
|
13
|
+
`parsers` only reaches `props.conf`/`transforms.conf`; `conf` reaches
|
|
14
|
+
every other conf file the same way, so nothing detection-relevant is
|
|
15
|
+
locked out of code review or CI.
|
|
16
|
+
|
|
17
|
+
There is **no blocklist** — `conf` can edit `authorize.conf`,
|
|
18
|
+
`server.conf`, and `web.conf` just as readily as `macros.conf`. The
|
|
19
|
+
dry-run guard and `--yes` are the only safety net: every `set`/`unset`/
|
|
20
|
+
`reload` preview names the exact file and stanza before it touches
|
|
21
|
+
anything, so review the preview before applying to a sensitive file.
|
|
22
|
+
|
|
23
|
+
## Commands
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
splunkctl conf files # list conf files
|
|
27
|
+
splunkctl conf list macros # list stanzas in macros.conf
|
|
28
|
+
splunkctl conf list macros --app my_app # scope to one app's stanzas
|
|
29
|
+
splunkctl conf get macros my_macro # full stanza config
|
|
30
|
+
splunkctl conf get macros my_macro --key definition # one key
|
|
31
|
+
splunkctl conf set macros my_macro \
|
|
32
|
+
definition='index=main' --yes # create/update keys
|
|
33
|
+
splunkctl conf unset macros my_macro definition --yes # clear a key
|
|
34
|
+
splunkctl conf reload macros --yes # reload the conf file
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Recipes
|
|
38
|
+
|
|
39
|
+
### Add a macro
|
|
40
|
+
|
|
41
|
+
Create a macro and verify it before rollout:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
splunkctl conf set macros my_macro \
|
|
45
|
+
definition='index=main sourcetype=syslog' --yes
|
|
46
|
+
splunkctl conf get macros my_macro
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Audit an eventtype
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
splunkctl conf get eventtypes authentication --json | jq .
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Review a stanza change before applying
|
|
56
|
+
|
|
57
|
+
`conf set` always previews a field-level diff — old value on the left,
|
|
58
|
+
new value on the right, `add` for a brand-new key:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
splunkctl conf set macros my_macro definition='index=main'
|
|
62
|
+
# [DRY RUN] ...
|
|
63
|
+
# definition: index=old -> index=main
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### List conf files to find the right one
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
splunkctl conf files --filter tag
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Tips
|
|
73
|
+
|
|
74
|
+
- `conf set` creates the stanza if it doesn't exist yet — there's no
|
|
75
|
+
separate create step.
|
|
76
|
+
- The REST API has no true per-key delete; `conf unset` sets keys to
|
|
77
|
+
the empty string (same mechanism `parsers unset` uses). To fully
|
|
78
|
+
remove a stanza, use the dedicated command group for that conf file
|
|
79
|
+
when one exists (e.g. `parsers delete` for `props.conf`).
|
|
80
|
+
- `--app` on `conf list`/`conf files` matters: the unscoped default
|
|
81
|
+
view can miss app-private stanzas, same as `rules list`/`dashboards
|
|
82
|
+
list`.
|
|
83
|
+
- Reload the conf file after a `set`/`unset` if the change needs to
|
|
84
|
+
take effect immediately (`conf reload <file> --yes`).
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Configure
|
|
2
|
+
|
|
3
|
+
## Interactive setup
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
splunkctl config init
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Prompts for host, port, auth method (token or username/password), tests the
|
|
10
|
+
connection, and writes `~/.splunkctl/config.yaml` with `0600` permissions.
|
|
11
|
+
|
|
12
|
+
## Config file
|
|
13
|
+
|
|
14
|
+
Location: `~/.splunkctl/config.yaml`
|
|
15
|
+
|
|
16
|
+
```yaml
|
|
17
|
+
host: "localhost"
|
|
18
|
+
port: 8089
|
|
19
|
+
scheme: "https"
|
|
20
|
+
username: "admin"
|
|
21
|
+
password: "" # optional, can use token instead
|
|
22
|
+
token: "" # bearer token (preferred)
|
|
23
|
+
verify: true # TLS cert verification (default: on)
|
|
24
|
+
app: "search" # default app context
|
|
25
|
+
owner: "nobody" # default owner context
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**TLS verification is on by default.** Production instances with valid
|
|
29
|
+
certificates work out of the box. For lab/dev instances with self-signed
|
|
30
|
+
certs, set `verify: false` explicitly in the profile — `config init` asks
|
|
31
|
+
during setup (default: yes).
|
|
32
|
+
|
|
33
|
+
## Profiles (dev/UAT/prod)
|
|
34
|
+
|
|
35
|
+
For more than one Splunk instance, add a `profiles:` map and a `current:`
|
|
36
|
+
pointer instead of the flat keys above:
|
|
37
|
+
|
|
38
|
+
```yaml
|
|
39
|
+
profiles:
|
|
40
|
+
dev:
|
|
41
|
+
host: "dev.splunk.internal"
|
|
42
|
+
username: "admin"
|
|
43
|
+
password: "devpass"
|
|
44
|
+
uat:
|
|
45
|
+
host: "uat.splunk.internal"
|
|
46
|
+
token: "..."
|
|
47
|
+
prod:
|
|
48
|
+
host: "prod.splunk.internal"
|
|
49
|
+
token: "..."
|
|
50
|
+
current: "uat" # active profile when nothing else selects one
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
splunkctl config init --profile uat ... # create/update one named profile
|
|
55
|
+
splunkctl config use uat # point 'current' at it (no connectivity test)
|
|
56
|
+
splunkctl config show # active profile (redacted) + other names
|
|
57
|
+
splunkctl config show --profile prod # show a specific profile without switching
|
|
58
|
+
splunkctl --profile prod rules list # override for a single invocation
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Selection precedence**: `--profile <name>` global flag > `current:`
|
|
62
|
+
pointer > `default`.
|
|
63
|
+
|
|
64
|
+
**Legacy files keep working.** A plain flat file (no `profiles:` key) is
|
|
65
|
+
treated as an implicit profile named `default` — nothing to migrate. Bare
|
|
66
|
+
`config init` writes that flat shape — unless the destination file already
|
|
67
|
+
has a `profiles:` key, in which case it folds the new values into
|
|
68
|
+
`profiles.default` instead, leaving sibling profiles and `current`
|
|
69
|
+
untouched (bare `config init` never clobbers an existing multi-profile
|
|
70
|
+
file). The first time you run `config init --profile <name>` against a
|
|
71
|
+
legacy file, it's upgraded to the `profiles:` schema in place: the old flat
|
|
72
|
+
keys move under `profiles.default`, the new named profile is added
|
|
73
|
+
alongside it, and file permissions stay `0600`.
|
|
74
|
+
|
|
75
|
+
**Guard banner.** Every dry-run preview and `--yes` confirmation prints
|
|
76
|
+
which instance is about to be mutated —
|
|
77
|
+
`[DRY RUN] ... (profile: uat @ uat.splunk.internal:8089)` — so switching
|
|
78
|
+
between dev/UAT/prod never happens silently. The banner is built from local
|
|
79
|
+
config only; it never opens a connection.
|
|
80
|
+
|
|
81
|
+
## Environment variables
|
|
82
|
+
|
|
83
|
+
| Variable | Maps to |
|
|
84
|
+
|---|---|
|
|
85
|
+
| `SPLUNK_HOST` | `host` |
|
|
86
|
+
| `SPLUNK_PORT` | `port` |
|
|
87
|
+
| `SPLUNK_TOKEN` | `token` |
|
|
88
|
+
| `SPLUNK_USER` | `username` |
|
|
89
|
+
| `SPLUNK_PASS` | `password` |
|
|
90
|
+
|
|
91
|
+
Env vars override fields of whichever profile is selected — same as they
|
|
92
|
+
override the flat config today.
|
|
93
|
+
|
|
94
|
+
## Resolution priority
|
|
95
|
+
|
|
96
|
+
1. CLI flags (`--host`, `--port`, `--token`)
|
|
97
|
+
2. Environment variables
|
|
98
|
+
3. Profile (config file)
|
|
99
|
+
|
|
100
|
+
## Watch mode
|
|
101
|
+
|
|
102
|
+
Re-run any read-only command at a fixed interval, clearing the screen
|
|
103
|
+
between runs (like `watch(1)` on Linux). Errors are printed in place and
|
|
104
|
+
the loop continues. Press Ctrl-C to stop.
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
splunkctl --watch 5 indexes list # refresh every 5 seconds
|
|
108
|
+
splunkctl --watch 10 server health # poll server health
|
|
109
|
+
splunkctl --watch 3 rules list --filter brute # filtered view
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Requires an interactive terminal (TTY). Mutation commands (those guarded
|
|
113
|
+
by `--yes`) are rejected.
|
|
114
|
+
|
|
115
|
+
## Verify
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
splunkctl config show # display config (secrets redacted)
|
|
119
|
+
splunkctl config test # test connectivity + auth
|
|
120
|
+
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Dashboards
|
|
2
|
+
|
|
3
|
+
## Commands
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
splunkctl dashboards list # list dashboards
|
|
7
|
+
splunkctl dashboards list --app search # filter by app
|
|
8
|
+
splunkctl dashboards get <name> # get definition (XML)
|
|
9
|
+
splunkctl dashboards create --name new_dash --file dash.xml \
|
|
10
|
+
--app search --yes
|
|
11
|
+
splunkctl dashboards update <name> --file updated.xml \
|
|
12
|
+
--app search --yes
|
|
13
|
+
splunkctl dashboards delete <name> --app search --yes
|
|
14
|
+
splunkctl dashboards export <name> --out dash.xml
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Uses the `Dashboard`/`Dashboards` entity classes from the SDK fork.
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Data models (CIM/tstats acceleration)
|
|
2
|
+
|
|
3
|
+
Mature SOC detections run on accelerated CIM data models via `| tstats`
|
|
4
|
+
— this group answers "which models exist," "is acceleration healthy,"
|
|
5
|
+
and "trigger a rebuild when stale." No SDK entity for data models
|
|
6
|
+
(unlike dashboards/lookups/HEC tokens) — every command is a thin, typed
|
|
7
|
+
wrapper around the raw `datamodel/model` and `admin/summarization` REST
|
|
8
|
+
collections, same pattern as `kvstore`/`server`.
|
|
9
|
+
|
|
10
|
+
## Why two REST resources
|
|
11
|
+
|
|
12
|
+
`datamodel/model`'s `content["acceleration"]` field is only the
|
|
13
|
+
**configuration** — `enabled`, `earliest_time` (the summarization
|
|
14
|
+
window), `cron_schedule`. It does **not** carry build progress. Percent
|
|
15
|
+
complete, the actual summarized earliest/latest range, size, and the
|
|
16
|
+
last build error live on a separate `admin/summarization` entity, one
|
|
17
|
+
per accelerated model, named `tstats:DM_<app>_<model>`.
|
|
18
|
+
|
|
19
|
+
This shape was confirmed against this project's own Splunk 10.4 install,
|
|
20
|
+
not guessed from REST trial and error alone: the installed
|
|
21
|
+
`splunk.models.summarization.Summarization` REST model class
|
|
22
|
+
(`$SPLUNK_HOME/lib/python3.13/site-packages/splunk/models/summarization.py`)
|
|
23
|
+
declares every `summary.*` field this group reads, and the bundled Data
|
|
24
|
+
Model Manager JS (`data_model_manager.js`) builds the exact
|
|
25
|
+
`tstats:DM_<app>_<model>` id when it fetches a model's acceleration
|
|
26
|
+
info in the Splunk Web UI. Both ship with splunkd itself, so they
|
|
27
|
+
describe exactly what this REST API version does — the same UI page an
|
|
28
|
+
admin would open to check acceleration health.
|
|
29
|
+
|
|
30
|
+
## Commands
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
splunkctl datamodels list # name, app, accelerated, disabled
|
|
34
|
+
splunkctl datamodels list --app Splunk_SA_CIM
|
|
35
|
+
splunkctl datamodels list --filter auth
|
|
36
|
+
|
|
37
|
+
splunkctl datamodels get Authentication # detection-engineering summary
|
|
38
|
+
splunkctl datamodels get Authentication --definition # raw objects/fields/calculations JSON
|
|
39
|
+
splunkctl datamodels get Authentication --app Splunk_SA_CIM
|
|
40
|
+
|
|
41
|
+
splunkctl datamodels acceleration # every accelerated model's build status
|
|
42
|
+
splunkctl datamodels acceleration Authentication # one model (accelerated or not)
|
|
43
|
+
|
|
44
|
+
splunkctl datamodels rebuild Authentication --yes # re-summarize from scratch (guarded)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## `list`: cheap collection fields only
|
|
48
|
+
|
|
49
|
+
Columns: `name`, `app`, `accelerated` (bool), `disabled` (bool) — all
|
|
50
|
+
read straight off the collection listing, no per-model follow-up call.
|
|
51
|
+
`--app` (default: all apps), plus the uniform `--limit`/`--offset`/
|
|
52
|
+
`--filter` paging (F2): `--filter` forces a full fetch with client-side
|
|
53
|
+
case-insensitive name matching; without it, `--limit`/`--offset` pass
|
|
54
|
+
straight through to the REST call as `count`/`offset`.
|
|
55
|
+
|
|
56
|
+
## `get`: detection-engineering summary, not the full blob
|
|
57
|
+
|
|
58
|
+
A data model's raw definition (`content["description"]`) is a
|
|
59
|
+
JSON-encoded string that can run past 250KB for a CIM model with dozens
|
|
60
|
+
of objects — `get` parses it once and surfaces only what a detection
|
|
61
|
+
engineer actually needs:
|
|
62
|
+
|
|
63
|
+
- `name`, `app`, `displayName`, `disabled`
|
|
64
|
+
- `acceleration_enabled`, `acceleration_earliest_time`,
|
|
65
|
+
`acceleration_cron_schedule` — the acceleration *config* (not status;
|
|
66
|
+
use `acceleration` for that)
|
|
67
|
+
- `object_count`, `objects` (comma-joined object names)
|
|
68
|
+
- `root_search` — the base object's first constraint search, i.e. what
|
|
69
|
+
raw index/sourcetype/tag the whole model actually covers
|
|
70
|
+
|
|
71
|
+
Pass `--definition` to get the raw, pretty-printed objects/fields/
|
|
72
|
+
calculations JSON instead — same shape as `dashboards get --definition`,
|
|
73
|
+
just for a data model's object hierarchy instead of a Studio dashboard's
|
|
74
|
+
visualization JSON.
|
|
75
|
+
|
|
76
|
+
## `acceleration`: the money command
|
|
77
|
+
|
|
78
|
+
`datamodels acceleration` (no argument) lists every model whose
|
|
79
|
+
acceleration config is enabled, with its build status:
|
|
80
|
+
|
|
81
|
+
- `enabled` — acceleration config state (should always be `true` here)
|
|
82
|
+
- `has_summary` — whether `admin/summarization` has an entity yet (a
|
|
83
|
+
freshly-enabled model with a cron that hasn't fired yet is
|
|
84
|
+
`enabled: true, has_summary: false` — accelerated, but nothing built)
|
|
85
|
+
- `is_complete` / `percent_complete` — from `summary.complete` (a 0–1
|
|
86
|
+
fraction server-side; rendered here as a 0–100 percentage, rounded to
|
|
87
|
+
1 decimal place: `round(float(complete) * 100, 1)`)
|
|
88
|
+
- `size`, `earliest_summarized`, `latest_summarized` — raw
|
|
89
|
+
`summary.size`/`summary.earliest_time`/`summary.latest_time`,
|
|
90
|
+
unmodified (epoch seconds, not reformatted)
|
|
91
|
+
- `last_error` — `summary.last_error` (a list server-side, one entry
|
|
92
|
+
per distributed peer) joined with `; `; empty string when clean
|
|
93
|
+
|
|
94
|
+
If nothing is accelerated, this cleanly renders an empty result — never
|
|
95
|
+
an error — and skips the `admin/summarization` fetch entirely (no
|
|
96
|
+
accelerated models means nothing to look up).
|
|
97
|
+
|
|
98
|
+
`datamodels acceleration <name>` shows one model regardless of whether
|
|
99
|
+
it's accelerated: `enabled: false` (with every other field blank/`null`)
|
|
100
|
+
is a valid, non-error answer to "is this model accelerated at all" — an
|
|
101
|
+
agent auditing acceleration coverage across many models shouldn't have
|
|
102
|
+
to special-case the read path for the ones that aren't accelerated yet.
|
|
103
|
+
Only a model that doesn't exist at all is an error (`kind: "not_found"`).
|
|
104
|
+
|
|
105
|
+
## `rebuild`: guarded, disable-then-re-enable
|
|
106
|
+
|
|
107
|
+
There is no dedicated "rebuild" REST verb for data model acceleration.
|
|
108
|
+
Splunk Web's own "Rebuild" button (confirmed from the installed Data
|
|
109
|
+
Model Manager JS) works by POSTing `datamodel/model/<name>` twice:
|
|
110
|
+
first `acceleration=0` (disable), then `acceleration=1` with the same
|
|
111
|
+
`acceleration.earliest_time` re-sent explicitly (re-enable) — this drops
|
|
112
|
+
the existing tsidx summary and re-summarizes historical data for the
|
|
113
|
+
same window from scratch. `datamodels rebuild <name>` does exactly this,
|
|
114
|
+
behind the standard dry-run guard:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
splunkctl datamodels rebuild Authentication # [DRY RUN] preview, no changes
|
|
118
|
+
splunkctl datamodels rebuild Authentication --yes # applies: disable, then re-enable
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The dry-run preview names the model, its app, the preserved
|
|
122
|
+
`earliest_time` window, and states plainly that this re-summarizes
|
|
123
|
+
historical data from scratch — there is no partial/incremental rebuild.
|
|
124
|
+
|
|
125
|
+
**Only meaningful for an already-accelerated model.** If the named
|
|
126
|
+
model's acceleration config is disabled, `rebuild` exits 1 with a clear
|
|
127
|
+
message *before* the dry-run/`--yes` guard even runs — passing `--yes`
|
|
128
|
+
against a non-accelerated model does not print a preview and does not
|
|
129
|
+
touch anything, it just fails the same way the bare dry-run would.
|
|
130
|
+
|
|
131
|
+
**Known caveat (inherent to the underlying REST API, not this CLI):**
|
|
132
|
+
because a rebuild is two separate POSTs, a failure between them (e.g. a
|
|
133
|
+
permission or connectivity error on the second call) can leave the
|
|
134
|
+
model disabled without the summary having restarted. This is exactly
|
|
135
|
+
the same risk Splunk Web's own Rebuild button carries — there is no
|
|
136
|
+
atomic rebuild operation to fall back to. A rebuild failure surfaces
|
|
137
|
+
through the normal F1 classified envelope; re-running `datamodels get
|
|
138
|
+
<name>` afterward shows whether acceleration ended up enabled again.
|
|
139
|
+
|
|
140
|
+
## Errors
|
|
141
|
+
|
|
142
|
+
REST failures are never caught locally — they flow straight through the
|
|
143
|
+
CLI's F1 error-envelope classification (`splunkctl.errors.classify`), so
|
|
144
|
+
a down or misconfigured instance always surfaces a clean `kind`/
|
|
145
|
+
`http_status`/`message`, never blank output or a raw traceback:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
$ splunkctl --json datamodels list
|
|
149
|
+
{"error": {"kind": "http", "http_status": 503, "message": "..."}}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Live-verified status
|
|
153
|
+
|
|
154
|
+
`list`/`get`/`acceleration` (read paths) and `rebuild`'s dry-run preview
|
|
155
|
+
and not-accelerated rejection are live-verified against the local dev
|
|
156
|
+
instance. The instance ships Splunk Security Essentials (sample content
|
|
157
|
+
and CIM-aware detections) but not the `Splunk_SA_CIM` add-on itself, so
|
|
158
|
+
no data model on it is actually accelerated — `acceleration`'s populated
|
|
159
|
+
build-status row (non-zero percent complete, a real summarized range)
|
|
160
|
+
and `rebuild --yes`'s two-POST apply path are unit-tested against the
|
|
161
|
+
REST shape above (verified via the installed Splunk source, not
|
|
162
|
+
guessed) rather than live-verified end-to-end; live verification of a
|
|
163
|
+
populated, real acceleration build is pending an instance with an
|
|
164
|
+
actually-accelerated CIM model.
|