You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

122 lines
4.4 KiB

5 months ago
import json
import logging
import os
import splunk.clilib.bundle_paths as bundle_paths
import splunk.clilib.cli_common as comm
from splunk.appbuilder import PACKAGE_PATH
logger = logging.getLogger('splunk.spl2')
FILELOCK_SERVICE_FAILED = "Service temporarily unavailable. Retry in 30 seconds."
DOWNLOAD_MODULES_ENDPOINT = "/spl2/modules/download?app={app_name}"
def sync_spl2_objects(handler_args, object_type, session_key, app_name):
if object_type == "spl2-modules":
dest = handler_args.get('dest', ["default"])[0]
module_filter = []
arg_data = handler_args.data
if 'filter' in arg_data and arg_data['filter'][0] is not None:
for entry in arg_data['filter'][0].split(','):
entry = entry.strip()
if entry:
module_filter.append(entry)
app_modules = _get_all_modules(app_name, session_key)
if not app_modules:
logger.debug("No SPL2 modules found for app '{}'".format(app_name))
return
bundle_paths.maybe_makedirs(PACKAGE_PATH, throw_exceptions=True)
# TODO: Add concurrency mechanism - SCP-69093
create_module_files(app_name, dest, app_modules, module_filter)
else:
raise NotImplementedError("No handler for object_type {}".format(object_type))
def create_module_files(app, dest, modules, module_filter):
app_path = bundle_paths.get_bundle(app).location()
temp_path = os.path.join(PACKAGE_PATH, 'SPL2_DELETEME_' + app)
spl2_path = os.path.join(app_path, dest, "data", "spl2")
# delete stale temp_path if exists from previous CLI invoke and re-create dirs
bundle_paths.safe_remove(temp_path)
bundle_paths.maybe_makedirs(temp_path)
# if ..app/{dest}/data/spl2 exists, copy all contents to temp_path
if os.path.lexists(spl2_path):
comm.mergeDirs(spl2_path, temp_path)
# delete all .spl2 files from temp_path
_delete_spl2_modules(temp_path)
# write module files to the temp_path
_write_module_files(temp_path, modules, module_filter)
# remove ..app/{dest}/data/spl2 and mv temp_path contents to /data/spl2
bundle_paths.safe_remove(spl2_path)
comm.moveItem(temp_path, spl2_path)
logger.info("Moved downloaded modules to {}".format(spl2_path))
def _write_module_files(des, modules, module_filter):
modules_written = []
for module in modules:
name = module['name']
dirs = module['namespace'].split('.')[2:] # remove apps.<app_name.
content = module['definition']
mod_resource_name = module['namespace'] + '.' + module['name']
folder_path = os.path.join(des, *dirs)
file_path = os.path.join(folder_path, name + ".spl2")
file_ns_name = ".".join(dirs + [name])
if module_filter:
if file_ns_name in module_filter:
_write_module(content, file_path, folder_path)
modules_written.append(mod_resource_name)
else:
logger.debug("Skipped writing module {}. Applied filter: {}".format(file_ns_name, module_filter))
continue
else:
_write_module(content, file_path, folder_path)
modules_written.append(mod_resource_name)
if modules_written:
logger.info("Wrote {} module(s) to {}. Modules: {}".format(len(modules_written), des, modules_written))
def _write_module(content, file_path, folder_path):
os.makedirs(folder_path, exist_ok=True)
with open(file_path, "w") as file:
file.write(content)
def _get_all_modules(app, auth):
from splunk import rest
download_path = DOWNLOAD_MODULES_ENDPOINT.format(app_name=app)
response, content = rest.simpleRequest(download_path, sessionKey=auth, raiseAllErrors=True)
if content:
modules = json.loads(content)
logger.debug("Downloaded {} modules from app: {} using REST".format(len(modules), app))
return modules
def _delete_spl2_modules(path, extension=".spl2"):
for root, dirs, files in os.walk(path, topdown=False):
for file in files:
if file.endswith(extension):
file_path = os.path.join(root, file)
os.remove(file_path)
# Now check and delete empty directories
for root, dirs, files in os.walk(path, topdown=False):
for dir_name in dirs:
dir_path = os.path.join(root, dir_name)
if not os.listdir(dir_path):
os.rmdir(dir_path)

Powered by BW's shoe-string budget.