20
20
import os .path as op
21
21
import socket
22
22
import subprocess
23
+ import json
23
24
from configparser import ConfigParser
24
25
from io import StringIO
25
26
from typing import List , Optional , Tuple , Union
26
27
28
+ from splunk .clilib .bundle_paths import make_splunkhome_path as msp
29
+ from splunk .rest import simpleRequest
30
+ from splunk import getSessionKey
31
+
27
32
from .utils import is_true
28
33
29
34
__all__ = [
36
41
"get_conf_key_value" ,
37
42
"get_conf_stanza" ,
38
43
"get_conf_stanzas" ,
44
+ "_get_conf_stanzas_from_splunk_api" ,
39
45
]
40
46
41
47
ETC_LEAF = "etc"
54
60
]
55
61
56
62
57
- def _splunk_home ():
58
- return os .path .normpath (os .environ ["SPLUNK_HOME" ])
59
-
60
-
61
- def _splunk_etc ():
62
- try :
63
- result = os .environ ["SPLUNK_ETC" ]
64
- except KeyError :
65
- result = op .join (_splunk_home (), ETC_LEAF )
66
-
67
- return os .path .normpath (result )
68
-
69
-
70
- def _get_shared_storage () -> Optional [str ]:
71
- """Get splunk shared storage name.
72
-
73
- Returns:
74
- Splunk shared storage name.
75
- """
76
-
77
- try :
78
- state = get_conf_key_value ("server" , "pooling" , "state" , APP_SYSTEM )
79
- storage = get_conf_key_value ("server" , "pooling" , "storage" , APP_SYSTEM )
80
- except KeyError :
81
- state = "disabled"
82
- storage = None
83
-
84
- if state == "enabled" and storage :
85
- return storage
86
-
87
- return None
88
-
89
-
90
- # Verify path prefix and return true if both paths have drives
91
- def _verify_path_prefix (path , start ):
92
- path_drive = os .path .splitdrive (path )[0 ]
93
- start_drive = os .path .splitdrive (start )[0 ]
94
- return len (path_drive ) == len (start_drive )
95
-
96
-
97
63
def make_splunkhome_path (parts : Union [List , Tuple ]) -> str :
98
64
"""Construct absolute path by $SPLUNK_HOME and `parts`.
99
65
@@ -111,53 +77,29 @@ def make_splunkhome_path(parts: Union[List, Tuple]) -> str:
111
77
Raises:
112
78
ValueError: Escape from intended parent directories.
113
79
"""
80
+ return msp (parts )
114
81
115
- relpath = os .path .normpath (os .path .join (* parts ))
116
-
117
- basepath = None
118
- shared_storage = _get_shared_storage ()
119
- if shared_storage :
120
- for candidate in on_shared_storage :
121
- # SPL-100508 On windows if the path is missing the drive letter,
122
- # construct fullpath manually and call relpath
123
- if os .name == "nt" and not _verify_path_prefix (relpath , candidate ):
124
- break
125
-
126
- if os .path .relpath (relpath , candidate )[0 :2 ] != ".." :
127
- basepath = shared_storage
128
- break
129
-
130
- if basepath is None :
131
- etc_with_trailing_sep = os .path .join (ETC_LEAF , "" )
132
- if relpath == ETC_LEAF or relpath .startswith (etc_with_trailing_sep ):
133
- # Redirect $SPLUNK_HOME/etc to $SPLUNK_ETC.
134
- basepath = _splunk_etc ()
135
- # Remove leading etc (and path separator, if present). Note: when
136
- # emitting $SPLUNK_ETC exactly, with no additional path parts, we
137
- # set <relpath> to the empty string.
138
- relpath = relpath [4 :]
139
- else :
140
- basepath = _splunk_home ()
141
-
142
- fullpath = os .path .normpath (os .path .join (basepath , relpath ))
143
-
144
- # Check that we haven't escaped from intended parent directories.
145
- if os .path .relpath (fullpath , basepath )[0 :2 ] == ".." :
146
- raise ValueError (
147
- f'Illegal escape from parent directory "{ basepath } ": { fullpath } '
148
- )
149
- return fullpath
150
82
151
-
152
- def get_splunk_host_info () -> Tuple :
83
+ def get_splunk_host_info (
84
+ use_btool : Optional [bool ] = False ,
85
+ session_key : Optional [str ] = None
86
+ ) -> Tuple :
153
87
"""Get splunk host info.
154
88
155
89
Returns:
156
90
Tuple of (server_name, host_name).
157
91
"""
158
92
159
- server_name = get_conf_key_value ("server" , "general" , "serverName" , APP_SYSTEM )
93
+ server_name = get_conf_key_value (
94
+ "server" ,
95
+ "general" ,
96
+ "serverName" ,
97
+ use_btool = use_btool ,
98
+ session_key = session_key ,
99
+ app_name = APP_SYSTEM
100
+ )
160
101
host_name = socket .gethostname ()
102
+
161
103
return server_name , host_name
162
104
163
105
@@ -175,21 +117,37 @@ def get_splunk_bin() -> str:
175
117
return make_splunkhome_path (("bin" , splunk_bin ))
176
118
177
119
178
- def get_splunkd_access_info () -> Tuple [str , str , int ]:
120
+ def get_splunkd_access_info (
121
+ use_btool : Optional [bool ] = False ,
122
+ session_key : Optional [str ] = None
123
+ ) -> Tuple [str , str , int ]:
179
124
"""Get splunkd server access info.
180
125
181
126
Returns:
182
127
Tuple of (scheme, host, port).
183
128
"""
129
+ enable_splunkd_ssl = get_conf_key_value (
130
+ "server" ,
131
+ "sslConfig" ,
132
+ "enableSplunkdSSL" ,
133
+ use_btool = use_btool ,
134
+ session_key = session_key ,
135
+ app_name = APP_SYSTEM
136
+ )
184
137
185
- if is_true (
186
- get_conf_key_value ("server" , "sslConfig" , "enableSplunkdSSL" , APP_SYSTEM )
187
- ):
138
+ if is_true (enable_splunkd_ssl ):
188
139
scheme = "https"
189
140
else :
190
141
scheme = "http"
191
142
192
- host_port = get_conf_key_value ("web" , "settings" , "mgmtHostPort" , APP_SYSTEM )
143
+ host_port = get_conf_key_value (
144
+ "web" ,
145
+ "settings" ,
146
+ "mgmtHostPort" ,
147
+ use_btool = use_btool ,
148
+ session_key = session_key ,
149
+ app_name = APP_SYSTEM
150
+ )
193
151
host_port = host_port .strip ()
194
152
host_port_split_parts = host_port .split (":" )
195
153
host = ":" .join (host_port_split_parts [:- 1 ])
@@ -203,14 +161,24 @@ def get_splunkd_access_info() -> Tuple[str, str, int]:
203
161
return scheme , host , port
204
162
205
163
206
- def get_scheme_from_hec_settings () -> str :
164
+ def get_scheme_from_hec_settings (
165
+ use_btool : Optional [bool ] = False ,
166
+ session_key : Optional [str ] = None
167
+ ) -> str :
207
168
"""Get scheme from HEC global settings.
208
169
209
170
Returns:
210
171
scheme (str)
211
172
"""
212
173
try :
213
- ssl_enabled = get_conf_key_value ("inputs" , "http" , "enableSSL" , APP_HEC )
174
+ ssl_enabled = get_conf_key_value (
175
+ "inputs" ,
176
+ "http" ,
177
+ "enableSSL" ,
178
+ use_btool = use_btool ,
179
+ session_key = session_key ,
180
+ app_name = APP_HEC
181
+ )
214
182
except KeyError :
215
183
raise KeyError (
216
184
"Cannot get enableSSL setting form conf: 'inputs' and stanza: '[http]'. "
@@ -237,20 +205,29 @@ def get_splunkd_uri() -> str:
237
205
if os .environ .get ("SPLUNKD_URI" ):
238
206
return os .environ ["SPLUNKD_URI" ]
239
207
240
- scheme , host , port = get_splunkd_access_info ()
208
+ scheme , host , port = get_splunkd_access_info (use_btool = True )
241
209
return f"{ scheme } ://{ host } :{ port } "
242
210
243
211
244
212
def get_conf_key_value (
245
- conf_name : str , stanza : str , key : str , app_name : Optional [str ] = None
213
+ conf_name : str ,
214
+ stanza : str ,
215
+ key : str ,
216
+ use_btool : Optional [bool ] = False ,
217
+ app_name : Optional [str ] = None ,
218
+ session_key : Optional [str ] = None ,
219
+ user : Optional [str ] = "nobody"
246
220
) -> Union [str , List , dict ]:
247
221
"""Get value of `key` of `stanza` in `conf_name`.
248
222
249
223
Arguments:
250
224
conf_name: Config file.
251
225
stanza: Stanza name.
252
226
key: Key name.
227
+ use_btool: If True, stanzas will be retrieved using cmd btool... otherwise using splunk API. Optional.
253
228
app_name: Application name. Optional.
229
+ session_key: If not provided solnlib will try to get it from splunk.getSessionKey(). Optional.
230
+ user: used for set user context in API call. Optional.
254
231
255
232
Returns:
256
233
Config value.
@@ -259,18 +236,43 @@ def get_conf_key_value(
259
236
KeyError: If `stanza` or `key` doesn't exist.
260
237
"""
261
238
262
- stanzas = get_conf_stanzas (conf_name , app_name )
263
- return stanzas [stanza ][key ]
239
+ if use_btool :
240
+ stanzas = get_conf_stanzas (conf_name , app_name )
241
+ return stanzas [stanza ][key ]
242
+
243
+ if not app_name :
244
+ raise KeyError ("app name must be specified if use_btool is True" )
245
+
246
+ stanzas = _get_conf_stanzas_from_splunk_api (
247
+ conf_name ,
248
+ app_name ,
249
+ session_key = session_key ,
250
+ user = user ,
251
+ stanza = stanza
252
+ )
253
+
254
+ stanza = stanzas .get ("entry" )[0 ].get ("content" )
255
+ requested_key = stanza [key ]
256
+ return requested_key
264
257
265
258
266
259
def get_conf_stanza (
267
- conf_name : str , stanza : str , app_name : Optional [str ] = None
260
+ conf_name : str ,
261
+ stanza : str ,
262
+ use_btool : Optional [bool ] = False ,
263
+ app_name : Optional [str ] = None ,
264
+ session_key : Optional [str ] = None ,
265
+ user : Optional [str ] = "nobody"
268
266
) -> dict :
269
267
"""Get `stanza` in `conf_name`.
270
268
271
269
Arguments:
272
270
conf_name: Config file.
273
271
stanza: Stanza name.
272
+ use_btool: If True, stanzas will be retrieved using cmd btool... otherwise using splunk API. Optional.
273
+ app_name: Application name. Optional.
274
+ session_key: If not provided solnlib will try to get it from splunk.getSessionKey(). Optional.
275
+ user: used for set user context in API call. Optional.
274
276
app_name: Application name. Optional.
275
277
276
278
Returns:
@@ -280,8 +282,23 @@ def get_conf_stanza(
280
282
KeyError: If stanza doesn't exist.
281
283
"""
282
284
283
- stanzas = get_conf_stanzas (conf_name , app_name )
284
- return stanzas [stanza ]
285
+ if use_btool :
286
+ stanzas = get_conf_stanzas (conf_name , app_name )
287
+ return stanzas [stanza ] # uncomment after tests
288
+
289
+ if not app_name :
290
+ raise KeyError ("app name must be specified if use_btool is True" )
291
+
292
+ stanzas = _get_conf_stanzas_from_splunk_api (
293
+ conf_name ,
294
+ app_name ,
295
+ session_key = session_key ,
296
+ user = user ,
297
+ stanza = stanza
298
+ )
299
+
300
+ stanza = stanzas .get ("entry" )[0 ].get ("content" )
301
+ return stanza
285
302
286
303
287
304
def get_conf_stanzas (conf_name : str , app_name : Optional [str ] = None ) -> dict :
@@ -330,3 +347,41 @@ def get_conf_stanzas(conf_name: str, app_name: Optional[str] = None) -> dict:
330
347
for section in parser .sections ():
331
348
out [section ] = {item [0 ]: item [1 ] for item in parser .items (section , raw = True )}
332
349
return out
350
+
351
+
352
+ def _get_conf_stanzas_from_splunk_api (
353
+ conf_name : str ,
354
+ app_name : str ,
355
+ session_key : Optional [str ] = None ,
356
+ user : Optional [str ] = "nobody" ,
357
+ stanza : Optional [str ] = None ,
358
+ ) -> dict :
359
+ """Get stanzas of `conf_name` using splunk API:
360
+ /servicesNS/{user}/{app_name}/configs/conf-{conf_name}/{stanza}
361
+
362
+ Arguments:
363
+ conf_name: Config file.
364
+ app_name: Application name.
365
+ session_key: Session key. Optional.
366
+ user: Username. Optional.
367
+ stanza: Stanza name. Optional.
368
+
369
+ Returns:
370
+ json response.
371
+ """
372
+
373
+ url = f"/servicesNS/{ user } /{ app_name } /configs/conf-{ conf_name } "
374
+
375
+ if stanza :
376
+ url = url + "/" + stanza
377
+
378
+ if not session_key :
379
+ session_key = getSessionKey ()
380
+
381
+ server_response , server_content = simpleRequest (
382
+ url , sessionKey = session_key , getargs = {"output_mode" : "json" }, logme = True
383
+ )
384
+
385
+ result = json .loads (server_content .decode ())
386
+
387
+ return result
0 commit comments