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
+
+