Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/data-sources/builtin-toolsets/servicenow.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ You should receive a JSON response. If you get an authentication error, check yo
config:
api_key: <your servicenow API key> # e.g. now_1234567890abcdef
api_url: <your servicenow instance URL> # e.g. https://dev12345.service-now.com

# Optional
api_key_header: x-sn-apikey # HTTP header name for the API key (default: x-sn-apikey)
health_check_table: sys_user # Table used to verify connectivity on startup (default: sys_user)
```

--8<-- "snippets/toolset_refresh_warning.md"
Expand All @@ -95,8 +99,19 @@ You should receive a JSON response. If you get an authentication error, check yo
config:
api_key: <your servicenow API key> # e.g. now_1234567890abcdef
api_url: <your servicenow instance URL> # e.g. https://dev12345.service-now.com

# Optional
api_key_header: x-sn-apikey # HTTP header name for the API key (default: x-sn-apikey)
health_check_table: sys_user # Table used to verify connectivity on startup (default: sys_user)
```

### Optional Fields

| Option | Default | Description |
|--------|---------|-------------|
| `api_key_header` | `x-sn-apikey` | HTTP header name used to pass the API key. Change this if your ServiceNow instance uses a custom authentication header. |
| `health_check_table` | `sys_user` | Table queried on startup to verify connectivity and permissions. Change this if your API key doesn't have access to the default table. |

## Capabilities

| Tool Name | Description |
Expand Down
27 changes: 16 additions & 11 deletions holmes/plugins/toolsets/servicenow_tables/servicenow_tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ class ServiceNowTablesConfig(ToolsetConfig):
description="HTTP header name to use for passing the API key",
examples=["x-sn-apikey"],
)
health_check_table: str = Field(
default="sys_user",
title="Health check table",
description="Table queried on startup to verify connectivity and permissions. Change this if your API key doesn't have access to the default table.",
examples=["sys_user", "incident", "sys_db_object"],
)


class ServiceNowTablesToolset(Toolset):
Expand Down Expand Up @@ -77,43 +83,42 @@ def prerequisites_callable(self, config: dict[str, Any]) -> Tuple[bool, str]:
# Validate the config using Pydantic - this will raise if required fields are missing
self.config = ServiceNowTablesConfig(**config)

# Perform health check
return self._perform_health_check()
return self._perform_health_check(table_name=self.config.health_check_table)

except Exception as e:
return False, f"Failed to validate ServiceNow configuration: {str(e)}"

def _perform_health_check(self) -> Tuple[bool, str]:
def _perform_health_check(self, table_name) -> Tuple[bool, str]:
Comment thread
arikalon1 marked this conversation as resolved.
"""Perform a health check by making a minimal API call."""
try:
# Query sys_db_object table with minimal data
data, headers = self._make_api_request(
endpoint="api/now/v2/table/sys_db_object",
query_params={"sysparm_limit": 1, "sysparm_fields": "sys_id"},
_, _ = self._make_api_request(
endpoint=f"api/now/v2/table/{table_name}",
query_params={"sysparm_limit": 1},
timeout=10,
)
return True, "ServiceNow configuration is valid and API is accessible."
return True, f"ServiceNow configuration is valid and API is accessible. (checked table: {table_name})"

except requests.exceptions.HTTPError as e:
if e.response.status_code == 401:
return (
False,
"ServiceNow authentication failed. Please check your API key.",
f"ServiceNow authentication failed. Please check your API key. Full error: {e.response.status_code} - {e.response.text}",
)
elif e.response.status_code == 403:
return (
False,
"ServiceNow access denied. Please ensure your user has Table API access.",
f"ServiceNow access denied. Please ensure your user has Table API access. Full error: {e.response.status_code} - {e.response.text}",
)
else:
return (
False,
f"ServiceNow API returned error: {e.response.status_code} - {e.response.text}",
)
except requests.exceptions.ConnectionError:
except requests.exceptions.ConnectionError as e:
return (
False,
f"Failed to connect to ServiceNow instance at {self.config.api_url if self.config else 'unknown'}",
f"Failed to connect to ServiceNow instance at {self.config.api_url if self.config else 'unknown'}. Full error: {str(e)}",
)
Comment thread
arikalon1 marked this conversation as resolved.
except requests.exceptions.Timeout:
return False, "ServiceNow health check timed out"
Expand Down
14 changes: 8 additions & 6 deletions tests/integration/test_kubernetes_transformer_execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -514,12 +514,13 @@ class TestTransformerPerformanceMetrics:

def setup_method(self):
"""Set up test fixtures."""
# Track whether llm_summarize was originally registered for restoration
self.llm_summarize_was_registered = registry.is_registered("llm_summarize")

# Clean up existing registrations
# Save original transformer registration if it exists
self.original_llm_summarize = None
if registry.is_registered("llm_summarize"):
self.original_llm_summarize = registry._transformers["llm_summarize"]
registry.unregister("llm_summarize")

# Clean up any mock registrations
if registry.is_registered("MockSummarizeTransformer"):
registry.unregister("MockSummarizeTransformer")

Expand All @@ -534,8 +535,9 @@ def teardown_method(self):
if registry.is_registered("MockSummarizeTransformer"):
registry.unregister("MockSummarizeTransformer")

# Note: Original transformer restoration is not possible without accessing private registry attributes.
# Test isolation is maintained by cleaning up our mock registrations.
# Restore original transformer if it existed
if self.original_llm_summarize is not None:
registry.register(self.original_llm_summarize)

def test_transformer_performance_logging(self):
"""Test that transformer execution metrics are logged."""
Expand Down
Loading