6. Action Modules¶
What’s An Action Module?¶
An administrative action module provides the ability to AMPS to
run an action at a specified time, in response to a particular Linux
signal, or in response to an event such as startup or shutdown. These
modules are intended to ease AMPS administration, particularly for
installations where access to facilities such as cron
is limited.
When to Implement an Administrative Action Module¶
Implement an action module when there is a specific action that needs to be taken in your environment that AMPS does not provide by default, when you can programmatically perform the action, and when your policies do not centralize administrative functions in another system.
Action Context¶
AMPS uses action modules to perform an action when a certain condition occurs. The same module may have different configuration settings for different instances of the action. Because the same module may be used with different parameters in different action configurations, AMPS allows you to save the parameters in an action context.
Your module implements the amps_action_create_context
function to create a
n authentication context. The function has this signature:
amps_action_context amps_action_create_context(amps_module_options options);
The action context is a pointer to data that your module defines. The AMPS server does not process or interpret this data. The server receives the pointer from your module when the module is initialized, and then provides the pointer back to your module for each authenticator request.
If your module is unable to successfully create the context, you return
a NULL context and use the amps_logger
provided to your module to
log information about the problem.
Notice that you cast the pointer to amps_action_context
before you
return it, and cast the pointer back to the type that your application
uses after AMPS returns the pointer to you.
AMPS passes configuration options to modules as a pointer to an array of
amps_option
structs. AMPS indicates the end of the array with an
option that has a NULL
key. Your module processes options until it
reaches an option with a NULL key. If no options are specified in the
configuration file, the first amps_option
in the array will have a
NULL key.
The following snippet shows one way to process options:
for (; options->key != NULL; ++options) {
// process the key/value pair here
}
When AMPS exits, AMPS calls amps_action_destroy_context
with each of
the action contexts created. This gives your module an opportunity to do
any resource management, cleanup or logging necessary before AMPS shuts
down. The function has this signature:
int amps_action_destroy_context(amps_action_context context);
Implementing an Action¶
Action modules implement a single function for performing an action:
Function | |
---|---|
amps_action_do |
Perform an action. Called when the condition that triggers the action occurs: for example, when AMPS receives the specified Linux signal. |
Table 6.1: Administrative Action function
To implement an action module, your module implements this method.
When AMPS runs the action, the AMPS server calls the following method:
int amps_action_do(amps_action_context context)
The action context provided is the pointer returned by the call to
amps_action_create_context()
for the instance of the action that is
being run.
Following is a simple, minimal implementation of amps_action_do
:
int amps_action_do(amps_action_context context)
{
amps_logger(amps_module_log_level_warning, "my_action_module: just logging a message");
// You can run any code here.
return AMPS_SUCCESS;
}
This simple implementation simply logs a message to the AMPS error log.
For your module, you would substitute code that implements whatever
action you need to perform. If the action succeeds, return
AMPS_SUCCESS
. If the action fails, use the logger provided in
amps_module_init
to log information about the failure and return
AMPS_FAILURE
.
Working With Variables¶
Your module can set and expand variables within actions, in the same way that the actions provided by 60East do. Your action can set a variable for use by other actions that follow it in the action configuration, and can expand variables, whether they are provided by AMPS or whether they are set by another action module.
AMPS tracks variables in symbol scopes. Within a scope, the variable is stored as a key / value pair, where the key is the name of the variable and the value is the string that should replace the variable. Symbol scopes are stored in an ordered list, with the most recent scope at the beginning of the list. When expanding a string that contains a variable, AMPS searches the scopes in order, and expands the variable with the first value found.
AMPS maintains a global scope with the default variables common to all
actions, as described in the AMPS User Guide. When an action runs, AMPS
constructs a scope for that action. The scope is shared between the
On
action and the set of Do
actions that the On
action
triggers.
To add variables to the current scope, you use
the amps_symbol_scope_put
function. This function has the following
signature:
int amps_symbol_scope_put(const char* key_, size_t keyLength_,
const char* value_, size_t valueLength_);
For example, to add a variable called MyCoolValue
with a value of
Amazing
to the current scope, you would use the following code:
amps_symbol_scope_put("MyCoolValue", 11,
"Amazing", 7);
To expand a string that uses variables and insert the current value of the variables, you use the amps_expand_action_string function. This function requires a preallocated buffer to write the expanded string to, as shown in the following code:
char * buffer = NULL;
size_t bufferSize = 25;
int rc = AMPS_FAILURE;
const char *sampleTemplate = "AMPS expansion is {{MyCoolValue}}";
amps_symbol_scope_put("MyCoolValue", 11, "Amazing", 7);
// Start with a small size. If that doesn't fit,
// make a new buffer with the correct size.
while (rc == AMPS_FAILURE)
{
if (buffer != NULL) { free(buffer); };
buffer = (char*)malloc(bufferSize);
if (buffer == NULL)
{
return AMPS_FAILURE;
}
rc = amps_expand_action_string(sampleTemplate, strlen(sampleTemplate), buffer, &bufferSize);
}
// .. use buffer
free(buffer);
To retrieve the value of a variable in the current scope, you can also use
int amps_symbol_scope_get(const char* key_, size_t keyLength,
const char** value_, size_t* valueLength_);
This function updates the provided value_
pointer to the location of the
value and updates the location specified by valueLength_
with the
length of the value.
The data returned by this function is guaranteed to be valid for the lifetime of the current function call from AMPS, but is not guaranteed to persist after that.