Branch data Line data Source code
1 : : // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
2 : : //
3 : : // Permission to use, copy, modify, and/or distribute this software for any
4 : : // purpose with or without fee is hereby granted, provided that the above
5 : : // copyright notice and this permission notice appear in all copies.
6 : : //
7 : : // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
8 : : // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
9 : : // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
10 : : // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11 : : // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
12 : : // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13 : : // PERFORMANCE OF THIS SOFTWARE.
14 : :
15 : : // Enable this if you use s# variants with PyArg_ParseTuple(), see
16 : : // http://docs.python.org/py3k/c-api/arg.html#strings-and-buffers
17 : : //#define PY_SSIZE_T_CLEAN
18 : :
19 : : // Python.h needs to be placed at the head of the program file, see:
20 : : // http://docs.python.org/py3k/extending/extending.html#a-simple-example
21 : : #include <Python.h>
22 : :
23 : : #include <util/python/pycppwrapper_util.h>
24 : :
25 : : #include <datasrc/client.h>
26 : : #include <datasrc/factory.h>
27 : : #include <datasrc/database.h>
28 : : #include <datasrc/data_source.h>
29 : : #include <datasrc/sqlite3_accessor.h>
30 : : #include <datasrc/iterator.h>
31 : :
32 : : #include <dns/python/name_python.h>
33 : : #include <dns/python/rrset_python.h>
34 : : #include <dns/python/pydnspp_common.h>
35 : :
36 : : #include "datasrc.h"
37 : : #include "client_python.h"
38 : : #include "finder_python.h"
39 : : #include "iterator_python.h"
40 : : #include "updater_python.h"
41 : : #include "journal_reader_python.h"
42 : : #include "client_inc.cc"
43 : :
44 : : using namespace std;
45 : : using namespace isc::util::python;
46 : : using namespace isc::dns::python;
47 : : using namespace isc::datasrc;
48 : : using namespace isc::datasrc::python;
49 : :
50 : : namespace {
51 : : // The s_* Class simply covers one instantiation of the object
52 : : class s_DataSourceClient : public PyObject {
53 : : public:
54 : : s_DataSourceClient() : cppobj(NULL) {};
55 : : DataSourceClientContainer* cppobj;
56 : : };
57 : :
58 : : PyObject*
59 : 175 : DataSourceClient_findZone(PyObject* po_self, PyObject* args) {
60 : 175 : s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
61 : : PyObject *name;
62 [ + - ]: 175 : if (PyArg_ParseTuple(args, "O!", &name_type, &name)) {
63 : : try {
64 : : DataSourceClient::FindResult find_result(
65 [ + - ][ + - ]: 175 : self->cppobj->getInstance().findZone(PyName_ToName(name)));
66 : :
67 : 175 : result::Result r = find_result.code;
68 : : ZoneFinderPtr zfp = find_result.zone_finder;
69 : : // Use N instead of O so refcount isn't increased twice
70 [ + - ][ + - ]: 175 : return (Py_BuildValue("IN", r, createZoneFinderObject(zfp, po_self)));
71 : 0 : } catch (const std::exception& exc) {
72 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), exc.what());
73 : : return (NULL);
74 [ # # ]: 0 : } catch (...) {
75 : : PyErr_SetString(getDataSourceException("Error"),
76 [ # # ][ # # ]: 0 : "Unexpected exception");
77 : : return (NULL);
78 : : }
79 : : } else {
80 : : return (NULL);
81 : : }
82 : : }
83 : :
84 : : PyObject*
85 : 10 : DataSourceClient_getIterator(PyObject* po_self, PyObject* args) {
86 : 10 : s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
87 : : PyObject* name_obj;
88 : 10 : PyObject* separate_rrs_obj = NULL;
89 [ + + ]: 10 : if (PyArg_ParseTuple(args, "O!|O", &name_type, &name_obj,
90 : 10 : &separate_rrs_obj)) {
91 : : try {
92 : 9 : bool separate_rrs = false;
93 [ + + ]: 9 : if (separate_rrs_obj != NULL) {
94 : : // store result in local var so we can explicitely check for
95 : : // -1 error return value
96 [ + - ]: 5 : int separate_rrs_true = PyObject_IsTrue(separate_rrs_obj);
97 [ + + ]: 5 : if (separate_rrs_true == 1) {
98 : : separate_rrs = true;
99 [ - + ]: 1 : } else if (separate_rrs_true == -1) {
100 : : PyErr_SetString(getDataSourceException("Error"),
101 [ # # ][ # # ]: 0 : "Error getting value of separate_rrs");
102 : : return (NULL);
103 : : }
104 : : }
105 : : return (createZoneIteratorObject(
106 [ + - ]: 9 : self->cppobj->getInstance().getIterator(PyName_ToName(name_obj),
107 : 9 : separate_rrs),
108 [ + - ][ + - ]: 9 : po_self));
109 : 0 : } catch (const isc::NotImplemented& ne) {
110 : : PyErr_SetString(getDataSourceException("NotImplemented"),
111 [ # # ][ # # ]: 0 : ne.what());
112 : : return (NULL);
113 : 0 : } catch (const DataSourceError& dse) {
114 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), dse.what());
115 : : return (NULL);
116 : 0 : } catch (const std::exception& exc) {
117 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), exc.what());
118 : : return (NULL);
119 [ # # # # ]: 0 : } catch (...) {
120 : : PyErr_SetString(getDataSourceException("Error"),
121 [ # # ][ # # ]: 0 : "Unexpected exception");
122 : : return (NULL);
123 : : }
124 : : } else {
125 : : return (NULL);
126 : : }
127 : : }
128 : :
129 : : PyObject*
130 : 33 : DataSourceClient_getUpdater(PyObject* po_self, PyObject* args) {
131 : 33 : s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
132 : : PyObject *name_obj;
133 : 33 : PyObject *replace_obj = NULL;
134 : 33 : PyObject *journaling_obj = Py_False;
135 [ + + ][ + + ]: 33 : if (PyArg_ParseTuple(args, "O!O|O", &name_type, &name_obj,
[ + + ][ + + ]
136 : 33 : &replace_obj, &journaling_obj) &&
137 : : PyBool_Check(replace_obj) && PyBool_Check(journaling_obj)) {
138 : 30 : const bool replace = (replace_obj != Py_False);
139 : 30 : const bool journaling = (journaling_obj == Py_True);
140 : : try {
141 : : ZoneUpdaterPtr updater =
142 [ + - ]: 30 : self->cppobj->getInstance().getUpdater(PyName_ToName(name_obj),
143 [ + + ]: 30 : replace, journaling);
144 [ + + ]: 29 : if (!updater) {
145 : : return (Py_None);
146 : : }
147 [ + - ]: 28 : return (createZoneUpdaterObject(updater, po_self));
148 : 0 : } catch (const isc::NotImplemented& ne) {
149 : : PyErr_SetString(getDataSourceException("NotImplemented"),
150 [ # # ][ # # ]: 0 : ne.what());
151 : : return (NULL);
152 : 0 : } catch (const DataSourceError& dse) {
153 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), dse.what());
154 : : return (NULL);
155 : 2 : } catch (const std::exception& exc) {
156 [ - + ][ - + ]: 1 : PyErr_SetString(getDataSourceException("Error"), exc.what());
157 : : return (NULL);
158 [ - - + - ]: 1 : } catch (...) {
159 : : PyErr_SetString(getDataSourceException("Error"),
160 [ # # ][ # # ]: 0 : "Unexpected exception");
161 : : return (NULL);
162 : : }
163 : : } else {
164 : : // PyBool_Check doesn't set the error, so we have to set it ourselves.
165 [ + + ][ + + ]: 3 : if (replace_obj != NULL && !PyBool_Check(replace_obj)) {
166 : : PyErr_SetString(PyExc_TypeError, "'replace' for "
167 : 1 : "DataSourceClient.get_updater must be boolean");
168 : : }
169 [ + + ]: 3 : if (!PyBool_Check(journaling_obj)) {
170 : : PyErr_SetString(PyExc_TypeError, "'journaling' for "
171 : 33 : "DataSourceClient.get_updater must be boolean");
172 : : }
173 : : return (NULL);
174 : : }
175 : : }
176 : :
177 : : PyObject*
178 : 10 : DataSourceClient_getJournalReader(PyObject* po_self, PyObject* args) {
179 : 10 : s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
180 : : PyObject *name_obj;
181 : : unsigned long begin_obj, end_obj;
182 : :
183 [ + + ]: 10 : if (PyArg_ParseTuple(args, "O!kk", &name_type, &name_obj,
184 : 10 : &begin_obj, &end_obj)) {
185 : : try {
186 : : pair<ZoneJournalReader::Result, ZoneJournalReaderPtr> result =
187 : 7 : self->cppobj->getInstance().getJournalReader(
188 [ + - ]: 7 : PyName_ToName(name_obj), static_cast<uint32_t>(begin_obj),
189 [ + - ]: 7 : static_cast<uint32_t>(end_obj));
190 : : PyObject* po_reader;
191 [ + + ]: 7 : if (result.first == ZoneJournalReader::SUCCESS) {
192 : : po_reader = createZoneJournalReaderObject(result.second,
193 [ + - ]: 4 : po_self);
194 : : } else {
195 : 3 : po_reader = Py_None;
196 : 3 : Py_INCREF(po_reader); // this will soon be released
197 : : }
198 [ + - ]: 7 : PyObjectContainer container(po_reader);
199 [ + - ]: 7 : return (Py_BuildValue("(iO)", result.first, container.get()));
200 : 0 : } catch (const isc::NotImplemented& ex) {
201 : : PyErr_SetString(getDataSourceException("NotImplemented"),
202 [ # # ][ # # ]: 0 : ex.what());
203 : 0 : } catch (const DataSourceError& ex) {
204 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), ex.what());
205 : 0 : } catch (const std::exception& ex) {
206 [ # # ]: 0 : PyErr_SetString(PyExc_SystemError, ex.what());
207 [ # # # # ]: 0 : } catch (...) {
208 [ # # ]: 0 : PyErr_SetString(PyExc_SystemError, "Unexpected exception");
209 : : }
210 : : }
211 : : return (NULL);
212 : : }
213 : :
214 : : // This list contains the actual set of functions we have in
215 : : // python. Each entry has
216 : : // 1. Python method name
217 : : // 2. Our static function here
218 : : // 3. Argument type
219 : : // 4. Documentation
220 : : PyMethodDef DataSourceClient_methods[] = {
221 : : { "find_zone", DataSourceClient_findZone, METH_VARARGS,
222 : : DataSourceClient_findZone_doc },
223 : : { "get_iterator",
224 : : DataSourceClient_getIterator, METH_VARARGS,
225 : : DataSourceClient_getIterator_doc },
226 : : { "get_updater", DataSourceClient_getUpdater,
227 : : METH_VARARGS, DataSourceClient_getUpdater_doc },
228 : : { "get_journal_reader", DataSourceClient_getJournalReader,
229 : : METH_VARARGS, DataSourceClient_getJournalReader_doc },
230 : : { NULL, NULL, 0, NULL }
231 : : };
232 : :
233 : : int
234 : 95 : DataSourceClient_init(PyObject* po_self, PyObject* args, PyObject*) {
235 : 95 : s_DataSourceClient* self = static_cast<s_DataSourceClient*>(po_self);
236 : : char* ds_type_str;
237 : : char* ds_config_str;
238 : : try {
239 : : // Turn the given argument into config Element; then simply call
240 : : // factory class to do its magic
241 : :
242 : : // for now, ds_config must be JSON string
243 [ + - ][ + + ]: 95 : if (PyArg_ParseTuple(args, "ss", &ds_type_str, &ds_config_str)) {
244 : : isc::data::ConstElementPtr ds_config =
245 [ + - ][ + + ]: 185 : isc::data::Element::fromJSON(ds_config_str);
246 : : self->cppobj = new DataSourceClientContainer(ds_type_str,
247 [ + - ][ + - ]: 276 : ds_config);
[ + + ]
248 : 85 : return (0);
249 : : } else {
250 : : return (-1);
251 : : }
252 : 2 : } catch (const isc::data::JSONError& je) {
253 : : const string ex_what = "JSON parse error in data source configuration "
254 : : "data for type " +
255 [ - + ][ - + ]: 2 : string(ds_type_str) + ":" + je.what();
[ - + ][ - + ]
256 [ - + ][ - + ]: 1 : PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
257 : : return (-1);
258 : 14 : } catch (const DataSourceError& dse) {
259 : : const string ex_what = "Failed to create DataSourceClient of type " +
260 [ - + ][ - + ]: 14 : string(ds_type_str) + ":" + dse.what();
[ - + ][ - + ]
261 [ - + ][ - + ]: 7 : PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
262 : : return (-1);
263 : 0 : } catch (const exception& ex) {
264 : : const string ex_what = "Failed to construct DataSourceClient object: " +
265 [ # # ][ # # ]: 0 : string(ex.what());
266 [ # # ][ # # ]: 0 : PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
267 : : return (-1);
268 [ + + - - ]: 8 : } catch (...) {
269 : : PyErr_SetString(PyExc_RuntimeError,
270 [ # # ]: 0 : "Unexpected exception in constructing DataSourceClient");
271 : : return (-1);
272 : : }
273 : : PyErr_SetString(PyExc_TypeError,
274 : : "Invalid arguments to DataSourceClient constructor");
275 : :
276 : : return (-1);
277 : : }
278 : :
279 : : void
280 : 95 : DataSourceClient_destroy(PyObject* po_self) {
281 : 95 : s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
282 [ + + ]: 95 : delete self->cppobj;
283 : 95 : self->cppobj = NULL;
284 : 95 : Py_TYPE(self)->tp_free(self);
285 : 95 : }
286 : :
287 : : } // end anonymous namespace
288 : :
289 : : namespace isc {
290 : : namespace datasrc {
291 : : namespace python {
292 : : // This defines the complete type for reflection in python and
293 : : // parsing of PyObject* to s_DataSourceClient
294 : : // Most of the functions are not actually implemented and NULL here.
295 : : PyTypeObject datasourceclient_type = {
296 : : PyVarObject_HEAD_INIT(NULL, 0)
297 : : "datasrc.DataSourceClient",
298 : : sizeof(s_DataSourceClient), // tp_basicsize
299 : : 0, // tp_itemsize
300 : : DataSourceClient_destroy, // tp_dealloc
301 : : NULL, // tp_print
302 : : NULL, // tp_getattr
303 : : NULL, // tp_setattr
304 : : NULL, // tp_reserved
305 : : NULL, // tp_repr
306 : : NULL, // tp_as_number
307 : : NULL, // tp_as_sequence
308 : : NULL, // tp_as_mapping
309 : : NULL, // tp_hash
310 : : NULL, // tp_call
311 : : NULL, // tp_str
312 : : NULL, // tp_getattro
313 : : NULL, // tp_setattro
314 : : NULL, // tp_as_buffer
315 : : Py_TPFLAGS_DEFAULT, // tp_flags
316 : : DataSourceClient_doc,
317 : : NULL, // tp_traverse
318 : : NULL, // tp_clear
319 : : NULL, // tp_richcompare
320 : : 0, // tp_weaklistoffset
321 : : NULL, // tp_iter
322 : : NULL, // tp_iternext
323 : : DataSourceClient_methods, // tp_methods
324 : : NULL, // tp_members
325 : : NULL, // tp_getset
326 : : NULL, // tp_base
327 : : NULL, // tp_dict
328 : : NULL, // tp_descr_get
329 : : NULL, // tp_descr_set
330 : : 0, // tp_dictoffset
331 : : DataSourceClient_init, // tp_init
332 : : NULL, // tp_alloc
333 : : PyType_GenericNew, // tp_new
334 : : NULL, // tp_free
335 : : NULL, // tp_is_gc
336 : : NULL, // tp_bases
337 : : NULL, // tp_mro
338 : : NULL, // tp_cache
339 : : NULL, // tp_subclasses
340 : : NULL, // tp_weaklist
341 : : NULL, // tp_del
342 : : 0 // tp_version_tag
343 : : };
344 : :
345 : : } // namespace python
346 : : } // namespace datasrc
347 : 104 : } // namespace isc
|