client_python.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  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 "client_inc.cc"
  36. using namespace std;
  37. using namespace isc::util::python;
  38. using namespace isc::dns::python;
  39. using namespace isc::datasrc;
  40. using namespace isc::datasrc::python;
  41. namespace {
  42. // The s_* Class simply covers one instantiation of the object
  43. class s_DataSourceClient : public PyObject {
  44. public:
  45. s_DataSourceClient() : cppobj(NULL) {};
  46. DataSourceClientContainer* cppobj;
  47. };
  48. PyObject*
  49. DataSourceClient_findZone(PyObject* po_self, PyObject* args) {
  50. s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
  51. PyObject *name;
  52. if (PyArg_ParseTuple(args, "O!", &name_type, &name)) {
  53. try {
  54. DataSourceClient::FindResult find_result(
  55. self->cppobj->getInstance().findZone(PyName_ToName(name)));
  56. result::Result r = find_result.code;
  57. ZoneFinderPtr zfp = find_result.zone_finder;
  58. // Use N instead of O so refcount isn't increased twice
  59. return (Py_BuildValue("IN", r, createZoneFinderObject(zfp, po_self)));
  60. } catch (const std::exception& exc) {
  61. PyErr_SetString(getDataSourceException("Error"), exc.what());
  62. return (NULL);
  63. } catch (...) {
  64. PyErr_SetString(getDataSourceException("Error"),
  65. "Unexpected exception");
  66. return (NULL);
  67. }
  68. } else {
  69. return (NULL);
  70. }
  71. }
  72. PyObject*
  73. DataSourceClient_getIterator(PyObject* po_self, PyObject* args) {
  74. s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
  75. PyObject* name_obj;
  76. PyObject* separate_rrs_obj = NULL;
  77. if (PyArg_ParseTuple(args, "O!|O", &name_type, &name_obj,
  78. &separate_rrs_obj)) {
  79. try {
  80. bool separate_rrs = false;
  81. if (separate_rrs_obj != NULL) {
  82. // store result in local var so we can explicitely check for
  83. // -1 error return value
  84. int separate_rrs_true = PyObject_IsTrue(separate_rrs_obj);
  85. if (separate_rrs_true == 1) {
  86. separate_rrs = true;
  87. } else if (separate_rrs_true == -1) {
  88. PyErr_SetString(getDataSourceException("Error"),
  89. "Error getting value of separate_rrs");
  90. return (NULL);
  91. }
  92. }
  93. return (createZoneIteratorObject(
  94. self->cppobj->getInstance().getIterator(PyName_ToName(name_obj),
  95. separate_rrs),
  96. po_self));
  97. } catch (const isc::NotImplemented& ne) {
  98. PyErr_SetString(getDataSourceException("NotImplemented"),
  99. ne.what());
  100. return (NULL);
  101. } catch (const DataSourceError& dse) {
  102. PyErr_SetString(getDataSourceException("Error"), dse.what());
  103. return (NULL);
  104. } catch (const std::exception& exc) {
  105. PyErr_SetString(getDataSourceException("Error"), exc.what());
  106. return (NULL);
  107. } catch (...) {
  108. PyErr_SetString(getDataSourceException("Error"),
  109. "Unexpected exception");
  110. return (NULL);
  111. }
  112. } else {
  113. return (NULL);
  114. }
  115. }
  116. PyObject*
  117. DataSourceClient_getUpdater(PyObject* po_self, PyObject* args) {
  118. s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
  119. PyObject *name_obj;
  120. PyObject *replace_obj;
  121. if (PyArg_ParseTuple(args, "O!O", &name_type, &name_obj, &replace_obj) &&
  122. PyBool_Check(replace_obj)) {
  123. bool replace = (replace_obj != Py_False);
  124. try {
  125. ZoneUpdaterPtr updater =
  126. self->cppobj->getInstance().getUpdater(PyName_ToName(name_obj),
  127. replace);
  128. if (!updater) {
  129. return (Py_None);
  130. }
  131. return (createZoneUpdaterObject(updater, po_self));
  132. } catch (const isc::NotImplemented& ne) {
  133. PyErr_SetString(getDataSourceException("NotImplemented"),
  134. ne.what());
  135. return (NULL);
  136. } catch (const DataSourceError& dse) {
  137. PyErr_SetString(getDataSourceException("Error"), dse.what());
  138. return (NULL);
  139. } catch (const std::exception& exc) {
  140. PyErr_SetString(getDataSourceException("Error"), exc.what());
  141. return (NULL);
  142. } catch (...) {
  143. PyErr_SetString(getDataSourceException("Error"),
  144. "Unexpected exception");
  145. return (NULL);
  146. }
  147. } else {
  148. return (NULL);
  149. }
  150. }
  151. // This list contains the actual set of functions we have in
  152. // python. Each entry has
  153. // 1. Python method name
  154. // 2. Our static function here
  155. // 3. Argument type
  156. // 4. Documentation
  157. PyMethodDef DataSourceClient_methods[] = {
  158. { "find_zone", reinterpret_cast<PyCFunction>(DataSourceClient_findZone),
  159. METH_VARARGS, DataSourceClient_findZone_doc },
  160. { "get_iterator",
  161. reinterpret_cast<PyCFunction>(DataSourceClient_getIterator), METH_VARARGS,
  162. DataSourceClient_getIterator_doc },
  163. { "get_updater", reinterpret_cast<PyCFunction>(DataSourceClient_getUpdater),
  164. METH_VARARGS, DataSourceClient_getUpdater_doc },
  165. { NULL, NULL, 0, NULL }
  166. };
  167. int
  168. DataSourceClient_init(s_DataSourceClient* self, PyObject* args) {
  169. char* ds_type_str;
  170. char* ds_config_str;
  171. try {
  172. // Turn the given argument into config Element; then simply call
  173. // factory class to do its magic
  174. // for now, ds_config must be JSON string
  175. if (PyArg_ParseTuple(args, "ss", &ds_type_str, &ds_config_str)) {
  176. isc::data::ConstElementPtr ds_config =
  177. isc::data::Element::fromJSON(ds_config_str);
  178. self->cppobj = new DataSourceClientContainer(ds_type_str,
  179. ds_config);
  180. return (0);
  181. } else {
  182. return (-1);
  183. }
  184. } catch (const isc::data::JSONError& je) {
  185. const string ex_what = "JSON parse error in data source configuration "
  186. "data for type " +
  187. string(ds_type_str) + ":" + je.what();
  188. PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
  189. return (-1);
  190. } catch (const DataSourceError& dse) {
  191. const string ex_what = "Failed to create DataSourceClient of type " +
  192. string(ds_type_str) + ":" + dse.what();
  193. PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
  194. return (-1);
  195. } catch (const exception& ex) {
  196. const string ex_what = "Failed to construct DataSourceClient object: " +
  197. string(ex.what());
  198. PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
  199. return (-1);
  200. } catch (...) {
  201. PyErr_SetString(PyExc_RuntimeError,
  202. "Unexpected exception in constructing DataSourceClient");
  203. return (-1);
  204. }
  205. PyErr_SetString(PyExc_TypeError,
  206. "Invalid arguments to DataSourceClient constructor");
  207. return (-1);
  208. }
  209. void
  210. DataSourceClient_destroy(s_DataSourceClient* const self) {
  211. delete self->cppobj;
  212. self->cppobj = NULL;
  213. Py_TYPE(self)->tp_free(self);
  214. }
  215. } // end anonymous namespace
  216. namespace isc {
  217. namespace datasrc {
  218. namespace python {
  219. // This defines the complete type for reflection in python and
  220. // parsing of PyObject* to s_DataSourceClient
  221. // Most of the functions are not actually implemented and NULL here.
  222. PyTypeObject datasourceclient_type = {
  223. PyVarObject_HEAD_INIT(NULL, 0)
  224. "datasrc.DataSourceClient",
  225. sizeof(s_DataSourceClient), // tp_basicsize
  226. 0, // tp_itemsize
  227. reinterpret_cast<destructor>(DataSourceClient_destroy),// tp_dealloc
  228. NULL, // tp_print
  229. NULL, // tp_getattr
  230. NULL, // tp_setattr
  231. NULL, // tp_reserved
  232. NULL, // tp_repr
  233. NULL, // tp_as_number
  234. NULL, // tp_as_sequence
  235. NULL, // tp_as_mapping
  236. NULL, // tp_hash
  237. NULL, // tp_call
  238. NULL, // tp_str
  239. NULL, // tp_getattro
  240. NULL, // tp_setattro
  241. NULL, // tp_as_buffer
  242. Py_TPFLAGS_DEFAULT, // tp_flags
  243. DataSourceClient_doc,
  244. NULL, // tp_traverse
  245. NULL, // tp_clear
  246. NULL, // tp_richcompare
  247. 0, // tp_weaklistoffset
  248. NULL, // tp_iter
  249. NULL, // tp_iternext
  250. DataSourceClient_methods, // tp_methods
  251. NULL, // tp_members
  252. NULL, // tp_getset
  253. NULL, // tp_base
  254. NULL, // tp_dict
  255. NULL, // tp_descr_get
  256. NULL, // tp_descr_set
  257. 0, // tp_dictoffset
  258. reinterpret_cast<initproc>(DataSourceClient_init),// tp_init
  259. NULL, // tp_alloc
  260. PyType_GenericNew, // tp_new
  261. NULL, // tp_free
  262. NULL, // tp_is_gc
  263. NULL, // tp_bases
  264. NULL, // tp_mro
  265. NULL, // tp_cache
  266. NULL, // tp_subclasses
  267. NULL, // tp_weaklist
  268. NULL, // tp_del
  269. 0 // tp_version_tag
  270. };
  271. } // namespace python
  272. } // namespace datasrc
  273. } // namespace isc