Tip
Check out the repository on GitHub
4 - Develop
The basic API interaction is handled in ‘ansibleguy.opnsense.plugins.module_utils.base.api’.
It is a generic abstraction layer for interacting with the api - therefore all plugins should be able to function with it!
API Definition
To get to know the API - you will have to read into the API’s XML-config that is linked in the OPNSense docs.
Per example: Alias.xml
As XML isn’t the most readable format - I would recommend translating it to YAML or JSON.
Here is a nice online-tool to do so: XML-to-YAML | XML-to-JSON
Module
There are module-templates that can be copied - so you don’t have to re-write the basic structure.
Adding new module
Testing
Copy the test-template ‘_tmpl.yml’ and rename all calls to the new module.
Run the tests like this:
# set these variables:
COL='name-of-new-collection'
COL_PATH="$(pwd)/../collections/ansible_collections/ansibleguy/opnsense" # path to your local collection
TEST_FIREWALL='192.168.0.1' # ip of your test-firewall
TEST_API_KEY="$(pwd)/opn.txt" # api credentials-file for your test-firewall
export ANSIBLE_DIFF_ALWAYS=yes # enable diff-mode for debugging
bash "${COL_PATH}/scripts/test_single.sh" "$TEST_FIREWALL" "$TEST_API_KEY" "$COL_PATH" "$COL" 1
API
One can choose to either:
create a http-session - faster if multiple calls are needed
p.e. check current state => create/update/delete
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.api import Session session = Session(module=module) session.get(cnf={'controller': 'alias', 'command': 'addItem', 'data': {'name': 'dummy', ...}}) session.post(cnf={'controller': 'alias', 'command': 'delItem', 'params': [uuid]}) session.close()
use a single call - if only one is needed
p.e. toggle a cronjob or restart a service
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.api import single_get, single_post single_get( module=module, cnf={'controller': 'alias', 'command': 'addItem', 'data': {'name': 'dummy', ...}} ) single_post( module=module, cnf={'controller': 'alias', 'command': 'delItem', 'params': [uuid]} )
For the controller/command/params/data definition - check the OPNSense API Docs!
Debugging
Verbose output
If you want to output something to ansible’s runtime - use ‘module.warn’:
module.warn(f"{before} != {after}")
You can also use the ‘debug’ argument to enable verbose output of the api requests.
- name: Example
ansibleguy.opnsense.alias:
debug: true
‘Multi’ modules also support the ‘debug’ parameter on a per-item basis - so you don’t get flooded.
When the debug-mode is enabled some useful log files are created in the directory ‘/tmp/ansibleguy.opnsense’
guy$ ls -l /tmp/ansibleguy.opnsense/
alias.log # time consumption profiling for the executed module: https://docs.python.org/3/library/profile.html
api_calls.log # a list api calls that were executed by the debugged module
Profiling
To profile a modules time-consumption - you can use the existing profiler function:
For it to work, you need to move your modules processing into a dedicated function or object!
The profiler will wrap around this function call and analyze it.
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.utils import profiler
from ansible_collections.ansibleguy.opnsense.plugins.module_utils.target_module import process
PROFILE = True
if PROFILE:
profiler(
check=process, kwargs=dict(
m=module, p=module.params, r=result,
),
log_file='target_module.log' # in folder: /tmp/ansibleguy.opnsense/
)
else:
process(m=module, p=module.params, r=result)
Note: these entries can be interpreted as waiting for the responses of HTTP requests:
‘read’ of ‘_ssl._SSLSocket’
‘connect’ of ‘_socket.socket’
‘do_handshake’ of ‘_ssl._SSLSocket’
One can only try to lower the needed HTTP calls.