xref: /netbsd-src/external/bsd/unbound/dist/pythonmod/doc/examples/example0.rst (revision 91f7d55fb697b5e0475da4718fa34c3a3ebeac85)
1.. _example_handler:
2
3Fundamentals
4================
5
6This basic example shows how to create simple python module which will pass on the requests to the iterator.
7
8How to enable python module
9----------------------------
10If you look into unbound configuration file, you can find the option `module-config` which specifies the names and the order of modules to be used.
11Example configuration::
12
13	module-config: "validator python iterator"
14
15As soon as the DNS query arrives, Unbound calls modules starting from leftmost - the validator *(it is the first module on the list)*.
16The validator does not know the answer *(it can only validate)*, thus it will pass on the event to the next module.
17Next module is python which can
18
19	a) generate answer *(response)*
20		When python module generates the response unbound calls validator. Validator grabs the answer and determines the security flag.
21
22	b) pass on the event to the iterator.
23		When iterator resolves the query, Unbound informs python module (event :data:`module_event_moddone`). In the end, when the python module is done, validator is called.
24
25Note that the python module is called with :data:`module_event_pass` event, because new DNS event was already handled by validator.
26
27Another situation occurs when we use the following configuration::
28
29	module-config: "python validator iterator"
30
31Python module is the first module here, so it's invoked with :data:`module_event_new` event *(new query)*.
32
33On Python module initialization, module loads script from `python-script` option::
34
35	python-script: "/unbound/test/ubmodule.py"
36
37Simple python module step by step
38---------------------------------
39
40Script file must contain four compulsory functions:
41
42.. function:: init(id, cfg)
43
44   Initialize module internals, like database etc.
45   Called just once on module load.
46
47   :param id: module identifier (integer)
48   :param cfg: :class:`config_file` configuration structure
49
50::
51
52   def init(id, cfg):
53      log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, cfg.port, mod_env['script']))
54      return True
55
56
57.. function:: init_standard(id, env)
58
59   Initialize module internals, like database etc.
60   Called just once on module load.
61
62   *Preferred* over the init() function above as this function's signature is the
63   same as the C counterpart and allows for extra functionality during init.
64   The previously accessible configuration options can now be found in env.cfg.
65
66   :param id: module identifier (integer)
67   :param env: :class:`module_env` module environment
68
69::
70
71    def init_standard(id, env):
72       log_info("pythonmod: init called, module id is %d port: %d script: %s" % (id, env.cfg.port, mod_env['script']))
73       return True
74
75
76.. function:: deinit(id)
77
78   Deinitialize module internals.
79   Called just once on module unload.
80
81   :param id: module identifier (integer)
82
83::
84
85   def deinit(id):
86      log_info("pythonmod: deinit called, module id is %d" % id)
87      return True
88
89
90.. function:: inform_super(id, qstate, superqstate, qdata)
91
92   Inform super querystate about the results from this subquerystate.
93   Is called when the querystate is finished.
94
95   :param id: module identifier (integer)
96   :param qstate: :class:`module_qstate` Query state
97   :param superqstate: :class:`pythonmod_qstate` Mesh state
98   :param qdata: :class:`query_info` Query data
99
100::
101
102   def inform_super(id, qstate, superqstate, qdata):
103      return True
104
105
106
107.. function:: operate(id, event, qstate, qdata)
108
109   Perform action on pending query. Accepts a new query, or work on pending query.
110
111   You have to set qstate.ext_state on exit.
112   The state informs unbound about result and controls the following states.
113
114   :param id: module identifier (integer)
115   :param qstate: :class:`module_qstate` query state structure
116   :param qdata: :class:`query_info` per query data, here you can store your own data
117
118::
119
120   def operate(id, event, qstate, qdata):
121      log_info("pythonmod: operate called, id: %d, event:%s" % (id, strmodulevent(event)))
122      if event == MODULE_EVENT_NEW:
123         qstate.ext_state[id] = MODULE_WAIT_MODULE
124         return True
125
126      if event == MODULE_EVENT_MODDONE:
127         qstate.ext_state[id] = MODULE_FINISHED
128         return True
129
130      if event == MODULE_EVENT_PASS:
131         qstate.ext_state[id] = MODULE_WAIT_MODULE
132         return True
133
134      log_err("pythonmod: BAD event")
135      qstate.ext_state[id] = MODULE_ERROR
136      return True
137
138
139Complete source code
140--------------------
141
142..	literalinclude:: example0-1.py
143	:language: python
144
145As you can see, the source code is much more flexible in contrast to C modules.
146Moreover, compulsory functions called on appropriate module events allows to handle almost
147anything from web control to query analysis.
148
149