configurableclientlist_python.cc 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  1. // Copyright (C) 2012 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 <string>
  21. #include <stdexcept>
  22. #include <util/python/pycppwrapper_util.h>
  23. #include <dns/python/rrclass_python.h>
  24. #include <dns/python/name_python.h>
  25. #include <dns/python/pydnspp_common.h>
  26. #include <datasrc/client_list.h>
  27. #include "configurableclientlist_python.h"
  28. #include "datasrc.h"
  29. #include "finder_python.h"
  30. #include "client_python.h"
  31. #include "zonewriter_python.h"
  32. #include "configurableclientlist_inc.cc"
  33. using namespace std;
  34. using namespace isc::util::python;
  35. using namespace isc::datasrc;
  36. using namespace isc::datasrc::memory;
  37. using namespace isc::datasrc::python;
  38. using namespace isc::datasrc::memory::python;
  39. using namespace isc::dns::python;
  40. //
  41. // ConfigurableClientList
  42. //
  43. // Trivial constructor.
  44. s_ConfigurableClientList::s_ConfigurableClientList() : cppobj(NULL) {
  45. }
  46. namespace {
  47. int
  48. ConfigurableClientList_init(PyObject* po_self, PyObject* args, PyObject*) {
  49. s_ConfigurableClientList* self =
  50. static_cast<s_ConfigurableClientList*>(po_self);
  51. try {
  52. const PyObject* rrclass;
  53. if (PyArg_ParseTuple(args, "O!", &isc::dns::python::rrclass_type,
  54. &rrclass)) {
  55. self->cppobj =
  56. new ConfigurableClientList(isc::dns::python::
  57. PyRRClass_ToRRClass(rrclass));
  58. return (0);
  59. }
  60. } catch (const exception& ex) {
  61. const string ex_what =
  62. "Failed to construct ConfigurableClientList object: " +
  63. string(ex.what());
  64. PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
  65. return (-1);
  66. } catch (...) {
  67. PyErr_SetString(PyExc_SystemError, "Unexpected C++ exception");
  68. return (-1);
  69. }
  70. return (-1);
  71. }
  72. void
  73. ConfigurableClientList_destroy(PyObject* po_self) {
  74. s_ConfigurableClientList* self =
  75. static_cast<s_ConfigurableClientList*>(po_self);
  76. delete self->cppobj;
  77. self->cppobj = NULL;
  78. Py_TYPE(self)->tp_free(self);
  79. }
  80. PyObject*
  81. ConfigurableClientList_configure(PyObject* po_self, PyObject* args) {
  82. s_ConfigurableClientList* self =
  83. static_cast<s_ConfigurableClientList*>(po_self);
  84. try {
  85. const char* configuration;
  86. int allow_cache;
  87. if (PyArg_ParseTuple(args, "si", &configuration, &allow_cache)) {
  88. const isc::data::ConstElementPtr
  89. element(isc::data::Element::fromJSON(string(configuration)));
  90. self->cppobj->configure(element, allow_cache);
  91. Py_RETURN_NONE;
  92. } else {
  93. return (NULL);
  94. }
  95. } catch (const isc::data::JSONError& jse) {
  96. const string ex_what(std::string("JSON parse error in data source"
  97. " configuration: ") + jse.what());
  98. PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
  99. return (NULL);
  100. } catch (const std::exception& exc) {
  101. PyErr_SetString(getDataSourceException("Error"), exc.what());
  102. return (NULL);
  103. } catch (...) {
  104. PyErr_SetString(getDataSourceException("Error"),
  105. "Unknown C++ exception");
  106. return (NULL);
  107. }
  108. }
  109. PyObject*
  110. ConfigurableClientList_resetMemorySegment(PyObject* po_self, PyObject* args) {
  111. s_ConfigurableClientList* self =
  112. static_cast<s_ConfigurableClientList*>(po_self);
  113. try {
  114. const char* datasrc_name_p;
  115. int mode_int;
  116. const char* config_p;
  117. if (PyArg_ParseTuple(args, "sis", &datasrc_name_p, &mode_int,
  118. &config_p)) {
  119. const std::string datasrc_name(datasrc_name_p);
  120. const isc::data::ConstElementPtr
  121. config(isc::data::Element::fromJSON(std::string(config_p)));
  122. ZoneTableSegment::MemorySegmentOpenMode mode =
  123. static_cast<ZoneTableSegment::MemorySegmentOpenMode>
  124. (mode_int);
  125. self->cppobj->resetMemorySegment(datasrc_name, mode, config);
  126. Py_RETURN_NONE;
  127. }
  128. } catch (const isc::data::JSONError& jse) {
  129. const string ex_what(std::string("JSON parse error in memory segment"
  130. " configuration: ") + jse.what());
  131. PyErr_SetString(getDataSourceException("Error"), ex_what.c_str());
  132. } catch (const std::exception& exc) {
  133. PyErr_SetString(getDataSourceException("Error"), exc.what());
  134. } catch (...) {
  135. PyErr_SetString(getDataSourceException("Error"),
  136. "Unknown C++ exception");
  137. }
  138. return (NULL);
  139. }
  140. PyObject*
  141. ConfigurableClientList_getCachedZoneWriter(PyObject* po_self, PyObject* args) {
  142. s_ConfigurableClientList* self =
  143. static_cast<s_ConfigurableClientList*>(po_self);
  144. try {
  145. PyObject* name_obj;
  146. const char* datasrc_name_p = "";
  147. if (PyArg_ParseTuple(args, "O!|s", &isc::dns::python::name_type,
  148. &name_obj, &datasrc_name_p)) {
  149. const isc::dns::Name
  150. name(isc::dns::python::PyName_ToName(name_obj));
  151. const std::string datasrc_name(datasrc_name_p);
  152. const ConfigurableClientList::ZoneWriterPair result =
  153. self->cppobj->getCachedZoneWriter(name, datasrc_name);
  154. PyObjectContainer writer;
  155. if (!result.second) {
  156. // Use the Py_BuildValue, as it takes care of the
  157. // reference counts correctly.
  158. writer.reset(Py_BuildValue(""));
  159. } else {
  160. // Make sure it keeps the writer alive.
  161. writer.reset(createZoneWriterObject(result.second,
  162. po_self));
  163. }
  164. return (Py_BuildValue("IO", result.first, writer.get()));
  165. } else {
  166. return (NULL);
  167. }
  168. } catch (const std::exception& exc) {
  169. PyErr_SetString(getDataSourceException("Error"), exc.what());
  170. return (NULL);
  171. } catch (...) {
  172. PyErr_SetString(getDataSourceException("Error"),
  173. "Unknown C++ exception");
  174. return (NULL);
  175. }
  176. }
  177. PyObject*
  178. ConfigurableClientList_getStatus(PyObject* po_self, PyObject*) {
  179. s_ConfigurableClientList* self =
  180. static_cast<s_ConfigurableClientList*>(po_self);
  181. try {
  182. const std::vector<DataSourceStatus> status = self->cppobj->getStatus();
  183. PyObjectContainer slist(PyList_New(status.size()));
  184. for (size_t i = 0; i < status.size(); ++i) {
  185. PyObjectContainer segment_type;
  186. if (status[i].getSegmentState() != SEGMENT_UNUSED) {
  187. segment_type.reset(Py_BuildValue(
  188. "s", status[i].getSegmentType().c_str()));
  189. } else {
  190. Py_INCREF(Py_None);
  191. segment_type.reset(Py_None);
  192. }
  193. PyObjectContainer tup(Py_BuildValue("(sOI)",
  194. status[i].getName().c_str(),
  195. segment_type.get(),
  196. status[i].getSegmentState()));
  197. // The following "steals" our reference on tup, so we must
  198. // not decref.
  199. PyList_SET_ITEM(slist.get(), i, tup.release());
  200. }
  201. return (slist.release());
  202. } catch (const std::exception& exc) {
  203. PyErr_SetString(getDataSourceException("Error"), exc.what());
  204. return (NULL);
  205. } catch (...) {
  206. PyErr_SetString(getDataSourceException("Error"),
  207. "Unknown C++ exception");
  208. return (NULL);
  209. }
  210. }
  211. PyObject*
  212. ConfigurableClientList_find(PyObject* po_self, PyObject* args) {
  213. s_ConfigurableClientList* self =
  214. static_cast<s_ConfigurableClientList*>(po_self);
  215. try {
  216. PyObject* name_obj;
  217. int want_exact_match = 0;
  218. int want_finder = 1;
  219. if (PyArg_ParseTuple(args, "O!|ii", &isc::dns::python::name_type,
  220. &name_obj, &want_exact_match, &want_finder)) {
  221. const isc::dns::Name
  222. name(isc::dns::python::PyName_ToName(name_obj));
  223. const ClientList::FindResult
  224. result(self->cppobj->find(name, want_exact_match,
  225. want_finder));
  226. PyObjectContainer dsrc;
  227. if (result.dsrc_client_ == NULL) {
  228. // Use the Py_BuildValue, as it takes care of the
  229. // reference counts correctly.
  230. dsrc.reset(Py_BuildValue(""));
  231. } else {
  232. // Make sure we have a keeper there too, so it doesn't
  233. // die when the underlying client list dies or is
  234. // reconfigured.
  235. //
  236. // However, as it is inside the C++ part, is there a
  237. // reasonable way to test it?
  238. dsrc.reset(wrapDataSourceClient(result.dsrc_client_,
  239. result.life_keeper_));
  240. }
  241. PyObjectContainer finder;
  242. if (result.finder_ == NULL) {
  243. finder.reset(Py_BuildValue(""));
  244. } else {
  245. // Make sure it keeps the data source client alive.
  246. finder.reset(createZoneFinderObject(result.finder_,
  247. dsrc.get()));
  248. }
  249. PyObjectContainer exact(PyBool_FromLong(result.exact_match_));
  250. return (Py_BuildValue("OOO", dsrc.get(), finder.get(),
  251. exact.get()));
  252. } else {
  253. return (NULL);
  254. }
  255. } catch (const std::exception& exc) {
  256. PyErr_SetString(getDataSourceException("Error"), exc.what());
  257. return (NULL);
  258. } catch (...) {
  259. PyErr_SetString(getDataSourceException("Error"),
  260. "Unknown C++ exception");
  261. return (NULL);
  262. }
  263. }
  264. // This list contains the actual set of functions we have in
  265. // python. Each entry has
  266. // 1. Python method name
  267. // 2. Our static function here
  268. // 3. Argument type
  269. // 4. Documentation
  270. PyMethodDef ConfigurableClientList_methods[] = {
  271. { "configure", ConfigurableClientList_configure,
  272. METH_VARARGS, ConfigurableClientList_configure_doc },
  273. { "reset_memory_segment", ConfigurableClientList_resetMemorySegment,
  274. METH_VARARGS, ConfigurableClientList_reset_memory_segment_doc },
  275. { "get_cached_zone_writer", ConfigurableClientList_getCachedZoneWriter,
  276. METH_VARARGS, ConfigurableClientList_get_cached_zone_writer_doc },
  277. { "get_status", ConfigurableClientList_getStatus,
  278. METH_NOARGS, ConfigurableClientList_get_status_doc },
  279. { "find", ConfigurableClientList_find,
  280. METH_VARARGS, ConfigurableClientList_find_doc },
  281. { NULL, NULL, 0, NULL }
  282. };
  283. } // end of unnamed namespace
  284. namespace isc {
  285. namespace datasrc {
  286. namespace python {
  287. // This defines the complete type for reflection in python and
  288. // parsing of PyObject* to s_ConfigurableClientList
  289. // Most of the functions are not actually implemented and NULL here.
  290. PyTypeObject configurableclientlist_type = {
  291. PyVarObject_HEAD_INIT(NULL, 0)
  292. "datasrc.ConfigurableClientList",
  293. sizeof(s_ConfigurableClientList), // tp_basicsize
  294. 0, // tp_itemsize
  295. ConfigurableClientList_destroy, // tp_dealloc
  296. NULL, // tp_print
  297. NULL, // tp_getattr
  298. NULL, // tp_setattr
  299. NULL, // tp_reserved
  300. NULL, // tp_repr
  301. NULL, // tp_as_number
  302. NULL, // tp_as_sequence
  303. NULL, // tp_as_mapping
  304. NULL, // tp_hash
  305. NULL, // tp_call
  306. NULL, // tp_str
  307. NULL, // tp_getattro
  308. NULL, // tp_setattro
  309. NULL, // tp_as_buffer
  310. Py_TPFLAGS_DEFAULT, // tp_flags
  311. ConfigurableClientList_doc,
  312. NULL, // tp_traverse
  313. NULL, // tp_clear
  314. NULL, // tp_richcompare
  315. 0, // tp_weaklistoffset
  316. NULL, // tp_iter
  317. NULL, // tp_iternext
  318. ConfigurableClientList_methods, // tp_methods
  319. NULL, // tp_members
  320. NULL, // tp_getset
  321. NULL, // tp_base
  322. NULL, // tp_dict
  323. NULL, // tp_descr_get
  324. NULL, // tp_descr_set
  325. 0, // tp_dictoffset
  326. ConfigurableClientList_init, // tp_init
  327. NULL, // tp_alloc
  328. PyType_GenericNew, // tp_new
  329. NULL, // tp_free
  330. NULL, // tp_is_gc
  331. NULL, // tp_bases
  332. NULL, // tp_mro
  333. NULL, // tp_cache
  334. NULL, // tp_subclasses
  335. NULL, // tp_weaklist
  336. NULL, // tp_del
  337. 0 // tp_version_tag
  338. };
  339. // Module Initialization, all statics are initialized here
  340. bool
  341. initModulePart_ConfigurableClientList(PyObject* mod) {
  342. // We initialize the static description object with PyType_Ready(),
  343. // then add it to the module. This is not just a check! (leaving
  344. // this out results in segmentation faults)
  345. if (PyType_Ready(&configurableclientlist_type) < 0) {
  346. return (false);
  347. }
  348. void* p = &configurableclientlist_type;
  349. if (PyModule_AddObject(mod, "ConfigurableClientList",
  350. static_cast<PyObject*>(p)) < 0) {
  351. return (false);
  352. }
  353. Py_INCREF(&configurableclientlist_type);
  354. try {
  355. // ConfigurableClientList::CacheStatus enum
  356. installClassVariable
  357. (configurableclientlist_type,
  358. "CACHE_STATUS_CACHE_DISABLED",
  359. Py_BuildValue("I", ConfigurableClientList::CACHE_DISABLED));
  360. installClassVariable
  361. (configurableclientlist_type,
  362. "CACHE_STATUS_ZONE_NOT_CACHED",
  363. Py_BuildValue("I", ConfigurableClientList::ZONE_NOT_CACHED));
  364. installClassVariable
  365. (configurableclientlist_type,
  366. "CACHE_STATUS_ZONE_NOT_FOUND",
  367. Py_BuildValue("I", ConfigurableClientList::ZONE_NOT_FOUND));
  368. installClassVariable
  369. (configurableclientlist_type,
  370. "CACHE_STATUS_CACHE_NOT_WRITABLE",
  371. Py_BuildValue("I", ConfigurableClientList::CACHE_NOT_WRITABLE));
  372. installClassVariable
  373. (configurableclientlist_type,
  374. "CACHE_STATUS_DATASRC_NOT_FOUND",
  375. Py_BuildValue("I", ConfigurableClientList::DATASRC_NOT_FOUND));
  376. installClassVariable
  377. (configurableclientlist_type,
  378. "CACHE_STATUS_ZONE_SUCCESS",
  379. Py_BuildValue("I", ConfigurableClientList::ZONE_SUCCESS));
  380. // MemorySegmentState enum
  381. installClassVariable(configurableclientlist_type,
  382. "SEGMENT_UNUSED",
  383. Py_BuildValue("I", SEGMENT_UNUSED));
  384. installClassVariable(configurableclientlist_type,
  385. "SEGMENT_WAITING",
  386. Py_BuildValue("I", SEGMENT_WAITING));
  387. installClassVariable(configurableclientlist_type,
  388. "SEGMENT_INUSE",
  389. Py_BuildValue("I", SEGMENT_INUSE));
  390. // FIXME: These should eventually be moved to the
  391. // ZoneTableSegment class when we add Python bindings for the
  392. // memory data source specific bits. But for now, we add these
  393. // enums here to support reloading a zone table segment.
  394. installClassVariable(configurableclientlist_type, "CREATE",
  395. Py_BuildValue("I", ZoneTableSegment::CREATE));
  396. installClassVariable(configurableclientlist_type, "READ_WRITE",
  397. Py_BuildValue("I", ZoneTableSegment::READ_WRITE));
  398. installClassVariable(configurableclientlist_type, "READ_ONLY",
  399. Py_BuildValue("I", ZoneTableSegment::READ_ONLY));
  400. } catch (const std::exception& ex) {
  401. const std::string ex_what =
  402. "Unexpected failure in ConfigurableClientList initialization: " +
  403. std::string(ex.what());
  404. PyErr_SetString(po_IscException, ex_what.c_str());
  405. return (false);
  406. } catch (...) {
  407. PyErr_SetString(PyExc_SystemError,
  408. "Unexpected failure in ConfigurableClientList initialization");
  409. return (false);
  410. }
  411. return (true);
  412. }
  413. } // namespace python
  414. } // namespace datasrc
  415. } // namespace isc