From b5ebf84ad0bb35deec0ece1afd101785cd50d912 Mon Sep 17 00:00:00 2001 From: sgoral Date: Mon, 16 Sep 2024 22:02:05 +0200 Subject: [PATCH 1/4] feat: extended rh_templates to pass custom validators to splunktaucclib model --- pyproject.toml | 1 + .../commands/rest_builder/endpoint/base.py | 19 ++++++- .../global_config_builder_schema.py | 51 ++++++++++++------- .../conf_files/create_account_conf.py | 2 +- .../conf_files/create_settings_conf.py | 2 +- .../bin/splunk_ta_uccexample_rh_account.py | 20 +++++++- .../bin/splunk_ta_uccexample_rh_settings.py | 18 +++++-- .../bin/splunk_ta_uccexample_rh_account.py | 20 +++++++- ...unk_ta_uccexample_rh_example_input_four.py | 20 +++++++- ...lunk_ta_uccexample_rh_example_input_one.py | 20 +++++++- ...lunk_ta_uccexample_rh_example_input_two.py | 20 +++++++- .../bin/splunk_ta_uccexample_rh_settings.py | 18 +++++-- .../test_create_account_conf_spec.py | 5 +- .../conf_files/test_create_settings_conf.py | 10 +++- 14 files changed, 191 insertions(+), 35 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 720c93b60..da138237c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,6 +42,7 @@ classifiers = [ python = "^3.7" jinja2 = ">=2,<4" addonfactory-splunk-conf-parser-lib = "^0.4.3" +splunktaucclib = "^6.4.0" dunamai = "^1.9.0" jsonschema = "^4.4.0" PyYAML = "^6.0" diff --git a/splunk_add_on_ucc_framework/commands/rest_builder/endpoint/base.py b/splunk_add_on_ucc_framework/commands/rest_builder/endpoint/base.py index 17b624463..9b76e319a 100644 --- a/splunk_add_on_ucc_framework/commands/rest_builder/endpoint/base.py +++ b/splunk_add_on_ucc_framework/commands/rest_builder/endpoint/base.py @@ -33,10 +33,14 @@ class RestEntityBuilder: _title_template = "[{}]" _rh_template = """ +special_fields = [ +{special_fields} +] + fields{name_rh} = [ {fields} ] -model{name_rh} = RestModel(fields{name_rh}, name={name}) +model{name_rh} = RestModel(fields{name_rh}, name={name}, special_fields=special_fields) """ _disabled_field_template = """ field.RestField( @@ -47,10 +51,15 @@ class RestEntityBuilder: """ def __init__( - self, name: Optional[str], fields: List["RestFieldBuilder"], **kwargs: Any + self, + name: Optional[str], + fields: List["RestFieldBuilder"], + special_fields: List["RestFieldBuilder"], + **kwargs: Any, ) -> None: self._name = name self._fields = fields + self._special_fields = special_fields self._conf_name = kwargs.get("conf_name") @property @@ -79,9 +88,13 @@ def generate_conf_with_default_values(self) -> str: def generate_rh(self) -> str: fields = [] + special_fields = [] for field in self._fields: field_line = field.generate_rh() fields.append(field_line) + for special_field in self._special_fields: + field_line = special_field.generate_rh() + special_fields.append(field_line) # add disabled field for data input entity_builder = self.__class__.__name__ if ( @@ -91,7 +104,9 @@ def generate_rh(self) -> str: ): fields.append(self._disabled_field_template) fields_lines = ", \n".join(fields) + special_fields_lines = ", \n".join(special_fields) return self._rh_template.format( + special_fields=indent(special_fields_lines), fields=indent(fields_lines), name_rh=self.name_rh, name=quote_string(self._name), 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 8551d9f5c..9555f129e 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 @@ -14,7 +14,7 @@ # limitations under the License. # import json -from typing import Dict, List, Set, Any +from typing import Dict, List, Set, Any, Tuple from splunk_add_on_ucc_framework import global_config as global_config_lib @@ -105,10 +105,11 @@ def _builder_configs(self) -> None: ) self._endpoints[name] = endpoint content = self._get_oauth_enitities(config["entity"]) - fields = self._parse_fields(content) + fields, special_fields = self._parse_fields(content) entity = SingleModelEntityBuilder( None, fields, + special_fields=special_fields, conf_name=config.get("conf"), ) endpoint.add_entity(entity) @@ -140,10 +141,11 @@ def _builder_settings(self) -> None: self._endpoints["settings"] = endpoint for setting in self.global_config.settings: content = self._get_oauth_enitities(setting["entity"]) - fields = self._parse_fields(content) + fields, special_fields = self._parse_fields(content) entity = MultipleModelEntityBuilder( setting["name"], fields, + special_fields=special_fields, ) endpoint.add_entity(entity) self._settings_conf_file_names.add(endpoint.conf_name) @@ -170,10 +172,11 @@ def _builder_inputs(self) -> None: ) self._endpoints[name] = single_model_endpoint content = self._get_oauth_enitities(input_item["entity"]) - fields = self._parse_fields(content) + fields, special_fields = self._parse_fields(content) single_model_entity = SingleModelEntityBuilder( None, fields, + special_fields=special_fields, conf_name=input_item["conf"], ) single_model_endpoint.add_entity(single_model_entity) @@ -189,28 +192,42 @@ def _builder_inputs(self) -> None: ) self._endpoints[name] = data_input_endpoint content = self._get_oauth_enitities(input_item["entity"]) - fields = self._parse_fields(content) + fields, special_fields = self._parse_fields(content) data_input_entity = DataInputEntityBuilder( None, fields, + special_fields=special_fields, input_type=input_item["name"], ) data_input_endpoint.add_entity(data_input_entity) def _parse_fields( self, fields_content: List[Dict[str, Any]] - ) -> List[RestFieldBuilder]: - return [ - RestFieldBuilder( - field["field"], - _is_true(field.get("required")), - _is_true(field.get("encrypted")), - field.get("defaultValue"), - ValidatorBuilder().build(field.get("validators")), - ) - for field in fields_content - if field["field"] != "name" - ] + ) -> Tuple[List[RestFieldBuilder], List[RestFieldBuilder]]: + fields = [] + special_fields = [] + for field in fields_content: + if field["field"] != "name": + fields.append( + RestFieldBuilder( + field["field"], + _is_true(field.get("required")), + _is_true(field.get("encrypted")), + field.get("defaultValue"), + ValidatorBuilder().build(field.get("validators")), + ) + ) + else: + special_fields.append( + RestFieldBuilder( + field["field"], + _is_true(field.get("required")), + _is_true(field.get("encrypted")), + field.get("defaultValue"), + ValidatorBuilder().build(field.get("validators")), + ) + ) + return fields, special_fields """ If the entity contains type oauth then we need to alter the content to generate proper entities to generate 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 index 05837ffd8..5f220dc58 100644 --- 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 @@ -36,7 +36,7 @@ def _set_attributes(self, **kwargs: Any) -> None: if account["name"] == "oauth": continue content = self._gc_schema._get_oauth_enitities(account["entity"]) - fields = self._gc_schema._parse_fields(content) + fields, special_fields = self._gc_schema._parse_fields(content) self.account_fields.append( ("", [f"{f._name} = " for f in fields]) ) 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 index f1c13bb3b..01a09e98b 100644 --- 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 @@ -33,7 +33,7 @@ def _set_attributes(self, **kwargs: Any) -> None: 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) + fields, special_fields = self._gc_schema._parse_fields(content) self.settings_stanzas.append( (setting["name"], [f"{f._name} = " for f in fields]) ) diff --git a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_account.py b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_account.py index 5e1500a78..62a50565d 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_account.py +++ b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_account.py @@ -14,6 +14,24 @@ util.remove_http_proxy_env_vars() +special_fields = [ + field.RestField( + 'name', + required=True, + encrypted=False, + default=None, + validator=validator.AllOf( + validator.String( + max_len=50, + min_len=1, + ), + validator.Pattern( + regex=r"""^[a-zA-Z]\w*$""", + ) + ) + ) +] + fields = [ field.RestField( 'custom_endpoint', @@ -128,7 +146,7 @@ validator=None ) ] -model = RestModel(fields, name=None) +model = RestModel(fields, name=None, special_fields=special_fields) endpoint = SingleModel( diff --git a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_settings.py b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_settings.py index 4845ea293..3025c1d26 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_settings.py +++ b/tests/testdata/expected_addons/expected_output_global_config_configuration/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_settings.py @@ -14,6 +14,10 @@ util.remove_http_proxy_env_vars() +special_fields = [ + +] + fields_proxy = [ field.RestField( 'proxy_enabled', @@ -78,9 +82,13 @@ validator=None ) ] -model_proxy = RestModel(fields_proxy, name='proxy') +model_proxy = RestModel(fields_proxy, name='proxy', special_fields=special_fields) +special_fields = [ + +] + fields_logging = [ field.RestField( 'loglevel', @@ -90,8 +98,12 @@ validator=None ) ] -model_logging = RestModel(fields_logging, name='logging') +model_logging = RestModel(fields_logging, name='logging', special_fields=special_fields) + +special_fields = [ + +] fields_custom_abc = [ field.RestField( @@ -160,7 +172,7 @@ ) ) ] -model_custom_abc = RestModel(fields_custom_abc, name='custom_abc') +model_custom_abc = RestModel(fields_custom_abc, name='custom_abc', special_fields=special_fields) endpoint = MultipleModel( diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_account.py b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_account.py index 4a5fe98b1..3d6a29574 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_account.py +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_account.py @@ -14,6 +14,24 @@ util.remove_http_proxy_env_vars() +special_fields = [ + field.RestField( + 'name', + required=True, + encrypted=False, + default=None, + validator=validator.AllOf( + validator.String( + max_len=50, + min_len=1, + ), + validator.Pattern( + regex=r"""^[a-zA-Z]\w*$""", + ) + ) + ) +] + fields = [ field.RestField( 'custom_endpoint', @@ -179,7 +197,7 @@ validator=None ) ] -model = RestModel(fields, name=None) +model = RestModel(fields, name=None, special_fields=special_fields) endpoint = SingleModel( diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_four.py b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_four.py index e16d4c802..b0b9cf4f6 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_four.py +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_four.py @@ -14,6 +14,24 @@ util.remove_http_proxy_env_vars() +special_fields = [ + field.RestField( + 'name', + required=True, + encrypted=False, + default=None, + validator=validator.AllOf( + validator.Pattern( + regex=r"""^[a-zA-Z]\w*$""", + ), + validator.String( + max_len=100, + min_len=1, + ) + ) + ) +] + fields = [ field.RestField( 'interval', @@ -32,7 +50,7 @@ ) ] -model = RestModel(fields, name=None) +model = RestModel(fields, name=None, special_fields=special_fields) diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_one.py b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_one.py index 56f85c4c4..f276322be 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_one.py +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_one.py @@ -14,6 +14,24 @@ util.remove_http_proxy_env_vars() +special_fields = [ + field.RestField( + 'name', + required=True, + encrypted=False, + default=None, + validator=validator.AllOf( + validator.Pattern( + regex=r"""^[a-zA-Z]\w*$""", + ), + validator.String( + max_len=100, + min_len=1, + ) + ) + ) +] + fields = [ field.RestField( 'input_one_checkbox', @@ -161,7 +179,7 @@ ) ] -model = RestModel(fields, name=None) +model = RestModel(fields, name=None, special_fields=special_fields) diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_two.py b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_two.py index eb23cedcd..6290bb4c1 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_two.py +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_example_input_two.py @@ -14,6 +14,24 @@ util.remove_http_proxy_env_vars() +special_fields = [ + field.RestField( + 'name', + required=True, + encrypted=False, + default=None, + validator=validator.AllOf( + validator.Pattern( + regex=r"""^[a-zA-Z]\w*$""", + ), + validator.String( + max_len=100, + min_len=1, + ) + ) + ) +] + fields = [ field.RestField( 'interval', @@ -119,7 +137,7 @@ ) ] -model = RestModel(fields, name=None) +model = RestModel(fields, name=None, special_fields=special_fields) diff --git a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_settings.py b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_settings.py index 38a133ac8..d805ae780 100644 --- a/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_settings.py +++ b/tests/testdata/expected_addons/expected_output_global_config_everything/Splunk_TA_UCCExample/bin/splunk_ta_uccexample_rh_settings.py @@ -14,6 +14,10 @@ util.remove_http_proxy_env_vars() +special_fields = [ + +] + fields_proxy = [ field.RestField( 'proxy_enabled', @@ -83,9 +87,13 @@ validator=None ) ] -model_proxy = RestModel(fields_proxy, name='proxy') +model_proxy = RestModel(fields_proxy, name='proxy', special_fields=special_fields) +special_fields = [ + +] + fields_logging = [ field.RestField( 'loglevel', @@ -95,8 +103,12 @@ validator=None ) ] -model_logging = RestModel(fields_logging, name='logging') +model_logging = RestModel(fields_logging, name='logging', special_fields=special_fields) + +special_fields = [ + +] fields_custom_abc = [ field.RestField( @@ -165,7 +177,7 @@ ) ) ] -model_custom_abc = RestModel(fields_custom_abc, name='custom_abc') +model_custom_abc = RestModel(fields_custom_abc, name='custom_abc', special_fields=special_fields) endpoint = MultipleModel( diff --git a/tests/unit/generators/conf_files/test_create_account_conf_spec.py b/tests/unit/generators/conf_files/test_create_account_conf_spec.py index b856dd367..c1ba5ee72 100644 --- a/tests/unit/generators/conf_files/test_create_account_conf_spec.py +++ b/tests/unit/generators/conf_files/test_create_account_conf_spec.py @@ -49,7 +49,10 @@ def test_set_attributes(global_config, input_dir, output_dir, ucc_dir, ta_name): ] account_spec._global_config.namespace = TA_NAME account_spec._gc_schema._get_oauth_enitities.return_value = "mocked_content" - account_spec._gc_schema._parse_fields.return_value = [MagicMock(_name="field2")] + account_spec._gc_schema._parse_fields.return_value = ( + [MagicMock(_name="field2")], + [MagicMock(_name="field3")], + ) account_spec._set_attributes() diff --git a/tests/unit/generators/conf_files/test_create_settings_conf.py b/tests/unit/generators/conf_files/test_create_settings_conf.py index 529c76ef8..bd8df9ef1 100644 --- a/tests/unit/generators/conf_files/test_create_settings_conf.py +++ b/tests/unit/generators/conf_files/test_create_settings_conf.py @@ -44,7 +44,10 @@ def test_set_attributes(global_config, input_dir, output_dir, ucc_dir, ta_name): settings_conf._global_config.settings = [{"entity": "entity1", "name": "setting1"}] settings_conf._global_config.namespace = TA_NAME settings_conf._gc_schema._get_oauth_enitities.return_value = "mocked_content" - settings_conf._gc_schema._parse_fields.return_value = [MagicMock(_name="field1")] + settings_conf._gc_schema._parse_fields.return_value = ( + [MagicMock(_name="field1")], + [MagicMock(_name="field3")], + ) settings_conf._gc_schema._endpoints = {"settings": MagicMock()} settings_conf._gc_schema._endpoints[ @@ -104,7 +107,10 @@ def test_set_attributes_no_settings_key( settings_conf._global_config.settings = [{"entity": "entity1", "name": "setting1"}] settings_conf._gc_schema._get_oauth_enitities.return_value = "mocked_content" - settings_conf._gc_schema._parse_fields.return_value = [MagicMock(_name="field1")] + settings_conf._gc_schema._parse_fields.return_value = ( + [MagicMock(_name="field1")], + [MagicMock(_name="field3")], + ) settings_conf._gc_schema._endpoints = {} From a5f5a989c81369f21b2d8c63290db100dd0a77c3 Mon Sep 17 00:00:00 2001 From: sgoral Date: Tue, 17 Sep 2024 10:25:40 +0200 Subject: [PATCH 2/4] chore: remove splunktaucclib from dependencies unitl proper version is released --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index da138237c..720c93b60 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,6 @@ classifiers = [ python = "^3.7" jinja2 = ">=2,<4" addonfactory-splunk-conf-parser-lib = "^0.4.3" -splunktaucclib = "^6.4.0" dunamai = "^1.9.0" jsonschema = "^4.4.0" PyYAML = "^6.0" From aeb06f4f1a9692a5ab811449084b6be1d046f865 Mon Sep 17 00:00:00 2001 From: sgoral Date: Mon, 30 Sep 2024 13:47:43 +0200 Subject: [PATCH 3/4] chore: split subprocess_call and subporcess_run into separate functions --- .../global_config_builder_schema.py | 17 +++--- .../install_python_libraries.py | 58 ++++++++++++++++--- 2 files changed, 59 insertions(+), 16 deletions(-) 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 9555f129e..fbd818260 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 @@ -207,16 +207,15 @@ def _parse_fields( fields = [] special_fields = [] for field in fields_content: + rest_field = RestFieldBuilder( + field["field"], + _is_true(field.get("required")), + _is_true(field.get("encrypted")), + field.get("defaultValue"), + ValidatorBuilder().build(field.get("validators")), + ) if field["field"] != "name": - fields.append( - RestFieldBuilder( - field["field"], - _is_true(field.get("required")), - _is_true(field.get("encrypted")), - field.get("defaultValue"), - ValidatorBuilder().build(field.get("validators")), - ) - ) + fields.append(rest_field) else: special_fields.append( RestFieldBuilder( diff --git a/splunk_add_on_ucc_framework/install_python_libraries.py b/splunk_add_on_ucc_framework/install_python_libraries.py index f499031b7..e6bb6b263 100644 --- a/splunk_add_on_ucc_framework/install_python_libraries.py +++ b/splunk_add_on_ucc_framework/install_python_libraries.py @@ -20,6 +20,8 @@ import subprocess import sys from pathlib import Path + +from packaging.version import Version from typing import List, Optional, Set, Iterable, Dict from splunk_add_on_ucc_framework.global_config import OSDependentLibraryConfig @@ -34,6 +36,10 @@ class CouldNotInstallRequirements(Exception): pass +class InvalidArguments(Exception): + pass + + def _subprocess_call( command: str, command_desc: Optional[str] = None, @@ -55,6 +61,24 @@ def _subprocess_call( raise e +def _subprocess_run( + command: str, + command_desc: Optional[str] = None, + env: Optional[Dict[str, str]] = None, +) -> subprocess.CompletedProcess[bytes]: + command_desc = command_desc or command + try: + logger.info(f"Executing: {command}") + process_result = subprocess.run( + command, shell=True, env=env, capture_output=True + ) + return process_result + + except OSError as e: + logger.error(f"Execution ({command_desc}) failed due to {e}") + raise e + + def _pip_install(installer: str, command: str, command_desc: str) -> None: cmd = f"{installer} -m pip install {command}" try: @@ -66,18 +90,36 @@ def _pip_install(installer: str, command: str, command_desc: str) -> None: def _pip_is_lib_installed( - installer: str, target: str, libname: str, version: Optional[str] = None + installer: str, + target: str, + libname: str, + version: Optional[str] = None, + allow_higher_version: bool = False, ) -> bool: + if not version and allow_higher_version: + raise InvalidArguments( + "Parameter 'allow_higher_version' can not be set to True if 'version' parameter is not provided" + ) + lib_installed_cmd = f"{installer} -m pip show --version {libname}" - lib_version_match_cmd = f'{lib_installed_cmd} | grep "Version: {version}"' - cmd = lib_version_match_cmd if version else lib_installed_cmd + if version and allow_higher_version: + cmd = f'{lib_installed_cmd} | grep "Version"' + elif version and not allow_higher_version: + cmd = f'{lib_installed_cmd} | grep "Version: {version}"' + else: + cmd = lib_installed_cmd try: my_env = os.environ.copy() my_env["PYTHONPATH"] = target - return_code = _subprocess_call(command=cmd, env=my_env) - return return_code == 0 + if allow_higher_version: + result = _subprocess_run(command=cmd, env=my_env) + result_version = result.stdout.decode("utf-8").split("Version:")[1].strip() + return Version(result_version) >= Version(version) + else: + return_code = _subprocess_call(command=cmd, env=my_env) + return return_code == 0 except OSError as e: raise CouldNotInstallRequirements from e @@ -116,10 +158,12 @@ def install_python_libraries( installer=python_binary_name, target=ucc_lib_target, libname="splunktaucclib", + version="6.4", + allow_higher_version=True, ): raise SplunktaucclibNotFound( - f"splunktaucclib is not found in {path_to_requirements_file}. " - f"Please add it there because this add-on has UI." + f"splunktaucclib is not found in {path_to_requirements_file} or has invalid version. " + f"Please add it there and check if it is at least version 6.4, because this add-on has UI." ) cleanup_libraries = install_os_dependent_libraries( From 8dc06bf1452747b4e560075fa4524fcbed38d42c Mon Sep 17 00:00:00 2001 From: sgoral Date: Mon, 30 Sep 2024 13:50:42 +0200 Subject: [PATCH 4/4] refactor: refactor fo _parse_fields --- .../rest_builder/global_config_builder_schema.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) 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 fbd818260..542c176a1 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 @@ -217,15 +217,8 @@ def _parse_fields( if field["field"] != "name": fields.append(rest_field) else: - special_fields.append( - RestFieldBuilder( - field["field"], - _is_true(field.get("required")), - _is_true(field.get("encrypted")), - field.get("defaultValue"), - ValidatorBuilder().build(field.get("validators")), - ) - ) + special_fields.append(rest_field) + return fields, special_fields """