Browse Source

Merge branch 'trac2908'

Paul Selkirk 12 years ago
parent
commit
638087de4e

+ 0 - 2
src/lib/datasrc/client_list.h

@@ -121,8 +121,6 @@ private:
     MemorySegmentState state_;
 };
 
-typedef boost::shared_ptr<const ZoneTableAccessor> ConstZoneTableAccessorPtr;
-
 /// \brief The list of data source clients.
 ///
 /// The purpose of this class is to hold several data source clients and search

+ 3 - 0
src/lib/datasrc/zone_table_accessor.h

@@ -202,6 +202,9 @@ public:
     virtual IteratorPtr getIterator() const = 0;
 };
 
+typedef boost::shared_ptr<ZoneTableAccessor> ZoneTableAccessorPtr;
+typedef boost::shared_ptr<const ZoneTableAccessor> ConstZoneTableAccessorPtr;
+
 }
 }
 

+ 2 - 0
src/lib/python/isc/datasrc/Makefile.am

@@ -21,6 +21,8 @@ datasrc_la_SOURCES += journal_reader_python.cc journal_reader_python.h
 datasrc_la_SOURCES += configurableclientlist_python.cc
 datasrc_la_SOURCES += configurableclientlist_python.h
 datasrc_la_SOURCES += zone_loader_python.cc zone_loader_python.h
+datasrc_la_SOURCES += zonetable_accessor_python.cc zonetable_accessor_python.h
+datasrc_la_SOURCES += zonetable_iterator_python.cc zonetable_iterator_python.h
 
 datasrc_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
 datasrc_la_CXXFLAGS = $(AM_CXXFLAGS) $(PYTHON_CXXFLAGS)

+ 47 - 5
src/lib/python/isc/datasrc/configurableclientlist_python.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2013  Internet Systems Consortium, Inc. ("ISC")
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
@@ -35,6 +35,7 @@
 #include "datasrc.h"
 #include "finder_python.h"
 #include "client_python.h"
+#include "zonetable_accessor_python.h"
 
 using namespace std;
 using namespace isc::util::python;
@@ -206,6 +207,37 @@ ConfigurableClientList_find(PyObject* po_self, PyObject* args) {
     }
 }
 
+PyObject*
+ConfigurableClientList_getZoneTableAccessor(PyObject* po_self, PyObject* args) {
+    s_ConfigurableClientList* self =
+        static_cast<s_ConfigurableClientList*>(po_self);
+    try {
+        const char* datasrc_name;
+        int use_cache;
+        if (PyArg_ParseTuple(args, "zi", &datasrc_name, &use_cache)) {
+            // python 'None' will be read as NULL, which we convert to an
+            // empty string, meaning "any data source"
+            const std::string name(datasrc_name ? datasrc_name : "");
+            const ConstZoneTableAccessorPtr
+                z(self->cppobj->getZoneTableAccessor(name, use_cache));
+            if (z == NULL) {
+                Py_RETURN_NONE;
+            } else {
+                return (createZoneTableAccessorObject(z, po_self));
+            }
+        } else {
+            return (NULL);
+        }
+    } catch (const std::exception& exc) {
+        PyErr_SetString(getDataSourceException("Error"), exc.what());
+        return (NULL);
+    } catch (...) {
+        PyErr_SetString(getDataSourceException("Error"),
+                        "Unknown C++ exception");
+        return (NULL);
+    }
+}
+
 // This list contains the actual set of functions we have in
 // python. Each entry has
 // 1. Python method name
@@ -261,6 +293,16 @@ you don't need it, but if you do need it, it is better to set it to True\
 instead of getting it from the datasrc_client later.\n\
 \n\
 If no answer is found, the datasrc_client and zone_finder are None." },
+    { "get_zone_table_accessor", ConfigurableClientList_getZoneTableAccessor,
+      METH_VARARGS,
+"get_zone_table_accessor(datasrc_name, use_cache) -> \
+isc.datasrc.ZoneTableAccessor\n\
+\n\
+Create a ZoneTableAccessor object for the specified data source.\n\
+\n\
+Parameters:\n\
+  datasrc_name      If not empty, the name of the data source\
+  use_cache         If true, create a zone table for in-memory cache." },
     { NULL, NULL, 0, NULL }
 };
 
@@ -286,9 +328,9 @@ namespace python {
 PyTypeObject configurableclientlist_type = {
     PyVarObject_HEAD_INIT(NULL, 0)
     "datasrc.ConfigurableClientList",
-    sizeof(s_ConfigurableClientList),                 // tp_basicsize
+    sizeof(s_ConfigurableClientList),   // tp_basicsize
     0,                                  // tp_itemsize
-    ConfigurableClientList_destroy,                 // tp_dealloc
+    ConfigurableClientList_destroy,     // tp_dealloc
     NULL,                               // tp_print
     NULL,                               // tp_getattr
     NULL,                               // tp_setattr
@@ -311,7 +353,7 @@ PyTypeObject configurableclientlist_type = {
     0,                                  // tp_weaklistoffset
     NULL,                               // tp_iter
     NULL,                               // tp_iternext
-    ConfigurableClientList_methods,                   // tp_methods
+    ConfigurableClientList_methods,     // tp_methods
     NULL,                               // tp_members
     NULL,                               // tp_getset
     NULL,                               // tp_base
@@ -319,7 +361,7 @@ PyTypeObject configurableclientlist_type = {
     NULL,                               // tp_descr_get
     NULL,                               // tp_descr_set
     0,                                  // tp_dictoffset
-    ConfigurableClientList_init,                    // tp_init
+    ConfigurableClientList_init,        // tp_init
     NULL,                               // tp_alloc
     PyType_GenericNew,                  // tp_new
     NULL,                               // tp_free

+ 48 - 0
src/lib/python/isc/datasrc/datasrc.cc

@@ -33,6 +33,8 @@
 #include "journal_reader_python.h"
 #include "configurableclientlist_python.h"
 #include "zone_loader_python.h"
+#include "zonetable_accessor_python.h"
+#include "zonetable_iterator_python.h"
 
 #include <util/python/pycppwrapper_util.h>
 #include <dns/python/pydnspp_common.h>
@@ -255,6 +257,42 @@ initModulePart_ZoneJournalReader(PyObject* mod) {
     return (true);
 }
 
+bool
+initModulePart_ZoneTableAccessor(PyObject* mod) {
+    // We initialize the static description object with PyType_Ready(),
+    // then add it to the module. This is not just a check! (leaving
+    // this out results in segmentation faults)
+    if (PyType_Ready(&zonetableaccessor_type) < 0) {
+        return (false);
+    }
+    void* p = &zonetableaccessor_type;
+    if (PyModule_AddObject(mod, "ZoneTableAccessor",
+                           static_cast<PyObject*>(p)) < 0) {
+        return (false);
+    }
+    Py_INCREF(&zonetableaccessor_type);
+
+    return (true);
+}
+
+bool
+initModulePart_ZoneTableIterator(PyObject* mod) {
+    // We initialize the static description object with PyType_Ready(),
+    // then add it to the module. This is not just a check! (leaving
+    // this out results in segmentation faults)
+    if (PyType_Ready(&zonetableiterator_type) < 0) {
+        return (false);
+    }
+    void* p = &zonetableiterator_type;
+    if (PyModule_AddObject(mod, "ZoneTableIterator",
+                           static_cast<PyObject*>(p)) < 0) {
+        return (false);
+    }
+    Py_INCREF(&zonetableiterator_type);
+
+    return (true);
+}
+
 PyObject* po_DataSourceError;
 PyObject* po_MasterFileError;
 PyObject* po_NotImplemented;
@@ -340,5 +378,15 @@ PyInit_datasrc(void) {
         return (NULL);
     }
 
+    if (!initModulePart_ZoneTableAccessor(mod)) {
+        Py_DECREF(mod);
+        return (NULL);
+    }
+
+    if (!initModulePart_ZoneTableIterator(mod)) {
+        Py_DECREF(mod);
+        return (NULL);
+    }
+
     return (mod);
 }

+ 2 - 2
src/lib/python/isc/datasrc/finder_python.cc

@@ -64,7 +64,7 @@ getFindResultFlags(const ZoneFinder::Context& context) {
 
 namespace isc_datasrc_internal {
 // This is the shared code for the find() call in the finder and the updater
-// Is is intentionally not available through any header, nor at our standard
+// It is intentionally not available through any header, nor at our standard
 // namespace, as it is not supposed to be called anywhere but from finder and
 // updater
 PyObject* ZoneFinder_helper(ZoneFinder* finder, PyObject* args) {
@@ -184,7 +184,7 @@ public:
     ZoneFinderPtr cppobj;
     // This is a reference to a base object; if the object of this class
     // depends on another object to be in scope during its lifetime,
-    // we use INCREF the base object upon creation, and DECREF it at
+    // we INCREF the base object upon creation, and DECREF it at
     // the end of the destructor
     // This is an optional argument to createXXX(). If NULL, it is ignored.
     PyObject* base_obj;

+ 82 - 2
src/lib/python/isc/datasrc/tests/clientlist_test.py

@@ -1,4 +1,4 @@
-# Copyright (C) 2012  Internet Systems Consortium.
+# Copyright (C) 2012-2013  Internet Systems Consortium.
 #
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
@@ -57,7 +57,7 @@ class ClientListTest(unittest.TestCase):
     def test_configure(self):
         """
         Test we can configure the client list. This tests if the valid
-        ones are acceptend and invalid rejected. We check the changes
+        ones are accepted and invalid rejected. We check the changes
         have effect.
         """
         self.clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN)
@@ -151,6 +151,86 @@ class ClientListTest(unittest.TestCase):
         self.assertRaises(TypeError, self.clist.find, "example.org")
         self.assertRaises(TypeError, self.clist.find)
 
+    def test_get_zone_table_accessor(self):
+        """
+        Test that we can get the zone table accessor and, thereby,
+        the zone table iterator.
+        """
+        self.clist = isc.datasrc.ConfigurableClientList(isc.dns.RRClass.IN)
+
+        # null configuration
+        self.clist.configure("[]", True)
+        self.assertIsNone(self.clist.get_zone_table_accessor(None, True))
+
+        # empty configuration
+        self.clist.configure('''[{
+            "type": "MasterFiles",
+            "params": {},
+            "cache-enable": true
+        }]''', True)
+        # bogus datasrc
+        self.assertIsNone(self.clist.get_zone_table_accessor("bogus", True))
+        # first datasrc - empty zone table
+        table = self.clist.get_zone_table_accessor(None, True)
+        self.assertIsNotNone(table)
+        iterator = iter(table)
+        self.assertIsNotNone(iterator)
+        self.assertEqual(0, len(list(iterator)))
+
+        # normal configuration
+        self.clist.configure('''[{
+            "type": "MasterFiles",
+            "params": {
+                "example.org": "''' + TESTDATA_PATH + '''example.org.zone"
+            },
+            "cache-enable": true
+        }]''', True)
+        # !use_cache => NotImplemented
+        self.assertRaises(isc.datasrc.Error,
+                          self.clist.get_zone_table_accessor, None, False)
+        # bogus datasrc
+        self.assertIsNone(self.clist.get_zone_table_accessor("bogus", True))
+
+        # first datasrc
+        table = self.clist.get_zone_table_accessor(None, True)
+        self.assertIsNotNone(table)
+        zonelist = list(table)
+        self.assertEqual(1, len(zonelist))
+        self.assertEqual(zonelist[0][1], isc.dns.Name("example.org"))
+
+        # named datasrc
+        table = self.clist.get_zone_table_accessor("MasterFiles", True)
+        self.assertEqual(zonelist, list(table))
+
+        # longer zone list for non-trivial iteration
+        self.clist.configure('''[{
+            "type": "MasterFiles",
+            "params": {
+                "example.org": "''' + TESTDATA_PATH + '''example.org.zone",
+                "example.com": "''' + TESTDATA_PATH + '''example.com.zone",
+                "example.net": "''' + TESTDATA_PATH + '''example.net.zone",
+                "example.biz": "''' + TESTDATA_PATH + '''example.biz.zone",
+                "example.edu": "''' + TESTDATA_PATH + '''example.edu.zone"
+            },
+            "cache-enable": true
+        }]''', True)
+        zonelist = list(self.clist.get_zone_table_accessor(None, True))
+        self.assertEqual(5, len(zonelist))
+        self.assertTrue((0, isc.dns.Name("example.net.")) in zonelist)
+
+        # ensure the iterator returns exactly and only the zones we expect
+        zonelist = [
+            isc.dns.Name("example.org"),
+            isc.dns.Name("example.com"),
+            isc.dns.Name("example.net"),
+            isc.dns.Name("example.biz"),
+            isc.dns.Name("example.edu")]
+        table = self.clist.get_zone_table_accessor("MasterFiles", True)
+        for index, zone in table:
+            self.assertTrue(zone in zonelist)
+            zonelist.remove(zone)
+        self.assertEqual(0, len(zonelist))
+
 if __name__ == "__main__":
     isc.log.init("bind10")
     isc.log.resetUnitTestRootLogger()

+ 178 - 0
src/lib/python/isc/datasrc/zonetable_accessor_python.cc

@@ -0,0 +1,178 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// Enable this if you use s# variants with PyArg_ParseTuple(), see
+// http://docs.python.org/py3k/c-api/arg.html#strings-and-buffers
+//#define PY_SSIZE_T_CLEAN
+
+// Python.h needs to be placed at the head of the program file, see:
+// http://docs.python.org/py3k/extending/extending.html#a-simple-example
+#include <Python.h>
+
+#include <datasrc/zone_table_accessor.h>
+
+#include "datasrc.h"
+#include "zonetable_accessor_python.h"
+#include "zonetable_iterator_python.h"
+
+using namespace std;
+using namespace isc::datasrc;
+using namespace isc::datasrc::python;
+
+namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_ZoneTableAccessor : public PyObject {
+public:
+    s_ZoneTableAccessor() : cppobj(ConstZoneTableAccessorPtr()) {};
+    ConstZoneTableAccessorPtr cppobj;
+    // This is a reference to a base object; if the object of this class
+    // depends on another object to be in scope during its lifetime,
+    // we use INCREF the base object upon creation, and DECREF it at
+    // the end of the destructor
+    // This is an optional argument to createXXX(). If NULL, it is ignored.
+    PyObject* base_obj;
+};
+
+int
+ZoneTableAccessor_init(PyObject*, PyObject*, PyObject*) {
+    // can't be called directly
+    PyErr_SetString(PyExc_TypeError,
+                    "ZoneTableAccessor cannot be constructed directly");
+
+    return (-1);
+}
+
+void
+ZoneTableAccessor_destroy(PyObject* po_self) {
+    s_ZoneTableAccessor* const self =
+        static_cast<s_ZoneTableAccessor*>(po_self);
+    // cppobj is a shared ptr, but to make sure things are not destroyed in
+    // the wrong order, we reset it here.
+    self->cppobj.reset();
+    if (self->base_obj != NULL) {
+        Py_DECREF(self->base_obj);
+    }
+    Py_TYPE(self)->tp_free(self);
+}
+
+PyObject*
+ZoneTableAccessor_iter(PyObject* po_self) {
+    s_ZoneTableAccessor* const self =
+        static_cast<s_ZoneTableAccessor*>(po_self);
+    try {
+        return (createZoneTableIteratorObject(self->cppobj->getIterator(),
+                                              po_self));
+    } catch (const std::exception& exc) {
+        PyErr_SetString(getDataSourceException("Error"), exc.what());
+        return (NULL);
+    } catch (...) {
+        PyErr_SetString(getDataSourceException("Error"),
+                        "Unexpected exception");
+        return (NULL);
+    }
+}
+
+// This list contains the actual set of functions we have in
+// python. Each entry has
+// 1. Python method name
+// 2. Our static function here
+// 3. Argument type
+// 4. Documentation
+PyMethodDef ZoneTableAccessor_methods[] = {
+    { NULL, NULL, 0, NULL }
+};
+
+const char* const ZoneTableAccessor_doc = "\
+An accessor to a zone table for a data source.\n\
+\n\
+This class object is intended to be used by applications that load zones\
+into memory, so that the application can get a list of zones to be loaded.";
+
+} // end anonymous namespace
+
+namespace isc {
+namespace datasrc {
+namespace python {
+// This defines the complete type for reflection in python and
+// parsing of PyObject* to s_ZoneTableAccessor
+// Most of the functions are not actually implemented and NULL here.
+PyTypeObject zonetableaccessor_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "datasrc.ZoneTableAccessor",
+    sizeof(s_ZoneTableAccessor),        // tp_basicsize
+    0,                                  // tp_itemsize
+    ZoneTableAccessor_destroy,          // tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash
+    NULL,                               // tp_call
+    NULL,                               // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                 // tp_flags
+    ZoneTableAccessor_doc,              // tp_doc
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    NULL,                               // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    ZoneTableAccessor_iter,             // tp_iter
+    NULL,                               // tp_iternext
+    ZoneTableAccessor_methods,          // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,                               // tp_base
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    ZoneTableAccessor_init,             // tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
+
+PyObject*
+createZoneTableAccessorObject(isc::datasrc::ConstZoneTableAccessorPtr source,
+                              PyObject* base_obj)
+{
+    s_ZoneTableAccessor* py_zt = static_cast<s_ZoneTableAccessor*>(
+        zonetableaccessor_type.tp_alloc(&zonetableaccessor_type, 0));
+    if (py_zt != NULL) {
+        py_zt->cppobj = source;
+        py_zt->base_obj = base_obj;
+        if (base_obj != NULL) {
+            Py_INCREF(base_obj);
+        }
+    }
+    return (py_zt);
+}
+
+} // namespace python
+} // namespace datasrc
+} // namespace isc

+ 43 - 0
src/lib/python/isc/datasrc/zonetable_accessor_python.h

@@ -0,0 +1,43 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef PYTHON_ZONETABLE_ACCESSOR_H
+#define PYTHON_ZONETABLE_ACCESSOR_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace datasrc {
+namespace python {
+
+extern PyTypeObject zonetableaccessor_type;
+
+/// \brief Create a ZoneTableAccessor python object
+///
+/// \param source The zone iterator pointer to wrap
+/// \param base_obj An optional PyObject that this ZoneFinder depends on
+///                 Its refcount is increased, and will be decreased when
+///                 this zone iterator is destroyed, making sure that the
+///                 base object is never destroyed before this zonefinder.
+PyObject* createZoneTableAccessorObject(
+    isc::datasrc::ConstZoneTableAccessorPtr source, PyObject* base_obj);
+
+} // namespace python
+} // namespace datasrc
+} // namespace isc
+#endif // PYTHON_ZONETABLE_ACCESSOR_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 197 - 0
src/lib/python/isc/datasrc/zonetable_iterator_python.cc

@@ -0,0 +1,197 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// Enable this if you use s# variants with PyArg_ParseTuple(), see
+// http://docs.python.org/py3k/c-api/arg.html#strings-and-buffers
+//#define PY_SSIZE_T_CLEAN
+
+// Python.h needs to be placed at the head of the program file, see:
+// http://docs.python.org/py3k/extending/extending.html#a-simple-example
+#include <Python.h>
+
+#include <datasrc/zone_table_accessor.h>
+#include <dns/python/name_python.h>
+
+#include "datasrc.h"
+#include "zonetable_iterator_python.h"
+
+using namespace std;
+using namespace isc::datasrc;
+using namespace isc::datasrc::python;
+
+namespace {
+// The s_* Class simply covers one instantiation of the object
+class s_ZoneTableIterator : public PyObject {
+public:
+    s_ZoneTableIterator() :
+        cppobj(ZoneTableAccessor::IteratorPtr()), base_obj(NULL)
+    {};
+
+    ZoneTableAccessor::IteratorPtr cppobj;
+    // This is a reference to a base object; if the object of this class
+    // depends on another object to be in scope during its lifetime,
+    // we use INCREF the base object upon creation, and DECREF it at
+    // the end of the destructor
+    // This is an optional argument to createXXX(). If NULL, it is ignored.
+    PyObject* base_obj;
+};
+
+// General creation and destruction
+int
+ZoneTableIterator_init(s_ZoneTableIterator* self, PyObject* args) {
+    // can't be called directly
+    PyErr_SetString(PyExc_TypeError,
+                    "ZoneTableIterator cannot be constructed directly");
+
+    return (-1);
+}
+
+void
+ZoneTableIterator_destroy(s_ZoneTableIterator* const self) {
+    // cppobj is a shared ptr, but to make sure things are not destroyed in
+    // the wrong order, we reset it here.
+    self->cppobj.reset();
+    if (self->base_obj != NULL) {
+        Py_DECREF(self->base_obj);
+    }
+    Py_TYPE(self)->tp_free(self);
+}
+
+//
+// We declare the functions here, the definitions are below
+// the type definition of the object, since both can use the other
+//
+PyObject*
+ZoneTableIterator_iter(PyObject *self) {
+    Py_INCREF(self);
+    return (self);
+}
+
+PyObject*
+ZoneTableIterator_next(PyObject* po_self) {
+    s_ZoneTableIterator* self = static_cast<s_ZoneTableIterator*>(po_self);
+    if (!self->cppobj || self->cppobj->isLast()) {
+        return (NULL);
+    }
+    try {
+        const isc::datasrc::ZoneSpec& zs = self->cppobj->getCurrent();
+        PyObject* result =
+            Py_BuildValue("iO", zs.index,
+                          isc::dns::python::createNameObject(zs.origin));
+        self->cppobj->next();
+        return (result);
+    } catch (const std::exception& exc) {
+        // isc::InvalidOperation is thrown when we call getCurrent()
+        // when we are already done iterating ('iterating past end')
+        // We could also simply return None again
+        PyErr_SetString(getDataSourceException("Error"), exc.what());
+        return (NULL);
+    } catch (...) {
+        PyErr_SetString(getDataSourceException("Error"),
+                        "Unexpected exception");
+        return (NULL);
+    }
+}
+
+PyMethodDef ZoneTableIterator_methods[] = {
+    { NULL, NULL, 0, NULL }
+};
+
+const char* const ZoneTableIterator_doc = "\
+Read-only iterator to a zone table.\n\
+\n\
+You can get an instance of the ZoneTableIterator from the\
+ZoneTableAccessor.get_iterator() method.\n\
+\n\
+There's no way to start iterating from the beginning again or return.\n\
+\n\
+The ZoneTableIterator is a Python iterator, and can be iterated over\
+directly.\n\
+";
+
+} // end of unnamed namespace
+
+namespace isc {
+namespace datasrc {
+namespace python {
+PyTypeObject zonetableiterator_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "datasrc.ZoneTableIterator",
+    sizeof(s_ZoneTableIterator),        // tp_basicsize
+    0,                                  // tp_itemsize
+    reinterpret_cast<destructor>(ZoneTableIterator_destroy),// tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash
+    NULL,                               // tp_call
+    NULL,                               // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                 // tp_flags
+    ZoneTableIterator_doc,              // tp_doc
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    NULL,                               // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    ZoneTableIterator_iter,             // tp_iter
+    ZoneTableIterator_next,             // tp_iternext
+    ZoneTableIterator_methods,          // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,                               // tp_base
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    reinterpret_cast<initproc>(ZoneTableIterator_init),// tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
+
+PyObject*
+createZoneTableIteratorObject(ZoneTableAccessor::IteratorPtr source,
+                              PyObject* base_obj)
+{
+    s_ZoneTableIterator* py_zi = static_cast<s_ZoneTableIterator*>(
+        zonetableiterator_type.tp_alloc(&zonetableiterator_type, 0));
+    if (py_zi != NULL) {
+        py_zi->cppobj = source;
+        py_zi->base_obj = base_obj;
+        if (base_obj != NULL) {
+            Py_INCREF(base_obj);
+        }
+    }
+    return (py_zi);
+}
+
+} // namespace python
+} // namespace datasrc
+} // namespace isc
+

+ 44 - 0
src/lib/python/isc/datasrc/zonetable_iterator_python.h

@@ -0,0 +1,44 @@
+// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef PYTHON_ZONETABLE_ITERATOR_H
+#define PYTHON_ZONETABLE_ITERATOR_H 1
+
+#include <Python.h>
+
+namespace isc {
+namespace datasrc {
+namespace python {
+
+extern PyTypeObject zonetableiterator_type;
+
+/// \brief Create a ZoneTableIterator python object
+///
+/// \param source The zone table iterator pointer to wrap
+/// \param base_obj An optional PyObject that this ZoneIterator depends on
+///                 Its refcount is increased, and will be decreased when
+///                 this zone iterator is destroyed, making sure that the
+///                 base object is never destroyed before this zone iterator.
+PyObject* createZoneTableIteratorObject(
+    isc::datasrc::ZoneTableAccessor::IteratorPtr source,
+    PyObject* base_obj = NULL);
+
+} // namespace python
+} // namespace datasrc
+} // namespace isc
+#endif // PYTHON_ZONETABLE_ITERATOR_H
+
+// Local Variables:
+// mode: c++
+// End: