Commit cf5ed0e7 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[trac983] added a new module function: load_request_acl()

parent 47286f0b
SUBDIRS = . tests
AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
#Do we need boost?
#AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CPPFLAGS += $(BOOST_INCLUDES)
AM_CXXFLAGS = $(B10_CXXFLAGS)
pyexec_LTLIBRARIES = dns.la
dns_la_SOURCES = dns.cc
dns_la_SOURCES = dns.cc dns_requestacl_python.h dns_requestacl_python.cc
dns_la_CPPFLAGS = $(AM_CPPFLAGS) $(PYTHON_INCLUDES)
dns_la_LDFLAGS = $(PYTHON_LDFLAGS)
# Note: PYTHON_CXXFLAGS may have some -Wno... workaround, which must be
......@@ -16,5 +15,5 @@ acl_la_CXXFLAGS = $(AM_CXXFLAGS) $(PYTHON_CXXFLAGS)
# Python prefers .so, while some OSes (specifically MacOS) use a different
# suffix for dynamic objects. -module is necessary to work this around.
dns_la_LDFLAGS += -module
dns_la_LIBADD = $(top_builddir)/src/lib/acl/libacl.la
dns_la_LIBADD = $(top_builddir)/src/lib/acl/libdnsacl.la
dns_la_LIBADD += $(PYTHON_LIB)
......@@ -14,17 +14,69 @@
#include <Python.h>
#include <stdexcept>
#include <boost/shared_ptr.hpp>
#include <util/python/pycppwrapper_util.h>
#include <cc/data.h>
#include <acl/acl.h>
#include <acl/dns.h>
#include "dns_requestacl_python.h"
using namespace std;
using boost::shared_ptr;
using namespace isc::util::python;
using namespace isc::data;
using namespace isc::acl::dns;
using namespace isc::acl::dns::python;
namespace {
PyObject* po_dns_LoaderError;
PyObject*
loadRequestACL(PyObject*, PyObject* args) {
const char* acl_config;
if (PyArg_ParseTuple(args, "s", &acl_config)) {
try {
shared_ptr<RequestACL> acl(
getRequestLoader().load(Element::fromJSON(acl_config)));
s_RequestACL* py_acl = static_cast<s_RequestACL*>(
requestacl_type.tp_alloc(&requestacl_type, 0));
if (py_acl != NULL) {
py_acl->cppobj = acl;
}
return (py_acl);
} catch (const exception& ex) {
PyErr_SetString(po_dns_LoaderError, ex.what());
return (NULL);
} catch (...) {
PyErr_SetString(PyExc_SystemError, "Unexpected C++ exception");
return (NULL);
}
}
return (NULL);
}
PyMethodDef methods[] = {
{ "load_request_acl", loadRequestACL, METH_VARARGS, "TBD" },
{ NULL, NULL, 0, NULL }
};
PyModuleDef dnsacl = {
{ PyObject_HEAD_INIT(NULL) NULL, 0, NULL},
"acl",
"isc.acl.dns",
"This module provides Python bindings for the C++ classes in the "
"isc::acl::dns namespace. Specifically, it defines Python interfaces of "
"handling access control lists (ACLs) with DNS related contexts.\n\n"
"These bindings are close match to the C++ API, but they are not complete "
"(some parts are not needed) and some are done in more python-like ways.",
-1,
NULL,
methods,
NULL,
NULL,
NULL,
......@@ -34,5 +86,25 @@ PyModuleDef dnsacl = {
PyMODINIT_FUNC
PyInit_dns(void) {
return (PyModule_Create(&dnsacl));
PyObject* mod = PyModule_Create(&dnsacl);
if (mod == NULL) {
return (NULL);
}
try {
po_dns_LoaderError = PyErr_NewException("isc.acl.dns.LoaderError",
NULL, NULL);
PyObjectContainer(po_dns_LoaderError).installToModule(mod,
"LoaderError");
} catch (...) {
Py_DECREF(mod);
return (NULL);
}
if (!initModulePart_RequestACL(mod)) {
Py_DECREF(mod);
return (NULL);
}
return (mod);
}
// Copyright (C) 2011 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 <string>
#include <stdexcept>
#include <util/python/pycppwrapper_util.h>
#include <acl/acl.h>
#include <acl/dns.h>
#include "dns_requestacl_python.h"
using namespace std;
using namespace isc::util::python;
using namespace isc::acl;
using namespace isc::acl::dns;
using namespace isc::acl::dns::python;
//
// Definition of the classes
//
// For each class, we need a struct, a helper functions (init, destroy,
// and static wrappers around the methods we export), a list of methods,
// and a type description
//
// RequestACL
//
// Trivial constructor.
s_RequestACL::s_RequestACL() {}
namespace {
// Shortcut type which would be convenient for adding class variables safely.
typedef CPPPyObjectContainer<s_RequestACL, RequestACL> RequestACLContainer;
//
// We declare the functions here, the definitions are below
// the type definition of the object, since both can use the other
//
// General creation and destruction
int RequestACL_init(s_RequestACL* self, PyObject* args);
void RequestACL_destroy(s_RequestACL* self);
// These are the functions we export
// For a minimal support, we don't need them.
// 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 RequestACL_methods[] = {
{ NULL, NULL, 0, NULL }
};
// This is a template of typical code logic of python class initialization
// with C++ backend. You'll need to adjust it according to details of the
// actual C++ class.
int
RequestACL_init(s_RequestACL* self, PyObject* /*args*/) {
// maybe we should prohibit direct creation of the ACL
try {
#ifdef notyet
if (PyArg_ParseTuple(args, "REPLACE ME")) {
// YOU'LL NEED SOME VALIDATION, PREPARATION, ETC, HERE.
self->cppobj = new RequestACL(/*NECESSARY PARAMS*/);
return (0);
}
#endif
self->cppobj.reset(new RequestACL(REJECT));
return (0);
} catch (const exception& ex) {
const string ex_what = "Failed to construct RequestACL object: " +
string(ex.what());
//PyErr_SetString(po_IscException, ex_what.c_str());
PyErr_SetString(PyExc_TypeError, ex_what.c_str());
return (-1);
} catch (...) {
PyErr_SetString(/*po_IscException*/PyExc_TypeError,
"Unexpected exception in constructing RequestACL");
return (-1);
}
PyErr_SetString(PyExc_TypeError,
"Invalid arguments to RequestACL constructor");
return (-1);
}
// This is a template of typical code logic of python object destructor.
// In many cases you can use it without modification, but check that carefully.
void
RequestACL_destroy(s_RequestACL* const self) {
self->cppobj.reset();
Py_TYPE(self)->tp_free(self);
}
} // end of unnamed namespace
namespace isc {
namespace acl {
namespace dns {
namespace python {
// This defines the complete type for reflection in python and
// parsing of PyObject* to s_RequestACL
// Most of the functions are not actually implemented and NULL here.
PyTypeObject requestacl_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"pydnspp.RequestACL",
sizeof(s_RequestACL), // tp_basicsize
0, // tp_itemsize
reinterpret_cast<destructor>(RequestACL_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
"The RequestACL class objects is...(COMPLETE THIS)",
NULL, // tp_traverse
NULL, // tp_clear
NULL, // tp_richcompare
0, // tp_weaklistoffset
NULL, // tp_iter
NULL, // tp_iternext
RequestACL_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>(RequestACL_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
};
// Module Initialization, all statics are initialized here
bool
initModulePart_RequestACL(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(&requestacl_type) < 0) {
return (false);
}
void* p = &requestacl_type;
if (PyModule_AddObject(mod, "RequestACL", static_cast<PyObject*>(p)) < 0) {
return (false);
}
Py_INCREF(&requestacl_type);
#if 0 // we probably don't have any class vars
// The following template is the typical procedure for installing class
// variables. If the class doesn't have a class variable, remove the
// entire try-catch clauses.
try {
// Constant class variables
installClassVariable(requestacl_type, "REPLACE_ME",
Py_BuildValue("REPLACE ME"));
} catch (const exception& ex) {
const string ex_what =
"Unexpected failure in RequestACL initialization: " +
string(ex.what());
PyErr_SetString(po_IscException, ex_what.c_str());
return (false);
} catch (...) {
PyErr_SetString(PyExc_SystemError,
"Unexpected failure in RequestACL initialization");
return (false);
}
#endif
return (true);
}
} // namespace python
} // namespace dns
} // namespace acl
} // namespace isc
// Copyright (C) 2011 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_REQUESTACL_H
#define __PYTHON_REQUESTACL_H 1
#include <Python.h>
#include <boost/shared_ptr.hpp>
#include <acl/dns.h>
namespace isc {
namespace acl {
namespace dns {
namespace python {
// The s_* Class simply covers one instantiation of the object
class s_RequestACL : public PyObject {
public:
s_RequestACL();
boost::shared_ptr<RequestACL> cppobj;
};
extern PyTypeObject requestacl_type;
bool initModulePart_RequestACL(PyObject* mod);
} // namespace python
} // namespace dns
} // namespace acl
} // namespace isc
#endif // __PYTHON_REQUESTACL_H
// Local Variables:
// mode: c++
// End:
......@@ -7,7 +7,7 @@ EXTRA_DIST = $(PYTESTS)
# required by loadable python modules.
LIBRARY_PATH_PLACEHOLDER =
if SET_ENV_LIBRARY_PATH
LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/acl/.libs:$(abs_top_builddir)/src/lib/cc/.libs:$(abs_top_builddir)/src/lib/config/.libs:$(abs_top_builddir)/src/lib/log/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
LIBRARY_PATH_PLACEHOLDER += $(ENV_LIBRARY_PATH)=$(abs_top_builddir)/src/lib/cryptolink/.libs:$(abs_top_builddir)/src/lib/dns/.libs:$(abs_top_builddir)/src/lib/acl/.libs:$(abs_top_builddir)/src/lib/cc/.libs:$(abs_top_builddir)/src/lib/config/.libs:$(abs_top_builddir)/src/lib/log/.libs:$(abs_top_builddir)/src/lib/util/.libs:$(abs_top_builddir)/src/lib/exceptions/.libs:$$$(ENV_LIBRARY_PATH)
endif
# test using command-line arguments, so use check-local target instead of TESTS
......
......@@ -16,10 +16,60 @@
import unittest
from isc.acl.dns import *
class DNSACLTest(unittest.TestCase):
class RequestACLTest(unittest.TestCase):
def test_placeholder(self):
pass
def test_request_loader(self):
# these shouldn't raise an exception
load_request_acl('[{"action": "DROP"}]')
load_request_acl('[{"action": "DROP", "from": "192.0.2.1"}]')
# Invalid types
self.assertRaises(TypeError, load_request_acl, 1)
self.assertRaises(TypeError, load_request_acl, [])
# Incorrect number of arguments
self.assertRaises(TypeError, load_request_acl,
'[{"action": "DROP"}]', 0)
def test_bad_acl_syntax(self):
# this test is derived from loader_test.cc
self.assertRaises(LoaderError, load_request_acl, '{}');
self.assertRaises(LoaderError, load_request_acl, '42');
self.assertRaises(LoaderError, load_request_acl, 'true');
self.assertRaises(LoaderError, load_request_acl, 'null');
self.assertRaises(LoaderError, load_request_acl, '"hello"');
self.assertRaises(LoaderError, load_request_acl, '[42]');
self.assertRaises(LoaderError, load_request_acl, '["hello"]');
self.assertRaises(LoaderError, load_request_acl, '[[]]');
self.assertRaises(LoaderError, load_request_acl, '[true]');
self.assertRaises(LoaderError, load_request_acl, '[null]');
self.assertRaises(LoaderError, load_request_acl, '[{}]');
def test_bad_acl_ipsyntax(self):
# this test is derived from ip_check_unittest.cc
self.assertRaises(LoaderError, load_request_acl,
'[{"action": "DROP", "from": "192.0.2.43/-1"}]')
self.assertRaises(LoaderError, load_request_acl,
'[{"action": "DROP", "from": "192.0.2.43//1"')
self.assertRaises(LoaderError, load_request_acl,
'[{"action": "DROP", "from": "192.0.2.43/1/"')
self.assertRaises(LoaderError, load_request_acl,
'[{"action": "DROP", "from": "/192.0.2.43/1"')
self.assertRaises(LoaderError, load_request_acl,
'[{"action": "DROP", "from": "2001:db8::/xxxx"')
self.assertRaises(LoaderError, load_request_acl,
'[{"action": "DROP", "from": "2001:db8::/32/s"')
self.assertRaises(LoaderError, load_request_acl,
'[{"action": "DROP", "from": "1/"')
self.assertRaises(LoaderError, load_request_acl,
'[{"action": "DROP", "from": "/1"')
self.assertRaises(LoaderError, load_request_acl,
'[{"action": "DROP", "from": "192.0.2.0/33"')
self.assertRaises(LoaderError, load_request_acl,
'[{"action": "DROP", "from": "::1/129"')
def test_construct(self):
RequestACL()
if __name__ == '__main__':
unittest.main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment