client_python.cc 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  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 <datasrc/client_list.h>
  28. #include <dns/python/name_python.h>
  29. #include <dns/python/rrset_python.h>
  30. #include <dns/python/pydnspp_common.h>
  31. #include "datasrc.h"
  32. #include "client_python.h"
  33. #include "finder_python.h"
  34. #include "iterator_python.h"
  35. #include "updater_python.h"
  36. #include "journal_reader_python.h"
  37. #include "client_inc.cc"
  38. using namespace std;
  39. using namespace isc::util::python;
  40. using namespace isc::dns::python;
  41. using namespace isc::datasrc;
  42. using namespace isc::datasrc::python;
  43. namespace {
  44. // The s_* Class simply covers one instantiation of the object
  45. class s_DataSourceClient : public PyObject {
  46. public:
  47. s_DataSourceClient() :
  48. cppobj(NULL),
  49. client(NULL),
  50. keeper(NULL)
  51. {};
  52. DataSourceClientContainer* cppobj;
  53. DataSourceClient* client;
  54. // We can't rely on the constructor or destructor being
  55. // called, so this is a pointer to shared pointer, so we
  56. // can call the new and delete explicitly.
  57. boost::shared_ptr<ClientList::FindResult::LifeKeeper>* keeper;
  58. };
  59. PyObject*
  60. DataSourceClient_findZone(PyObject* po_self, PyObject* args) {
  61. s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
  62. PyObject *name;
  63. if (PyArg_ParseTuple(args, "O!", &name_type, &name)) {
  64. try {
  65. DataSourceClient::FindResult find_result(
  66. self->client->findZone(PyName_ToName(name)));
  67. 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. return (Py_BuildValue("IN", r, createZoneFinderObject(zfp, po_self)));
  71. } catch (const std::exception& exc) {
  72. PyErr_SetString(getDataSourceException("Error"), exc.what());
  73. return (NULL);
  74. } catch (...) {
  75. PyErr_SetString(getDataSourceException("Error"),
  76. "Unexpected exception");
  77. return (NULL);
  78. }
  79. } else {
  80. return (NULL);
  81. }
  82. }
  83. PyObject*
  84. DataSourceClient_createZone(PyObject* po_self, PyObject* args) {
  85. s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
  86. PyObject* name;
  87. if (PyArg_ParseTuple(args, "O!", &name_type, &name)) {
  88. try {
  89. if (self->client->createZone(PyName_ToName(name))) {
  90. Py_RETURN_TRUE;
  91. } else {
  92. Py_RETURN_FALSE;
  93. }
  94. } catch (const DataSourceError& dse) {
  95. PyErr_SetString(getDataSourceException("Error"), dse.what());
  96. return (NULL);
  97. } catch (const isc::NotImplemented& ni) {
  98. PyErr_SetString(getDataSourceException("NotImplemented"),
  99. ni.what());
  100. return (NULL);
  101. } catch (const std::exception& exc) {
  102. PyErr_SetString(getDataSourceException("Error"), exc.what());
  103. return (NULL);
  104. } catch (...) {
  105. PyErr_SetString(getDataSourceException("Error"),
  106. "Unexpected exception");
  107. return (NULL);
  108. }
  109. } else {
  110. return (NULL);
  111. }
  112. }
  113. PyObject*
  114. DataSourceClient_getIterator(PyObject* po_self, PyObject* args) {
  115. s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
  116. PyObject* name_obj;
  117. PyObject* separate_rrs_obj = NULL;
  118. if (PyArg_ParseTuple(args, "O!|O", &name_type, &name_obj,
  119. &separate_rrs_obj)) {
  120. try {
  121. bool separate_rrs = false;
  122. if (separate_rrs_obj != NULL) {
  123. // store result in local var so we can explicitely check for
  124. // -1 error return value
  125. int separate_rrs_true = PyObject_IsTrue(separate_rrs_obj);
  126. if (separate_rrs_true == 1) {
  127. separate_rrs = true;
  128. } else if (separate_rrs_true == -1) {
  129. PyErr_SetString(getDataSourceException("Error"),
  130. "Error getting value of separate_rrs");
  131. return (NULL);
  132. }
  133. }
  134. return (createZoneIteratorObject(
  135. self->client->getIterator(PyName_ToName(name_obj),
  136. separate_rrs),
  137. po_self));
  138. } catch (const isc::NotImplemented& ne) {
  139. PyErr_SetString(getDataSourceException("NotImplemented"),
  140. ne.what());
  141. return (NULL);
  142. } catch (const DataSourceError& dse) {
  143. PyErr_SetString(getDataSourceException("Error"), dse.what());
  144. return (NULL);
  145. } catch (const std::exception& exc) {
  146. PyErr_SetString(getDataSourceException("Error"), exc.what());
  147. return (NULL);
  148. } catch (...) {
  149. PyErr_SetString(getDataSourceException("Error"),
  150. "Unexpected exception");
  151. return (NULL);
  152. }
  153. } else {
  154. return (NULL);
  155. }
  156. }
  157. PyObject*
  158. DataSourceClient_getUpdater(PyObject* po_self, PyObject* args) {
  159. s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
  160. PyObject *name_obj;
  161. PyObject *replace_obj = NULL;
  162. PyObject *journaling_obj = Py_False;
  163. if (PyArg_ParseTuple(args, "O!O|O", &name_type, &name_obj,
  164. &replace_obj, &journaling_obj) &&
  165. PyBool_Check(replace_obj) && PyBool_Check(journaling_obj)) {
  166. const bool replace = (replace_obj != Py_False);
  167. const bool journaling = (journaling_obj == Py_True);
  168. try {
  169. ZoneUpdaterPtr updater =
  170. self->client->getUpdater(PyName_ToName(name_obj),
  171. replace, journaling);
  172. if (!updater) {
  173. return (Py_None);
  174. }
  175. return (createZoneUpdaterObject(updater, po_self));
  176. } catch (const isc::NotImplemented& ne) {
  177. PyErr_SetString(getDataSourceException("NotImplemented"),
  178. ne.what());
  179. return (NULL);
  180. } catch (const DataSourceError& dse) {
  181. PyErr_SetString(getDataSourceException("Error"), dse.what());
  182. return (NULL);
  183. } catch (const std::exception& exc) {
  184. PyErr_SetString(getDataSourceException("Error"), exc.what());
  185. return (NULL);
  186. } catch (...) {
  187. PyErr_SetString(getDataSourceException("Error"),
  188. "Unexpected exception");
  189. return (NULL);
  190. }
  191. } else {
  192. // PyBool_Check doesn't set the error, so we have to set it ourselves.
  193. if (replace_obj != NULL && !PyBool_Check(replace_obj)) {
  194. PyErr_SetString(PyExc_TypeError, "'replace' for "
  195. "DataSourceClient.get_updater must be boolean");
  196. }
  197. if (!PyBool_Check(journaling_obj)) {
  198. PyErr_SetString(PyExc_TypeError, "'journaling' for "
  199. "DataSourceClient.get_updater must be boolean");
  200. }
  201. return (NULL);
  202. }
  203. }
  204. PyObject*
  205. DataSourceClient_getJournalReader(PyObject* po_self, PyObject* args) {
  206. s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
  207. PyObject *name_obj;
  208. unsigned long begin_obj, end_obj;
  209. if (PyArg_ParseTuple(args, "O!kk", &name_type, &name_obj,
  210. &begin_obj, &end_obj)) {
  211. try {
  212. pair<ZoneJournalReader::Result, ZoneJournalReaderPtr> result =
  213. self->client->getJournalReader(
  214. PyName_ToName(name_obj), static_cast<uint32_t>(begin_obj),
  215. static_cast<uint32_t>(end_obj));
  216. PyObject* po_reader;
  217. if (result.first == ZoneJournalReader::SUCCESS) {
  218. po_reader = createZoneJournalReaderObject(result.second,
  219. po_self);
  220. } else {
  221. po_reader = Py_None;
  222. Py_INCREF(po_reader); // this will soon be released
  223. }
  224. PyObjectContainer container(po_reader);
  225. return (Py_BuildValue("(iO)", result.first, container.get()));
  226. } catch (const isc::NotImplemented& ex) {
  227. PyErr_SetString(getDataSourceException("NotImplemented"),
  228. ex.what());
  229. } catch (const DataSourceError& ex) {
  230. PyErr_SetString(getDataSourceException("Error"), ex.what());
  231. } catch (const std::exception& ex) {
  232. PyErr_SetString(PyExc_SystemError, ex.what());
  233. } catch (...) {
  234. PyErr_SetString(PyExc_SystemError, "Unexpected exception");
  235. }
  236. }
  237. return (NULL);
  238. }
  239. // This list contains the actual set of functions we have in
  240. // python. Each entry has
  241. // 1. Python method name
  242. // 2. Our static function here
  243. // 3. Argument type
  244. // 4. Documentation
  245. PyMethodDef DataSourceClient_methods[] = {
  246. { "find_zone", DataSourceClient_findZone, METH_VARARGS,
  247. DataSourceClient_findZone_doc },
  248. { "create_zone", DataSourceClient_createZone, METH_VARARGS,
  249. DataSourceClient_createZone_doc },
  250. { "get_iterator",
  251. DataSourceClient_getIterator, METH_VARARGS,
  252. DataSourceClient_getIterator_doc },
  253. { "get_updater", DataSourceClient_getUpdater,
  254. METH_VARARGS, DataSourceClient_getUpdater_doc },
  255. { "get_journal_reader", DataSourceClient_getJournalReader,
  256. METH_VARARGS, DataSourceClient_getJournalReader_doc },
  257. { NULL, NULL, 0, NULL }
  258. };
  259. int
  260. DataSourceClient_init(PyObject* po_self, PyObject* args, PyObject*) {
  261. s_DataSourceClient* self = static_cast<s_DataSourceClient*>(po_self);
  262. char* ds_type_str;
  263. char* ds_config_str;
  264. try {
  265. // Turn the given argument into config Element; then simply call
  266. // factory class to do its magic
  267. // for now, ds_config must be JSON string
  268. if (PyArg_ParseTuple(args, "ss", &ds_type_str, &ds_config_str)) {
  269. isc::data::ConstElementPtr ds_config =
  270. isc::data::Element::fromJSON(ds_config_str);
  271. self->cppobj = new DataSourceClientContainer(ds_type_str,
  272. ds_config);
  273. self->client = &self->cppobj->getInstance();
  274. self->keeper = NULL;
  275. return (0);
  276. } else {
  277. return (-1);
  278. }
  279. } catch (const isc::data::JSONError& je) {
  280. const string ex_what = "JSON parse error in data source configuration "
  281. "data for type " +
  282. string(ds_type_str) + ":" + je.what();
  283. PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
  284. return (-1);
  285. } catch (const DataSourceError& dse) {
  286. const string ex_what = "Failed to create DataSourceClient of type " +
  287. string(ds_type_str) + ":" + dse.what();
  288. PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
  289. return (-1);
  290. } catch (const exception& ex) {
  291. const string ex_what = "Failed to construct DataSourceClient object: " +
  292. string(ex.what());
  293. PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
  294. return (-1);
  295. } catch (...) {
  296. PyErr_SetString(PyExc_RuntimeError,
  297. "Unexpected exception in constructing DataSourceClient");
  298. return (-1);
  299. }
  300. PyErr_SetString(PyExc_TypeError,
  301. "Invalid arguments to DataSourceClient constructor");
  302. return (-1);
  303. }
  304. void
  305. DataSourceClient_destroy(PyObject* po_self) {
  306. s_DataSourceClient* const self = static_cast<s_DataSourceClient*>(po_self);
  307. delete self->cppobj;
  308. delete self->keeper;
  309. self->cppobj = NULL;
  310. self->client = NULL;
  311. self->keeper = NULL;
  312. Py_TYPE(self)->tp_free(self);
  313. }
  314. } // end anonymous namespace
  315. namespace isc {
  316. namespace datasrc {
  317. namespace python {
  318. // This defines the complete type for reflection in python and
  319. // parsing of PyObject* to s_DataSourceClient
  320. // Most of the functions are not actually implemented and NULL here.
  321. PyTypeObject datasourceclient_type = {
  322. PyVarObject_HEAD_INIT(NULL, 0)
  323. "datasrc.DataSourceClient",
  324. sizeof(s_DataSourceClient), // tp_basicsize
  325. 0, // tp_itemsize
  326. DataSourceClient_destroy, // tp_dealloc
  327. NULL, // tp_print
  328. NULL, // tp_getattr
  329. NULL, // tp_setattr
  330. NULL, // tp_reserved
  331. NULL, // tp_repr
  332. NULL, // tp_as_number
  333. NULL, // tp_as_sequence
  334. NULL, // tp_as_mapping
  335. NULL, // tp_hash
  336. NULL, // tp_call
  337. NULL, // tp_str
  338. NULL, // tp_getattro
  339. NULL, // tp_setattro
  340. NULL, // tp_as_buffer
  341. Py_TPFLAGS_DEFAULT, // tp_flags
  342. DataSourceClient_doc,
  343. NULL, // tp_traverse
  344. NULL, // tp_clear
  345. NULL, // tp_richcompare
  346. 0, // tp_weaklistoffset
  347. NULL, // tp_iter
  348. NULL, // tp_iternext
  349. DataSourceClient_methods, // tp_methods
  350. NULL, // tp_members
  351. NULL, // tp_getset
  352. NULL, // tp_base
  353. NULL, // tp_dict
  354. NULL, // tp_descr_get
  355. NULL, // tp_descr_set
  356. 0, // tp_dictoffset
  357. DataSourceClient_init, // tp_init
  358. NULL, // tp_alloc
  359. PyType_GenericNew, // tp_new
  360. NULL, // tp_free
  361. NULL, // tp_is_gc
  362. NULL, // tp_bases
  363. NULL, // tp_mro
  364. NULL, // tp_cache
  365. NULL, // tp_subclasses
  366. NULL, // tp_weaklist
  367. NULL, // tp_del
  368. 0 // tp_version_tag
  369. };
  370. PyObject*
  371. wrapDataSourceClient(DataSourceClient* client,
  372. const boost::shared_ptr<ClientList::FindResult::
  373. LifeKeeper>& life_keeper)
  374. {
  375. s_DataSourceClient *result =
  376. static_cast<s_DataSourceClient*>(PyObject_New(s_DataSourceClient,
  377. &datasourceclient_type));
  378. CPPPyObjectContainer<s_DataSourceClient, DataSourceClientContainer>
  379. container(result);
  380. result->cppobj = NULL;
  381. result->keeper =
  382. new boost::shared_ptr<ClientList::FindResult::LifeKeeper>(life_keeper);
  383. result->client = client;
  384. return (container.release());
  385. }
  386. DataSourceClient&
  387. PyDataSourceClient_ToDataSourceClient(PyObject* client_obj) {
  388. if (client_obj == NULL) {
  389. isc_throw(PyCPPWrapperException,
  390. "argument NULL in DataSourceClient PyObject conversion");
  391. }
  392. s_DataSourceClient* client = static_cast<s_DataSourceClient*>(client_obj);
  393. return (*client->client);
  394. }
  395. } // namespace python
  396. } // namespace datasrc
  397. } // namespace isc