client_python.cc 14 KB

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