Skip to content

Commit d24c344

Browse files
committed
Now tested on Windows and Splunk Cloud (note this version of the app is not installed on SplunkCloud, the VersionControl for SplunkCloud is the app to install on the SplunkCloud instance, this variation of the app includes only what is required to remotely backup/restore a SplunkCloud instance
This app is still used for SplunkCloud instances, but this app is installed on-prem Updates include: - Updated python SDK to 1.6.13 - New options in both backup & restore so that you can specify the location of the git / SSH command - The ability to only backup particular apps by default rather than to backup all and rely on an exclusion list (appsList) - Support for passwords.conf instead of plain text passwords - Proxy support - Re-wrote the runOSProcess function so that it works on Windows as expected The README.md has had various updates including more details around setup and how this was tested on Windows
1 parent 3d9e44b commit d24c344

File tree

14 files changed

+211
-52
lines changed

14 files changed

+211
-52
lines changed

README.md

Lines changed: 134 additions & 10 deletions
Large diffs are not rendered by default.

README/inputs.conf.spec

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@ python.version = python3
55
srcURL = <value>
66
* This the URL to be used for the REST API access of the Splunk instance, https://localhost:8089/ for example (does not have to be localhost)
77
srcUsername = <value>
8-
* username to use for REST API of srcURL argument (only required if not using useLocalAuth)
8+
* username to use for REST API of srcURL argument (required if not using useLocalAuth)
99
srcPassword = <value>
10-
* password to use for REST API of srcURL argument (only required if not using useLocalAuth)
10+
* password to use for REST API of srcURL argument (required if not using useLocalAuth), use 'password:<name in passwords.conf>' and the app will attempt to find the password in your passwords.conf file
1111
gitTempDir = <value>
12-
* location where to store the output of the script on the filesystem
12+
* location where to store the output of the script on the filesystem (note this directory will be deleted/re-created but the parent dir must exist)
1313
gitRepoURL = <value>
1414
* git repository URL to store the objects (SSH URL only)
1515
noPrivate = <boolean>
16-
* disable the backup of user level / private objects (true/false)
16+
* disable the backup of user level / private objects (true/false), default false
1717
noDisabled = <boolean>
18-
* disable the backup of objects with a disabled status in Splunk (true/false)
18+
* disable the backup of objects with a disabled status in Splunk (true/false), default false
1919
includeEntities = <value>
2020
* comma separated list of object values to include
2121
excludeEntities = <value>
@@ -25,32 +25,44 @@ includeOwner = <value>
2525
excludeOwner = <value>
2626
* comma separated list of owners objects that should be transferred
2727
debugMode = <boolean>
28-
* turn on DEBUG level logging (defaults to INFO) (true/false)
28+
* turn on DEBUG level logging (defaults to INFO) (true/false), default false
2929
useLocalAuth = <boolean>
30-
* do not use the srcUsername/srcPassword, use the session_key of the user running the modular input instead (works on localhost only) (true/false)
30+
* do not use the srcUsername/srcPassword, use the session_key of the user running the modular input instead (works on localhost only) (true/false), default false
3131
remoteAppName = <value>
32-
* defaults to SplunkVersionControl, this app needs to contain the savedsearches and potentially the splunkversioncontrol_globalexclusionlist
32+
* defaults to SplunkVersionControl, this app needs to contain the savedsearches and potentially the splunkversioncontrol_globalexclusionlist, use SplunkVersionControlCloud on a cloud-based instance
3333
appsList = <value>
34-
* Comma separated list of apps, this changes Splunk Version Control to not list all applications and instead only runs a backup on the specified apps. Useful for Splunk Cloud where you cannot access the apps REST endpoint
34+
* Comma separated list of apps, this changes Splunk Version Control to not list all applications and instead only runs a backup on the specified apps
35+
git_command = <value>
36+
* defaults to 'git', can be overriden (for example on a Windows server) to use a full path to the git command
37+
ssh_command = <value>
38+
* defaults to 'ssh', can be overriden (for example on a Windows server) to use a full path to the ssh command
39+
proxy = <value>
40+
* If supplied provides a proxy setting to use to access the srcURL (https proxy). Use https://user:password:passwordinpasswordsconf@10.10.1.0:3128 and the application will obtain the password for the entry 'passwordinpasswordsconf'. If password: is not used the password is used as per a normal proxy setting, for example https://user:password@10.10.1.0:3128
3541

3642
[splunkversioncontrol_restore://<name>]
3743
destURL = <value>
3844
* This the URL to be used for the REST API access of the Splunk instance, https://localhost:8089/ for example (does not have to be localhost)
3945
destUsername = <value>
4046
* username to use for REST API of srcURL argument (only required if not using useLocalAuth)
4147
destPassword = <value>
42-
* password to use for REST API of srcURL argument (only required if not using useLocalAuth)
48+
* password to use for REST API of srcURL argument (only required if not using useLocalAuth), use 'password:<name in passwords.conf>' and the app will attempt to find the password in your passwords.conf file
4349
gitTempDir = <value>
44-
* location where to store the output of the script on the filesystem
50+
* location where to store the output of the script on the filesystem (note this directory will be deleted/re-created but the parent dir must exist)
4551
gitRepoURL = <value>
4652
* git repository URL to store the objects (SSH URL only)
4753
auditLogsLookupBackTime = <value>
4854
* This is how far back the audit logs will be checked to ensure that a restore entry is valid, this should be set to your interval time or slightly more, defaults to -1h (use Splunk format)
4955
debugMode = <boolean>
50-
* turn on DEBUG level logging (defaults to INFO) (true/false)
56+
* turn on DEBUG level logging (defaults to INFO) (true/false), default false
5157
useLocalAuth = <boolean>
52-
* do not use the srcUsername/srcPassword, use the session_key of the user running the modular input instead (works on localhost only) (true/false)
58+
* do not use the srcUsername/srcPassword, use the session_key of the user running the modular input instead (works on localhost only) (true/false), default false
5359
remoteAppName = <value>
54-
* defaults to SplunkVersionControl, this app needs to contain the savedsearches and potentially the splunkversioncontrol_globalexclusionlist
60+
* defaults to SplunkVersionControl, this app needs to contain the savedsearches and potentially the splunkversioncontrol_globalexclusionlist, use SplunkVersionControlCloud on a cloud-based instance
5561
timewait = <value>
5662
* defaults to 600, if the kvstore contains an entry advising there is a restore running, how many seconds should pass before the entry is deleted and the restore happens anyway?
63+
git_command = <value>
64+
* defaults to 'git', can be overriden (for example on a Windows server) to use a full path to the git command
65+
ssh_command = <value>
66+
* defaults to 'ssh', can be overriden (for example on a Windows server) to use a full path to the ssh command
67+
proxy = <value>
68+
* If supplied provides a proxy setting to use to access the destURL (https proxy). Use https://user:password:passwordinpasswordsconf@10.10.1.0:3128 and the application will obtain the password for the entry 'passwordinpasswordsconf'. If password: is not used the password is used as per a normal proxy setting, for example https://user:password@10.10.1.0:3128

default/app.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ label = SplunkVersionControl
1212
[launcher]
1313
author = Gareth Anderson
1414
description = Version Control software for Splunk instances (backup/restore from git)
15-
version = 1.0.12
15+
version = 1.1.0
1616

1717
[package]
1818
id = SplunkVersionControl

default/props.conf

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
[source::.../splunkversioncontrol_backup.log]
1+
[source::...(/|\\)var(/|\\)log(/|\\)splunk(/|\\)splunkversioncontrol_backup.log]
22
sourcetype = splunkversioncontrol
33

4-
[source::.../splunkversioncontrol_restore.log]
4+
[source::...(/|\\)var(/|\\)log(/|\\)splunk(/|\\)splunkversioncontrol_restore.log]
55
sourcetype = splunkversioncontrol
66

7-
[source::.../splunkversioncontrol_rest_restore.log]
7+
[source::...(/|\\)var(/|\\)log(/|\\)splunk(/|\\)splunkversioncontrol_rest_restore.log]
88
sourcetype = splunkversioncontrol
99

10-
[source::.../splunkversioncontrol_postversioncontrolrestore.log]
10+
[source::...(/|\\)var(/|\\)log(/|\\)splunk(/|\\)splunkversioncontrol_postversioncontrolrestore.log]
1111
sourcetype = splunkversioncontrol
1212

1313
[splunkversioncontrol]

lib/splunklib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@
1616

1717
from __future__ import absolute_import
1818
from splunklib.six.moves import map
19-
__version_info__ = (1, 6, 12)
19+
__version_info__ = (1, 6, 13)
2020
__version__ = ".".join(map(str, __version_info__))

lib/splunklib/binding.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1378,7 +1378,7 @@ def request(url, message, **kwargs):
13781378
head = {
13791379
"Content-Length": str(len(body)),
13801380
"Host": host,
1381-
"User-Agent": "splunk-sdk-python/1.6.12",
1381+
"User-Agent": "splunk-sdk-python/1.6.13",
13821382
"Accept": "*/*",
13831383
"Connection": "Close",
13841384
} # defaults

lib/splunklib/modularinput/event_writer.py

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import sys
1717

1818
from io import TextIOWrapper, TextIOBase
19-
from splunklib.six import ensure_text
19+
from splunklib.six import ensure_str
2020
from .event import ET
2121

2222
try:
@@ -43,15 +43,8 @@ def __init__(self, output = sys.stdout, error = sys.stderr):
4343
:param output: Where to write the output; defaults to sys.stdout.
4444
:param error: Where to write any errors; defaults to sys.stderr.
4545
"""
46-
if isinstance(output, TextIOBase):
47-
self._out = output
48-
else:
49-
self._out = TextIOWrapper(output)
50-
51-
if isinstance(error, TextIOBase):
52-
self._err = error
53-
else:
54-
self._err = TextIOWrapper(error)
46+
self._out = output
47+
self._err = error
5548

5649
# has the opening <stream> tag been written yet?
5750
self.header_written = False
@@ -63,18 +56,20 @@ def write_event(self, event):
6356
"""
6457

6558
if not self.header_written:
66-
self._out.write(ensure_text("<stream>"))
59+
self._out.write("<stream>")
6760
self.header_written = True
6861

6962
event.write_to(self._out)
7063

7164
def log(self, severity, message):
7265
"""Logs messages about the state of this modular input to Splunk.
7366
These messages will show up in Splunk's internal logs.
67+
7468
:param severity: ``string``, severity of message, see severities defined as class constants.
7569
:param message: ``string``, message to log.
7670
"""
77-
self._err.write(ensure_text("%s %s\n" % (severity, message)))
71+
72+
self._err.write("%s %s\n" % (severity, message))
7873
self._err.flush()
7974

8075
def write_xml_document(self, document):
@@ -83,11 +78,10 @@ def write_xml_document(self, document):
8378
8479
:param document: An ``ElementTree`` object.
8580
"""
86-
data = ET.tostring(document)
87-
self._out.write(ensure_text(data))
81+
self._out.write(ensure_str(ET.tostring(document)))
8882
self._out.flush()
8983

9084
def close(self):
9185
"""Write the closing </stream> tag to make this XML well formed."""
92-
self._out.write(ensure_text("</stream>"))
86+
self._out.write("</stream>")
9387
self._out.flush()

lib/splunklib/modularinput/script.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,7 @@ def run_script(self, args, event_writer, input_stream):
105105
return 1
106106

107107
except Exception as e:
108-
err_string = EventWriter.ERROR + str(e)
109-
event_writer._err.write(err_string)
108+
event_writer.log(EventWriter.ERROR, str(e))
110109
return 1
111110

112111
@property

lib/splunklib/searchcommands/eventing_command.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from __future__ import absolute_import, division, print_function, unicode_literals
1818

19+
from splunklib import six
1920
from splunklib.six.moves import map as imap
2021

2122
from .decorators import ConfigurationSetting
@@ -135,8 +136,14 @@ def fix_up(cls, command):
135136
raise AttributeError('No EventingCommand.transform override')
136137
SearchCommand.ConfigurationSettings.fix_up(command)
137138

139+
# TODO: Stop looking like a dictionary because we don't obey the semantics
140+
# N.B.: Does not use Python 2 dict copy semantics
138141
def iteritems(self):
139142
iteritems = SearchCommand.ConfigurationSettings.iteritems(self)
140143
return imap(lambda name_value: (name_value[0], 'events' if name_value[0] == 'type' else name_value[1]), iteritems)
141144

145+
# N.B.: Does not use Python 3 dict view semantics
146+
if not six.PY2:
147+
items = iteritems
148+
142149
# endregion

lib/splunklib/searchcommands/generating_command.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from .decorators import ConfigurationSetting
2020
from .search_command import SearchCommand
2121

22+
from splunklib import six
2223
from splunklib.six.moves import map as imap, filter as ifilter
2324

2425
# P1 [O] TODO: Discuss generates_timeorder in the class-level documentation for GeneratingCommand
@@ -324,6 +325,8 @@ def fix_up(cls, command):
324325
if command.generate == GeneratingCommand.generate:
325326
raise AttributeError('No GeneratingCommand.generate override')
326327

328+
# TODO: Stop looking like a dictionary because we don't obey the semantics
329+
# N.B.: Does not use Python 2 dict copy semantics
327330
def iteritems(self):
328331
iteritems = SearchCommand.ConfigurationSettings.iteritems(self)
329332
version = self.command.protocol_version
@@ -334,6 +337,10 @@ def iteritems(self):
334337
lambda name_value: (name_value[0], 'stateful') if name_value[0] == 'type' else (name_value[0], name_value[1]), iteritems)
335338
return iteritems
336339

340+
# N.B.: Does not use Python 3 dict view semantics
341+
if not six.PY2:
342+
items = iteritems
343+
337344
pass
338345
# endregion
339346

0 commit comments

Comments
 (0)