Custom REST Handlers¶
It is possible to extend the default behaviour of the UCC-generated REST handlers.
For example, if your add-on requires an API key to operate and you want to validate this API key during its creation, you might want to use the custom REST handlers to achieve that.
Note:
ucc-gen
will not override the REST handler code if you use the correct file name under thebin
folder.
See the following example of how it can be done. It contains a REST handler for creating an organization, with the organization_id
and organization_api_key
fields, which are not custom ones, generated by ucc-gen
. But, also in the example, there is a custom handler, CustomRestHandler
class which has additional steps for configuration creation and edit operations, specifically handleEdit
and handleCreate
methods:
import import_declare_test
import logging
from splunktaucclib.rest_handler import admin_external, util
from splunktaucclib.rest_handler.admin_external import AdminExternalHandler
from splunktaucclib.rest_handler.endpoint import (
RestModel,
SingleModel,
field,
validator,
)
util.remove_http_proxy_env_vars()
fields = [
field.RestField(
"organization_id",
required=True,
encrypted=False,
default=None,
validator=validator.AllOf(
validator.String(
max_len=50,
min_len=1,
),
validator.Pattern(
regex=r"""^\d+$""",
),
),
),
field.RestField(
"organization_api_key",
required=True,
encrypted=True,
default=None,
validator=validator.AllOf(
validator.String(
max_len=50,
min_len=1,
),
validator.Pattern(
regex=r"""^[a-z0-9]+$""",
),
),
),
]
model = RestModel(fields, name=None)
endpoint = SingleModel(
"addon_name_organization", model, config_name="organization"
)
def _validate_organization(organization_id, organization_api_key):
# Some code to validate the API key.
# Should return nothing if the configuration is valid.
# Should raise an exception splunktaucclib.rest_handler.error.RestError if the configuration is not valid.
...
class CustomRestHandler(AdminExternalHandler):
def __init__(self, *args, **kwargs):
AdminExternalHandler.__init__(self, *args, **kwargs)
def handleList(self, confInfo):
AdminExternalHandler.handleList(self, confInfo)
def handleEdit(self, confInfo):
_validate_organization(
self.payload.get("organization_id"),
self.payload.get("organization_api_key"),
)
AdminExternalHandler.handleEdit(self, confInfo)
def handleCreate(self, confInfo):
_validate_organization(
self.payload.get("organization_id"),
self.payload.get("organization_api_key"),
)
AdminExternalHandler.handleCreate(self, confInfo)
def handleRemove(self, confInfo):
AdminExternalHandler.handleRemove(self, confInfo)
if __name__ == "__main__":
logging.getLogger().addHandler(logging.NullHandler())
admin_external.handle(
endpoint,
handler=CustomRestHandler,
)
Native support from UCC for Modular Inputs¶
UCC 5.18.0 natively supports custom REST handlers for the modular inputs.
One common scenario is to delete a checkpoint after you delete an input in the Inputs page. Otherwise, users may face strange consequences if they create an input with the same name as the input that was deleted, and this newly created input will reuse the old checkpoint, because the names of the inputs are the same. We would like to avoid this situation in the add-on.
This can be done without a need to modify the REST handler code
automatically by running ucc-gen
.
See the following automatically generated REST handler code for a modular input REST handler:
import import_declare_test
from splunktaucclib.rest_handler.endpoint import (
field,
validator,
RestModel,
DataInputModel,
)
from splunktaucclib.rest_handler import admin_external, util
from splunktaucclib.rest_handler.admin_external import AdminExternalHandler
import logging
util.remove_http_proxy_env_vars()
fields = [
field.RestField(
'interval',
required=True,
encrypted=False,
default=None,
validator=validator.Pattern(
regex=r"""^\-[1-9]\d*$|^\d*$""",
)
),
field.RestField(
'disabled',
required=False,
validator=None
)
]
model = RestModel(fields, name=None)
endpoint = DataInputModel(
'example_input_one',
model,
)
if __name__ == '__main__':
logging.getLogger().addHandler(logging.NullHandler())
admin_external.handle(
endpoint,
handler=AdminExternalHandler,
)
New file needs to be created in the bin
folder of the add-on. Let’s call it
splunk_ta_uccexample_delete_checkpoint_rh.py
(name can be different).
And put the following content into the file.
import import_declare_test
from splunktaucclib.rest_handler.admin_external import AdminExternalHandler
class CustomRestHandlerDeleteCheckpoint(AdminExternalHandler):
def __init__(self, *args, **kwargs):
AdminExternalHandler.__init__(self, *args, **kwargs)
def handleList(self, confInfo):
AdminExternalHandler.handleList(self, confInfo)
def handleEdit(self, confInfo):
AdminExternalHandler.handleEdit(self, confInfo)
def handleCreate(self, confInfo):
AdminExternalHandler.handleCreate(self, confInfo)
def handleRemove(self, confInfo):
# Add your code here to delete the checkpoint!
AdminExternalHandler.handleRemove(self, confInfo)
Then, in globalConfig file you need to change the behaviour of the UCC to reuse the REST handler that was just created.
{
"name": "example_input_one",
"restHandlerModule": "splunk_ta_uccexample_delete_checkpoint_rh", <----- new field
"restHandlerClass": "CustomRestHandlerDeleteCheckpoint", <----- new field
"entity": [
"..."
],
"title": "Example Input One"
}
After ucc-gen
command is executed again, the generated REST handler for this
input will be changed to the following.
import import_declare_test
from splunktaucclib.rest_handler.endpoint import (
field,
validator,
RestModel,
DataInputModel,
)
from splunktaucclib.rest_handler import admin_external, util
from splunk_ta_uccexample_delete_checkpoint_rh import CustomRestHandlerDeleteCheckpoint # <----- changed
import logging
util.remove_http_proxy_env_vars()
fields = [
field.RestField(
'interval',
required=True,
encrypted=False,
default=None,
validator=validator.Pattern(
regex=r"""^\-[1-9]\d*$|^\d*$""",
)
),
field.RestField(
'disabled',
required=False,
validator=None
)
]
model = RestModel(fields, name=None)
endpoint = DataInputModel(
'example_input_one',
model,
)
if __name__ == '__main__':
logging.getLogger().addHandler(logging.NullHandler())
admin_external.handle(
endpoint,
handler=CustomRestHandlerDeleteCheckpoint, # <----- changed
)
Native support from UCC for Configuration Page¶
UCC 5.41.0 natively supports custom REST handlers for the configuration page
As mentioned at the top, when the API key provided by a user in your add-on and it needs to be validated, you can now directly mention the name of the file that contains the validating code and the class name of it. Hence, your validation script now becomes something as below:
import import_declare_test
from splunktaucclib.rest_handler.admin_external import AdminExternalHandler
# any other imports required for validation
def _validate_organization(organization_id, organization_api_key):
# Some code to validate the API key.
# Should return nothing if the configuration is valid.
# Should raise an exception splunktaucclib.rest_handler.error.RestError if the configuration is not valid.
...
class CustomAccountValidator(AdminExternalHandler):
def __init__(self, *args, **kwargs):
AdminExternalHandler.__init__(self, *args, **kwargs)
def handleList(self, confInfo):
AdminExternalHandler.handleList(self, confInfo)
def handleEdit(self, confInfo):
_validate_organization(
self.payload.get("organization_id"),
self.payload.get("organization_api_key"),
)
AdminExternalHandler.handleEdit(self, confInfo)
def handleCreate(self, confInfo):
_validate_organization(
self.payload.get("organization_id"),
self.payload.get("organization_api_key"),
)
AdminExternalHandler.handleCreate(self, confInfo)
def handleRemove(self, confInfo):
AdminExternalHandler.handleRemove(self, confInfo)
Place the above content in a file in the bin
folder of the add-on. Let’s call it
splunk_ta_uccexample_account_validator_rh.py
(name can be different).
Then, in globalConfig file you need to change the behaviour of the UCC to reuse the REST handler that was just created.
{
"configuration": {
"tabs": [
{
"name": "account",
"title": "Account",
"restHandlerModule": "splunk_ta_uccexample_account_validator_rh", <----- new field
"restHandlerClass": "CustomAccountValidator", <----- new field
"table": {
"..." : "..."
},
"entity": [
"..."
]
}
]
}
}
After ucc-gen
command is executed again, the generated REST handler for this
configuration page will be updated to the following.
import import_declare_test
from splunktaucclib.rest_handler.endpoint import (
field,
validator,
RestModel,
SingleModel,
)
from splunktaucclib.rest_handler import admin_external, util
from splunk_ta_uccexample_account_validator_rh import CustomAccountValidator # <----- changed
import logging
util.remove_http_proxy_env_vars()
fields = [
# all the fields and its validators mentioned in globalConfig in the configuration page
# that are auto generated by UCC framework
]
model = RestModel(fields, name=None)
endpoint = SingleModel(
"addon_name_account", model, config_name="account"
)
if __name__ == '__main__':
logging.getLogger().addHandler(logging.NullHandler())
admin_external.handle(
endpoint,
handler=CustomAccountValidator, # <----- changed
)