diff --git a/docs/alert_actions/index.md b/docs/alert_actions/index.md index 00b7b9c3e..7716b4487 100644 --- a/docs/alert_actions/index.md +++ b/docs/alert_actions/index.md @@ -25,7 +25,7 @@ Developers are required to add alerts in the global config file to create an Ale | Property | Type | Description | |---------------------------------------------------------------------------|--------|--------------------------------------------------------------------------------------------------------| -| type\* | string | The type of the user input in the alert. Available choices: "text", "checkbox", "singleSelect", "radio", "singleSelectSplunkSearch". | +| type\* | string | The type of the user input in the alert. Available choices: "text", "textarea", "checkbox", "singleSelect", "radio", "singleSelectSplunkSearch". | | label\* | string | The text that would be shown in the alert action UI. | | field\* | string | The field that would be used in the scripts to get the value from the user input. These are defined as `param.` in the `alert_actions.conf`. | | options | array | Static choices that a user can select in the alert action UI. | diff --git a/docs/generated_files.md b/docs/generated_files.md index 1d7e0a2c6..8f6e3801b 100644 --- a/docs/generated_files.md +++ b/docs/generated_files.md @@ -8,6 +8,16 @@ Below table describes the files generated by UCC framework | File Name | File Location | File Description | | ------------ | ------------ | ----------------- | +| app.conf | output/<YOUR_ADDON_NAME>/default | Generates `app.conf` with the details mentioned in globalConfig[meta] | +| inputs.conf | output/<YOUR_ADDON_NAME>/default | Generates `inputs.conf` and `inputs.conf.spec` file for the services mentioned in globalConfig | +| server.conf | output/<YOUR_ADDON_NAME>/default | Generates `server.conf` for the custom conf files created as per configurations in globalConfig | +| restmap.conf | output/<YOUR_ADDON_NAME>/default | Generates `restmap.conf` for the custom REST handlers that are generated based on configs from globalConfig | +| web.conf | output/<YOUR_ADDON_NAME>/default | Generates `web.conf` to expose the endpoints generated in `restmap.conf` which is generated based on configurations from globalConfig. | +| alert_actions.conf | output/<YOUR_ADDON_NAME>/default | Generates `alert_actions.conf` and `alert_actions.conf.spec` file for the custom alert actions defined in globalConfig | +| eventtypes.conf | output/<YOUR_ADDON_NAME>/default | Generates `eventtypes.conf` file if the sourcetype is mentioned in Adaptive Response of custom alert action in globalConfig | +| tags.conf | output/<YOUR_ADDON_NAME>/default | Generates `tags.conf` file based on the `eventtypes.conf` created for custom alert actions. | +| _account.conf | output/<YOUR_ADDON_NAME>/README | Generates `_account.conf.spec` file for the configuration mentioned in globalConfig | +| _settings.conf | output/<YOUR_ADDON_NAME>/README | Generates `_settings.conf.spec` file for the Proxy, Logging or Custom Tab mentioned in globalConfig | | configuration.xml | output/<YOUR_ADDON_NAME>/default/data/ui/views | Generates configuration.xml file in `default/data/ui/views/` folder if globalConfig is present. | | dashboard.xml | output/<YOUR_ADDON_NAME>/default/data/ui/views | Generates dashboard.xml file based on dashboard configuration present in globalConfig in `default/data/ui/views` folder. | | default.xml | output/<YOUR_ADDON_NAME>/default/data/ui/nav | Generates default.xml file based on configs present in globalConfigin in `default/data/ui/nav` folder. | diff --git a/splunk_add_on_ucc_framework/app_conf.py b/splunk_add_on_ucc_framework/app_conf.py deleted file mode 100644 index 5aff1e130..000000000 --- a/splunk_add_on_ucc_framework/app_conf.py +++ /dev/null @@ -1,75 +0,0 @@ -# -# Copyright 2024 Splunk Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import time -from typing import Sequence - -import addonfactory_splunk_conf_parser_lib as conf_parser -from splunk_add_on_ucc_framework import app_manifest as app_manifest_lib - -APP_CONF_FILE_NAME = "app.conf" - - -class AppConf: - def __init__(self) -> None: - self._app_conf = conf_parser.TABConfigParser() - - def read(self, path: str) -> None: - self._app_conf.read(path) - - def update( - self, - version: str, - app_manifest: app_manifest_lib.AppManifest, - conf_file_names: Sequence[str], - is_visible: bool, - **kwargs: str, - ) -> None: - if "launcher" not in self._app_conf: - self._app_conf.add_section("launcher") - if "id" not in self._app_conf: - self._app_conf.add_section("id") - if "install" not in self._app_conf: - self._app_conf.add_section("install") - if "package" not in self._app_conf: - self._app_conf.add_section("package") - if "ui" not in self._app_conf: - self._app_conf.add_section("ui") - if "triggers" not in self._app_conf and conf_file_names: - self._app_conf.add_section("triggers") - - self._app_conf["launcher"]["version"] = version - self._app_conf["launcher"]["description"] = app_manifest.get_description() - authors = app_manifest.get_authors() - first_author = authors[0] - self._app_conf["launcher"]["author"] = first_author["name"] - self._app_conf["id"]["version"] = version - self._app_conf["id"]["name"] = app_manifest.get_addon_name() - self._app_conf["install"]["build"] = str(int(time.time())) - self._app_conf["install"]["is_configured"] = "false" - self._app_conf["install"]["state"] = "enabled" - self._app_conf["package"]["id"] = app_manifest.get_addon_name() - self._app_conf["package"]["check_for_updates"] = kwargs["check_for_updates"] - - self._app_conf["ui"]["label"] = app_manifest.get_title() - if kwargs.get("supported_themes") != "": - self._app_conf["ui"]["supported_themes"] = kwargs["supported_themes"] - self._app_conf["ui"]["is_visible"] = "true" if is_visible else "false" - for conf_file_name in conf_file_names: - self._app_conf["triggers"][f"reload.{conf_file_name}"] = "simple" - - def write(self, path: str) -> None: - with open(path, "w") as fd: - self._app_conf.write(fd) diff --git a/splunk_add_on_ucc_framework/commands/build.py b/splunk_add_on_ucc_framework/commands/build.py index 224ce04e5..d1c2ccadc 100644 --- a/splunk_add_on_ucc_framework/commands/build.py +++ b/splunk_add_on_ucc_framework/commands/build.py @@ -13,7 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import configparser import glob import json import logging @@ -34,9 +33,7 @@ utils, ) from splunk_add_on_ucc_framework import dashboard -from splunk_add_on_ucc_framework import app_conf as app_conf_lib from splunk_add_on_ucc_framework import meta_conf as meta_conf_lib -from splunk_add_on_ucc_framework import server_conf as server_conf_lib from splunk_add_on_ucc_framework import app_manifest as app_manifest_lib from splunk_add_on_ucc_framework import global_config as global_config_lib from splunk_add_on_ucc_framework.commands.modular_alert_builder import ( @@ -54,6 +51,7 @@ ucc_to_oas, ) from splunk_add_on_ucc_framework.generators.file_generator import begin +from splunk_add_on_ucc_framework.generators.conf_files.create_app_conf import AppConf logger = logging.getLogger("ucc_gen") @@ -160,19 +158,6 @@ def _add_modular_input( with open(helper_filename, "w") as helper_file: helper_file.write(content) - input_default = os.path.join(outputdir, ta_name, "default", "inputs.conf") - config = configparser.ConfigParser() - if os.path.exists(input_default): - config.read(input_default) - - if config.has_section(input_name): - config[input_name]["python.version"] = "python3" - else: - config[input_name] = {"python.version": "python3"} - - with open(input_default, "w") as configfile: - config.write(configfile) - def _get_ignore_list( addon_name: str, ucc_ignore_path: str, output_directory: str @@ -454,6 +439,7 @@ def generate( gc_path = _get_and_check_global_config_path(source, config_path) if gc_path: + ui_available = True logger.info(f"Using globalConfig file located @ {gc_path}") global_config = global_config_lib.GlobalConfig(gc_path) # handle the update of globalConfig before validating @@ -536,31 +522,13 @@ def generate( _add_modular_input(ta_name, global_config, output_directory) if global_config.has_alerts(): logger.info("Generating alerts code") - alert_builder.generate_alerts( - global_config, ta_name, internal_root_dir, output_directory - ) + alert_builder.generate_alerts(global_config, ta_name, output_directory) conf_file_names = [] conf_file_names.extend(list(scheme.settings_conf_file_names)) conf_file_names.extend(list(scheme.configs_conf_file_names)) conf_file_names.extend(list(scheme.oauth_conf_file_names)) - source_server_conf_path = os.path.join(source, "default", "server.conf") - # For now, only create server.conf only if no server.conf is present in - # the source package. - if not os.path.isfile(source_server_conf_path): - server_conf = server_conf_lib.ServerConf() - server_conf.create_default(conf_file_names) - output_server_conf_path = os.path.join( - output_directory, - ta_name, - "default", - server_conf_lib.SERVER_CONF_FILE_NAME, - ) - server_conf.write(output_server_conf_path) - logger.info( - f"Created default {server_conf_lib.SERVER_CONF_FILE_NAME} file in the output folder" - ) if global_config.has_dashboard(): logger.info("Including dashboard") dashboard_definition_json_path = os.path.join( @@ -632,31 +600,17 @@ def generate( f"Updated {app_manifest_lib.APP_MANIFEST_FILE_NAME} file in the output folder" ) - app_conf = app_conf_lib.AppConf() - output_app_conf_path = os.path.join( - output_directory, ta_name, "default", app_conf_lib.APP_CONF_FILE_NAME - ) - app_conf.read(output_app_conf_path) - should_be_visible = False - check_for_updates = "true" - supported_themes = "" - if global_config: - should_be_visible = True - if global_config.meta.get("checkForUpdates") is False: - check_for_updates = "false" - if global_config.meta.get("supportedThemes") is not None: - supported_themes = ", ".join(global_config.meta["supportedThemes"]) - app_conf.update( - addon_version, - app_manifest, - conf_file_names, - should_be_visible, - check_for_updates=check_for_updates, - supported_themes=supported_themes, - ) - app_conf.write(output_app_conf_path) - logger.info(f"Updated {app_conf_lib.APP_CONF_FILE_NAME} file in the output folder") - + # NOTE: merging source and generated 'app.conf' as per previous design + AppConf( + global_config=global_config, + input_dir=source, + output_dir=output_directory, + ucc_dir=internal_root_dir, + addon_name=ta_name, + app_manifest=app_manifest, + addon_version=addon_version, + has_ui=ui_available, + ).generate() license_dir = os.path.abspath(os.path.join(source, os.pardir, "LICENSES")) if os.path.exists(license_dir): logger.info("Copy LICENSES directory") diff --git a/splunk_add_on_ucc_framework/commands/modular_alert_builder/alert_actions_conf_gen.py b/splunk_add_on_ucc_framework/commands/modular_alert_builder/alert_actions_conf_gen.py deleted file mode 100644 index 9fe8c964b..000000000 --- a/splunk_add_on_ucc_framework/commands/modular_alert_builder/alert_actions_conf_gen.py +++ /dev/null @@ -1,274 +0,0 @@ -# -# Copyright 2024 Splunk Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -import json -import logging -from os import linesep, makedirs, path as op -import shutil -from typing import Dict, Any - -from jinja2 import Environment, FileSystemLoader - -from splunk_add_on_ucc_framework.commands.modular_alert_builder import ( - arf_consts as ac, -) -from splunk_add_on_ucc_framework.utils import ( - write_file, -) -from splunk_add_on_ucc_framework.commands.modular_alert_builder.alert_actions_merge import ( - remove_alert_from_conf_file, -) - -logger = logging.getLogger("ucc_gen") - - -class AlertActionsConfGeneration: - def __init__( - self, - input_setting: Dict[str, Any], - package_path: str, - internal_source_path: str, - ) -> None: - self._alert_conf_name = "alert_actions.conf" - self._alert_spec_name = "alert_actions.conf.spec" - self._eventtypes_conf = "eventtypes.conf" - self._tags_conf = "tags.conf" - self._alert_settings = input_setting[ac.MODULAR_ALERTS] - self._package_path = package_path - self._internal_source_path = internal_source_path - # nosemgrep: splunk.autoescape-disabled, python.jinja2.security.audit.autoescape-disabled.autoescape-disabled - self._templates = Environment( - loader=FileSystemLoader( - op.join(op.dirname(op.realpath(__file__)), "arf_template") - ), - trim_blocks=True, - lstrip_blocks=True, - keep_trailing_newline=True, - ) - self._html_fields = [ac.PARAMETERS] - self._default_conf_settings = { - "python.version": "python3", - "is_custom": 1, - "payload_format": "json", - "icon_path": "alerticon.png", - } - - def get_local_conf_file_path(self, conf_name: str) -> str: - local_path = op.join(self._package_path, "default") - if not op.exists(local_path): - makedirs(local_path) - - return op.join(local_path, conf_name) - - def get_spec_file_path(self) -> str: - readme_path = op.join(self._package_path, "README") - if not op.exists(readme_path): - makedirs(readme_path) - return op.join(readme_path, self._alert_spec_name) - - def generate_conf(self) -> None: - logger.info( - 'status="starting", operation="generate", ' - + 'object="alert_actions.conf", object_type="file"' - ) - template = self._templates.get_template("alert_actions.conf.template") - deny_list = frozenset( - [ - "short_name", - "alert_props", - "parameters", - "uuid", - "code", - "largeIcon", - "smallIcon", - "index", - "iconFileName", # it is a config from globalConfig that gets written to icon_path - "customScript", # it is a config from globalConfig only for Python script - ] - ) - alerts: Dict[str, Any] = {} - for alert in self._alert_settings: - alert_name = alert["short_name"] - alerts[alert_name] = [] - for k, v in alert.items(): - if k == "adaptive_response": - new_cam = { - sub_k: sub_v - for sub_k, sub_v in list(v.items()) - if sub_k != "sourcetype" and sub_v - } - value = f"param._cam = {json.dumps(new_cam)}" - alerts[alert_name].append(value) - elif k == "alert_props": - if alert.get("iconFileName", "alerticon.png") != "alerticon.png": - alert["alert_props"]["icon_path"] = alert["iconFileName"] - else: - # we copy UCC framework's alerticon.png only when a custom isn't provided - shutil.copy( - op.join( - self._internal_source_path, "static", "alerticon.png" - ), - op.join(self._package_path, "appserver", "static"), - ) - for pk, pv in v.items(): - value = f"{str(pk).strip()} = {str(pv).strip()}" - alerts[alert_name].append(value) - elif k not in deny_list: - value = f"{str(k).strip()} = {str(v).strip()}" - alerts[alert_name].append(value) - for k, v in alert.items(): - if k == "parameters": - for param in v: - param_name = param["name"].strip() - if param.get("default_value") is not None: - param_default_value = str( - param.get("default_value") - ).strip() - alerts[alert_name].append( - f"param.{param_name} = {param_default_value}" - ) - else: - alerts[alert_name].append(f"param.{param_name} = ") - final_string = template.render(alerts=alerts) - text = linesep.join([s.strip() for s in final_string.splitlines()]) - write_file( - self._alert_conf_name, - self.get_local_conf_file_path(self._alert_conf_name), - text, - ) - logger.info( - 'status="success", operation="generate", ' - + 'object="alert_actions.conf", object_type="file"' - ) - - def generate_eventtypes(self) -> None: - logger.info( - 'status="starting", operation="generate", ' - + 'object="eventtypes.conf", object_type="file"' - ) - template = self._templates.get_template("eventtypes.conf.template") - final_string = template.render(mod_alerts=self._alert_settings) - text = linesep.join([s.strip() for s in final_string.splitlines()]) - file_path = self.get_local_conf_file_path(self._eventtypes_conf) - write_file(self._eventtypes_conf, file_path, text) - - # remove the stanza if not checked - for alert in self._alert_settings: - if alert.get("adaptive_response") and alert["adaptive_response"].get( - "sourcetype" - ): - continue - remove_alert_from_conf_file(alert, file_path) - logger.info( - 'status="success", operation="generate", ' - + 'object="eventtypes.conf", object_type="file"' - ) - - def generate_tags(self) -> None: - logger.info( - 'status="starting", operation="generate", ' - + 'object="tags.conf", object_type="file"' - ) - template = self._templates.get_template("tags.conf.template") - final_string = template.render(mod_alerts=self._alert_settings) - text = linesep.join([s.strip() for s in final_string.splitlines()]) - file_path = self.get_local_conf_file_path(self._tags_conf) - write_file(self._tags_conf, file_path, text) - - # remove the stanza if not checked - for alert in self._alert_settings: - if alert.get("adaptive_response") and alert["adaptive_response"].get( - "sourcetype" - ): - continue - remove_alert_from_conf_file(alert, file_path) - logger.info( - 'status="success", operation="generate", ' - + 'object="tags.conf", object_type="file"' - ) - - def generate_spec(self) -> None: - logger.info( - 'status="starting", operation="generate", ' - + 'object="alert_actions.conf.spec", object_type="file"' - ) - template = self._templates.get_template("alert_actions.conf.spec.template") - _router = { - "dropdownlist": "list", - "text": "string", - "textarea": "string", - "checkbox": "bool", - "password": "password", - "dropdownlist_splunk_search": "list", - "radio": "list", - } - alerts: Dict[str, Any] = {} - for alert in self._alert_settings: - alert_name = alert["short_name"] - alerts[alert_name] = [] - for k, v in alert.items(): - if k == "adaptive_response": - alerts[alert_name].append( - "param._cam = Adaptive Response parameters." - ) - elif k == "parameters": - for param in v: - format_type = _router[param["format_type"]] - is_required = ( - "It's a required parameter." - if param.get("required") and param["required"] - else "" - ) - param_default_value = param.get("default_value") - default_value = ( - f"It's default value is {param_default_value}." - if param_default_value - else "" - ) - value = ( - f'param.{param["name"]} = <{format_type}> ' - f'{param["label"]}. {is_required} {default_value}' - ) - alerts[alert_name].append(value) - final_string = template.render(alerts=alerts) - text = linesep.join([s.strip() for s in final_string.splitlines()]) - write_file(self._alert_spec_name, self.get_spec_file_path(), text) - logger.info( - 'status="success", operation="generate", ' - + 'object="alert_actions.conf.spec", object_type="file"' - ) - - def handle(self) -> None: - self.add_default_settings() - self.generate_conf() - self.generate_spec() - self.generate_eventtypes() - self.generate_tags() - - def add_default_settings(self) -> None: - for alert in self._alert_settings: - if ac.ALERT_PROPS not in list(alert.keys()): - alert[ac.ALERT_PROPS] = {} - for k, v in list(self._default_conf_settings.items()): - if k in list(alert[ac.ALERT_PROPS].keys()): - continue - - alert[ac.ALERT_PROPS][k] = v - logger.info( - 'status="success", operation="Add default setting", alert_name="%s", "%s"="%s"', - alert[ac.SHORT_NAME], - k, - v, - ) diff --git a/splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_consts.py b/splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_consts.py index cf23aaa7f..5ab91027e 100644 --- a/splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_consts.py +++ b/splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_consts.py @@ -15,6 +15,4 @@ # SHORT_NAME = "short_name" -PARAMETERS = "parameters" MODULAR_ALERTS = "modular_alerts" -ALERT_PROPS = "alert_props" diff --git a/splunk_add_on_ucc_framework/commands/modular_alert_builder/builder.py b/splunk_add_on_ucc_framework/commands/modular_alert_builder/builder.py index 7dfbd20cb..4bf09d4c1 100644 --- a/splunk_add_on_ucc_framework/commands/modular_alert_builder/builder.py +++ b/splunk_add_on_ucc_framework/commands/modular_alert_builder/builder.py @@ -18,7 +18,6 @@ from splunk_add_on_ucc_framework import global_config as global_config_lib from splunk_add_on_ucc_framework.commands.modular_alert_builder import ( - alert_actions_conf_gen, normalize, ) from splunk_add_on_ucc_framework.commands.modular_alert_builder import ( @@ -31,7 +30,6 @@ def generate_alerts( global_config: global_config_lib.GlobalConfig, addon_name: str, - internal_source_dir: str, output_dir: str, ) -> None: envs = normalize.normalize( @@ -41,13 +39,6 @@ def generate_alerts( package_dir = os.path.join(output_dir, addon_name) schema_content = envs["schema.content"] - conf_gen = alert_actions_conf_gen.AlertActionsConfGeneration( - input_setting=schema_content, - package_path=package_dir, - internal_source_path=internal_source_dir, - ) - conf_gen.handle() - py_gen = alert_actions_py_gen.AlertActionsPyGenerator( addon_name=addon_name, input_setting=schema_content, diff --git a/splunk_add_on_ucc_framework/commands/rest_builder/builder.py b/splunk_add_on_ucc_framework/commands/rest_builder/builder.py index d78af7097..eaa32ee8f 100644 --- a/splunk_add_on_ucc_framework/commands/rest_builder/builder.py +++ b/splunk_add_on_ucc_framework/commands/rest_builder/builder.py @@ -20,8 +20,6 @@ from splunk_add_on_ucc_framework.commands.rest_builder import ( global_config_builder_schema, ) -from splunk_add_on_ucc_framework.rest_map_conf import RestmapConf -from splunk_add_on_ucc_framework.web_conf import WebConf from splunk_add_on_ucc_framework.global_config import OSDependentLibraryConfig __all__ = ["RestBuilder"] @@ -142,50 +140,12 @@ def _add_executable_attribute(file_path: str) -> None: def build(self) -> None: for endpoint in self._schema.endpoints: - # If the endpoint is oauth, which is for getting accesstoken. Conf file entries should not get created. - if endpoint._name != "oauth": - if endpoint._name == "settings": - self.output.put( - self.output.default, - f"{endpoint.conf_name}.conf", - endpoint.generate_conf_with_default_values(), - ) - - self.output.put( - self.output.readme, - f"{endpoint.conf_name}.conf.spec", - endpoint.generate_spec(), - ) - - # Add data input of self defined conf to inputs.conf.spec - if endpoint._entities[0] and endpoint._entities[0]._conf_name: - lines = [ - f"[{endpoint._name}://]", - "placeholder = placeholder", - ] - self.output.put( - self.output.readme, "inputs.conf.spec", "\n".join(lines) - ) - self.output.put( self.output.bin, endpoint.rh_name + ".py", endpoint.generate_rh(), ) - self.output.put( - self.output.default, - "restmap.conf", - RestmapConf.build( - self._schema.endpoints, - self._schema.namespace, - ), - ) - self.output.put( - self.output.default, - "web.conf", - WebConf.build(self._schema.endpoints), - ) self.output.put( self.output.bin, "import_declare_test.py", diff --git a/splunk_add_on_ucc_framework/commands/rest_builder/global_config_builder_schema.py b/splunk_add_on_ucc_framework/commands/rest_builder/global_config_builder_schema.py index 74007c3a7..8551d9f5c 100644 --- a/splunk_add_on_ucc_framework/commands/rest_builder/global_config_builder_schema.py +++ b/splunk_add_on_ucc_framework/commands/rest_builder/global_config_builder_schema.py @@ -112,7 +112,7 @@ def _builder_configs(self) -> None: conf_name=config.get("conf"), ) endpoint.add_entity(entity) - # If we have given oauth support then we have to add endpoint for accesstoken + # If we have given oauth support then we have to add endpoint for access_token for entity_element in config["entity"]: if entity_element["type"] == "oauth": log_details = self.global_config.logging_tab diff --git a/splunk_add_on_ucc_framework/generators/conf_files/__init__.py b/splunk_add_on_ucc_framework/generators/conf_files/__init__.py new file mode 100644 index 000000000..07d3fd346 --- /dev/null +++ b/splunk_add_on_ucc_framework/generators/conf_files/__init__.py @@ -0,0 +1,40 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from .conf_generator import ConfGenerator +from .create_alert_actions_conf import AlertActionsConf +from .create_app_conf import AppConf +from .create_eventtypes_conf import EventtypesConf +from .create_inputs_conf import InputsConf +from .create_restmap_conf import RestMapConf +from .create_server_conf import ServerConf +from .create_tags_conf import TagsConf +from .create_web_conf import WebConf +from .create_account_conf import AccountConf +from .create_settings_conf import SettingsConf + +__all__ = [ + "ConfGenerator", + "ServerConf", + "RestMapConf", + "WebConf", + "AlertActionsConf", + "EventtypesConf", + "TagsConf", + "AppConf", + "InputsConf", + "AccountConf", + "SettingsConf", +] diff --git a/splunk_add_on_ucc_framework/generators/conf_files/conf_generator.py b/splunk_add_on_ucc_framework/generators/conf_files/conf_generator.py new file mode 100644 index 000000000..8468cf94d --- /dev/null +++ b/splunk_add_on_ucc_framework/generators/conf_files/conf_generator.py @@ -0,0 +1,47 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from typing import Any, Dict, Union, NoReturn +from ..file_generator import FileGenerator + + +class ConfGenerator(FileGenerator): + __description__ = "DESCRIBE THE CONF FILE THAT IS GENERATED" + + def _set_attributes(self, **kwargs: Any) -> Union[NoReturn, None]: + # parse self._global_config and set the require attributes for self + raise NotImplementedError() + + def generate(self) -> Dict[str, str]: + conf_files: Dict[str, str] = {} + conf_file = self.generate_conf() + conf_spec_file = self.generate_conf_spec() + if conf_file: + conf_files.update(conf_file) + if conf_spec_file: + conf_files.update(conf_spec_file) + return conf_files + + def generate_conf(self) -> Union[Dict[str, str], None]: + # logic to pass the configs to template file + # uses the attributes set in _set_attributes method to render the template + # use self.get_file_output_path() to get the output file to create the file + return {"": ""} + + def generate_conf_spec(self) -> Union[Dict[str, str], None]: + # logic to pass the configs to template file + # uses the attributes set in _set_attributes method to render the template + # use self.get_file_output_path() to get the output file to create the file + return {"": ""} diff --git a/splunk_add_on_ucc_framework/generators/conf_files/create_account_conf.py b/splunk_add_on_ucc_framework/generators/conf_files/create_account_conf.py new file mode 100644 index 000000000..05837ffd8 --- /dev/null +++ b/splunk_add_on_ucc_framework/generators/conf_files/create_account_conf.py @@ -0,0 +1,59 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from typing import Any, Tuple, List, Dict, Union + +from splunk_add_on_ucc_framework.generators.conf_files import ConfGenerator + + +class AccountConf(ConfGenerator): + __description__ = ( + "Generates `_account.conf.spec` " + "file for the configuration mentioned in globalConfig" + ) + + def _set_attributes(self, **kwargs: Any) -> None: + self.account_fields: List[Tuple[str, List[str]]] = [] + if self._global_config and self._gc_schema: + self.conf_spec_file = ( + self._global_config.namespace.lower() + "_account.conf.spec" + ) + for account in self._global_config.configs: + # If the endpoint is oauth, which is for getting access_token, conf file entries + # should not get created (compatibility to previous versions) + if account["name"] == "oauth": + continue + content = self._gc_schema._get_oauth_enitities(account["entity"]) + fields = self._gc_schema._parse_fields(content) + self.account_fields.append( + ("", [f"{f._name} = " for f in fields]) + ) + + def generate_conf_spec(self) -> Union[Dict[str, str], None]: + if not self.account_fields: + return None + + file_path = self.get_file_output_path(["README", self.conf_spec_file]) + self.set_template_and_render( + template_file_path=["README"], file_name="account_conf_spec.template" + ) + + rendered_content = self._template.render(account_stanzas=self.account_fields) + self.writer( + file_name=self.conf_spec_file, + file_path=file_path, + content=rendered_content, + ) + return {self.conf_spec_file: file_path} diff --git a/splunk_add_on_ucc_framework/generators/conf_files/create_alert_actions_conf.py b/splunk_add_on_ucc_framework/generators/conf_files/create_alert_actions_conf.py new file mode 100644 index 000000000..de448ab95 --- /dev/null +++ b/splunk_add_on_ucc_framework/generators/conf_files/create_alert_actions_conf.py @@ -0,0 +1,161 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import json +import shutil +from os import path +from typing import Any, Dict, Union + +from splunk_add_on_ucc_framework.commands.modular_alert_builder import normalize +from splunk_add_on_ucc_framework.generators.conf_files import ConfGenerator + + +class AlertActionsConf(ConfGenerator): + __description__ = ( + "Generates `alert_actions.conf` and `alert_actions.conf.spec` file " + "for the custom alert actions defined in globalConfig" + ) + + def _set_attributes(self, **kwargs: Any) -> None: + self.conf_file = "alert_actions.conf" + self.conf_spec_file = f"{self.conf_file}.spec" + if self._global_config is None: + return + + envs = normalize.normalize( + self._global_config.alerts, + self._global_config.namespace, + ) + schema_content = envs["schema.content"] + self._alert_settings = schema_content["modular_alerts"] + + deny_list = frozenset( + [ + "short_name", + "alert_props", + "parameters", + "uuid", + "code", + "largeIcon", + "smallIcon", + "index", + "iconFileName", # it is a config from globalConfig that gets written to icon_path + "customScript", # it is a config from globalConfig only for Python script + ] + ) + _router = { + "dropdownlist": "list", + "text": "string", + "textarea": "string", + "checkbox": "bool", + "password": "password", + "dropdownlist_splunk_search": "list", + "radio": "list", + } + + self.alerts: Dict[str, Any] = {} + self.alerts_spec: Dict[str, Any] = {} + + for alert in self._alert_settings: + alert_name = alert["short_name"] + self.alerts[alert_name] = [] + self.alerts_spec[alert_name] = [] + # process the 'iconFileName' property for alert actions + if alert.get("iconFileName", "alerticon.png") != "alerticon.png": + self.alerts[alert_name].append(f"icon_path = {alert['iconFileName']}") + else: + self.alerts[alert_name].append("icon_path = alerticon.png") + # we copy UCC framework's alerticon.png only when a custom isn't provided + shutil.copy( + path.join(kwargs["ucc_dir"], "static", "alerticon.png"), + path.join(self._get_output_dir(), "appserver", "static"), + ) + # process alert action properties in bulk + for k, v in alert.items(): + if k == "adaptive_response": + new_cam = { + sub_k: sub_v + for sub_k, sub_v in list(v.items()) + if sub_k != "sourcetype" and sub_v + } + value = f"param._cam = {json.dumps(new_cam)}" + self.alerts[alert_name].append(value) + self.alerts_spec[alert_name].append( + "param._cam = Adaptive Response parameters." + ) + elif k == "parameters": + for param in v: + param_name = param["name"].strip() + if param.get("default_value") is not None: + self.alerts[alert_name].append( + f"param.{param_name} = {str(param['default_value']).strip()}" + ) + else: + self.alerts[alert_name].append(f"param.{param_name} = ") + + # fetching details for alert_actions.conf.spec file + format_type = _router[param["format_type"]] + is_required = ( + "It's a required parameter." + if param.get("required") and param["required"] + else "" + ) + param_default_value = param.get("default_value") + default_value = ( + f"It's default value is {param_default_value}." + if param_default_value + else "" + ) + value = ( + f'param.{param["name"]} = <{format_type}> ' + f'{param["label"]}. {is_required} {default_value}' + ) + self.alerts_spec[alert_name].append(value) + elif k not in deny_list: + value = f"{str(k).strip()} = {str(v).strip()}" + self.alerts[alert_name].append(value) + + def generate_conf(self) -> Union[Dict[str, str], None]: + if not self.alerts: + return None + + file_path = self.get_file_output_path(["default", self.conf_file]) + self.set_template_and_render( + template_file_path=["conf_files"], file_name="alert_actions_conf.template" + ) + rendered_content = self._template.render(alerts=self.alerts) + self.writer( + file_name=self.conf_file, + file_path=file_path, + content=rendered_content, + ) + return {self.conf_file: file_path} + + def generate_conf_spec(self) -> Union[Dict[str, str], None]: + if not self.alerts_spec: + return None + + file_path = self.get_file_output_path(["README", self.conf_spec_file]) + self.set_template_and_render( + template_file_path=["README"], + file_name="alert_actions_conf_spec.template", + ) + rendered_content = self._template.render(alerts=self.alerts_spec) + self.writer( + file_name=self.conf_spec_file, + file_path=file_path, + content=rendered_content, + ) + return {self.conf_spec_file: file_path} diff --git a/splunk_add_on_ucc_framework/generators/conf_files/create_app_conf.py b/splunk_add_on_ucc_framework/generators/conf_files/create_app_conf.py new file mode 100644 index 000000000..00aa02fec --- /dev/null +++ b/splunk_add_on_ucc_framework/generators/conf_files/create_app_conf.py @@ -0,0 +1,77 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from time import time +from typing import Any, Dict + +from splunk_add_on_ucc_framework.generators.conf_files import ConfGenerator + + +class AppConf(ConfGenerator): + __description__ = ( + "Generates `app.conf` with the details mentioned in globalConfig[meta]" + ) + + def _set_attributes(self, **kwargs: Any) -> None: + self.conf_file = "app.conf" + self.check_for_updates = "true" + self.custom_conf = [] + self.name = self._addon_name + self.id = self._addon_name + self.supported_themes = "" + + if self._global_config and self._gc_schema: + self.custom_conf.extend(list(self._gc_schema.settings_conf_file_names)) + self.custom_conf.extend(list(self._gc_schema.configs_conf_file_names)) + self.custom_conf.extend(list(self._gc_schema.oauth_conf_file_names)) + + if self._global_config.meta.get("checkForUpdates") is False: + self.check_for_updates = "false" + if self._global_config.meta.get("supportedThemes") is not None: + self.supported_themes = ", ".join( + self._global_config.meta["supportedThemes"] + ) + + self.addon_version = kwargs["addon_version"] + self.is_visible = str(kwargs["has_ui"]).lower() + self.description = kwargs["app_manifest"].get_description() + self.author = kwargs["app_manifest"].get_authors()[0]["name"] + self.build = str(int(time())) + + def generate_conf(self) -> Dict[str, str]: + file_path = self.get_file_output_path(["default", self.conf_file]) + self.set_template_and_render( + template_file_path=["conf_files"], file_name="app_conf.template" + ) + rendered_content = self._template.render( + custom_conf=self.custom_conf, + addon_version=self.addon_version, + check_for_updates=self.check_for_updates, + supported_themes=self.supported_themes, + description=self.description, + author=self.author, + name=self.name, + build=self.build, + id=self.id, + label=self.description, + is_visible=self.is_visible, + ) + self.writer( + file_name=self.conf_file, + file_path=file_path, + content=rendered_content, + merge_mode="item_overwrite", + ) + return {self.conf_file: file_path} diff --git a/splunk_add_on_ucc_framework/generators/conf_files/create_eventtypes_conf.py b/splunk_add_on_ucc_framework/generators/conf_files/create_eventtypes_conf.py new file mode 100644 index 000000000..517468e04 --- /dev/null +++ b/splunk_add_on_ucc_framework/generators/conf_files/create_eventtypes_conf.py @@ -0,0 +1,53 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from typing import Any, Dict, List, Union + +from splunk_add_on_ucc_framework.commands.modular_alert_builder import normalize +from splunk_add_on_ucc_framework.generators.conf_files import ConfGenerator + + +class EventtypesConf(ConfGenerator): + __description__ = ( + "Generates `eventtypes.conf` file if the sourcetype is mentioned" + " in Adaptive Response of custom alert action in globalConfig" + ) + + def _set_attributes(self, **kwargs: Any) -> None: + self.conf_file = "eventtypes.conf" + self.alert_settings: Dict[str, List[Dict[str, Any]]] = {} + if self._global_config: + envs = normalize.normalize( + self._global_config.alerts, + self._global_config.namespace, + ) + schema_content = envs["schema.content"] + self.alert_settings = schema_content["modular_alerts"] + + def generate_conf(self) -> Union[Dict[str, str], None]: + if not self.alert_settings: + return None + + file_path = self.get_file_output_path(["default", self.conf_file]) + self.set_template_and_render( + template_file_path=["conf_files"], file_name="eventtypes_conf.template" + ) + rendered_content = self._template.render(mod_alerts=self.alert_settings) + self.writer( + file_name=self.conf_file, + file_path=file_path, + content=rendered_content, + ) + return {self.conf_file: file_path} diff --git a/splunk_add_on_ucc_framework/generators/conf_files/create_inputs_conf.py b/splunk_add_on_ucc_framework/generators/conf_files/create_inputs_conf.py new file mode 100644 index 000000000..e5ec4f47e --- /dev/null +++ b/splunk_add_on_ucc_framework/generators/conf_files/create_inputs_conf.py @@ -0,0 +1,90 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from typing import Any, Dict, List, Union + +from splunk_add_on_ucc_framework.generators.conf_files import ConfGenerator + + +class InputsConf(ConfGenerator): + __description__ = ( + "Generates `inputs.conf` and `inputs.conf.spec` " + "file for the services mentioned in globalConfig" + ) + + def _set_attributes(self, **kwargs: Any) -> None: + self.conf_file = "inputs.conf" + self.conf_spec_file = f"{self.conf_file}.spec" + self.input_names: List[Dict[str, List[str]]] = [] + if self._global_config: + for service in self._global_config.inputs: + properties = [] + if service.get("conf") is not None: + # Add data input of self defined conf to inputs.conf.spec + self.input_names.append( + {service["name"]: ["placeholder = placeholder"]} + ) + continue + for entity in service.get("entity", {"field": "name"}): + # TODO: add the details and updates on what to skip and process + if entity["field"] == "name": + continue + nl = "\n" # hack for `f-string expression part cannot include a backslash` + # TODO: enhance the message formation for inputs.conf.spec file + properties.append( + f"{entity['field']} = {entity.get('help', '').replace(nl, ' ')} " + f"{'' if entity.get('defaultValue') is None else ' Default: ' + str(entity['defaultValue'])}" + ) + + self.input_names.append({service["name"]: properties}) + + def generate_conf(self) -> Union[Dict[str, str], None]: + if not self.input_names: + return None + + file_path = self.get_file_output_path(["default", self.conf_file]) + stanzas: List[str] = [] + for k in self.input_names: + stanzas.extend(k.keys()) + self.set_template_and_render( + template_file_path=["conf_files"], file_name="inputs_conf.template" + ) + + rendered_content = self._template.render(input_names=stanzas) + self.writer( + file_name=self.conf_file, + file_path=file_path, + content=rendered_content, + ) + return {self.conf_file: file_path} + + def generate_conf_spec(self) -> Union[Dict[str, str], None]: + if not self.input_names: + return None + + file_path = self.get_file_output_path(["README", self.conf_spec_file]) + self.set_template_and_render( + template_file_path=["README"], file_name="inputs_conf_spec.template" + ) + + rendered_content = self._template.render( + input_stanzas=self.input_names, + ) + self.writer( + file_name=self.conf_spec_file, + file_path=file_path, + content=rendered_content, + ) + return {self.conf_spec_file: file_path} diff --git a/splunk_add_on_ucc_framework/generators/conf_files/create_restmap_conf.py b/splunk_add_on_ucc_framework/generators/conf_files/create_restmap_conf.py new file mode 100644 index 000000000..6e0b5ca39 --- /dev/null +++ b/splunk_add_on_ucc_framework/generators/conf_files/create_restmap_conf.py @@ -0,0 +1,52 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from typing import Any, Dict, Union + +from splunk_add_on_ucc_framework.generators.conf_files import ConfGenerator + + +class RestMapConf(ConfGenerator): + __description__ = ( + "Generates `restmap.conf` for the custom REST handlers that " + "are generated based on configs from globalConfig" + ) + + def _set_attributes(self, **kwargs: Any) -> None: + self.conf_file = "restmap.conf" + if self._gc_schema: + self.endpoints = self._gc_schema.endpoints + self.endpoint_names = ", ".join(sorted([ep.name for ep in self.endpoints])) + self.namespace = self._gc_schema.namespace + + def generate_conf(self) -> Union[Dict[str, str], None]: + if not self._gc_schema: + return None + + file_path = self.get_file_output_path(["default", self.conf_file]) + self.set_template_and_render( + template_file_path=["conf_files"], file_name="restmap_conf.template" + ) + rendered_content = self._template.render( + endpoints=self.endpoints, + endpoint_names=self.endpoint_names, + namespace=self.namespace, + ) + self.writer( + file_name=self.conf_file, + file_path=file_path, + content=rendered_content, + ) + return {self.conf_file: file_path} diff --git a/splunk_add_on_ucc_framework/generators/conf_files/create_server_conf.py b/splunk_add_on_ucc_framework/generators/conf_files/create_server_conf.py new file mode 100644 index 000000000..e49a3c100 --- /dev/null +++ b/splunk_add_on_ucc_framework/generators/conf_files/create_server_conf.py @@ -0,0 +1,53 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from os.path import isfile, join +from typing import Any, Dict, Union +from splunk_add_on_ucc_framework.generators.conf_files import ConfGenerator + + +class ServerConf(ConfGenerator): + __description__ = ( + "Generates `server.conf` for the custom conf " + "files created as per configurations in globalConfig" + ) + + def _set_attributes(self, **kwargs: Any) -> None: + self.conf_file = "server.conf" + self.custom_conf = [] + if self._gc_schema: + self.custom_conf.extend(list(self._gc_schema.settings_conf_file_names)) + self.custom_conf.extend(list(self._gc_schema.configs_conf_file_names)) + self.custom_conf.extend(list(self._gc_schema.oauth_conf_file_names)) + + def generate_conf(self) -> Union[Dict[str, str], None]: + if not self.custom_conf: + return None + + file_path = self.get_file_output_path(["default", self.conf_file]) + # For now, only create server.conf only if + # no server.conf is present in the source package. + if isfile(join(self._input_dir, "default", self.conf_file)): + return {"": ""} + self.set_template_and_render( + template_file_path=["conf_files"], file_name="server_conf.template" + ) + rendered_content = self._template.render(custom_conf=self.custom_conf) + self.writer( + file_name=self.conf_file, + file_path=file_path, + content=rendered_content, + ) + return {self.conf_file: file_path} diff --git a/splunk_add_on_ucc_framework/generators/conf_files/create_settings_conf.py b/splunk_add_on_ucc_framework/generators/conf_files/create_settings_conf.py new file mode 100644 index 000000000..f1c13bb3b --- /dev/null +++ b/splunk_add_on_ucc_framework/generators/conf_files/create_settings_conf.py @@ -0,0 +1,77 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from typing import Any, Tuple, List, Dict, Union + +from splunk_add_on_ucc_framework.generators.conf_files import ConfGenerator + + +class SettingsConf(ConfGenerator): + __description__ = ( + "Generates `_settings.conf.spec` " + "file for the Proxy, Logging or Custom Tab mentioned in globalConfig" + ) + + def _set_attributes(self, **kwargs: Any) -> None: + self.settings_stanzas: List[Tuple[str, List[str]]] = [] + self.default_content: str = "" + + if self._global_config and self._gc_schema: + self.conf_file = self._global_config.namespace.lower() + "_settings.conf" + self.conf_spec_file = f"{self.conf_file}.spec" + for setting in self._global_config.settings: + content = self._gc_schema._get_oauth_enitities(setting["entity"]) + fields = self._gc_schema._parse_fields(content) + self.settings_stanzas.append( + (setting["name"], [f"{f._name} = " for f in fields]) + ) + if self._gc_schema._endpoints.get("settings") is not None: + self.default_content = self._gc_schema._endpoints[ + "settings" + ].generate_conf_with_default_values() + + def generate_conf(self) -> Union[Dict[str, str], None]: + if not self.default_content: + return None + + file_path = self.get_file_output_path(["default", self.conf_file]) + self.set_template_and_render( + template_file_path=["conf_files"], file_name="settings_conf.template" + ) + + rendered_content = self._template.render(default_content=self.default_content) + self.writer( + file_name=self.conf_file, + file_path=file_path, + content=rendered_content, + ) + return {self.conf_file: file_path} + + def generate_conf_spec(self) -> Union[Dict[str, str], None]: + if not self.settings_stanzas: + return None + + file_path = self.get_file_output_path(["README", self.conf_spec_file]) + self.set_template_and_render( + template_file_path=["README"], file_name="settings_conf_spec.template" + ) + + rendered_content = self._template.render(settings_stanzas=self.settings_stanzas) + self.writer( + file_name=self.conf_spec_file, + file_path=file_path, + content=rendered_content, + ) + return {self.conf_spec_file: file_path} diff --git a/splunk_add_on_ucc_framework/generators/conf_files/create_tags_conf.py b/splunk_add_on_ucc_framework/generators/conf_files/create_tags_conf.py new file mode 100644 index 000000000..7306c864b --- /dev/null +++ b/splunk_add_on_ucc_framework/generators/conf_files/create_tags_conf.py @@ -0,0 +1,52 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from typing import Any, Dict, List, Union +from splunk_add_on_ucc_framework.commands.modular_alert_builder import normalize +from splunk_add_on_ucc_framework.generators.conf_files import ConfGenerator + + +class TagsConf(ConfGenerator): + __description__ = ( + "Generates `tags.conf` file based on the " + "`eventtypes.conf` created for custom alert actions." + ) + + def _set_attributes(self, **kwargs: Any) -> None: + self.conf_file = "tags.conf" + self.alert_settings: Dict[str, List[Dict[str, Any]]] = {} + if self._global_config: + envs = normalize.normalize( + self._global_config.alerts, + self._global_config.namespace, + ) + schema_content = envs["schema.content"] + self.alert_settings = schema_content["modular_alerts"] + + def generate_conf(self) -> Union[Dict[str, str], None]: + if not self.alert_settings: + return None + + file_path = self.get_file_output_path(["default", self.conf_file]) + self.set_template_and_render( + template_file_path=["conf_files"], file_name="tags_conf.template" + ) + rendered_content = self._template.render(mod_alerts=self.alert_settings) + self.writer( + file_name=self.conf_file, + file_path=file_path, + content=rendered_content, + ) + return {self.conf_file: file_path} diff --git a/splunk_add_on_ucc_framework/generators/conf_files/create_web_conf.py b/splunk_add_on_ucc_framework/generators/conf_files/create_web_conf.py new file mode 100644 index 000000000..477d0803c --- /dev/null +++ b/splunk_add_on_ucc_framework/generators/conf_files/create_web_conf.py @@ -0,0 +1,48 @@ +# +# Copyright 2024 Splunk Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +from typing import Any, Dict, Union + +from splunk_add_on_ucc_framework.generators.conf_files import ConfGenerator + + +class WebConf(ConfGenerator): + __description__ = ( + "Generates `web.conf` to expose the endpoints generated in " + "`restmap.conf` which is generated based on configurations from globalConfig." + ) + + def _set_attributes(self, **kwargs: Any) -> None: + self.conf_file = "web.conf" + if self._gc_schema: + self.endpoints = self._gc_schema.endpoints + + def generate_conf(self) -> Union[Dict[str, str], None]: + if not self._gc_schema: + return None + + file_path = self.get_file_output_path(["default", self.conf_file]) + self.set_template_and_render( + template_file_path=["conf_files"], file_name="web_conf.template" + ) + rendered_content = self._template.render( + endpoints=self.endpoints, + ) + self.writer( + file_name=self.conf_file, + file_path=file_path, + content=rendered_content, + ) + return {self.conf_file: file_path} diff --git a/splunk_add_on_ucc_framework/generators/file_const.py b/splunk_add_on_ucc_framework/generators/file_const.py index eac29f61b..b843b915c 100644 --- a/splunk_add_on_ucc_framework/generators/file_const.py +++ b/splunk_add_on_ucc_framework/generators/file_const.py @@ -15,6 +15,7 @@ # from typing import List, NamedTuple, Type, Union from .file_generator import FileGenerator + from splunk_add_on_ucc_framework.generators.xml_files import ( ConfigurationXml, DashboardXml, @@ -23,6 +24,18 @@ RedirectXml, ) from splunk_add_on_ucc_framework.generators.html_files import AlertActionsHtml +from splunk_add_on_ucc_framework.generators.conf_files import ( + AlertActionsConf, + AppConf, + EventtypesConf, + InputsConf, + RestMapConf, + ServerConf, + TagsConf, + WebConf, + AccountConf, + SettingsConf, +) __all__ = ["FileClass", "GEN_FILE_LIST"] @@ -35,6 +48,23 @@ class FileClass(NamedTuple): GEN_FILE_LIST: List[FileClass] = [ + FileClass("app.conf", AppConf, "default", AppConf.__description__), + FileClass("inputs.conf", InputsConf, "default", InputsConf.__description__), + FileClass("server.conf", ServerConf, "default", ServerConf.__description__), + FileClass("restmap.conf", RestMapConf, "default", RestMapConf.__description__), + FileClass("web.conf", WebConf, "default", WebConf.__description__), + FileClass( + "alert_actions.conf", + AlertActionsConf, + "default", + AlertActionsConf.__description__, + ), + FileClass( + "eventtypes.conf", EventtypesConf, "default", EventtypesConf.__description__ + ), + FileClass("tags.conf", TagsConf, "default", TagsConf.__description__), + FileClass("_account.conf", AccountConf, "README", AccountConf.__description__), + FileClass("_settings.conf", SettingsConf, "README", SettingsConf.__description__), FileClass( "configuration.xml", ConfigurationXml, diff --git a/splunk_add_on_ucc_framework/rest_map_conf.py b/splunk_add_on_ucc_framework/rest_map_conf.py deleted file mode 100644 index 00f050421..000000000 --- a/splunk_add_on_ucc_framework/rest_map_conf.py +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright 2024 Splunk Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from typing import Sequence - -from splunk_add_on_ucc_framework.commands.rest_builder.endpoint.base import ( - RestEndpointBuilder, -) - - -class RestmapConf: - _admin_template = """ -[admin:{namespace}] -match = / -members = {endpoints} -""" - - _external_template = """ -[admin_external:{name}] -handlertype = python -python.version = python3 -handlerfile = {rh_name}.py -handleractions = {actions} -handlerpersistentmode = true -""" - - @classmethod - def build(cls, endpoints: Sequence[RestEndpointBuilder], namespace: str) -> str: - externals = [ - cls._admin_template.format( - namespace=namespace, - endpoints=", ".join([ep.name for ep in endpoints]), - ) - ] - for endpoint in endpoints: - external = cls._external_template.format( - name=endpoint.name, - rh_name=endpoint.rh_name, - actions=", ".join(endpoint.actions()), - ) - externals.append(external) - return "".join(externals) diff --git a/splunk_add_on_ucc_framework/schema/schema.json b/splunk_add_on_ucc_framework/schema/schema.json index 5fcbeade8..d5b48b4f8 100644 --- a/splunk_add_on_ucc_framework/schema/schema.json +++ b/splunk_add_on_ucc_framework/schema/schema.json @@ -19,6 +19,7 @@ "type": "string", "enum": [ "text", + "textarea", "checkbox", "singleSelect", "radio", diff --git a/splunk_add_on_ucc_framework/server_conf.py b/splunk_add_on_ucc_framework/server_conf.py deleted file mode 100644 index bf4c95477..000000000 --- a/splunk_add_on_ucc_framework/server_conf.py +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright 2024 Splunk Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from typing import Sequence - -import addonfactory_splunk_conf_parser_lib as conf_parser - -SERVER_CONF_FILE_NAME = "server.conf" - - -class ServerConf: - def __init__(self) -> None: - self._server_conf = conf_parser.TABConfigParser() - - def create_default(self, conf_file_names: Sequence[str]) -> None: - self._server_conf.add_section("shclustering") - for conf_file_name in conf_file_names: - self._server_conf["shclustering"][ - f"conf_replication_include.{conf_file_name}" - ] = "true" - - def write(self, path: str) -> None: - with open(path, "w") as fd: - self._server_conf.write(fd) diff --git a/splunk_add_on_ucc_framework/templates/README/account_conf_spec.template b/splunk_add_on_ucc_framework/templates/README/account_conf_spec.template new file mode 100644 index 000000000..bdaa7adc4 --- /dev/null +++ b/splunk_add_on_ucc_framework/templates/README/account_conf_spec.template @@ -0,0 +1,4 @@ +{% for stanza in account_stanzas %} +[{{ stanza[0] }}] +{{ stanza[1] | sort() | join("\n") }} +{% endfor %} diff --git a/splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/alert_actions.conf.spec.template b/splunk_add_on_ucc_framework/templates/README/alert_actions_conf_spec.template similarity index 89% rename from splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/alert_actions.conf.spec.template rename to splunk_add_on_ucc_framework/templates/README/alert_actions_conf_spec.template index 280d9c390..e2d64d50e 100644 --- a/splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/alert_actions.conf.spec.template +++ b/splunk_add_on_ucc_framework/templates/README/alert_actions_conf_spec.template @@ -3,5 +3,4 @@ {% for param in params %} {{ param }} {% endfor %} - -{% endfor %} \ No newline at end of file +{% endfor %} diff --git a/splunk_add_on_ucc_framework/templates/README/inputs_conf_spec.template b/splunk_add_on_ucc_framework/templates/README/inputs_conf_spec.template new file mode 100644 index 000000000..e6e09dc31 --- /dev/null +++ b/splunk_add_on_ucc_framework/templates/README/inputs_conf_spec.template @@ -0,0 +1,6 @@ +{% for stanza in input_stanzas %} +{{ "[" ~ stanza.keys() | join("") ~ "://]" }} + {% for property in stanza.values() -%} +{{ property | sort() | join("\n") }} + {% endfor %} +{% endfor %} diff --git a/splunk_add_on_ucc_framework/templates/README/settings_conf_spec.template b/splunk_add_on_ucc_framework/templates/README/settings_conf_spec.template new file mode 100644 index 000000000..c18a7b3c5 --- /dev/null +++ b/splunk_add_on_ucc_framework/templates/README/settings_conf_spec.template @@ -0,0 +1,4 @@ +{% for stanza in settings_stanzas %} +[{{ stanza[0] }}] +{{ stanza[1] | sort() | join("\n") }} +{% endfor %} diff --git a/splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/alert_actions.conf.template b/splunk_add_on_ucc_framework/templates/conf_files/alert_actions_conf.template similarity index 61% rename from splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/alert_actions.conf.template rename to splunk_add_on_ucc_framework/templates/conf_files/alert_actions_conf.template index 280d9c390..a9e35e2cf 100644 --- a/splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/alert_actions.conf.template +++ b/splunk_add_on_ucc_framework/templates/conf_files/alert_actions_conf.template @@ -2,6 +2,8 @@ [{{ alert }}] {% for param in params %} {{ param }} +python.version: python3 +is_custom: 1 +payload_format: json {% endfor %} - -{% endfor %} \ No newline at end of file +{% endfor %} diff --git a/splunk_add_on_ucc_framework/templates/conf_files/app_conf.template b/splunk_add_on_ucc_framework/templates/conf_files/app_conf.template new file mode 100644 index 000000000..938e44d21 --- /dev/null +++ b/splunk_add_on_ucc_framework/templates/conf_files/app_conf.template @@ -0,0 +1,31 @@ +[launcher] +version = {{ addon_version }} +description = {{ description }} +author = {{ author }} + +[id] +version = {{ addon_version }} +name = {{ name }} + +[install] +build = {{ build }} +is_configured = false +state = enabled + +[package] +id = {{ id }} +check_for_updates = {{ check_for_updates }} + +[ui] +label = {{ label }} +{% if supported_themes %} +supported_themes = {{ supported_themes }} +{% endif %} +is_visible = {{ is_visible }} + +{% if custom_conf %} +[triggers] +{% for conf in custom_conf %} +reload.{{ conf }} = simple +{% endfor %} +{% endif %} diff --git a/splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/eventtypes.conf.template b/splunk_add_on_ucc_framework/templates/conf_files/eventtypes_conf.template similarity index 66% rename from splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/eventtypes.conf.template rename to splunk_add_on_ucc_framework/templates/conf_files/eventtypes_conf.template index a2466777d..d9b467dca 100644 --- a/splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/eventtypes.conf.template +++ b/splunk_add_on_ucc_framework/templates/conf_files/eventtypes_conf.template @@ -1,5 +1,5 @@ {% for alert in mod_alerts %} - {% if alert.get("adaptive_response") and alert.adaptive_response.get("sourcetype") %} + {% if alert.get("adaptive_response", {}).get("sourcetype") %} [{{ alert.short_name }}_modaction_result] search = {{ 'sourcetype="' + alert.adaptive_response.sourcetype + '"' }} {% endif %} diff --git a/splunk_add_on_ucc_framework/templates/conf_files/inputs_conf.template b/splunk_add_on_ucc_framework/templates/conf_files/inputs_conf.template new file mode 100644 index 000000000..32b840bb9 --- /dev/null +++ b/splunk_add_on_ucc_framework/templates/conf_files/inputs_conf.template @@ -0,0 +1,4 @@ +{% for input_name in input_names %} +{{ "[" ~ input_name ~ "]"}} +python.version = python3 +{% endfor %} diff --git a/splunk_add_on_ucc_framework/templates/conf_files/restmap_conf.template b/splunk_add_on_ucc_framework/templates/conf_files/restmap_conf.template new file mode 100644 index 000000000..dd2e49f8b --- /dev/null +++ b/splunk_add_on_ucc_framework/templates/conf_files/restmap_conf.template @@ -0,0 +1,12 @@ +[admin:{{ namespace }}] +match = / +members = {{ endpoint_names }} + +{% for endpoint in endpoints %} +[admin_external:{{ endpoint.name }}] +handlertype = python +python.version = python3 +handlerfile = {{ endpoint.rh_name }}.py +handleractions = {{ endpoint.actions() | join(', ') }} +handlerpersistentmode = true +{% endfor %} diff --git a/splunk_add_on_ucc_framework/templates/conf_files/server_conf.template b/splunk_add_on_ucc_framework/templates/conf_files/server_conf.template new file mode 100644 index 000000000..b83497b73 --- /dev/null +++ b/splunk_add_on_ucc_framework/templates/conf_files/server_conf.template @@ -0,0 +1,4 @@ +[shclustering] +{% for conf in custom_conf %} +conf_replication_include.{{ conf }} = true +{% endfor %} diff --git a/splunk_add_on_ucc_framework/templates/conf_files/settings_conf.template b/splunk_add_on_ucc_framework/templates/conf_files/settings_conf.template new file mode 100644 index 000000000..4d6bb3c9f --- /dev/null +++ b/splunk_add_on_ucc_framework/templates/conf_files/settings_conf.template @@ -0,0 +1 @@ +{{ default_content }} diff --git a/splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/tags.conf.template b/splunk_add_on_ucc_framework/templates/conf_files/tags_conf.template similarity index 100% rename from splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/tags.conf.template rename to splunk_add_on_ucc_framework/templates/conf_files/tags_conf.template diff --git a/splunk_add_on_ucc_framework/templates/conf_files/web_conf.template b/splunk_add_on_ucc_framework/templates/conf_files/web_conf.template new file mode 100644 index 000000000..4cd6ceed4 --- /dev/null +++ b/splunk_add_on_ucc_framework/templates/conf_files/web_conf.template @@ -0,0 +1,9 @@ +{% for endpoint in endpoints %} +[expose:{{ endpoint.name }}] +pattern = {{ endpoint.name }} +methods = POST, GET + +[expose:{{ endpoint.name }}_specified] +pattern = {{ endpoint.name }}/* +methods = POST, GET, DELETE +{% endfor %} diff --git a/splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/default_html_theme/textarea.html b/splunk_add_on_ucc_framework/templates/html_templates/textarea.html similarity index 100% rename from splunk_add_on_ucc_framework/commands/modular_alert_builder/arf_template/default_html_theme/textarea.html rename to splunk_add_on_ucc_framework/templates/html_templates/textarea.html diff --git a/splunk_add_on_ucc_framework/web_conf.py b/splunk_add_on_ucc_framework/web_conf.py deleted file mode 100644 index 095962c4f..000000000 --- a/splunk_add_on_ucc_framework/web_conf.py +++ /dev/null @@ -1,52 +0,0 @@ -# -# Copyright 2024 Splunk Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -from typing import Sequence - -from splunk_add_on_ucc_framework.commands.rest_builder.endpoint.base import ( - RestEndpointBuilder, -) - - -class WebConf: - _template = """ -[expose:{name}] -pattern = {name} -methods = POST, GET -""" - - _specified_template = """ -[expose:{name}_specified] -pattern = {name}/* -methods = POST, GET, DELETE -""" - - @classmethod - def build(cls, endpoints: Sequence[RestEndpointBuilder]) -> str: - stanzas = [] - for endpoint in endpoints: - stanzas.append( - cls._template.format( - namespace=endpoint.namespace, - name=endpoint.name, - ) - ) - stanzas.append( - cls._specified_template.format( - namespace=endpoint.namespace, - name=endpoint.name, - ) - ) - return "".join(stanzas) diff --git a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/README/splunk_ta_uccexample_account.conf.spec b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/README/splunk_ta_uccexample_account.conf.spec index 44d8466d5..67a64483e 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/README/splunk_ta_uccexample_account.conf.spec +++ b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/README/splunk_ta_uccexample_account.conf.spec @@ -1,17 +1,17 @@ [] -custom_endpoint = -endpoint = +access_token = account_checkbox = -account_radio = account_multiple_select = -example_help_link = -username = -password = -token = +account_radio = +auth_type = client_id = client_secret = +custom_endpoint = +endpoint = +example_help_link = +instance_url = +password = redirect_url = -access_token = refresh_token = -instance_url = -auth_type = \ No newline at end of file +token = +username = \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/README/splunk_ta_uccexample_settings.conf.spec b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/README/splunk_ta_uccexample_settings.conf.spec index 4328f2f12..a359f3958 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/README/splunk_ta_uccexample_settings.conf.spec +++ b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/README/splunk_ta_uccexample_settings.conf.spec @@ -1,20 +1,20 @@ [proxy] proxy_enabled = +proxy_password = +proxy_port = +proxy_rdns = proxy_type = proxy_url = -proxy_port = proxy_username = -proxy_password = -proxy_rdns = [logging] loglevel = [custom_abc] -testString = -testNumber = -testRegex = +testDate = testEmail = testIpv4 = -testDate = +testNumber = +testRegex = +testString = testUrl = \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/app.conf b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/app.conf index e127851ca..ad55141fd 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/app.conf +++ b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/app.conf @@ -32,5 +32,4 @@ version = 1.0.0 [triggers] reload.splunk_ta_uccexample_account = simple reload.splunk_ta_uccexample_oauth = simple -reload.splunk_ta_uccexample_settings = simple - +reload.splunk_ta_uccexample_settings = simple \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/restmap.conf b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/restmap.conf index c43d121fb..411bf07f8 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/restmap.conf +++ b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/restmap.conf @@ -1,4 +1,3 @@ - [admin:splunk_ta_uccexample] match = / members = splunk_ta_uccexample_account, splunk_ta_uccexample_oauth, splunk_ta_uccexample_settings @@ -22,4 +21,4 @@ handlertype = python python.version = python3 handlerfile = splunk_ta_uccexample_rh_settings.py handleractions = edit, list -handlerpersistentmode = true +handlerpersistentmode = true \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/server.conf b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/server.conf index f89d933c0..5a7326859 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/server.conf +++ b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/server.conf @@ -1,4 +1,4 @@ [shclustering] conf_replication_include.splunk_ta_uccexample_settings = true conf_replication_include.splunk_ta_uccexample_account = true -conf_replication_include.splunk_ta_uccexample_oauth = true +conf_replication_include.splunk_ta_uccexample_oauth = true \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/web.conf b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/web.conf index 9f58918dd..c1495c278 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/web.conf +++ b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/default/web.conf @@ -1,4 +1,3 @@ - [expose:splunk_ta_uccexample_account] pattern = splunk_ta_uccexample_account methods = POST, GET @@ -21,4 +20,4 @@ methods = POST, GET [expose:splunk_ta_uccexample_settings_specified] pattern = splunk_ta_uccexample_settings/* -methods = POST, GET, DELETE +methods = POST, GET, DELETE \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/alert_actions.conf.spec b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/alert_actions.conf.spec index 12ca0db1e..46492994d 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/alert_actions.conf.spec +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/alert_actions.conf.spec @@ -1,7 +1,8 @@ [test_alert] param._cam = Adaptive Response parameters. param.name = Name. It's a required parameter. It's default value is xyz. +param.description = Description. It's a required parameter. It's default value is some sample description. param.all_incidents = All Incidents. param.table_list = Table List. It's default value is problem. param.action = Action:. It's a required parameter. It's default value is update. -param.account = Select Account. It's a required parameter. +param.account = Select Account. It's a required parameter. \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/inputs.conf.spec b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/inputs.conf.spec index eb0eade4d..d1d44e2c8 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/inputs.conf.spec +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/inputs.conf.spec @@ -1,38 +1,38 @@ [example_input_one://] -input_one_checkbox = -input_one_radio = -singleSelectTest = -multipleSelectTest = -interval = -index = account = -object = -object_fields = -order_by = -use_existing_checkpoint = -start_date = -limit = -example_textarea_field = example_help_link = -hide_in_ui = -hard_disabled = +example_textarea_field = Help message +hard_disabled = +hide_in_ui = +index = Default: default +input_one_checkbox = This is an example checkbox for the input one entity Default: True +input_one_radio = This is an example radio button for the input one entity Default: yes +interval = Time interval of the data input, in seconds. +limit = The maximum number of results returned by the query. Default: 1000 +multipleSelectTest = Default: a|b +object = The name of the object to query for. +object_fields = Object fields from which to collect data. Delimit multiple fields using a comma. +order_by = The datetime field by which to query results in ascending order for indexing. Default: LastModifiedDate +singleSelectTest = +start_date = The datetime after which to query and index records, in this format: "YYYY-MM-DDThh:mm:ss.000z". Defaults to 90 days earlier from now. +use_existing_checkpoint = Data input already exists. Select `No` if you want to reset the data collection. Default: yes [example_input_two://] -interval = -index = account = -input_two_multiple_select = -input_two_checkbox = -input_two_radio = -use_existing_checkpoint = -start_date = -example_help_link = apis = -hide_in_ui = -hard_disabled = +example_help_link = +hard_disabled = +hide_in_ui = +index = Default: default +input_two_checkbox = This is an example checkbox for the input two entity +input_two_multiple_select = This is an example multipleSelect for input two entity +input_two_radio = This is an example radio button for the input two entity +interval = Time interval of the data input, in seconds. +start_date = The date and time, in "YYYY-MM-DDThh:mm:ss.000z" format, after which to query and index records. The default is 90 days before today. +use_existing_checkpoint = Data input already exists. Select `No` if you want to reset the data collection. Default: yes [example_input_three://] -interval = +interval = Time interval of the data input, in seconds. [example_input_four://] -interval = \ No newline at end of file +interval = Time interval of the data input, in seconds. diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/splunk_ta_uccexample_account.conf.spec b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/splunk_ta_uccexample_account.conf.spec index 06bdcd08f..f922e33d2 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/splunk_ta_uccexample_account.conf.spec +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/splunk_ta_uccexample_account.conf.spec @@ -1,24 +1,24 @@ [] -custom_endpoint = -endpoint = -url = +access_token = account_checkbox = -account_radio = account_multiple_select = -example_help_link = -config1_help_link = -config2_help_link = -username = -password = -token = +account_radio = +auth_type = basic_oauth_text = client_id = client_secret = -redirect_url = -endpoint_token = +config1_help_link = +config2_help_link = +custom_endpoint = +endpoint = endpoint_authorize = +endpoint_token = +example_help_link = +instance_url = oauth_oauth_text = -access_token = +password = +redirect_url = refresh_token = -instance_url = -auth_type = \ No newline at end of file +token = +url = +username = \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/splunk_ta_uccexample_settings.conf.spec b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/splunk_ta_uccexample_settings.conf.spec index 4328f2f12..a359f3958 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/splunk_ta_uccexample_settings.conf.spec +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/README/splunk_ta_uccexample_settings.conf.spec @@ -1,20 +1,20 @@ [proxy] proxy_enabled = +proxy_password = +proxy_port = +proxy_rdns = proxy_type = proxy_url = -proxy_port = proxy_username = -proxy_password = -proxy_rdns = [logging] loglevel = [custom_abc] -testString = -testNumber = -testRegex = +testDate = testEmail = testIpv4 = -testDate = +testNumber = +testRegex = +testString = testUrl = \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/test_alert.py b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/test_alert.py index c33336d17..a0db490ee 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/test_alert.py +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/test_alert.py @@ -19,6 +19,10 @@ def validate_params(self): if not self.get_param("name"): self.log_error('name is a mandatory parameter, but its value is None.') return False + + if not self.get_param("description"): + self.log_error('description is a mandatory parameter, but its value is None.') + return False if not self.get_param("action"): self.log_error('action is a mandatory parameter, but its value is None.') diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/default/alert_actions.conf b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/default/alert_actions.conf index 77d525655..57834810c 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/default/alert_actions.conf +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/default/alert_actions.conf @@ -1,13 +1,14 @@ [test_alert] -label = Test Alert -description = Description for test Alert Action -param._cam = {"task": ["Create", "Update"], "subject": ["endpoint"], "category": ["Information Conveyance", "Information Portrayal"], "technology": [{"version": ["1.0.0"], "product": "Test Incident Update", "vendor": "Splunk"}], "supports_adhoc": true, "supports_cloud": true, "drilldown_uri": "search?q=search%20index%3D\"_internal\"&earliest=0&latest="} +icon_path = test icon.png python.version = python3 is_custom = 1 payload_format = json -icon_path = test icon.png +label = Test Alert +description = Description for test Alert Action +param._cam = {"task": ["Create", "Update"], "subject": ["endpoint"], "category": ["Information Conveyance", "Information Portrayal"], "technology": [{"version": ["1.0.0"], "product": "Test Incident Update", "vendor": "Splunk"}], "supports_adhoc": true, "supports_cloud": true, "drilldown_uri": "search?q=search%20index%3D\"_internal\"&earliest=0&latest="} param.name = xyz +param.description = some sample description param.all_incidents = 0 param.table_list = problem param.action = update -param.account = +param.account = \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/default/app.conf b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/default/app.conf index e541f2c34..51a81dada 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/default/app.conf +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/default/app.conf @@ -24,5 +24,4 @@ version = 5.5.8R5fd76615 [triggers] reload.splunk_ta_uccexample_account = simple reload.splunk_ta_uccexample_oauth = simple -reload.splunk_ta_uccexample_settings = simple - +reload.splunk_ta_uccexample_settings = simple \ No newline at end of file diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/default/data/ui/alerts/test_alert.html b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/default/data/ui/alerts/test_alert.html index 5d91aae06..c655d084d 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/default/data/ui/alerts/test_alert.html +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/default/data/ui/alerts/test_alert.html @@ -9,6 +9,16 @@ +
+ +
+ + + Please enter the description for the alert + +
+