diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..5da8bea --- /dev/null +++ b/.clang-format @@ -0,0 +1,8 @@ +# PEP 7 +BasedOnStyle: Google +AlwaysBreakAfterReturnType: All +ColumnLimit: 0 +IndentWidth: 4 +Language: Cpp +PointerAlignment: Right +SpaceAfterCStyleCast: false diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..ae3c5ca --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,38 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/python +{ + "name": "Python KEA Development", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "build": { + "dockerfile": "../containers/kea-python-dev/Dockerfile", + "context": "..", + "args": { + "BASE_OS_VERSION": "ubuntu-20.04", + "ARG PYTHON_VERSION": "3.8", + "ARG KEA_VERSION": "2.6.0" + } + }, + + "customizations": { + "vscode": { + "extensions": [ + "ms-vscode.cpptools-extension-pack" + ] + } + }, + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "pip3 install --user -r requirements.txt", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + "remoteUser": "root" +} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..c3146d6 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,18 @@ +repos: + +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.1.0 + hooks: + - id: check-added-large-files + - id: check-merge-conflict + - id: check-symlinks + - id: check-yaml + - id: detect-private-key + - id: end-of-file-fixer + - id: trailing-whitespace + +- repo: https://github.com/pre-commit/mirrors-clang-format + rev: 'v18.1.8' # Use the sha / tag you want to point at + hooks: + - id: clang-format + types_or: [c++, c] diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index b5a5b25..0000000 --- a/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -ARG VER -FROM kea-dev:$VER AS build - -WORKDIR /source -COPY . . - -RUN make clean install \ - && mkdir /dist \ - && cd /usr/local \ - && find lib -name \*.so\* | tar cf - -T - | (cd /dist; tar xf -) \ - && tar cf - etc share/man bin sbin var | (cd /dist; tar xf -) - -FROM ubuntu:21.04 -ENV DEBIAN_FRONTEND noninteractive - -RUN apt-get update -y \ - && apt-get -y install \ - procps \ - socat \ - python3 \ - libpython3.9 \ - liblog4cplus-2.0.5 \ - libboost-system1.74.0 \ - libffi8ubuntu1 \ - libpq5 \ - libmariadb3 - -COPY --from=build /dist /usr/local - -RUN ldconfig diff --git a/DockerfileDev b/DockerfileDev deleted file mode 100644 index 7591791..0000000 --- a/DockerfileDev +++ /dev/null @@ -1,37 +0,0 @@ -# syntax=docker/dockerfile:1 - -FROM debian:bullseye-slim AS build - -ARG VER -ENV DEBIAN_FRONTEND noninteractive - -WORKDIR /source -COPY kea-$VER.tar.gz . - -RUN apt-get update -y \ - && apt-get -y install --no-install-recommends \ - build-essential \ - libboost-system-dev \ - libkrb5-dev \ - liblog4cplus-dev \ - libmariadb-dev \ - libmariadb-dev-compat \ - libssl-dev=1.1.1* \ - libpython3-dev \ - postgresql-server-dev-all \ - python3-pytest \ - python3-setuptools \ - && tar xzf kea-$VER.tar.gz \ - && cd kea-$VER \ - && ./configure \ - --enable-shell \ - --with-site-packages=/usr/lib/python3/dist-packages \ - --enable-perfdhcp \ - --enable-generate-messages \ - --with-mysql=/usr/bin/mysql_config \ - --with-pgsql=/usr/bin/pg_config \ - && make --silent --jobs=$(nproc) \ - && make install \ - && ldconfig \ - && apt-get clean \ - && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* /source \ No newline at end of file diff --git a/Makefile.am b/Makefile.am index 1f77b29..2d329fc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,28 +7,28 @@ AUTOMAKE_OPTIONS = foreign SUBDIRS = keahook keamodule -KEA_VESION ?= 2.4.1 +KEA_VERSION ?= 2.6.0 CONTAINER_RUNTIME ?= $(if $(shell command -v podman ;),podman,docker) .PHONY: build-kea-dev build-kea-dev: - $(CONTAINER_RUNTIME) build --build-arg KEA_VESION=$(KEA_VESION) -f DockerfileDev --tag kea-dev:$(KEA_VESION) . + $(CONTAINER_RUNTIME) build -f containers/kea-python-dev/Dockerfile --build-arg KEA_VERSION=$(KEA_VERSION) --tag kea-dev:$(KEA_VERSION) . .PHONY: build-kea build-kea: - $(CONTAINER_RUNTIME) build --build-arg KEA_VESION=$(KEA_VESION) --tag kea:$(KEA_VESION) . + $(CONTAINER_RUNTIME) build -f containers/kea-python/Dockerfile --build-arg KEA_VERSION=$(KEA_VERSION) --tag kea:$(KEA_VERSION) . .PHONY: build-dhtest build-dhtest: - cd dhtest && $(CONTAINER_RUNTIME) build --tag dhtest . + $(CONTAINER_RUNTIME) build -f containers/dhtest/Dockerfile --tag dhtest . .PHONY: run-kea-dev run-kea-dev: kea-network - $(CONTAINER_RUNTIME) run --rm -it --network kea -e LANG=C.UTF-8 --privileged -v`pwd`:/workdir --name kea-dev kea-dev:$(KEA_VESION) bash + $(CONTAINER_RUNTIME) run --rm -it --network kea -e LANG=C.UTF-8 --privileged -v`pwd`:/workdir --name kea-dev kea-dev:$(KEA_VERSION) bash .PHONY: run-kea run-kea: kea-network - $(CONTAINER_RUNTIME) run --rm -it --network kea -e LANG=C.UTF-8 --privileged -v`pwd`:/workdir --name kea kea:$(KEA_VESION) bash + $(CONTAINER_RUNTIME) run --rm -it --network kea -e LANG=C.UTF-8 --privileged -v`pwd`:/workdir --name kea kea:$(KEA_VERSION) bash .PHONY: run-mysql run-mysql: kea-network dhcpdb_create.mysql.sql @@ -48,5 +48,8 @@ kea-network: .PHONY: dhcpdb_create.mysql.sql dhcpdb_create.mysql.sql: - tar xz --strip-components 6 -f kea-$(KEA_VESION).tar.gz kea-$(KEA_VESION)/src/share/database/scripts/mysql/dhcpdb_create.mysql - mv dhcpdb_create.mysql dhcpdb_create.mysql.sql \ No newline at end of file + tar xz --strip-components 6 -f kea-$(KEA_VERSION).tar.gz kea-$(KEA_VERSION)/src/share/database/scripts/mysql/dhcpdb_create.mysql + mv dhcpdb_create.mysql dhcpdb_create.mysql.sql + +install-exec-hook: + cd $(srcdir)/keamodule && $(MAKE) install diff --git a/configure.ac b/configure.ac index bb964cf..341d4d1 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. -AC_INIT(kea_python, 1.1) +AC_INIT([kea-python], [1.2.0], [jgomez@phicus.es], [kea-python]) AM_INIT_AUTOMAKE(foreign) diff --git a/dhtest/Dockerfile b/containers/dhtest/Dockerfile similarity index 100% rename from dhtest/Dockerfile rename to containers/dhtest/Dockerfile diff --git a/containers/kea-python-dev/Dockerfile b/containers/kea-python-dev/Dockerfile new file mode 100644 index 0000000..64cdf26 --- /dev/null +++ b/containers/kea-python-dev/Dockerfile @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: MPL-2.0 + +ARG BASE_OS_VERSION=ubuntu-20.04 +FROM mcr.microsoft.com/vscode/devcontainers/cpp:${BASE_OS_VERSION} + +ARG PYTHON_VERSION=3.8 +ARG KEA_VERSION=2.6.0 + +LABEL org.opencontainers.image.authors="Juan Gomez " + +ENV DEBIAN_FRONTEND=noninteractive \ + BASE_OS_VERSION=${BASE_OS_VERSION} \ + PYTHON_VERSION=${PYTHON_VERSION} \ + KEA_VERSION=${KEA_VERSION} + + +RUN apt-get update \ + && apt-get upgrade -y \ + && apt-get install --no-install-recommends -y \ + software-properties-common \ + apt-transport-https \ + apt-utils \ + bash \ + ca-certificates \ + curl \ + gnupg \ + && add-apt-repository -y ppa:deadsnakes/ppa \ + && curl -1sLf "https://dl.cloudsmith.io/public/isc/kea-$(echo "${KEA_VERSION}" | cut -c1;)-$(echo "${KEA_VERSION}" | cut -c3;)/setup.deb.sh" | bash \ + && apt-get update \ + && apt-get install --no-install-recommends -y \ + autoconf \ + automake \ + autoconf-archive \ + libtool \ + libffi-dev \ + libboost-dev \ + libboost-system-dev \ + make \ + g++ \ + python${PYTHON_VERSION} \ + python${PYTHON_VERSION}-dev \ + python3-pip \ + isc-kea-dev \ + isc-kea-hooks \ + isc-kea-dhcp4 \ + # Clean up to reduce image size + && apt-get clean \ + && rm -rf /etc/apt/sources.list.d/isc-kea-* /var/lib/apt/lists/* /tmp/* /var/tmp/* \ + && update-alternatives --install /usr/bin/python3 python3 /usr/bin/python${PYTHON_VERSION} 1 diff --git a/containers/kea-python/Dockerfile b/containers/kea-python/Dockerfile new file mode 100644 index 0000000..f8fdbca --- /dev/null +++ b/containers/kea-python/Dockerfile @@ -0,0 +1,38 @@ +ARG KEA_VERSION=2.6.0 + +FROM kea-dev:$KEA_VERSION AS build + +WORKDIR /source +COPY . . + +# RUN make clean install \ +# && mkdir /dist \ +# && cd /usr/local \ +# && find lib -name \*.so\* | tar cf - -T - | (cd /dist; tar xf -) \ +# && tar cf - etc share/man bin sbin var | (cd /dist; tar xf -) + +RUN autoreconf -i && \ + ./configure --prefix=/usr --libdir=${prefix}/lib/x86_64-linux-gnu --libexecdir=${prefix}/lib/x86_64-linux-gnu && \ + make install + +# FROM ubuntu:21.04 +# ENV DEBIAN_FRONTEND noninteractive + +# RUN apt-get update -y \ +# && apt-get -y install \ +# procps \ +# socat \ +# python3 \ +# libpython3.9 \ +# liblog4cplus-2.0.5 \ +# libboost-system1.74.0 \ +# libffi8ubuntu1 \ +# libpq5 \ +# libmariadb3 + +# COPY --from=build /dist /usr/local + +# RUN ldconfig + + +# podman build -f ./containers/kea-python/Dockerfile --build-arg KEA_VERSION=2.6.0 -t kea-python:2.6.0 -t kea-python . && podman run -it kea-python bash diff --git a/keamodule/Makefile.am b/keamodule/Makefile.am index 68ca29e..0b039fc 100644 --- a/keamodule/Makefile.am +++ b/keamodule/Makefile.am @@ -1,3 +1,14 @@ -install: - $(PYTHON) setup.py install \ No newline at end of file + +EXTRA_DIST = setup.py + +install: setup.py + $(PYTHON) setup.py install + +all-local: setup.py + $(PYTHON) setup.py build + +clean-local: setup.py + -$(PYTHON) setup.py clean --all + -find $(srcdir) \( -name "build" -o -name "dist" -o -name "*.pyc" \ + -o -name "*.egg-info" \) -exec rm -rf '{}' \+ \ No newline at end of file diff --git a/keamodule/callout_handle.cc b/keamodule/callout_handle.cc index d598cf1..9ad227c 100644 --- a/keamodule/callout_handle.cc +++ b/keamodule/callout_handle.cc @@ -1,6 +1,7 @@ -#include "keamodule.h" #include +#include "keamodule.h" + using namespace std; using namespace isc::hooks; using namespace isc::dhcp; @@ -21,8 +22,7 @@ CalloutHandle_getArgument(CalloutHandleObject *self, PyObject *args) { Lease4Ptr ptr; self->handle->getArgument(name, ptr); return (Lease4_from_handle(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -33,21 +33,18 @@ CalloutHandle_getArgument(CalloutHandleObject *self, PyObject *args) { Lease4CollectionPtr ptr; self->handle->getArgument(name, ptr); return (Leases4_from_handle(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } } - if (strcmp(name, "query4") == 0 || strcmp(name, "response4") == 0) { try { Pkt4Ptr ptr; self->handle->getArgument(name, ptr); return (Pkt4_from_handle(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -58,8 +55,7 @@ CalloutHandle_getArgument(CalloutHandleObject *self, PyObject *args) { ConstElementPtr ptr; self->handle->getArgument(name, ptr); return (element_to_object(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -86,8 +82,7 @@ CalloutHandle_setArgument(CalloutHandleObject *self, PyObject *args) { try { self->handle->setArgument(name, ((Lease4Object *)value)->ptr); Py_RETURN_NONE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -101,8 +96,7 @@ CalloutHandle_setArgument(CalloutHandleObject *self, PyObject *args) { try { self->handle->setArgument(name, ((Pkt4Object *)value)->ptr); Py_RETURN_NONE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -116,8 +110,7 @@ CalloutHandle_setArgument(CalloutHandleObject *self, PyObject *args) { } self->handle->setArgument(name, ptr); Py_RETURN_NONE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -127,9 +120,8 @@ CalloutHandle_setArgument(CalloutHandleObject *self, PyObject *args) { return (0); } - -ObjectHolder::ObjectHolder(PyObject *obj): obj_(obj) { - Py_INCREF(obj); +ObjectHolder::ObjectHolder(PyObject *obj) : obj_(obj) { + Py_INCREF(obj); } ObjectHolder::~ObjectHolder() { @@ -154,8 +146,7 @@ CalloutHandle_setContext(CalloutHandleObject *self, PyObject *args) { try { self->handle->setContext(name, ObjectHolderPtr(new ObjectHolder(value))); Py_RETURN_NONE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -174,8 +165,7 @@ CalloutHandle_getContext(CalloutHandleObject *self, PyObject *args) { self->handle->getContext(name, ptr); Py_INCREF(ptr->obj_); return (ptr->obj_); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -192,8 +182,7 @@ CalloutHandle_deleteContext(CalloutHandleObject *self, PyObject *args) { try { self->handle->deleteContext(name); Py_RETURN_NONE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -203,8 +192,7 @@ static PyObject * CalloutHandle_getStatus(CalloutHandleObject *self, PyObject *args) { try { return PyLong_FromLong(self->handle->getStatus()); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -221,27 +209,26 @@ CalloutHandle_setStatus(CalloutHandleObject *self, PyObject *args) { try { self->handle->setStatus(CalloutHandle::CalloutNextStep(status)); Py_RETURN_NONE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } } static PyMethodDef CalloutHandle_methods[] = { - {"getArgument", (PyCFunction) CalloutHandle_getArgument, METH_VARARGS, + {"getArgument", (PyCFunction)CalloutHandle_getArgument, METH_VARARGS, "Gets the value of an argument."}, - {"setArgument", (PyCFunction) CalloutHandle_setArgument, METH_VARARGS, + {"setArgument", (PyCFunction)CalloutHandle_setArgument, METH_VARARGS, "Sets the value of an argument."}, - {"setContext", (PyCFunction) CalloutHandle_setContext, METH_VARARGS, + {"setContext", (PyCFunction)CalloutHandle_setContext, METH_VARARGS, "Sets an element in the context associated with the current library."}, - {"getContext", (PyCFunction) CalloutHandle_getContext, METH_VARARGS, + {"getContext", (PyCFunction)CalloutHandle_getContext, METH_VARARGS, "Gets an element from the context associated with the current library."}, - {"deleteContext", (PyCFunction) CalloutHandle_deleteContext, METH_VARARGS, + {"deleteContext", (PyCFunction)CalloutHandle_deleteContext, METH_VARARGS, "Deletes an item of the given name from the context associated with the current library. If an item of that name does not exist, the method is a no-op."}, - {"getStatus", (PyCFunction) CalloutHandle_getStatus, METH_NOARGS, + {"getStatus", (PyCFunction)CalloutHandle_getStatus, METH_NOARGS, "Gets the next processing step."}, - {"setStatus", (PyCFunction) CalloutHandle_setStatus, METH_VARARGS, + {"setStatus", (PyCFunction)CalloutHandle_setStatus, METH_VARARGS, "Sets the next processing step."}, {0} // Sentinel }; @@ -251,7 +238,7 @@ CalloutHandle_dealloc(CalloutHandleObject *self) { if (self->is_owner) { delete self->handle; } - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); } static int @@ -269,8 +256,7 @@ CalloutHandle_init(CalloutHandleObject *self, PyObject *args, PyObject *kwds) { try { self->handle = new CalloutHandle(((CalloutManagerObject *)manager)->manager); self->is_owner = true; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -281,20 +267,19 @@ CalloutHandle_init(CalloutHandleObject *self, PyObject *args, PyObject *kwds) { static PyObject * CalloutHandle_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { CalloutHandleObject *self; - self = (CalloutHandleObject *) type->tp_alloc(type, 0); + self = (CalloutHandleObject *)type->tp_alloc(type, 0); if (self) { self->handle = 0; self->is_owner = false; } - return ((PyObject *) self); + return ((PyObject *)self); } PyTypeObject CalloutHandleType = { - PyObject_HEAD_INIT(0) - "kea.CalloutHandle", // tp_name + PyObject_HEAD_INIT(0) "kea.CalloutHandle", // tp_name sizeof(CalloutHandleObject), // tp_basicsize 0, // tp_itemsize - (destructor) CalloutHandle_dealloc, // tp_dealloc + (destructor)CalloutHandle_dealloc, // tp_dealloc 0, // tp_vectorcall_offset 0, // tp_getattr 0, // tp_setattr @@ -325,7 +310,7 @@ PyTypeObject CalloutHandleType = { 0, // tp_descr_get 0, // tp_descr_set 0, // tp_dictoffset - (initproc) CalloutHandle_init, // tp_init + (initproc)CalloutHandle_init, // tp_init PyType_GenericAlloc, // tp_alloc CalloutHandle_new // tp_new }; @@ -341,17 +326,17 @@ CalloutHandle_from_handle(CalloutHandle *handle) { } int -CalloutHandle_define() { +CalloutHandle_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&CalloutHandleType) < 0) { - return (1); + return -1; } Py_INCREF(&CalloutHandleType); - if (PyModule_AddObject(kea_module, "CalloutHandle", (PyObject *) &CalloutHandleType) < 0) { + if (PyModule_AddObject( + kea_module, "CalloutHandle", (PyObject *)&CalloutHandleType) < 0) { Py_DECREF(&CalloutHandleType); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/callout_manager.cc b/keamodule/callout_manager.cc index 8bfdec1..d58ee27 100644 --- a/keamodule/callout_manager.cc +++ b/keamodule/callout_manager.cc @@ -15,19 +15,19 @@ CalloutManager_use_count(CalloutManagerObject *self, void *closure) { } static PyGetSetDef CalloutManager_getsetters[] = { - {(char *)"use_count", (getter) CalloutManager_use_count, (setter) 0, (char *)"shared_ptr use count", 0}, + {(char *)"use_count", (getter)CalloutManager_use_count, (setter)0, (char *)"shared_ptr use count", 0}, {0} // Sentinel }; static void CalloutManager_dealloc(CalloutManagerObject *self) { self->manager.~CalloutManagerPtr(); - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); } static int CalloutManager_init(CalloutManagerObject *self, PyObject *args, PyObject *kwds) { - new(&self->manager) CalloutManagerPtr; + new (&self->manager) CalloutManagerPtr; if (kwds != 0) { PyErr_SetString(PyExc_TypeError, "keyword arguments are not supported"); @@ -39,8 +39,7 @@ CalloutManager_init(CalloutManagerObject *self, PyObject *args, PyObject *kwds) try { self->manager.reset(new CalloutManager()); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -51,66 +50,64 @@ CalloutManager_init(CalloutManagerObject *self, PyObject *args, PyObject *kwds) static PyObject * CalloutManager_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { CalloutManagerObject *self; - self = (CalloutManagerObject *) type->tp_alloc(type, 0); + self = (CalloutManagerObject *)type->tp_alloc(type, 0); if (self) { - new(&self->manager) CalloutManagerPtr; + new (&self->manager) CalloutManagerPtr; } - return ((PyObject *) self); + return ((PyObject *)self); } PyTypeObject CalloutManagerType = { - PyObject_HEAD_INIT(0) - "kea.CalloutManager", // tp_name - sizeof(CalloutManagerObject), // tp_basicsize - 0, // tp_itemsize - (destructor) CalloutManager_dealloc, // tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server CalloutManager", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - CalloutManager_methods, // tp_methods - 0, // tp_members - CalloutManager_getsetters, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc) CalloutManager_init, // tp_init - PyType_GenericAlloc, // tp_alloc - CalloutManager_new // tp_new + PyObject_HEAD_INIT(0) "kea.CalloutManager", // tp_name + sizeof(CalloutManagerObject), // tp_basicsize + 0, // tp_itemsize + (destructor)CalloutManager_dealloc, // tp_dealloc + 0, // tp_vectorcall_offset + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_as_async + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "Kea server CalloutManager", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + CalloutManager_methods, // tp_methods + 0, // tp_members + CalloutManager_getsetters, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + (initproc)CalloutManager_init, // tp_init + PyType_GenericAlloc, // tp_alloc + CalloutManager_new // tp_new }; int -CalloutManager_define() { +CalloutManager_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&CalloutManagerType) < 0) { - return (1); + return -1; } Py_INCREF(&CalloutManagerType); - if (PyModule_AddObject(kea_module, "CalloutManager", (PyObject *) &CalloutManagerType) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&CalloutManagerType) < 0) { Py_DECREF(&CalloutManagerType); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/capsule.cc b/keamodule/capsule.cc index 20f85cc..2c79f3a 100644 --- a/keamodule/capsule.cc +++ b/keamodule/capsule.cc @@ -1,8 +1,9 @@ #include "keamodule.h" #define KEA_MODULE -#include "keacapsule.h" #include +#include "keacapsule.h" + using namespace isc::hooks; using namespace isc::log; using namespace std; @@ -45,8 +46,7 @@ Logger_debug(LoggerObject *self, PyObject *args) { } try { LOG_DEBUG(*kea_logger, DBGLVL_TRACE_BASIC, *kea_message_id).arg(string(msg)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -63,8 +63,7 @@ Logger_info(LoggerObject *self, PyObject *args) { } try { LOG_INFO(*kea_logger, *kea_message_id).arg(string(msg)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -81,8 +80,7 @@ Logger_warn(LoggerObject *self, PyObject *args) { } try { LOG_WARN(*kea_logger, *kea_message_id).arg(string(msg)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -90,7 +88,6 @@ Logger_warn(LoggerObject *self, PyObject *args) { Py_RETURN_NONE; } - static PyObject * Logger_error(LoggerObject *self, PyObject *args) { char *msg; @@ -100,8 +97,7 @@ Logger_error(LoggerObject *self, PyObject *args) { } try { LOG_ERROR(*kea_logger, *kea_message_id).arg(string(msg)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -118,8 +114,7 @@ Logger_fatal(LoggerObject *self, PyObject *args) { } try { LOG_FATAL(*kea_logger, *kea_message_id).arg(string(msg)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -142,16 +137,13 @@ Logger_exception(LoggerObject *self, PyObject *args) { if (!format_python_traceback(exc_type, exc_value, exc_traceback, traceback)) { if (strlen(msg) == 0) { LOG_ERROR(*kea_logger, *kea_message_id).arg(traceback); - } - else { + } else { LOG_ERROR(*kea_logger, *kea_message_id).arg(string(msg) + "\n" + traceback); } - } - else { + } else { LOG_ERROR(*kea_logger, *kea_message_id).arg(string(msg)); } - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -160,17 +152,17 @@ Logger_exception(LoggerObject *self, PyObject *args) { } static PyMethodDef Logger_methods[] = { - {"debug", (PyCFunction) Logger_debug, METH_VARARGS, + {"debug", (PyCFunction)Logger_debug, METH_VARARGS, "Log a debug message to the kea logger"}, - {"info", (PyCFunction) Logger_info, METH_VARARGS, + {"info", (PyCFunction)Logger_info, METH_VARARGS, "Log an info message to the kea logger."}, - {"warn", (PyCFunction) Logger_warn, METH_VARARGS, + {"warn", (PyCFunction)Logger_warn, METH_VARARGS, "Log an warn message to the kea logger."}, - {"error", (PyCFunction) Logger_error, METH_VARARGS, + {"error", (PyCFunction)Logger_error, METH_VARARGS, "Log an error message to the kea logger."}, - {"fatal", (PyCFunction) Logger_fatal, METH_VARARGS, + {"fatal", (PyCFunction)Logger_fatal, METH_VARARGS, "Log a fatal message to the kea logger."}, - {"exception", (PyCFunction) Logger_exception, METH_VARARGS, + {"exception", (PyCFunction)Logger_exception, METH_VARARGS, "Log an error and traceback to the kea logger."}, {0} // Sentinel }; @@ -181,44 +173,43 @@ Logger_dealloc(LoggerObject *self) { } static PyTypeObject LoggerType = { - PyObject_HEAD_INIT(0) - "kea.Logger", // tp_name - sizeof(LoggerObject), // tp_basicsize - 0, // tp_itemsize - (destructor)Logger_dealloc, // tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server logging", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - Logger_methods, // tp_methods - 0, // tp_members - 0, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - 0, // tp_init - PyType_GenericAlloc, // tp_alloc - PyType_GenericNew // tp_new + PyObject_HEAD_INIT(0) "kea.Logger", // tp_name + sizeof(LoggerObject), // tp_basicsize + 0, // tp_itemsize + (destructor)Logger_dealloc, // tp_dealloc + 0, // tp_vectorcall_offset + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_as_async + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "Kea server logging", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + Logger_methods, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + PyType_GenericAlloc, // tp_alloc + PyType_GenericNew // tp_new }; void @@ -229,8 +220,7 @@ log_error(string msg) { } if (kea_logger) { LOG_ERROR(*kea_logger, *kea_message_id).arg(msg); - } - else { + } else { PyObject *exc_type, *exc_value, *exc_traceback; PyObject *logger = 0; PyObject *res = 0; @@ -242,7 +232,7 @@ log_error(string msg) { } res = PyObject_CallMethod(logger, "error", "s", msg.c_str()); -error: + error: Py_XDECREF(logger); Py_XDECREF(res); PyErr_Restore(exc_type, exc_value, exc_traceback); @@ -250,7 +240,7 @@ log_error(string msg) { } static void -Kea_SetLogger(Logger &logger, MessageID& ident) { +Kea_SetLogger(Logger &logger, MessageID &ident) { kea_logger = &logger; kea_message_id = &ident; } @@ -267,8 +257,7 @@ split_module_path(const string module, string &module_path, string &module_name) // extract module basename by removing .py if it is present if (boost::algorithm::ends_with(module, ".py")) { module_name = module.substr(basename_pos, module.size() - basename_pos - 3); - } - else { + } else { module_name = module.substr(basename_pos, module.size() - basename_pos); } return (0); @@ -370,7 +359,7 @@ Kea_Unload() { } int -Capsule_define() { +Capsule_registerTypes(PyObject *mod) { static void *kea_capsule[Kea_API_pointers]; PyObject *c_api_object = 0; @@ -382,16 +371,15 @@ Capsule_define() { c_api_object = PyCapsule_New((void *)kea_capsule, "kea._C_API", 0); if (PyModule_AddObject(kea_module, "_C_API", c_api_object) < 0) { Py_XDECREF(c_api_object); - return (1); + return -1; } // initialize logger of None - will be replaced with Capsule Kea_Load Py_INCREF(Py_None); if (PyModule_AddObject(kea_module, "logger", Py_None) < 0) { Py_DECREF(Py_None); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/cfg_mgr.cc b/keamodule/cfg_mgr.cc index b1d4dee..dfd4378 100644 --- a/keamodule/cfg_mgr.cc +++ b/keamodule/cfg_mgr.cc @@ -1,114 +1,167 @@ -#include "keamodule.h" #include +#include "keamodule.h" + using namespace std; using namespace isc::dhcp; extern "C" { +static PyObject * +CfgMgr_instance(CfgMgrObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { + static CfgMgrObject *cfg_mgr_obj = NULL; + + if (cfg_mgr_obj == NULL) { + cfg_mgr_obj = (CfgMgrObject *)CfgMgrType.tp_alloc(&CfgMgrType, 0); + if (cfg_mgr_obj == NULL) { + return PyErr_NoMemory(); + } + try { + cfg_mgr_obj->cfg_mgr = &CfgMgr::instance(); + } catch (const std::exception &e) { + Py_DECREF(cfg_mgr_obj); + cfg_mgr_obj = NULL; + PyErr_SetString(PyExc_RuntimeError, e.what()); + return NULL; + } + } + + Py_INCREF(cfg_mgr_obj); + return (PyObject *)cfg_mgr_obj; +} + +static PyObject * +CfgMgr_getDataDir(CfgMgrObject *self, PyObject *Py_UNUSED(args)) { + const char *datadir = self->cfg_mgr->getDataDir().get().c_str(); + + PyObject *result = PyUnicode_DecodeUTF8(datadir, strlen(datadir), NULL); + + if (result == NULL) { + return PyErr_NoMemory(); + } + + return result; +} + +static PyObject * +CfgMgr_setDataDir(CfgMgrObject *self, PyObject *args) { + const char *datadir; + int unspecified = 1; + + if (!PyArg_ParseTuple(args, "s|i", &datadir, &unspecified)) { + return NULL; + } + + self->cfg_mgr->setDataDir(std::string(datadir), unspecified); + + Py_RETURN_NONE; +} + static PyObject * CfgMgr_getCurrentCfg(CfgMgrObject *self, PyObject *args) { try { - SrvConfigPtr ptr = CfgMgr::instance().getCurrentCfg(); - return (SrvConfig_from_ptr(ptr)); - } - catch (const exception &e) { + SrvConfigPtr ptr = self->cfg_mgr->getCurrentCfg(); + return SrvConfig_from_ptr(ptr); + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); - return (0); + return NULL; } } static PyObject * CfgMgr_getStagingCfg(CfgMgrObject *self, PyObject *args) { try { - SrvConfigPtr ptr = CfgMgr::instance().getStagingCfg(); + SrvConfigPtr ptr = self->cfg_mgr->getStagingCfg(); return (SrvConfig_from_ptr(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); - return (0); + return NULL; } } +PyDoc_STRVAR(CfgMgr_instance_doc, + "Returns a single instance of Configuration Manager\n\n" + "CfgMgr.instance() is a singleton."); + +PyDoc_STRVAR(CfgMgr_getDataDir_doc, + "Returns path do the data directory\n\n" + "This method returns a path to writable directory that DHCP servers can store data in."); + +PyDoc_STRVAR(CfgMgr_setDataDir_doc, + "Sets new data directory."); + +PyDoc_STRVAR(CfgMgr_getCurrentCfg_doc, + "Returns the current configuration.\n\n" + "This function returns pointer to the current configuration. If the current configuration " + "is not set it will create a default configuration and return it."); + +PyDoc_STRVAR(CfgMgr_getStagingCfg_doc, + "Returns the staging configuration.\n\n" + "The staging configuration is used by the configuration parsers to create new configuration. " + "The staging configuration doesn't affect the server's operation until it is committed. " + "The staging configuration is a non-const object which can be modified by the caller."); + static PyMethodDef CfgMgr_methods[] = { - {"getCurrentCfg", (PyCFunction) CfgMgr_getCurrentCfg, METH_NOARGS, - "Returns the current configuration."}, - {"getStagingCfg", (PyCFunction) CfgMgr_getStagingCfg, METH_NOARGS, - "Returns the staging configuration."}, - {0} // Sentinel -}; + // clang-format off + {"instance", (PyCFunction)CfgMgr_instance, METH_NOARGS | METH_STATIC, + CfgMgr_instance_doc}, + {"getDataDir", (PyCFunction)CfgMgr_getDataDir, METH_NOARGS, + CfgMgr_getDataDir_doc}, + {"setDataDir", (PyCFunction)CfgMgr_setDataDir, METH_VARARGS, + CfgMgr_setDataDir_doc}, + {"getCurrentCfg", (PyCFunction)CfgMgr_getCurrentCfg, METH_NOARGS, + CfgMgr_getCurrentCfg_doc}, + {"getStagingCfg", (PyCFunction)CfgMgr_getStagingCfg, METH_NOARGS, + CfgMgr_getStagingCfg_doc}, + {NULL, NULL, 0, NULL} // Sentinel +}; // clang-format on static void CfgMgr_dealloc(CfgMgrObject *self) { - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); } -static int -CfgMgr_init(CfgMgrObject *self, PyObject *args, PyObject *kwds) { - if (kwds != 0) { - PyErr_SetString(PyExc_TypeError, "keyword arguments are not supported"); - return (-1); +static PyObject * +CfgMgr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + static CfgMgrObject *instance = NULL; + static char *kwlist[] = {NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { + PyErr_SetString(PyExc_TypeError, "kea.CfgMgr() takes no arguments"); + return NULL; } - if (!PyArg_ParseTuple(args, "")) { - return (-1); + + if (instance == NULL) { + instance = (CfgMgrObject *)CfgMgr_instance(instance, args); } - return (0); + Py_INCREF(instance); + return (PyObject *)instance; } -PyTypeObject CfgMgrType = { - PyObject_HEAD_INIT(0) - "kea.CfgMgr", // tp_name - sizeof(CfgMgrObject), // tp_basicsize - 0, // tp_itemsize - (destructor) CfgMgr_dealloc, // tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server CfgMgr", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - CfgMgr_methods, // tp_methods - 0, // tp_members - 0, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc) CfgMgr_init, // tp_init - PyType_GenericAlloc, // tp_alloc - PyType_GenericNew // tp_new -}; +PyTypeObject CfgMgrType = { // clang-format off + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "kea.CfgMgr", + .tp_basicsize = sizeof(CfgMgrObject), + .tp_dealloc = (destructor) CfgMgr_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = PyDoc_STR("Kea CfgMgr singleton object"), + .tp_methods = CfgMgr_methods, + .tp_new = CfgMgr_new +}; // clang-format on int -CfgMgr_define() { +CfgMgr_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&CfgMgrType) < 0) { - return (1); + return -1; } Py_INCREF(&CfgMgrType); - if (PyModule_AddObject(kea_module, "CfgMgr", (PyObject *) &CfgMgrType) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&CfgMgrType) < 0) { Py_DECREF(&CfgMgrType); - return (1); + return -1; } - return (0); + return 0; } -} +} // extern "C" diff --git a/keamodule/cfg_subnets4.cc b/keamodule/cfg_subnets4.cc index ef7797b..f20638f 100644 --- a/keamodule/cfg_subnets4.cc +++ b/keamodule/cfg_subnets4.cc @@ -25,11 +25,9 @@ CfgSubnets4_getAll(CfgSubnets4Object *self, PyObject *args) { Py_DECREF(list); return (0); } - } return (list); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -49,8 +47,7 @@ CfgSubnets4_getSubnet(CfgSubnets4Object *self, PyObject *args) { Py_RETURN_NONE; } return (Subnet4_from_ptr(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -70,8 +67,7 @@ CfgSubnets4_selectSubnet(CfgSubnets4Object *self, PyObject *args) { Py_RETURN_NONE; } return (Subnet4_from_ptr(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -82,21 +78,20 @@ CfgSubnets4_toElement(CfgSubnets4Object *self, PyObject *args) { try { ElementPtr ptr = self->ptr->toElement(); return (element_to_object(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } } static PyMethodDef CfgSubnets4_methods[] = { - {"getAll", (PyCFunction) CfgSubnets4_getAll, METH_NOARGS, + {"getAll", (PyCFunction)CfgSubnets4_getAll, METH_NOARGS, "Returns collection of all IPv4 subnets."}, - {"getSubnet", (PyCFunction) CfgSubnets4_getSubnet, METH_VARARGS, + {"getSubnet", (PyCFunction)CfgSubnets4_getSubnet, METH_VARARGS, "Returns subnet with specified subnet-id value."}, - {"selectSubnet", (PyCFunction) CfgSubnets4_selectSubnet, METH_VARARGS, + {"selectSubnet", (PyCFunction)CfgSubnets4_selectSubnet, METH_VARARGS, "Returns a pointer to the selected subnet."}, - {"toElement", (PyCFunction) CfgSubnets4_toElement, METH_NOARGS, + {"toElement", (PyCFunction)CfgSubnets4_toElement, METH_NOARGS, "Unparse configuration object."}, {0} // Sentinel }; @@ -107,19 +102,19 @@ CfgSubnets4_use_count(OptionObject *self, void *closure) { } static PyGetSetDef CfgSubnets4_getsetters[] = { - {(char *)"use_count", (getter) CfgSubnets4_use_count, (setter) 0, (char *)"shared_ptr use count", 0}, + {(char *)"use_count", (getter)CfgSubnets4_use_count, (setter)0, (char *)"shared_ptr use count", 0}, {0} // Sentinel }; static void CfgSubnets4_dealloc(CfgSubnets4Object *self) { self->ptr.~CfgSubnets4Ptr(); - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); } static int CfgSubnets4_init(CfgSubnets4Object *self, PyObject *args, PyObject *kwds) { - new(&self->ptr) CfgSubnets4Ptr; + new (&self->ptr) CfgSubnets4Ptr; PyErr_SetString(PyExc_RuntimeError, "cannot directly construct"); return (-1); @@ -128,75 +123,73 @@ CfgSubnets4_init(CfgSubnets4Object *self, PyObject *args, PyObject *kwds) { static PyObject * CfgSubnets4_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { CfgSubnets4Object *self; - self = (CfgSubnets4Object *) type->tp_alloc(type, 0); + self = (CfgSubnets4Object *)type->tp_alloc(type, 0); if (self) { - new(&self->ptr) CfgSubnets4Ptr; + new (&self->ptr) CfgSubnets4Ptr; } - return ((PyObject *) self); + return ((PyObject *)self); } PyTypeObject CfgSubnets4Type = { - PyObject_HEAD_INIT(0) - "kea.CfgSubnets4", // tp_name - sizeof(CfgSubnets4Object), // tp_basicsize - 0, // tp_itemsize - (destructor) CfgSubnets4_dealloc, // tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server CfgSubnets4", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - CfgSubnets4_methods, // tp_methods - 0, // tp_members - CfgSubnets4_getsetters, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc) CfgSubnets4_init, // tp_init - PyType_GenericAlloc, // tp_alloc - CfgSubnets4_new // tp_new + PyObject_HEAD_INIT(0) "kea.CfgSubnets4", // tp_name + sizeof(CfgSubnets4Object), // tp_basicsize + 0, // tp_itemsize + (destructor)CfgSubnets4_dealloc, // tp_dealloc + 0, // tp_vectorcall_offset + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_as_async + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "Kea server CfgSubnets4", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + CfgSubnets4_methods, // tp_methods + 0, // tp_members + CfgSubnets4_getsetters, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + (initproc)CfgSubnets4_init, // tp_init + PyType_GenericAlloc, // tp_alloc + CfgSubnets4_new // tp_new }; PyObject * CfgSubnets4_from_ptr(CfgSubnets4Ptr &ptr) { CfgSubnets4Object *self = PyObject_New(CfgSubnets4Object, &CfgSubnets4Type); if (self) { - new(&self->ptr) CfgSubnets4Ptr; + new (&self->ptr) CfgSubnets4Ptr; self->ptr = ptr; } return (PyObject *)self; } int -CfgSubnets4_define() { +CfgSubnets4_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&CfgSubnets4Type) < 0) { - return (1); + return -1; } - if (PyModule_AddObject(kea_module, "CfgSubnets4", (PyObject *) &CfgSubnets4Type) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&CfgSubnets4Type) < 0) { Py_DECREF(&CfgSubnets4Type); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/constants.cc b/keamodule/constants.cc index 8d97a4d..3463406 100644 --- a/keamodule/constants.cc +++ b/keamodule/constants.cc @@ -11,7 +11,8 @@ typedef struct { int value; } KeaConstant; -#define constant(name) {#name, name} +#define constant(name) \ + {#name, name} static KeaConstant constants[] = { constant(BOOTREQUEST), @@ -200,13 +201,12 @@ static KeaConstant constants[] = { #define num_constants (sizeof(constants) / sizeof(constants[0])) int -Constants_define() { +Constants_registerTypes(PyObject *mod) { for (unsigned int i = 0; i < num_constants; i++) { - if (PyModule_AddIntConstant(kea_module, constants[i].name, constants[i].value) < 0) { - return (1); + if (PyModule_AddIntConstant(mod, constants[i].name, constants[i].value) < 0) { + return -1; } } - return (0); + return 0; } - } diff --git a/keamodule/host.cc b/keamodule/host.cc index 19748f9..9c41b39 100644 --- a/keamodule/host.cc +++ b/keamodule/host.cc @@ -12,8 +12,7 @@ Host_getHostId(HostObject *self, PyObject *args) { try { HostID host_id = (self->is_const ? self->const_ptr : self->ptr)->getHostId(); return (PyLong_FromUnsignedLongLong(host_id)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -24,20 +23,27 @@ Host_toElement(HostObject *self, PyObject *args) { try { ElementPtr ptr = (self->is_const ? self->const_ptr : self->ptr)->toElement4(); return (element_to_object(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); - return (0); + return NULL; } } +static PyObject * +Host_getIdentifier(HostObject *self, PyObject *args) { + return PyUnicode_FromString((self->is_const ? self->const_ptr : self->ptr)->toText().c_str()); +} + static PyMethodDef Host_methods[] = { + // clang-format off {"getHostId", (PyCFunction) Host_getHostId, METH_NOARGS, "Returns Host ID (primary key in MySQL, PostgreSQL and Cassandra backends)."}, {"toElement", (PyCFunction) Host_toElement, METH_NOARGS, "Element representation of the host."}, - {0} // Sentinel -}; + {"getIdentifier", (PyCFunction) Host_getIdentifier, METH_NOARGS, + "Host::getIdentifier()"}, + {NULL, NULL, 0, NULL} // Sentinel +}; // clang-format on static PyObject * Host_use_count(HostObject *self, void *closure) { @@ -45,15 +51,20 @@ Host_use_count(HostObject *self, void *closure) { } static PyGetSetDef Host_getsetters[] = { - {(char *)"use_count", (getter) Host_use_count, (setter) 0, (char *)"shared_ptr use count", 0}, - {0} // Sentinel + {(char *)"use_count", (getter)Host_use_count, (setter)0, (char *)"shared_ptr use count", 0}, + {NULL, NULL, 0, NULL} // Sentinel }; static void Host_dealloc(HostObject *self) { self->ptr.~HostPtr(); self->const_ptr.~ConstHostPtr(); - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyObject * +Host_str(HostObject *self) { + return PyUnicode_FromString((self->is_const ? self->const_ptr : self->ptr)->toText().c_str()); } static int @@ -64,85 +75,57 @@ Host_init(HostObject *self, PyObject *args, PyObject *kwds) { unsigned long subnet_id; const char *ipv4_reservation; - new(&self->ptr) HostPtr; - new(&self->const_ptr) ConstHostPtr; + new (&self->ptr) HostPtr; + new (&self->const_ptr) ConstHostPtr; if (!PyArg_ParseTupleAndKeywords(args, kwds, "ssks", (char **)kwlist, - &identifier, &identifier_type, &subnet_id, &ipv4_reservation)) { - return (-1); + &identifier, &identifier_type, &subnet_id, &ipv4_reservation)) { + return -1; } try { self->ptr.reset(new Host(identifier, identifier_type, subnet_id, 0, IOAddress(string(ipv4_reservation)))); self->const_ptr.reset(); self->is_const = false; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); - return (-1); + return -1; } - return (0); + return 0; } static PyObject * Host_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { HostObject *self; - self = (HostObject *) type->tp_alloc(type, 0); + self = (HostObject *)type->tp_alloc(type, 0); if (self) { - new(&self->ptr) HostPtr; - new(&self->const_ptr) ConstHostPtr; + new (&self->ptr) HostPtr; + new (&self->const_ptr) ConstHostPtr; } - return ((PyObject *) self); + return ((PyObject *)self); } -PyTypeObject HostType = { - PyObject_HEAD_INIT(0) - "kea.Host", // tp_name - sizeof(HostObject), // tp_basicsize - 0, // tp_itemsize - (destructor) Host_dealloc, // tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server Host", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - Host_methods, // tp_methods - 0, // tp_members - Host_getsetters, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc) Host_init, // tp_init - PyType_GenericAlloc, // tp_alloc - Host_new // tp_new -}; +PyTypeObject HostType = { // clang-format off + PyVarObject_HEAD_INIT(NULL, 0).tp_name = "kea.Host", + .tp_basicsize = sizeof(HostObject), + .tp_dealloc = (destructor) Host_dealloc, + .tp_str = (reprfunc) Host_str, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = PyDoc_STR("Kea server Host"), + .tp_methods = Host_methods, + .tp_getset = Host_getsetters, + .tp_init = (initproc) Host_init, + .tp_alloc = PyType_GenericAlloc, + .tp_new = Host_new +}; // clang-format on PyObject * Host_from_ptr(HostPtr host) { HostObject *self = PyObject_New(HostObject, &HostType); if (self) { - new(&self->ptr) HostPtr; - new(&self->const_ptr) ConstHostPtr; + new (&self->ptr) HostPtr; + new (&self->const_ptr) ConstHostPtr; self->is_const = false; self->ptr = host; } @@ -153,8 +136,8 @@ PyObject * Host_from_constptr(ConstHostPtr host) { HostObject *self = PyObject_New(HostObject, &HostType); if (self) { - new(&self->ptr) HostPtr; - new(&self->const_ptr) ConstHostPtr; + new (&self->ptr) HostPtr; + new (&self->const_ptr) ConstHostPtr; self->is_const = true; self->const_ptr = host; } @@ -162,17 +145,16 @@ Host_from_constptr(ConstHostPtr host) { } int -Host_define() { +Host_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&HostType) < 0) { - return (1); + return -1; } Py_INCREF(&HostType); - if (PyModule_AddObject(kea_module, "Host", (PyObject *) &HostType) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&HostType) < 0) { Py_DECREF(&HostType); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/host_mgr.cc b/keamodule/host_mgr.cc index cdea506..5ecb317 100644 --- a/keamodule/host_mgr.cc +++ b/keamodule/host_mgr.cc @@ -21,49 +21,80 @@ HostMgr_add(HostMgrObject *self, PyObject *args) { try { self->mgr->add(host->ptr, target); Py_RETURN_NONE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } } static PyObject * -HostMgr_get(HostMgrObject *self, PyObject *args) { +HostMgr_get4(HostMgrObject *self, PyObject *args) { unsigned long subnet_id; const char *ip_address = 0; + HostMgrOperationTarget target = HostMgrOperationTarget::ALL_SOURCES; + + if (!PyArg_ParseTuple(args, "ks|i", &subnet_id, &ip_address, &target)) { + return NULL; + } + + try { + ConstHostPtr host; + host = self->mgr->get4(subnet_id, IOAddress(ip_address), target); + if (!host.get()) { + Py_RETURN_NONE; + } + return Host_from_constptr(host); + } catch (const exception &e) { + PyErr_SetString(PyExc_TypeError, e.what()); + return (0); + } +} + +static PyObject * +HostMgr_get4Any(HostMgrObject *self, PyObject *args) { + unsigned long subnet_id; const char *identifier_type = 0; const char *identifier = 0; - HostMgrOperationTarget target = HostMgrOperationTarget::ALTERNATE_SOURCES; + HostMgrOperationTarget target = HostMgrOperationTarget::ALL_SOURCES; - if (!PyArg_ParseTuple(args, "ks|si", &subnet_id, &identifier_type, &identifier, &target)) { - return (0); + if (!PyArg_ParseTuple( + args, "kss|i", &subnet_id, &identifier_type, &identifier, &target)) { + return NULL; } try { ConstHostPtr host; - if (ip_address != 0) { - host = self->mgr->get4(subnet_id, IOAddress(ip_address)); - } else { - std::vector binary = str::quotedStringToBinary(identifier); - if (binary.empty()) { - str::decodeFormattedHexString(identifier, binary); - } - host = self->mgr->get4(subnet_id, Host::getIdentifierType(identifier_type), &binary.front(), binary.size(), target); + std::vector binary = str::quotedStringToBinary(identifier); + if (binary.empty()) { + str::decodeFormattedHexString(identifier, binary); } + host = self->mgr->get4Any( + subnet_id, + Host::getIdentifierType(identifier_type), + &binary.front(), + binary.size(), + target); if (!host.get()) { Py_RETURN_NONE; } return Host_from_constptr(host); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } } static PyObject * -collection_to_list(ConstHostCollection& hosts) { +HostMgr_get(HostMgrObject *self, PyObject *args) { + if (PyTuple_Size(args) >= 3 && PyUnicode_Check(PyTuple_GetItem(args, 2))) { + return HostMgr_get4Any(self, args); + } else { + return HostMgr_get4(self, args); + } +} + +static PyObject * +collection_to_list(ConstHostCollection &hosts) { PyObject *result = PyList_New(hosts.size()); if (result == 0) { return 0; @@ -86,18 +117,18 @@ collection_to_list(ConstHostCollection& hosts) { static PyObject * HostMgr_getAll4(HostMgrObject *self, PyObject *args) { unsigned long subnet_id; + HostMgrOperationTarget target = HostMgrOperationTarget::ALL_SOURCES; - if (!PyArg_ParseTuple(args, "k", &subnet_id)) { - return (0); + if (!PyArg_ParseTuple(args, "k|i", &subnet_id, &target)) { + return NULL; } try { - ConstHostCollection hosts = self->mgr->getAll4(subnet_id); + ConstHostCollection hosts = self->mgr->getAll4(subnet_id, target); return (collection_to_list(hosts)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); - return (0); + return NULL; } } @@ -109,7 +140,7 @@ HostMgr_getPage4(HostMgrObject *self, PyObject *args) { unsigned long page_size = 0; if (!PyArg_ParseTuple(args, "kkKk", &subnet_id, &source_index, &lower_host_id, &page_size)) { - return (0); + return NULL; } try { @@ -122,8 +153,7 @@ HostMgr_getPage4(HostMgrObject *self, PyObject *args) { PyObject *result = Py_BuildValue("Ok", host_list, source_index); Py_DECREF(host_list); return (result); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -145,8 +175,7 @@ HostMgr_del_(HostMgrObject *self, PyObject *args) { } else { Py_RETURN_FALSE; } - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -160,7 +189,7 @@ HostMgr_del4(HostMgrObject *self, PyObject *args) { HostMgrOperationTarget target = HostMgrOperationTarget::ALTERNATE_SOURCES; if (!PyArg_ParseTuple(args, "kss|i", &subnet_id, &identifier_type, &identifier, &target)) { - return (0); + return NULL; } try { @@ -168,15 +197,14 @@ HostMgr_del4(HostMgrObject *self, PyObject *args) { if (binary.empty()) { str::decodeFormattedHexString(identifier, binary); } - if (self->mgr->del4(subnet_id, Host::getIdentifierType(identifier_type), &binary.front(), binary.size()), target) { + if (self->mgr->del4(subnet_id, Host::getIdentifierType(identifier_type), &binary.front(), binary.size(), target)) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); - return (0); + return NULL; } } @@ -190,25 +218,40 @@ HostMgr_from_ptr(HostMgr *mgr) { } static PyObject * -HostMgr_instance(HostMgrObject *self, PyObject *args) { - try { - HostMgr &mgr = HostMgr::instance(); - return (HostMgr_from_ptr(&mgr)); - } - catch (const exception &e) { - PyErr_SetString(PyExc_TypeError, e.what()); - return (0); +HostMgr_instance(HostMgrObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { + static HostMgrObject *instance = NULL; + + if (instance == NULL) { + instance = (HostMgrObject *)HostMgrType.tp_alloc(&HostMgrType, 0); + if (instance == NULL) { + return PyErr_NoMemory(); + } + try { + instance->mgr = &HostMgr::instance(); + } catch (const std::exception &e) { + Py_DECREF(instance); + instance = NULL; + PyErr_SetString(PyExc_RuntimeError, e.what()); + return NULL; + } } -} + Py_INCREF(instance); + return (PyObject *)instance; +} static PyMethodDef HostMgr_methods[] = { - {"instance", (PyCFunction) HostMgr_instance, METH_NOARGS|METH_STATIC, + // clang-format off + {"instance", (PyCFunction) HostMgr_instance, METH_NOARGS | METH_STATIC, "Returns a sole instance of the HostMgr."}, {"add", (PyCFunction) HostMgr_add, METH_VARARGS, "Adds a new host to the alternate data source."}, {"get", (PyCFunction) HostMgr_get, METH_VARARGS, "Returns a host connected to the IPv4 subnet."}, + {"get4", (PyCFunction) HostMgr_get4, METH_VARARGS, + "Returns a host connected to the IPv4 subnet by address."}, + {"get4Any", (PyCFunction) HostMgr_get4Any, METH_VARARGS, + "Returns a host connected to the IPv4 subnet by (subnet4-id, identifier)."}, {"getAll4", (PyCFunction) HostMgr_getAll4, METH_VARARGS, "Return all hosts in a DHCPv4 subnet."}, {"getPage4", (PyCFunction) HostMgr_getPage4, METH_VARARGS, @@ -217,68 +260,52 @@ static PyMethodDef HostMgr_methods[] = { "Attempts to delete a host by address."}, {"del4", (PyCFunction) HostMgr_del4, METH_VARARGS, "Attempts to delete a host by (subnet4-id, identifier, identifier-type)."}, - {0} // Sentinel -}; + {NULL, NULL, 0, NULL} // Sentinel +}; // clang-format on +static void +HostMgr_dealloc(HostMgrObject *self) { + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyObject * +HostMgr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + static HostMgrObject *instance = NULL; + static char *kwlist[] = {NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { + PyErr_SetString(PyExc_TypeError, "kea.HostMgr() takes no arguments"); + return NULL; + } -static int -HostMgr_init(HostMgrObject *self, PyObject *args, PyObject *kwds) { - PyErr_SetString(PyExc_RuntimeError, "cannot directly construct"); - return (-1); + if (instance == NULL) { + instance = (HostMgrObject *)HostMgr_instance(instance, args); + } + + Py_INCREF(instance); + return (PyObject *)instance; } -PyTypeObject HostMgrType = { - PyObject_HEAD_INIT(0) - "kea.HostMgr", // tp_name - sizeof(HostMgrObject), // tp_basicsize - 0, // tp_itemsize - 0, // tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server HostMgr", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - HostMgr_methods, // tp_methods - 0, // tp_members - 0, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc) HostMgr_init, // tp_init - PyType_GenericAlloc, // tp_alloc - PyType_GenericNew // tp_new -}; +PyTypeObject HostMgrType = { // clang-format off + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "kea.HostMgr", + .tp_basicsize = sizeof(HostMgrObject), + .tp_dealloc = (destructor) HostMgr_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = PyDoc_STR("Kea HostMgr singleton object"), + .tp_methods = HostMgr_methods, + .tp_new = HostMgr_new +}; // clang-format on int -HostMgr_define() { +HostMgr_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&HostMgrType) < 0) { - return (1); + return -1; } Py_INCREF(&HostMgrType); - if (PyModule_AddObject(kea_module, "HostMgr", (PyObject *) &HostMgrType) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&HostMgrType) < 0) { Py_DECREF(&HostMgrType); - return (1); + return -1; } - - return (0); + return 0; } - } diff --git a/keamodule/host_reservation_parser4.cc b/keamodule/host_reservation_parser4.cc index 909794f..f81b7fb 100644 --- a/keamodule/host_reservation_parser4.cc +++ b/keamodule/host_reservation_parser4.cc @@ -18,16 +18,14 @@ HostReservationParser4_parse(HostReservationParser4Object *self, PyObject *args) ElementPtr data = object_to_element(config); HostPtr host = self->parser->parse(subnet_id, data); return Host_from_ptr(host); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } } - static PyMethodDef HostReservationParser4_methods[] = { - {"parse", (PyCFunction) HostReservationParser4_parse, METH_VARARGS, + {"parse", (PyCFunction)HostReservationParser4_parse, METH_VARARGS, "Parses a single entry for host reservation."}, {0} // Sentinel }; @@ -35,7 +33,7 @@ static PyMethodDef HostReservationParser4_methods[] = { static void HostReservationParser4_dealloc(HostReservationParser4Object *self) { delete self->parser; - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); } static int @@ -54,64 +52,62 @@ HostReservationParser4_init(HostReservationParser4Object *self, PyObject *args, static PyObject * HostReservationParser4_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { HostReservationParser4Object *self; - self = (HostReservationParser4Object *) type->tp_alloc(type, 0); + self = (HostReservationParser4Object *)type->tp_alloc(type, 0); self->parser = new HostReservationParser4(); - return ((PyObject *) self); + return ((PyObject *)self); } PyTypeObject HostReservationParser4Type = { - PyObject_HEAD_INIT(0) - "kea.HostReservationParser4", // tp_name - sizeof(HostReservationParser4Object), // tp_basicsize - 0, // tp_itemsize - (destructor) HostReservationParser4_dealloc,// tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server HostReservationParser4", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - HostReservationParser4_methods, // tp_methods - 0, // tp_members - 0, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc) HostReservationParser4_init, // tp_init - PyType_GenericAlloc, // tp_alloc - HostReservationParser4_new // tp_new + PyObject_HEAD_INIT(0) "kea.HostReservationParser4", // tp_name + sizeof(HostReservationParser4Object), // tp_basicsize + 0, // tp_itemsize + (destructor)HostReservationParser4_dealloc, // tp_dealloc + 0, // tp_vectorcall_offset + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_as_async + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "Kea server HostReservationParser4", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + HostReservationParser4_methods, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + (initproc)HostReservationParser4_init, // tp_init + PyType_GenericAlloc, // tp_alloc + HostReservationParser4_new // tp_new }; int -HostReservationParser4_define() { +HostReservationParser4_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&HostReservationParser4Type) < 0) { - return (1); + return -1; } Py_INCREF(&HostReservationParser4Type); - if (PyModule_AddObject(kea_module, "HostReservationParser4", (PyObject *) &HostReservationParser4Type) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&HostReservationParser4Type) < 0) { Py_DECREF(&HostReservationParser4Type); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/kea.cc b/keamodule/kea.cc index eb35c3f..8a9ed05 100644 --- a/keamodule/kea.cc +++ b/keamodule/kea.cc @@ -1,3 +1,5 @@ +#include + #include "keamodule.h" using namespace std; @@ -6,8 +8,22 @@ extern "C" { PyObject *kea_module; +static PyObject * +kea__loggerInit(PyObject *self, PyObject *args) { + char *logger_name; + + if (!PyArg_ParseTuple(args, "s", &logger_name)) { + return NULL; + } + + isc::process::Daemon::setDefaultLoggerName(logger_name); + isc::process::Daemon::loggerInit(logger_name, true); + Py_RETURN_NONE; +} + static PyMethodDef kea_methods[] = { - {0, 0, 0, 0} // sentinel + {"_loggerInit", (PyCFunction)kea__loggerInit, METH_VARARGS, "Init logger for test propouses."}, + {NULL, NULL, 0, NULL} // Sentinel }; static PyModuleDef kea_module_def = { @@ -15,39 +31,105 @@ static PyModuleDef kea_module_def = { "kea", 0, -1, - kea_methods -}; + kea_methods}; PyMODINIT_FUNC PyInit_kea(void) { kea_module = PyModule_Create(&kea_module_def); - if (!kea_module) { - return (0); - } - - if (PyModule_AddStringConstant(kea_module, "__version__", VERSION) < 0 - || Capsule_define() - || Constants_define() - || CalloutClosure_define() - || LibraryHandle_define() - || CalloutManager_define() - || CalloutHandle_define() - || Lease4_define() - || Pkt4_define() - || Option_define() - || CfgMgr_define() - || SrvConfig_define() - || CfgSubnets4_define() - || Subnet4_define() - || LeaseMgr_define() - || Host_define() - || HostMgr_define() - || HostReservationParser4_define()) { - Py_DECREF(kea_module); - return (0); + if (kea_module == NULL) { + return NULL; + } + + if (PyModule_AddStringConstant(kea_module, "__version__", MODULE_VERSION) < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (PyModule_AddStringConstant(kea_module, "KEA_VERSION", VERSION) < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (Constants_registerTypes(kea_module) < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (Capsule_registerTypes(kea_module) < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (LibraryHandle_registerType(kea_module, "LibraryHandle") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (CalloutManager_registerType(kea_module, "CalloutManager") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (CalloutHandle_registerType(kea_module, "CalloutHandle") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (Lease4_registerType(kea_module, "Lease4") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (Pkt4_registerType(kea_module, "Pkt4") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (Option_registerType(kea_module, "Option") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (CfgMgr_registerType(kea_module, "CfgMgr") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (SrvConfig_registerType(kea_module, "SrvConfig") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (CfgSubnets4_registerType(kea_module, "CfgSubnets4") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (Subnet4_registerType(kea_module, "Subnet4") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (LeaseMgr_registerType(kea_module, "LeaseMgr") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (Host_registerType(kea_module, "Host") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (HostMgr_registerType(kea_module, "HostMgr") < 0) { + Py_DECREF(kea_module); + return NULL; + } + + if (HostReservationParser4_registerType(kea_module, "HostReservationParser4") < 0) { + Py_DECREF(kea_module); + return NULL; } return (kea_module); } - } diff --git a/keamodule/keamodule.h b/keamodule/keamodule.h index fcbb948..cfef88f 100644 --- a/keamodule/keamodule.h +++ b/keamodule/keamodule.h @@ -1,16 +1,16 @@ -#include #include -#include -#include -#include -#include +#include #include #include -#include #include -#include -#include +#include +#include #include +#include +#include +#include +#include +#include extern "C" { @@ -21,37 +21,51 @@ extern "C" { extern PyObject *kea_module; // errors.cc -extern int Errors_initialize(); -extern int Errors_finalize(); +extern int +Errors_initialize(); +extern int +Errors_finalize(); // steals reference to exc_* objects -extern int format_python_traceback(PyObject *exc_type, PyObject *exc_value, PyObject *exc_traceback, std::string &traceback); -extern int log_python_traceback(); +extern int +format_python_traceback(PyObject *exc_type, PyObject *exc_value, PyObject *exc_traceback, std::string &traceback); +extern int +log_python_traceback(); // capsule.cc extern PyObject *hook_module; extern isc::log::Logger *kea_logger; extern isc::log::MessageID *kea_message_id; -extern void begin_allow_threads(); -extern void end_allow_threads(); +extern void +begin_allow_threads(); +extern void +end_allow_threads(); -extern void log_error(std::string msg); -extern int Capsule_define(); +extern void +log_error(std::string msg); +extern int +Capsule_registerTypes(PyObject *mod); // constants.cc -extern int Constants_define(); +extern int +Constants_registerTypes(PyObject *mod); // utils.cc -extern int assert_long_value(PyObject *value, const char *name); -extern int assert_string_value(PyObject *value, const char *name, bool allow_none); -extern int assert_bool_value(PyObject *value, const char *name); -extern PyObject *element_to_object(isc::data::ConstElementPtr ptr); -extern isc::data::ElementPtr object_to_element(PyObject *obj); +extern int +assert_long_value(PyObject *value, const char *name); +extern int +assert_string_value(PyObject *value, const char *name, bool allow_none); +extern int +assert_bool_value(PyObject *value, const char *name); +extern PyObject * +element_to_object(isc::data::ConstElementPtr ptr); +extern isc::data::ElementPtr +object_to_element(PyObject *obj); // callout_closure.cc typedef struct { PyObject_HEAD - PyObject *name; + PyObject *name; PyObject *callout; ffi_cif cif; ffi_type *args[1]; @@ -59,49 +73,57 @@ typedef struct { ffi_closure *closure; } CalloutClosureObject; -extern PyObject *CalloutClosure_from_object(PyObject *name, PyObject *callout); -extern int CalloutClosure_define(); +extern PyObject * +CalloutClosure_from_object(PyObject *name, PyObject *callout); +extern int +CalloutClosure_registerType(PyObject *mod, const char *name); // callouts.cc -extern int Callouts_add_closure(CalloutClosureObject *obj); -extern int Callouts_register(isc::hooks::LibraryHandle *handle); -extern int Callouts_unregister(); +extern int +Callouts_add_closure(CalloutClosureObject *obj); +extern int +Callouts_register(isc::hooks::LibraryHandle *handle); +extern int +Callouts_unregister(); // library_handle.cc typedef struct { PyObject_HEAD - isc::hooks::LibraryHandle *handle; + isc::hooks::LibraryHandle *handle; bool is_owner; } LibraryHandleObject; #define LibraryHandle_Check(op) (Py_TYPE(op) == &LibraryHandleType) extern PyTypeObject LibraryHandleType; -extern PyObject *LibraryHandle_from_handle(isc::hooks::LibraryHandle *handle); -extern int LibraryHandle_define(); +extern PyObject * +LibraryHandle_from_handle(isc::hooks::LibraryHandle *handle); +extern int +LibraryHandle_registerType(PyObject *mod, const char *name); // callout_manager.cc typedef boost::shared_ptr CalloutManagerPtr; typedef struct { PyObject_HEAD - CalloutManagerPtr manager; + CalloutManagerPtr manager; } CalloutManagerObject; #define CalloutManager_Check(op) (Py_TYPE(op) == &CalloutManagerType) extern PyTypeObject CalloutManagerType; -extern int CalloutManager_define(); +extern int +CalloutManager_registerType(PyObject *mod, const char *name); // callout_handle.cc typedef struct { PyObject_HEAD - isc::hooks::CalloutHandle *handle; + isc::hooks::CalloutHandle *handle; bool is_owner; } CalloutHandleObject; class ObjectHolder { -public: + public: ObjectHolder(PyObject *obj); ~ObjectHolder(); PyObject *obj_; @@ -110,137 +132,159 @@ typedef boost::shared_ptr ObjectHolderPtr; #define CalloutHandle_Check(op) (Py_TYPE(op) == &CalloutHandleType) extern PyTypeObject CalloutHandleType; -extern PyObject *CalloutHandle_from_handle(isc::hooks::CalloutHandle *handle); -extern int CalloutHandle_define(); +extern PyObject * +CalloutHandle_from_handle(isc::hooks::CalloutHandle *handle); +extern int +CalloutHandle_registerType(PyObject *mod, const char *name); // lease4.cc typedef struct { PyObject_HEAD - isc::dhcp::Lease4Ptr ptr; + isc::dhcp::Lease4Ptr ptr; } Lease4Object; #define Lease4_Check(op) (Py_TYPE(op) == &Lease4Type) extern PyTypeObject Lease4Type; -extern PyObject *Lease4_from_handle(isc::dhcp::Lease4Ptr &ptr); -extern int Lease4_define(); +extern PyObject * +Lease4_from_handle(isc::dhcp::Lease4Ptr &ptr); +extern int +Lease4_registerType(PyObject *mod, const char *name); // pkt4.cc typedef struct { PyObject_HEAD - isc::dhcp::Pkt4Ptr ptr; + isc::dhcp::Pkt4Ptr ptr; } Pkt4Object; #define Pkt4_Check(op) (Py_TYPE(op) == &Pkt4Type) extern PyTypeObject Pkt4Type; -extern PyObject *Pkt4_from_handle(isc::dhcp::Pkt4Ptr &ptr); -extern int Pkt4_define(); +extern PyObject * +Pkt4_from_handle(isc::dhcp::Pkt4Ptr &ptr); +extern int +Pkt4_registerType(PyObject *mod, const char *name); // option.cc typedef struct { PyObject_HEAD - isc::dhcp::OptionPtr ptr; + isc::dhcp::OptionPtr ptr; } OptionObject; #define Option_Check(op) (Py_TYPE(op) == &OptionType) extern PyTypeObject OptionType; -extern PyObject *Option_from_handle(isc::dhcp::OptionPtr &ptr); -extern int Option_define(); +extern PyObject * +Option_from_handle(isc::dhcp::OptionPtr &ptr); +extern int +Option_registerType(PyObject *mod, const char *name); // cfg_mgr.cc typedef struct { PyObject_HEAD + isc::dhcp::CfgMgr *cfg_mgr; } CfgMgrObject; #define CfgMgr_Check(op) (Py_TYPE(op) == &CfgMgrType) extern PyTypeObject CfgMgrType; -extern int CfgMgr_define(); +extern int +CfgMgr_registerType(PyObject *mod, const char *name); // srv_config.cc typedef struct { PyObject_HEAD - isc::dhcp::SrvConfigPtr ptr; + isc::dhcp::SrvConfigPtr ptr; } SrvConfigObject; #define SrvConfig_Check(op) (Py_TYPE(op) == &SrvConfigType) extern PyTypeObject SrvConfigType; -extern PyObject *SrvConfig_from_ptr(isc::dhcp::SrvConfigPtr &ptr); -extern int SrvConfig_define(); +extern PyObject * +SrvConfig_from_ptr(isc::dhcp::SrvConfigPtr &ptr); +extern int +SrvConfig_registerType(PyObject *mod, const char *name); // cfg_subnets4.cc typedef struct { PyObject_HEAD - isc::dhcp::CfgSubnets4Ptr ptr; + isc::dhcp::CfgSubnets4Ptr ptr; } CfgSubnets4Object; #define CfgSubnets4_Check(op) (Py_TYPE(op) == &CfgSubnets4Type) extern PyTypeObject CfgSubnets4Type; -extern PyObject *CfgSubnets4_from_ptr(isc::dhcp::CfgSubnets4Ptr &ptr); -extern int CfgSubnets4_define(); +extern PyObject * +CfgSubnets4_from_ptr(isc::dhcp::CfgSubnets4Ptr &ptr); +extern int +CfgSubnets4_registerType(PyObject *mod, const char *name); // lease_mgr.cc typedef struct { PyObject_HEAD - isc::dhcp::LeaseMgr *mgr; + isc::dhcp::LeaseMgr *mgr; } LeaseMgrObject; #define LeaseMgr_Check(op) (Py_TYPE(op) == &LeaseMgrType) extern PyTypeObject LeaseMgrType; -extern int LeaseMgr_define(); -extern PyObject *Leases4_from_handle(isc::dhcp::Lease4CollectionPtr &ptr); +extern int +LeaseMgr_registerType(PyObject *mod, const char *name); +extern PyObject * +Leases4_from_handle(isc::dhcp::Lease4CollectionPtr &ptr); // subnet4.cc typedef struct { PyObject_HEAD - isc::dhcp::Subnet4Ptr ptr; + isc::dhcp::Subnet4Ptr ptr; } Subnet4Object; #define Subnet4_Check(op) (Py_TYPE(op) == &Subnet4Type) extern PyTypeObject Subnet4Type; -extern PyObject *Subnet4_from_ptr(isc::dhcp::Subnet4Ptr &ptr); -extern int Subnet4_define(); +extern PyObject * +Subnet4_from_ptr(isc::dhcp::Subnet4Ptr &ptr); +extern int +Subnet4_registerType(PyObject *mod, const char *name); // host.cc typedef struct { PyObject_HEAD - bool is_const; + bool is_const; isc::dhcp::HostPtr ptr; isc::dhcp::ConstHostPtr const_ptr; } HostObject; #define Host_Check(op) (Py_TYPE(op) == &HostType) extern PyTypeObject HostType; -extern PyObject *Host_from_ptr(isc::dhcp::HostPtr host); -extern PyObject *Host_from_constptr(isc::dhcp::ConstHostPtr host); -extern int Host_define(); +extern PyObject * +Host_from_ptr(isc::dhcp::HostPtr host); +extern PyObject * +Host_from_constptr(isc::dhcp::ConstHostPtr host); +extern int +Host_registerType(PyObject *mod, const char *name); // host_mgr.cc typedef struct { PyObject_HEAD - isc::dhcp::HostMgr *mgr; + isc::dhcp::HostMgr *mgr; } HostMgrObject; #define HostMgr_Check(op) (Py_TYPE(op) == &HostMgrType) extern PyTypeObject HostMgrType; -extern int HostMgr_define(); +extern int +HostMgr_registerType(PyObject *mod, const char *name); // host_reservation_parser4.cc typedef struct { PyObject_HEAD - isc::dhcp::HostReservationParser4 *parser; + isc::dhcp::HostReservationParser4 *parser; } HostReservationParser4Object; #define HostReservationParser4_Check(op) (Py_TYPE(op) == &HostReservationParser4Type) extern PyTypeObject HostReservationParser4Type; -extern int HostReservationParser4_define(); - +extern int +HostReservationParser4_registerType(PyObject *mod, const char *name); } diff --git a/keamodule/lease4.cc b/keamodule/lease4.cc index d6a537f..ec749ca 100644 --- a/keamodule/lease4.cc +++ b/keamodule/lease4.cc @@ -19,8 +19,7 @@ Lease4_setContext(Lease4Object *self, PyObject *args) { self->ptr->setContext(object_to_element(ctx)); Py_INCREF(self); return ((PyObject *)self); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -30,8 +29,7 @@ static PyObject * Lease4_getContext(Lease4Object *self, PyObject *args) { try { return (element_to_object(self->ptr->getContext())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -47,19 +45,18 @@ Lease4_toElement(Lease4Object *self, PyObject *args) { } ElementPtr ptr = self->ptr->toElement(); return (element_to_object(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } } static PyMethodDef Lease4_methods[] = { - {"setContext", (PyCFunction) Lease4_setContext, METH_VARARGS, + {"setContext", (PyCFunction)Lease4_setContext, METH_VARARGS, "Sets user context."}, - {"getContext", (PyCFunction) Lease4_getContext, METH_NOARGS, + {"getContext", (PyCFunction)Lease4_getContext, METH_NOARGS, "Returns user context."}, - {"toElement", (PyCFunction) Lease4_toElement, METH_NOARGS, + {"toElement", (PyCFunction)Lease4_toElement, METH_NOARGS, "Return the JSON representation of a lease."}, {0} // Sentinel }; @@ -74,8 +71,7 @@ Lease4_get_addr(Lease4Object *self, void *closure) { try { string addr = self->ptr->addr_.toText(); return (PyUnicode_FromString(addr.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -90,8 +86,7 @@ Lease4_set_addr(Lease4Object *self, PyObject *value, void *closure) { const char *addr = PyUnicode_AsUTF8(value); self->ptr->addr_ = isc::asiolink::IOAddress(string(addr)); return (0); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -101,8 +96,7 @@ static PyObject * Lease4_get_valid_lft(Lease4Object *self, void *closure) { try { return (PyLong_FromLong(self->ptr->valid_lft_)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -116,8 +110,7 @@ Lease4_set_valid_lft(Lease4Object *self, PyObject *value, void *closure) { try { self->ptr->valid_lft_ = PyLong_AsLong(value); return (0); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -127,8 +120,7 @@ static PyObject * Lease4_get_cltt(Lease4Object *self, void *closure) { try { return (PyLong_FromLong(self->ptr->cltt_)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -142,8 +134,7 @@ Lease4_set_cltt(Lease4Object *self, PyObject *value, void *closure) { try { self->ptr->cltt_ = PyLong_AsLong(value); return (0); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -153,8 +144,7 @@ static PyObject * Lease4_get_subnet_id(Lease4Object *self, void *closure) { try { return (PyLong_FromLong(self->ptr->subnet_id_)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -168,8 +158,7 @@ Lease4_set_subnet_id(Lease4Object *self, PyObject *value, void *closure) { try { self->ptr->subnet_id_ = PyLong_AsLong(value); return (0); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -182,8 +171,7 @@ Lease4_get_hostname(Lease4Object *self, void *closure) { Py_RETURN_NONE; } return (PyUnicode_FromString(self->ptr->hostname_.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -197,14 +185,12 @@ Lease4_set_hostname(Lease4Object *self, PyObject *value, void *closure) { try { if (value == Py_None) { self->ptr->hostname_.clear(); - } - else { + } else { self->ptr->hostname_ = PyUnicode_AsUTF8(value); boost::algorithm::to_lower(self->ptr->hostname_); } return (0); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -217,8 +203,7 @@ Lease4_get_fqdn_fwd(Lease4Object *self, void *closure) { Py_RETURN_TRUE; } Py_RETURN_FALSE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -232,8 +217,7 @@ Lease4_set_fqdn_fwd(Lease4Object *self, PyObject *value, void *closure) { try { self->ptr->fqdn_fwd_ = value == Py_True; return (0); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -246,8 +230,7 @@ Lease4_get_fqdn_rev(Lease4Object *self, void *closure) { Py_RETURN_TRUE; } Py_RETURN_FALSE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -261,8 +244,7 @@ Lease4_set_fqdn_rev(Lease4Object *self, PyObject *value, void *closure) { try { self->ptr->fqdn_rev_ = value == Py_True; return (0); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -276,8 +258,7 @@ Lease4_get_hwaddr(Lease4Object *self, void *closure) { } string hwaddr = self->ptr->hwaddr_->toText(false); return (PyUnicode_FromString(hwaddr.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -292,8 +273,7 @@ Lease4_set_hwaddr(Lease4Object *self, PyObject *value, void *closure) { HWAddr hw = HWAddr::fromText(PyUnicode_AsUTF8(value)); self->ptr->hwaddr_ = HWAddrPtr(new HWAddr(hw)); return (0); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -306,8 +286,7 @@ Lease4_get_client_id(Lease4Object *self, void *closure) { Py_RETURN_NONE; } return (PyUnicode_FromString(self->ptr->client_id_->toText().c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -321,13 +300,11 @@ Lease4_set_client_id(Lease4Object *self, PyObject *value, void *closure) { try { if (value == Py_None) { self->ptr->client_id_.reset(); - } - else { + } else { self->ptr->client_id_ = ClientId::fromText(PyUnicode_AsUTF8(value)); } return (0); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -337,8 +314,7 @@ static PyObject * Lease4_get_state(Lease4Object *self, void *closure) { try { return (PyLong_FromLong(self->ptr->state_)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -352,37 +328,36 @@ Lease4_set_state(Lease4Object *self, PyObject *value, void *closure) { try { self->ptr->state_ = PyLong_AsLong(value); return (0); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } } static PyGetSetDef Lease4_getsetters[] = { - {(char *)"use_count", (getter) Lease4_use_count, (setter) 0, (char *)"shared_ptr use count", 0}, - {(char *)"addr", (getter) Lease4_get_addr, (setter) Lease4_set_addr, (char *)"Address in string form", 0}, - {(char *)"valid_lft", (getter) Lease4_get_valid_lft, (setter) Lease4_set_valid_lft, (char *)"Valid lifetime", 0}, - {(char *)"cltt", (getter) Lease4_get_cltt, (setter) Lease4_set_cltt, (char *)"Client last transmission time", 0}, - {(char *)"subnet_id", (getter) Lease4_get_subnet_id, (setter) Lease4_set_subnet_id, (char *)"Subnet identifier", 0}, - {(char *)"hostname", (getter) Lease4_get_hostname, (setter) Lease4_set_hostname, (char *)"Client hostname", 0}, - {(char *)"fqdn_fwd", (getter) Lease4_get_fqdn_fwd, (setter) Lease4_set_fqdn_fwd, (char *)"Forward zone updated?", 0}, - {(char *)"fqdn_rev", (getter) Lease4_get_fqdn_rev, (setter) Lease4_set_fqdn_rev, (char *)"Reverse zone updated?", 0}, - {(char *)"hwaddr", (getter) Lease4_get_hwaddr, (setter) Lease4_set_hwaddr, (char *)"Client's MAC/hardware address", 0}, - {(char *)"client_id", (getter) Lease4_get_client_id, (setter) Lease4_set_client_id, (char *)"Client identifier", 0}, - {(char *)"state", (getter) Lease4_get_state, (setter) Lease4_set_state, (char *)"Holds the lease state(s)", 0}, + {(char *)"use_count", (getter)Lease4_use_count, (setter)0, (char *)"shared_ptr use count", 0}, + {(char *)"addr", (getter)Lease4_get_addr, (setter)Lease4_set_addr, (char *)"Address in string form", 0}, + {(char *)"valid_lft", (getter)Lease4_get_valid_lft, (setter)Lease4_set_valid_lft, (char *)"Valid lifetime", 0}, + {(char *)"cltt", (getter)Lease4_get_cltt, (setter)Lease4_set_cltt, (char *)"Client last transmission time", 0}, + {(char *)"subnet_id", (getter)Lease4_get_subnet_id, (setter)Lease4_set_subnet_id, (char *)"Subnet identifier", 0}, + {(char *)"hostname", (getter)Lease4_get_hostname, (setter)Lease4_set_hostname, (char *)"Client hostname", 0}, + {(char *)"fqdn_fwd", (getter)Lease4_get_fqdn_fwd, (setter)Lease4_set_fqdn_fwd, (char *)"Forward zone updated?", 0}, + {(char *)"fqdn_rev", (getter)Lease4_get_fqdn_rev, (setter)Lease4_set_fqdn_rev, (char *)"Reverse zone updated?", 0}, + {(char *)"hwaddr", (getter)Lease4_get_hwaddr, (setter)Lease4_set_hwaddr, (char *)"Client's MAC/hardware address", 0}, + {(char *)"client_id", (getter)Lease4_get_client_id, (setter)Lease4_set_client_id, (char *)"Client identifier", 0}, + {(char *)"state", (getter)Lease4_get_state, (setter)Lease4_set_state, (char *)"Holds the lease state(s)", 0}, {0} // Sentinel }; static void Lease4_dealloc(Lease4Object *self) { self->ptr.~Lease4Ptr(); - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); } static int Lease4_init(Lease4Object *self, PyObject *args, PyObject *kwds) { - new(&self->ptr) Lease4Ptr; + new (&self->ptr) Lease4Ptr; if (kwds != 0) { PyErr_SetString(PyExc_TypeError, "keyword arguments are not supported"); @@ -399,76 +374,74 @@ Lease4_init(Lease4Object *self, PyObject *args, PyObject *kwds) { static PyObject * Lease4_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { Lease4Object *self; - self = (Lease4Object *) type->tp_alloc(type, 0); + self = (Lease4Object *)type->tp_alloc(type, 0); if (self) { - new(&self->ptr) Lease4Ptr; + new (&self->ptr) Lease4Ptr; } - return ((PyObject *) self); + return ((PyObject *)self); } PyTypeObject Lease4Type = { - PyObject_HEAD_INIT(0) - "kea.Lease4", // tp_name - sizeof(Lease4Object), // tp_basicsize - 0, // tp_itemsize - (destructor) Lease4_dealloc, // tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server Lease4", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - Lease4_methods, // tp_methods - 0, // tp_members - Lease4_getsetters, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc) Lease4_init, // tp_init - PyType_GenericAlloc, // tp_alloc - Lease4_new // tp_new + PyObject_HEAD_INIT(0) "kea.Lease4", // tp_name + sizeof(Lease4Object), // tp_basicsize + 0, // tp_itemsize + (destructor)Lease4_dealloc, // tp_dealloc + 0, // tp_vectorcall_offset + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_as_async + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "Kea server Lease4", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + Lease4_methods, // tp_methods + 0, // tp_members + Lease4_getsetters, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + (initproc)Lease4_init, // tp_init + PyType_GenericAlloc, // tp_alloc + Lease4_new // tp_new }; PyObject * Lease4_from_handle(Lease4Ptr &ptr) { Lease4Object *self = PyObject_New(Lease4Object, &Lease4Type); if (self) { - new(&self->ptr) Lease4Ptr; + new (&self->ptr) Lease4Ptr; self->ptr = ptr; } return (PyObject *)self; } int -Lease4_define() { +Lease4_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&Lease4Type) < 0) { - return (1); + return -1; } Py_INCREF(&Lease4Type); - if (PyModule_AddObject(kea_module, "Lease4", (PyObject *) &Lease4Type) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&Lease4Type) < 0) { Py_DECREF(&Lease4Type); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/lease_mgr.cc b/keamodule/lease_mgr.cc index 7d2a179..a35a0ae 100644 --- a/keamodule/lease_mgr.cc +++ b/keamodule/lease_mgr.cc @@ -1,6 +1,7 @@ -#include "keamodule.h" #include +#include "keamodule.h" + using namespace std; using namespace isc::dhcp; using namespace isc::asiolink; @@ -21,8 +22,7 @@ lease_list_from_collection(Lease4Collection &leases) { return (0); } } - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); Py_DECREF(list); return (0); @@ -62,13 +62,11 @@ LeaseMgr_getLease4(LeaseMgrObject *self, PyObject *args, PyObject *kwargs) { if (addr != 0 && !hwaddr && !client_id && !have_subnet_id) { // Lease4Ptr getLease4(const IOAddress &addr) ptr = self->mgr->getLease4(IOAddress(string(addr))); - } - else if (!addr && hwaddr != 0 && !client_id && have_subnet_id) { + } else if (!addr && hwaddr != 0 && !client_id && have_subnet_id) { // Lease4Ptr getLease4(const HWAddr &hwaddr, SubnetID subnet_id) HWAddr hw = HWAddr::fromText(hwaddr); ptr = self->mgr->getLease4(hw, subnet_id); - } - else if (!addr && !hwaddr && client_id != 0 && have_subnet_id) { + } else if (!addr && !hwaddr && client_id != 0 && have_subnet_id) { // Lease4Ptr getLease4(const ClientId &clientid, SubnetID subnet_id) ClientIdPtr clientid_ptr = ClientId::fromText(client_id); ptr = self->mgr->getLease4(*clientid_ptr, subnet_id); @@ -85,14 +83,12 @@ LeaseMgr_getLease4(LeaseMgrObject *self, PyObject *args, PyObject *kwargs) { HWAddr hw = HWAddr::fromText(hwaddr); Lease4Collection leases = self->mgr->getLease4(hw); return (lease_list_from_collection(leases)); - } - else if (!addr && !hwaddr && client_id != 0 && !have_subnet_id) { + } else if (!addr && !hwaddr && client_id != 0 && !have_subnet_id) { // Lease4Collection getLease4(const ClientId &clientid) ClientIdPtr clientid_ptr = ClientId::fromText(client_id); Lease4Collection leases = self->mgr->getLease4(*clientid_ptr); return (lease_list_from_collection(leases)); - } - else { + } else { PyErr_SetString(PyExc_TypeError, "Invalid argument combination"); return (0); } @@ -100,8 +96,7 @@ LeaseMgr_getLease4(LeaseMgrObject *self, PyObject *args, PyObject *kwargs) { Py_RETURN_NONE; } return (Lease4_from_handle(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -110,13 +105,13 @@ LeaseMgr_getLease4(LeaseMgrObject *self, PyObject *args, PyObject *kwargs) { static PyObject * LeaseMgr_getLeases4(LeaseMgrObject *self, PyObject *args, PyObject *kwargs) { #if MISSING_GETLEASES4_HOSTNAME - #define KWLIST {"subnet_id", "lower_bound_address", "page_size", NULL} - #define KWFORMAT "|ksk" - #define KWVARS &subnet_id, &lower_bound_address, &page_size +#define KWLIST {"subnet_id", "lower_bound_address", "page_size", NULL} +#define KWFORMAT "|ksk" +#define KWVARS &subnet_id, &lower_bound_address, &page_size #else - #define KWLIST {"subnet_id", "hostname", "lower_bound_address", "page_size", NULL} - #define KWFORMAT "|kssk" - #define KWVARS &subnet_id, &hostname, &lower_bound_address, &page_size +#define KWLIST {"subnet_id", "hostname", "lower_bound_address", "page_size", NULL} +#define KWFORMAT "|kssk" +#define KWVARS &subnet_id, &hostname, &lower_bound_address, &page_size #endif static const char *kwlist[] = KWLIST; unsigned long subnet_id = 0; @@ -146,7 +141,7 @@ LeaseMgr_getLeases4(LeaseMgrObject *self, PyObject *args, PyObject *kwargs) { Lease4Collection leases; if (have_subnet_id && !hostname && !lower_bound_address && !have_page_size) { // Lease4Collection getLeases4(SubnetID subnet_id) - leases = self->mgr->getLeases4((SubnetID) subnet_id); + leases = self->mgr->getLeases4((SubnetID)subnet_id); } #ifndef MISSING_GETLEASES4_HOSTNAME else if (!have_subnet_id && hostname != 0 && !lower_bound_address && !have_page_size) { @@ -157,19 +152,16 @@ LeaseMgr_getLeases4(LeaseMgrObject *self, PyObject *args, PyObject *kwargs) { else if (!have_subnet_id && !hostname && !lower_bound_address && !have_page_size) { // Lease4Collection getLeases4() leases = self->mgr->getLeases4(); - } - else if (!have_subnet_id && !hostname && lower_bound_address != 0 && have_page_size) { + } else if (!have_subnet_id && !hostname && lower_bound_address != 0 && have_page_size) { // Lease4Collection getLeases4(const IOAddress &lower_bound_address, const LeasePageSize &page_size) leases = self->mgr->getLeases4(IOAddress(string(lower_bound_address)), LeasePageSize(page_size)); - } - else { + } else { PyErr_SetString(PyExc_TypeError, "Invalid argument combination"); return (0); } return (lease_list_from_collection(leases)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -186,8 +178,7 @@ LeaseMgr_addLease(LeaseMgrObject *self, PyObject *args) { try { self->mgr->addLease(lease->ptr); Py_RETURN_NONE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -219,8 +210,7 @@ LeaseMgr_deleteLease(LeaseMgrObject *self, PyObject *args) { Py_RETURN_TRUE; } Py_RETURN_FALSE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -237,8 +227,7 @@ LeaseMgr_updateLease4(LeaseMgrObject *self, PyObject *args) { try { self->mgr->updateLease4(lease->ptr); Py_RETURN_NONE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -253,34 +242,33 @@ LeaseMgr_wipeLeases4(LeaseMgrObject *self, PyObject *args) { } try { - size_t result = self->mgr->wipeLeases4((SubnetID) subnet_id); + size_t result = self->mgr->wipeLeases4((SubnetID)subnet_id); return (PyLong_FromLong(result)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } } static PyMethodDef LeaseMgr_methods[] = { - {"getLease4", (PyCFunction) LeaseMgr_getLease4, METH_VARARGS | METH_KEYWORDS, + {"getLease4", (PyCFunction)LeaseMgr_getLease4, METH_VARARGS | METH_KEYWORDS, "Returns an IPv4 lease for specified IPv4 address."}, - {"getLeases4", (PyCFunction) LeaseMgr_getLeases4, METH_VARARGS | METH_KEYWORDS, + {"getLeases4", (PyCFunction)LeaseMgr_getLeases4, METH_VARARGS | METH_KEYWORDS, "Returns all IPv4 leases for the particular subnet identifier."}, - {"addLease", (PyCFunction) LeaseMgr_addLease, METH_VARARGS, + {"addLease", (PyCFunction)LeaseMgr_addLease, METH_VARARGS, "Adds an IPv4 lease."}, - {"deleteLease", (PyCFunction) LeaseMgr_deleteLease, METH_VARARGS, + {"deleteLease", (PyCFunction)LeaseMgr_deleteLease, METH_VARARGS, "Deletes a lease."}, - {"updateLease4", (PyCFunction) LeaseMgr_updateLease4, METH_VARARGS, + {"updateLease4", (PyCFunction)LeaseMgr_updateLease4, METH_VARARGS, "Updates IPv4 lease."}, - {"wipeLeases4", (PyCFunction) LeaseMgr_wipeLeases4, METH_VARARGS, + {"wipeLeases4", (PyCFunction)LeaseMgr_wipeLeases4, METH_VARARGS, "Virtual method which removes specified leases."}, {0} // Sentinel }; static void LeaseMgr_dealloc(LeaseMgrObject *self) { - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); } static int @@ -295,8 +283,7 @@ LeaseMgr_init(LeaseMgrObject *self, PyObject *args, PyObject *kwds) { try { self->mgr = &LeaseMgrFactory::instance(); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -307,66 +294,64 @@ LeaseMgr_init(LeaseMgrObject *self, PyObject *args, PyObject *kwds) { static PyObject * LeaseMgr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { LeaseMgrObject *self; - self = (LeaseMgrObject *) type->tp_alloc(type, 0); + self = (LeaseMgrObject *)type->tp_alloc(type, 0); if (self) { self->mgr = 0; } - return ((PyObject *) self); + return ((PyObject *)self); } PyTypeObject LeaseMgrType = { - PyObject_HEAD_INIT(0) - "kea.LeaseMgr", // tp_name - sizeof(LeaseMgrObject), // tp_basicsize - 0, // tp_itemsize - (destructor) LeaseMgr_dealloc, // tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server LeaseMgr", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - LeaseMgr_methods, // tp_methods - 0, // tp_members - 0, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc) LeaseMgr_init, // tp_init - PyType_GenericAlloc, // tp_alloc - LeaseMgr_new // tp_new + PyObject_HEAD_INIT(0) "kea.LeaseMgr", // tp_name + sizeof(LeaseMgrObject), // tp_basicsize + 0, // tp_itemsize + (destructor)LeaseMgr_dealloc, // tp_dealloc + 0, // tp_vectorcall_offset + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_as_async + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "Kea server LeaseMgr", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + LeaseMgr_methods, // tp_methods + 0, // tp_members + 0, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + (initproc)LeaseMgr_init, // tp_init + PyType_GenericAlloc, // tp_alloc + LeaseMgr_new // tp_new }; int -LeaseMgr_define() { +LeaseMgr_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&LeaseMgrType) < 0) { - return (1); + return -1; } Py_INCREF(&LeaseMgrType); - if (PyModule_AddObject(kea_module, "LeaseMgr", (PyObject *) &LeaseMgrType) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&LeaseMgrType) < 0) { Py_DECREF(&LeaseMgrType); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/library_handle.cc b/keamodule/library_handle.cc index 9973cb4..8429f6f 100644 --- a/keamodule/library_handle.cc +++ b/keamodule/library_handle.cc @@ -1,4 +1,5 @@ #include + #include "keamodule.h" using namespace std; @@ -23,7 +24,7 @@ LibraryHandle_registerCommandCallout(LibraryHandleObject *self, PyObject *args) return (0); } - CalloutClosureObject *obj = (CalloutClosureObject *) CalloutClosure_from_object(name, callout); + CalloutClosureObject *obj = (CalloutClosureObject *)CalloutClosure_from_object(name, callout); if (!obj) { return (0); } @@ -35,8 +36,7 @@ LibraryHandle_registerCommandCallout(LibraryHandleObject *self, PyObject *args) Py_DECREF(obj); try { self->handle->registerCommandCallout(PyUnicode_AsUTF8(name), (CalloutPtr)obj->bound_callout); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -45,7 +45,7 @@ LibraryHandle_registerCommandCallout(LibraryHandleObject *self, PyObject *args) } static PyMethodDef LibraryHandle_methods[] = { - {"registerCommandCallout", (PyCFunction) LibraryHandle_registerCommandCallout, METH_VARARGS, + {"registerCommandCallout", (PyCFunction)LibraryHandle_registerCommandCallout, METH_VARARGS, "Register control command handler."}, {0} // Sentinel }; @@ -55,7 +55,7 @@ LibraryHandle_dealloc(LibraryHandleObject *self) { if (self->is_owner) { delete self->handle; } - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); } static int @@ -77,8 +77,7 @@ LibraryHandle_init(LibraryHandleObject *self, PyObject *args, PyObject *kwds) { self->handle = new LibraryHandle(*manager->manager); #endif self->is_owner = true; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (-1); } @@ -89,20 +88,19 @@ LibraryHandle_init(LibraryHandleObject *self, PyObject *args, PyObject *kwds) { static PyObject * LibraryHandle_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { LibraryHandleObject *self; - self = (LibraryHandleObject *) type->tp_alloc(type, 0); + self = (LibraryHandleObject *)type->tp_alloc(type, 0); if (self) { self->handle = 0; self->is_owner = false; } - return ((PyObject *) self); + return ((PyObject *)self); } PyTypeObject LibraryHandleType = { - PyObject_HEAD_INIT(0) - "kea.LibraryHandle", // tp_name + PyObject_HEAD_INIT(0) "kea.LibraryHandle", // tp_name sizeof(LibraryHandleObject), // tp_basicsize 0, // tp_itemsize - (destructor) LibraryHandle_dealloc, // tp_dealloc + (destructor)LibraryHandle_dealloc, // tp_dealloc 0, // tp_vectorcall_offset 0, // tp_getattr 0, // tp_setattr @@ -133,7 +131,7 @@ PyTypeObject LibraryHandleType = { 0, // tp_descr_get 0, // tp_descr_set 0, // tp_dictoffset - (initproc) LibraryHandle_init, // tp_init + (initproc)LibraryHandle_init, // tp_init PyType_GenericAlloc, // tp_alloc LibraryHandle_new // tp_new }; @@ -149,17 +147,16 @@ LibraryHandle_from_handle(LibraryHandle *handle) { } int -LibraryHandle_define() { +LibraryHandle_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&LibraryHandleType) < 0) { - return (1); + return -1; } Py_INCREF(&LibraryHandleType); - if (PyModule_AddObject(kea_module, "LibraryHandle", (PyObject *) &LibraryHandleType) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&LibraryHandleType) < 0) { Py_DECREF(&LibraryHandleType); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/option.cc b/keamodule/option.cc index d7d3cba..a439d73 100644 --- a/keamodule/option.cc +++ b/keamodule/option.cc @@ -21,7 +21,7 @@ static PyObject * Option_getBytes(OptionObject *self, PyObject *args) { try { vector value = self->ptr->toBinary(); - return (PyBytes_FromStringAndSize((const char *) &value[0], value.size())); + return (PyBytes_FromStringAndSize((const char *)&value[0], value.size())); } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); @@ -54,7 +54,7 @@ static PyObject * Option_getString(OptionObject *self, PyObject *args) { try { vector value = self->ptr->toBinary(); - return (PyUnicode_FromStringAndSize((const char *) &value[0], value.size())); + return (PyUnicode_FromStringAndSize((const char *)&value[0], value.size())); } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); @@ -208,8 +208,7 @@ Option_pack(OptionObject *self, PyObject *args) { OutputBuffer buf(64); self->ptr->pack(buf); return (PyBytes_FromStringAndSize((char *)buf.getData(), buf.getLength())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -220,43 +219,42 @@ Option_toText(OptionObject *self, PyObject *args) { try { string addr = self->ptr->toText(); return (PyUnicode_FromString(addr.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } } static PyMethodDef Option_methods[] = { - {"getType", (PyCFunction) Option_getType, METH_NOARGS, + {"getType", (PyCFunction)Option_getType, METH_NOARGS, "Returns option type."}, - {"getBytes", (PyCFunction) Option_getBytes, METH_NOARGS, + {"getBytes", (PyCFunction)Option_getBytes, METH_NOARGS, "Returns option data."}, - {"setBytes", (PyCFunction) Option_setBytes, METH_VARARGS, + {"setBytes", (PyCFunction)Option_setBytes, METH_VARARGS, "Sets content to data."}, - {"getString", (PyCFunction) Option_getString, METH_NOARGS, + {"getString", (PyCFunction)Option_getString, METH_NOARGS, "Returns option data from UTF-8 decoded string."}, - {"setString", (PyCFunction) Option_setString, METH_VARARGS, + {"setString", (PyCFunction)Option_setString, METH_VARARGS, "Sets content to UTF-8 encoded string."}, - {"getUint8", (PyCFunction) Option_getUint8, METH_NOARGS, + {"getUint8", (PyCFunction)Option_getUint8, METH_NOARGS, "Returns content of first byte."}, - {"setUint8", (PyCFunction) Option_setUint8, METH_VARARGS, + {"setUint8", (PyCFunction)Option_setUint8, METH_VARARGS, "Sets content to single uint8 value."}, - {"getUint16", (PyCFunction) Option_getUint16, METH_NOARGS, + {"getUint16", (PyCFunction)Option_getUint16, METH_NOARGS, "Returns content of first word."}, - {"setUint16", (PyCFunction) Option_setUint16, METH_VARARGS, + {"setUint16", (PyCFunction)Option_setUint16, METH_VARARGS, "Sets content to single uint16 value."}, - {"getUint32", (PyCFunction) Option_getUint32, METH_NOARGS, + {"getUint32", (PyCFunction)Option_getUint32, METH_NOARGS, "Returns content of first double word."}, - {"setUint32", (PyCFunction) Option_setUint32, METH_VARARGS, + {"setUint32", (PyCFunction)Option_setUint32, METH_VARARGS, "Sets content to single uint32 value."}, - {"addOption", (PyCFunction) Option_addOption, METH_VARARGS, + {"addOption", (PyCFunction)Option_addOption, METH_VARARGS, "Adds a sub-option."}, - {"getOption", (PyCFunction) Option_getOption, METH_VARARGS, + {"getOption", (PyCFunction)Option_getOption, METH_VARARGS, "Returns suboption of specific type."}, - {"pack", (PyCFunction) Option_pack, METH_NOARGS, + {"pack", (PyCFunction)Option_pack, METH_NOARGS, "Return option in wire-format."}, - {"toText", (PyCFunction) Option_toText, METH_NOARGS, + {"toText", (PyCFunction)Option_toText, METH_NOARGS, "Returns string representation of the option."}, {0} // Sentinel }; @@ -267,21 +265,21 @@ Option_use_count(OptionObject *self, void *closure) { } static PyGetSetDef Option_getsetters[] = { - {(char *)"use_count", (getter) Option_use_count, (setter) 0, (char *)"shared_ptr use count", 0}, + {(char *)"use_count", (getter)Option_use_count, (setter)0, (char *)"shared_ptr use count", 0}, {0} // Sentinel }; static void Option_dealloc(OptionObject *self) { self->ptr.~OptionPtr(); - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); } static int Option_init(OptionObject *self, PyObject *args, PyObject *kwds) { unsigned short type; - new(&self->ptr) OptionPtr; + new (&self->ptr) OptionPtr; if (kwds != 0) { PyErr_SetString(PyExc_TypeError, "keyword arguments are not supported"); @@ -298,76 +296,74 @@ Option_init(OptionObject *self, PyObject *args, PyObject *kwds) { static PyObject * Option_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { OptionObject *self; - self = (OptionObject *) type->tp_alloc(type, 0); + self = (OptionObject *)type->tp_alloc(type, 0); if (self) { - new(&self->ptr) OptionPtr; + new (&self->ptr) OptionPtr; } - return ((PyObject *) self); + return ((PyObject *)self); } PyTypeObject OptionType = { - PyObject_HEAD_INIT(0) - "kea.Option", // tp_name - sizeof(OptionObject), // tp_basicsize - 0, // tp_itemsize - (destructor) Option_dealloc, // tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server Option", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - Option_methods, // tp_methods - 0, // tp_members - Option_getsetters, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc) Option_init, // tp_init - PyType_GenericAlloc, // tp_alloc - Option_new // tp_new + PyObject_HEAD_INIT(0) "kea.Option", // tp_name + sizeof(OptionObject), // tp_basicsize + 0, // tp_itemsize + (destructor)Option_dealloc, // tp_dealloc + 0, // tp_vectorcall_offset + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_as_async + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "Kea server Option", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + Option_methods, // tp_methods + 0, // tp_members + Option_getsetters, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + (initproc)Option_init, // tp_init + PyType_GenericAlloc, // tp_alloc + Option_new // tp_new }; PyObject * Option_from_handle(OptionPtr &ptr) { OptionObject *self = PyObject_New(OptionObject, &OptionType); if (self) { - new(&self->ptr) OptionPtr; + new (&self->ptr) OptionPtr; self->ptr = ptr; } return (PyObject *)self; } int -Option_define() { +Option_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&OptionType) < 0) { - return (1); + return -1; } Py_INCREF(&OptionType); - if (PyModule_AddObject(kea_module, "Option", (PyObject *) &OptionType) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&OptionType) < 0) { Py_DECREF(&OptionType); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/pkt4.cc b/keamodule/pkt4.cc index 57a8bdc..bf2baf8 100644 --- a/keamodule/pkt4.cc +++ b/keamodule/pkt4.cc @@ -12,8 +12,7 @@ Pkt4_getType(Pkt4Object *self, PyObject *args) { try { uint8_t type = self->ptr->getType(); return (PyLong_FromLong(type)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -31,8 +30,7 @@ Pkt4_setType(Pkt4Object *self, PyObject *args) { self->ptr->setType(type); Py_INCREF(self); return ((PyObject *)self); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -43,8 +41,7 @@ Pkt4_getFlags(Pkt4Object *self, PyObject *args) { try { uint16_t flags = self->ptr->getFlags(); return (PyLong_FromLong(flags)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -62,8 +59,7 @@ Pkt4_setFlags(Pkt4Object *self, PyObject *args) { self->ptr->setFlags(flags); Py_INCREF(self); return ((PyObject *)self); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -74,8 +70,7 @@ Pkt4_getLocalAddr(Pkt4Object *self, PyObject *args) { try { string addr = self->ptr->getLocalAddr().toText(); return (PyUnicode_FromString(addr.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -93,8 +88,7 @@ Pkt4_setLocalAddr(Pkt4Object *self, PyObject *args) { self->ptr->setLocalAddr(IOAddress(string(addr))); Py_INCREF(self); return ((PyObject *)self); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -105,8 +99,7 @@ Pkt4_getRemoteAddr(Pkt4Object *self, PyObject *args) { try { string addr = self->ptr->getRemoteAddr().toText(); return (PyUnicode_FromString(addr.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -124,8 +117,7 @@ Pkt4_setRemoteAddr(Pkt4Object *self, PyObject *args) { self->ptr->setRemoteAddr(IOAddress(string(addr))); Py_INCREF(self); return ((PyObject *)self); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -136,8 +128,7 @@ Pkt4_getCiaddr(Pkt4Object *self, PyObject *args) { try { string addr = self->ptr->getCiaddr().toText(); return (PyUnicode_FromString(addr.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -155,8 +146,7 @@ Pkt4_setCiaddr(Pkt4Object *self, PyObject *args) { self->ptr->setCiaddr(IOAddress(string(addr))); Py_INCREF(self); return ((PyObject *)self); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -167,8 +157,7 @@ Pkt4_getGiaddr(Pkt4Object *self, PyObject *args) { try { string addr = self->ptr->getGiaddr().toText(); return (PyUnicode_FromString(addr.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -186,8 +175,7 @@ Pkt4_setGiaddr(Pkt4Object *self, PyObject *args) { self->ptr->setGiaddr(IOAddress(string(addr))); Py_INCREF(self); return ((PyObject *)self); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -198,8 +186,7 @@ Pkt4_getSiaddr(Pkt4Object *self, PyObject *args) { try { string addr = self->ptr->getSiaddr().toText(); return (PyUnicode_FromString(addr.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -217,8 +204,7 @@ Pkt4_setSiaddr(Pkt4Object *self, PyObject *args) { self->ptr->setSiaddr(IOAddress(string(addr))); Py_INCREF(self); return ((PyObject *)self); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -229,8 +215,7 @@ Pkt4_getYiaddr(Pkt4Object *self, PyObject *args) { try { string addr = self->ptr->getYiaddr().toText(); return (PyUnicode_FromString(addr.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -248,8 +233,7 @@ Pkt4_setYiaddr(Pkt4Object *self, PyObject *args) { self->ptr->setYiaddr(IOAddress(string(addr))); Py_INCREF(self); return ((PyObject *)self); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -260,8 +244,7 @@ Pkt4_getHWAddr(Pkt4Object *self, PyObject *args) { try { string hwaddr = self->ptr->getHWAddr()->toText(false); return (PyUnicode_FromString(hwaddr.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -280,8 +263,7 @@ Pkt4_setHWAddr(Pkt4Object *self, PyObject *args) { self->ptr->setHWAddr(HWAddrPtr(new HWAddr(hw))); Py_INCREF(self); return ((PyObject *)self); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -298,8 +280,7 @@ Pkt4_delOption(Pkt4Object *self, PyObject *args) { try { bool res = self->ptr->delOption(type); return (PyBool_FromLong(res)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -317,8 +298,7 @@ Pkt4_addOption(Pkt4Object *self, PyObject *args) { self->ptr->addOption(((OptionObject *)opt)->ptr); Py_INCREF(self); return ((PyObject *)self); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -338,8 +318,7 @@ Pkt4_getOption(Pkt4Object *self, PyObject *args) { Py_RETURN_NONE; } return (Option_from_handle(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -352,16 +331,14 @@ Pkt4_getOptions(Pkt4Object *self) { if (!self->ptr->options_.empty()) { for (isc::dhcp::OptionCollection::const_iterator opt = self->ptr->options_.begin(); - opt != self->ptr->options_.end(); ++opt) { - + opt != self->ptr->options_.end(); ++opt) { PyList_Append(options, PyLong_FromUnsignedLong(opt->second->getType())); } } else { Py_RETURN_NONE; } return (options); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -372,8 +349,7 @@ Pkt4_toText(Pkt4Object *self, PyObject *args) { try { string addr = self->ptr->toText(); return (PyUnicode_FromString(addr.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -384,8 +360,7 @@ Pkt4_pack(Pkt4Object *self, PyObject *args) { try { self->ptr->pack(); return (PyBytes_FromStringAndSize((char *)self->ptr->getBuffer().getData(), self->ptr->getBuffer().getLength())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -396,63 +371,62 @@ Pkt4_unpack(Pkt4Object *self, PyObject *args) { try { self->ptr->unpack(); Py_RETURN_NONE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } } static PyMethodDef Pkt4_methods[] = { - {"getType", (PyCFunction) Pkt4_getType, METH_NOARGS, + {"getType", (PyCFunction)Pkt4_getType, METH_NOARGS, "For packets without DHCP Message Type option, it returns DHCP_NOTYPE (0)."}, - {"setType", (PyCFunction) Pkt4_setType, METH_VARARGS, + {"setType", (PyCFunction)Pkt4_setType, METH_VARARGS, "Sets DHCP message type."}, - {"getFlags", (PyCFunction) Pkt4_getFlags, METH_NOARGS, + {"getFlags", (PyCFunction)Pkt4_getFlags, METH_NOARGS, "Returns flags field."}, - {"setFlags", (PyCFunction) Pkt4_setFlags, METH_VARARGS, + {"setFlags", (PyCFunction)Pkt4_setFlags, METH_VARARGS, "Sets flags field."}, - {"getLocalAddr", (PyCFunction) Pkt4_getLocalAddr, METH_NOARGS, + {"getLocalAddr", (PyCFunction)Pkt4_getLocalAddr, METH_NOARGS, "Returns local IP address."}, - {"setLocalAddr", (PyCFunction) Pkt4_setLocalAddr, METH_VARARGS, + {"setLocalAddr", (PyCFunction)Pkt4_setLocalAddr, METH_VARARGS, "Sets local IP address."}, - {"getRemoteAddr", (PyCFunction) Pkt4_getRemoteAddr, METH_NOARGS, + {"getRemoteAddr", (PyCFunction)Pkt4_getRemoteAddr, METH_NOARGS, "Returns remote IP address."}, - {"setRemoteAddr", (PyCFunction) Pkt4_setRemoteAddr, METH_VARARGS, + {"setRemoteAddr", (PyCFunction)Pkt4_setRemoteAddr, METH_VARARGS, "Sets remote IP address."}, - {"getCiaddr", (PyCFunction) Pkt4_getCiaddr, METH_NOARGS, + {"getCiaddr", (PyCFunction)Pkt4_getCiaddr, METH_NOARGS, "Returns ciaddr field."}, - {"setCiaddr", (PyCFunction) Pkt4_setCiaddr, METH_VARARGS, + {"setCiaddr", (PyCFunction)Pkt4_setCiaddr, METH_VARARGS, "Sets ciaddr field."}, - {"getGiaddr", (PyCFunction) Pkt4_getGiaddr, METH_NOARGS, + {"getGiaddr", (PyCFunction)Pkt4_getGiaddr, METH_NOARGS, "Returns giaddr field."}, - {"setGiaddr", (PyCFunction) Pkt4_setGiaddr, METH_VARARGS, + {"setGiaddr", (PyCFunction)Pkt4_setGiaddr, METH_VARARGS, "Sets giaddr field."}, - {"getSiaddr", (PyCFunction) Pkt4_getSiaddr, METH_NOARGS, + {"getSiaddr", (PyCFunction)Pkt4_getSiaddr, METH_NOARGS, "Returns siaddr field."}, - {"setSiaddr", (PyCFunction) Pkt4_setSiaddr, METH_VARARGS, + {"setSiaddr", (PyCFunction)Pkt4_setSiaddr, METH_VARARGS, "Sets siaddr field."}, - {"getYiaddr", (PyCFunction) Pkt4_getYiaddr, METH_NOARGS, + {"getYiaddr", (PyCFunction)Pkt4_getYiaddr, METH_NOARGS, "Returns yiaddr field."}, - {"setYiaddr", (PyCFunction) Pkt4_setYiaddr, METH_VARARGS, + {"setYiaddr", (PyCFunction)Pkt4_setYiaddr, METH_VARARGS, "Sets yiaddr field."}, - {"getHWAddr", (PyCFunction) Pkt4_getHWAddr, METH_NOARGS, + {"getHWAddr", (PyCFunction)Pkt4_getHWAddr, METH_NOARGS, "Returns hardware address."}, - {"setHWAddr", (PyCFunction) Pkt4_setHWAddr, METH_VARARGS, + {"setHWAddr", (PyCFunction)Pkt4_setHWAddr, METH_VARARGS, "Sets hardware address."}, - {"delOption", (PyCFunction) Pkt4_delOption, METH_VARARGS, + {"delOption", (PyCFunction)Pkt4_delOption, METH_VARARGS, "Attempts to delete first suboption of requested type."}, - {"addOption", (PyCFunction) Pkt4_addOption, METH_VARARGS, + {"addOption", (PyCFunction)Pkt4_addOption, METH_VARARGS, "Adds an option to this packet."}, - {"getOption", (PyCFunction) Pkt4_getOption, METH_VARARGS, + {"getOption", (PyCFunction)Pkt4_getOption, METH_VARARGS, "Returns the first option of specified type."}, - {"getOptions", (PyCFunction) Pkt4_getOptions, METH_NOARGS, + {"getOptions", (PyCFunction)Pkt4_getOptions, METH_NOARGS, "Returns a list of all of the options."}, - {"toText", (PyCFunction) Pkt4_toText, METH_NOARGS, + {"toText", (PyCFunction)Pkt4_toText, METH_NOARGS, "Returns text representation of the packet."}, - {"pack", (PyCFunction) Pkt4_pack, METH_NOARGS, + {"pack", (PyCFunction)Pkt4_pack, METH_NOARGS, "Prepares on-wire format of DHCPv4 packet."}, - {"unpack", (PyCFunction) Pkt4_unpack, METH_NOARGS, + {"unpack", (PyCFunction)Pkt4_unpack, METH_NOARGS, "Parses on-wire form of DHCPv4 packet."}, {0} // Sentinel }; @@ -463,14 +437,14 @@ Pkt4_use_count(Pkt4Object *self, void *closure) { } static PyGetSetDef Pkt4_getsetters[] = { - {(char *)"use_count", (getter) Pkt4_use_count, (setter) 0, (char *)"shared_ptr use count", 0}, + {(char *)"use_count", (getter)Pkt4_use_count, (setter)0, (char *)"shared_ptr use count", 0}, {0} // Sentinel }; static void Pkt4_dealloc(Pkt4Object *self) { self->ptr.~Pkt4Ptr(); - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); } static int @@ -479,7 +453,7 @@ Pkt4_init(Pkt4Object *self, PyObject *args, PyObject *kwds) { unsigned long transid; PyObject *data; - new(&self->ptr) Pkt4Ptr; + new (&self->ptr) Pkt4Ptr; if (kwds != 0) { PyErr_SetString(PyExc_TypeError, "keyword arguments are not supported"); @@ -492,11 +466,10 @@ Pkt4_init(Pkt4Object *self, PyObject *args, PyObject *kwds) { } uint8_t *buff; Py_ssize_t len; - PyBytes_AsStringAndSize(data, (char**)&buff, &len); + PyBytes_AsStringAndSize(data, (char **)&buff, &len); self->ptr.reset(new Pkt4(buff, len)); - } - else { + } else { if (!PyArg_ParseTuple(args, "bk", &msg_type, &transid)) { return (-1); } @@ -510,76 +483,74 @@ Pkt4_init(Pkt4Object *self, PyObject *args, PyObject *kwds) { static PyObject * Pkt4_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { Pkt4Object *self; - self = (Pkt4Object *) type->tp_alloc(type, 0); + self = (Pkt4Object *)type->tp_alloc(type, 0); if (self) { - new(&self->ptr) Pkt4Ptr; + new (&self->ptr) Pkt4Ptr; } - return ((PyObject *) self); + return ((PyObject *)self); } PyTypeObject Pkt4Type = { - PyObject_HEAD_INIT(0) - "kea.Pkt4", // tp_name - sizeof(Pkt4Object), // tp_basicsize - 0, // tp_itemsize - (destructor) Pkt4_dealloc, // tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server Pkt4", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - Pkt4_methods, // tp_methods - 0, // tp_members - Pkt4_getsetters, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc) Pkt4_init, // tp_init - PyType_GenericAlloc, // tp_alloc - Pkt4_new // tp_new + PyObject_HEAD_INIT(0) "kea.Pkt4", // tp_name + sizeof(Pkt4Object), // tp_basicsize + 0, // tp_itemsize + (destructor)Pkt4_dealloc, // tp_dealloc + 0, // tp_vectorcall_offset + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_as_async + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "Kea server Pkt4", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + Pkt4_methods, // tp_methods + 0, // tp_members + Pkt4_getsetters, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + (initproc)Pkt4_init, // tp_init + PyType_GenericAlloc, // tp_alloc + Pkt4_new // tp_new }; PyObject * Pkt4_from_handle(Pkt4Ptr &ptr) { Pkt4Object *self = PyObject_New(Pkt4Object, &Pkt4Type); if (self) { - new(&self->ptr) Pkt4Ptr; + new (&self->ptr) Pkt4Ptr; self->ptr = ptr; } return (PyObject *)self; } int -Pkt4_define() { +Pkt4_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&Pkt4Type) < 0) { - return (1); + return -1; } Py_INCREF(&Pkt4Type); - if (PyModule_AddObject(kea_module, "Pkt4", (PyObject *) &Pkt4Type) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&Pkt4Type) < 0) { Py_DECREF(&Pkt4Type); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/setup.py.in b/keamodule/setup.py.in index b988e1f..3bed037 100644 --- a/keamodule/setup.py.in +++ b/keamodule/setup.py.in @@ -2,6 +2,8 @@ import os import re from setuptools import setup, Extension +version = "@PACKAGE_VERSION@" + def transform_includes_to_list(include_string): return [e.replace('-I', '', 1) for e in include_string.split() if e.startswith('-I')] @@ -43,9 +45,10 @@ kea = Extension('kea', 'kea-hooks', 'kea-dhcpsrv', 'ffi'], + define_macros=[('MODULE_VERSION', f'"{version}"')], extra_compile_args=['-std=c++11']) setup(name='kea', - version='@PACKAGE_VERSION@', + version=version, description='Extension module for Kea', ext_modules=[kea]) diff --git a/keamodule/srv_config.cc b/keamodule/srv_config.cc index 9c03ba1..2d33cde 100644 --- a/keamodule/srv_config.cc +++ b/keamodule/srv_config.cc @@ -12,8 +12,7 @@ SrvConfig_toElement(SrvConfigObject *self, PyObject *args) { try { ElementPtr ptr = self->ptr->toElement(); return (element_to_object(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -24,17 +23,16 @@ SrvConfig_getCfgSubnets4(SrvConfigObject *self, PyObject *args) { try { CfgSubnets4Ptr ptr = self->ptr->getCfgSubnets4(); return (CfgSubnets4_from_ptr(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } } static PyMethodDef SrvConfig_methods[] = { - {"toElement", (PyCFunction) SrvConfig_toElement, METH_NOARGS, + {"toElement", (PyCFunction)SrvConfig_toElement, METH_NOARGS, "Unparse configuration object."}, - {"getCfgSubnets4", (PyCFunction) SrvConfig_getCfgSubnets4, METH_NOARGS, + {"getCfgSubnets4", (PyCFunction)SrvConfig_getCfgSubnets4, METH_NOARGS, "Returns object holding subnets configuration for DHCPv4."}, {0} // Sentinel }; @@ -45,19 +43,19 @@ SrvConfig_use_count(OptionObject *self, void *closure) { } static PyGetSetDef SrvConfig_getsetters[] = { - {(char *)"use_count", (getter) SrvConfig_use_count, (setter) 0, (char *)"shared_ptr use count", 0}, + {(char *)"use_count", (getter)SrvConfig_use_count, (setter)0, (char *)"shared_ptr use count", 0}, {0} // Sentinel }; static void SrvConfig_dealloc(SrvConfigObject *self) { self->ptr.~SrvConfigPtr(); - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); } static int SrvConfig_init(SrvConfigObject *self, PyObject *args, PyObject *kwds) { - new(&self->ptr) SrvConfigPtr; + new (&self->ptr) SrvConfigPtr; PyErr_SetString(PyExc_RuntimeError, "cannot directly construct"); return (-1); @@ -66,75 +64,73 @@ SrvConfig_init(SrvConfigObject *self, PyObject *args, PyObject *kwds) { static PyObject * SrvConfig_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { SrvConfigObject *self; - self = (SrvConfigObject *) type->tp_alloc(type, 0); + self = (SrvConfigObject *)type->tp_alloc(type, 0); if (self) { - new(&self->ptr) SrvConfigPtr; + new (&self->ptr) SrvConfigPtr; } - return ((PyObject *) self); + return ((PyObject *)self); } PyTypeObject SrvConfigType = { - PyObject_HEAD_INIT(0) - "kea.SrvConfig", // tp_name - sizeof(SrvConfigObject), // tp_basicsize - 0, // tp_itemsize - (destructor) SrvConfig_dealloc, // tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server SrvConfig", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - SrvConfig_methods, // tp_methods - 0, // tp_members - SrvConfig_getsetters, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - (initproc) SrvConfig_init, // tp_init - PyType_GenericAlloc, // tp_alloc - SrvConfig_new // tp_new + PyObject_HEAD_INIT(0) "kea.SrvConfig", // tp_name + sizeof(SrvConfigObject), // tp_basicsize + 0, // tp_itemsize + (destructor)SrvConfig_dealloc, // tp_dealloc + 0, // tp_vectorcall_offset + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_as_async + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "Kea server SrvConfig", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + SrvConfig_methods, // tp_methods + 0, // tp_members + SrvConfig_getsetters, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + (initproc)SrvConfig_init, // tp_init + PyType_GenericAlloc, // tp_alloc + SrvConfig_new // tp_new }; PyObject * SrvConfig_from_ptr(SrvConfigPtr &ptr) { SrvConfigObject *self = PyObject_New(SrvConfigObject, &SrvConfigType); if (self) { - new(&self->ptr) SrvConfigPtr; + new (&self->ptr) SrvConfigPtr; self->ptr = ptr; } return (PyObject *)self; } int -SrvConfig_define() { +SrvConfig_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&SrvConfigType) < 0) { - return (1); + return -1; } - if (PyModule_AddObject(kea_module, "SrvConfig", (PyObject *) &SrvConfigType) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&SrvConfigType) < 0) { Py_DECREF(&SrvConfigType); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/subnet4.cc b/keamodule/subnet4.cc index 2656220..c9bee3e 100644 --- a/keamodule/subnet4.cc +++ b/keamodule/subnet4.cc @@ -13,8 +13,7 @@ Subnet4_getID(Subnet4Object *self, PyObject *args) { try { SubnetID subnet_id = self->ptr->getID(); return (PyLong_FromLong(subnet_id)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -25,8 +24,7 @@ Subnet4_getValid(Subnet4Object *self, PyObject *args) { try { uint32_t valid = self->ptr->getValid(); return (PyLong_FromLong(valid)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -45,8 +43,7 @@ Subnet4_inRange(Subnet4Object *self, PyObject *args) { Py_RETURN_TRUE; } Py_RETURN_FALSE; - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -57,8 +54,7 @@ Subnet4_toText(Subnet4Object *self, PyObject *args) { try { string text = self->ptr->toText(); return (PyUnicode_FromString(text.c_str())); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } @@ -69,23 +65,22 @@ Subnet4_toElement(Subnet4Object *self, PyObject *args) { try { ElementPtr ptr = self->ptr->toElement(); return (element_to_object(ptr)); - } - catch (const exception &e) { + } catch (const exception &e) { PyErr_SetString(PyExc_TypeError, e.what()); return (0); } } static PyMethodDef Subnet4_methods[] = { - {"getID", (PyCFunction) Subnet4_getID, METH_NOARGS, + {"getID", (PyCFunction)Subnet4_getID, METH_NOARGS, "Return unique ID for subnet."}, - {"getValid", (PyCFunction) Subnet4_getValid, METH_NOARGS, + {"getValid", (PyCFunction)Subnet4_getValid, METH_NOARGS, "Return unique ID for subnet."}, - {"inRange", (PyCFunction) Subnet4_inRange, METH_VARARGS, + {"inRange", (PyCFunction)Subnet4_inRange, METH_VARARGS, "Checks if specified address is in range."}, - {"toText", (PyCFunction) Subnet4_toText, METH_NOARGS, + {"toText", (PyCFunction)Subnet4_toText, METH_NOARGS, "Returns text representation of the subnet."}, - {"toElement", (PyCFunction) Subnet4_toElement, METH_NOARGS, + {"toElement", (PyCFunction)Subnet4_toElement, METH_NOARGS, "Unparse configuration object."}, {0} // Sentinel }; @@ -96,89 +91,87 @@ Subnet4_use_count(OptionObject *self, void *closure) { } static PyGetSetDef Subnet4_getsetters[] = { - {(char *)"use_count", (getter) Subnet4_use_count, (setter) 0, (char *)"shared_ptr use count", 0}, + {(char *)"use_count", (getter)Subnet4_use_count, (setter)0, (char *)"shared_ptr use count", 0}, {0} // Sentinel }; static void Subnet4_dealloc(Subnet4Object *self) { self->ptr.~Subnet4Ptr(); - Py_TYPE(self)->tp_free((PyObject *) self); + Py_TYPE(self)->tp_free((PyObject *)self); } static PyObject * Subnet4_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { Subnet4Object *self; - self = (Subnet4Object *) type->tp_alloc(type, 0); + self = (Subnet4Object *)type->tp_alloc(type, 0); if (self) { - new(&self->ptr) Subnet4Ptr; + new (&self->ptr) Subnet4Ptr; } - return ((PyObject *) self); + return ((PyObject *)self); } PyTypeObject Subnet4Type = { - PyObject_HEAD_INIT(0) - "kea.Subnet4", // tp_name - sizeof(Subnet4Object), // tp_basicsize - 0, // tp_itemsize - (destructor) Subnet4_dealloc, // tp_dealloc - 0, // tp_vectorcall_offset - 0, // tp_getattr - 0, // tp_setattr - 0, // tp_as_async - 0, // tp_repr - 0, // tp_as_number - 0, // tp_as_sequence - 0, // tp_as_mapping - 0, // tp_hash - 0, // tp_call - 0, // tp_str - 0, // tp_getattro - 0, // tp_setattro - 0, // tp_as_buffer - Py_TPFLAGS_DEFAULT, // tp_flags - "Kea server Subnet4", // tp_doc - 0, // tp_traverse - 0, // tp_clear - 0, // tp_richcompare - 0, // tp_weaklistoffset - 0, // tp_iter - 0, // tp_iternext - Subnet4_methods, // tp_methods - 0, // tp_members - Subnet4_getsetters, // tp_getset - 0, // tp_base - 0, // tp_dict - 0, // tp_descr_get - 0, // tp_descr_set - 0, // tp_dictoffset - 0, // tp_init - PyType_GenericAlloc, // tp_alloc - Subnet4_new // tp_new + PyObject_HEAD_INIT(0) "kea.Subnet4", // tp_name + sizeof(Subnet4Object), // tp_basicsize + 0, // tp_itemsize + (destructor)Subnet4_dealloc, // tp_dealloc + 0, // tp_vectorcall_offset + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_as_async + 0, // tp_repr + 0, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT, // tp_flags + "Kea server Subnet4", // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + Subnet4_methods, // tp_methods + 0, // tp_members + Subnet4_getsetters, // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + 0, // tp_init + PyType_GenericAlloc, // tp_alloc + Subnet4_new // tp_new }; PyObject * Subnet4_from_ptr(Subnet4Ptr &ptr) { Subnet4Object *self = PyObject_New(Subnet4Object, &Subnet4Type); if (self) { - new(&self->ptr) Subnet4Ptr; + new (&self->ptr) Subnet4Ptr; self->ptr = ptr; } return (PyObject *)self; } int -Subnet4_define() { +Subnet4_registerType(PyObject *mod, const char *name) { if (PyType_Ready(&Subnet4Type) < 0) { - return (1); + return -1; } Py_INCREF(&Subnet4Type); - if (PyModule_AddObject(kea_module, "Subnet4", (PyObject *) &Subnet4Type) < 0) { + if (PyModule_AddObject(mod, name, (PyObject *)&Subnet4Type) < 0) { Py_DECREF(&Subnet4Type); - return (1); + return -1; } - return (0); + return 0; } - } diff --git a/keamodule/tests/conftest.py b/keamodule/tests/conftest.py new file mode 100644 index 0000000..468a447 --- /dev/null +++ b/keamodule/tests/conftest.py @@ -0,0 +1,6 @@ +import kea + + +def pytest_sessionstart(session): + # Initialize the kea logger + kea._loggerInit("pytest") diff --git a/keamodule/tests/test_callout_handle.py b/keamodule/tests/test_callout_handle.py index e45e46c..b6822c3 100644 --- a/keamodule/tests/test_callout_handle.py +++ b/keamodule/tests/test_callout_handle.py @@ -1,231 +1,219 @@ import sys import kea +import pytest import utils class TestCalloutHandle_new(utils.BaseTestCase): - def test_badarg_count(self): self.assert_constructor_one_arg_no_keywords(kea.CalloutHandle) def test_badarg_type(self): - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: kea.CalloutHandle(1) - self.assertEqual(("argument 1 must be kea.CalloutManager, not int",), cm.exception.args) + assert cm.value.args == ("argument 1 must be kea.CalloutManager, not int",) def test_ok(self): m = kea.CalloutManager() h = kea.CalloutHandle(m) - self.assertEqual(2, m.use_count) + assert m.use_count == 2 del h - self.assertEqual(1, m.use_count) + assert m.use_count == 1 class TestCalloutHandle_getArgument(utils.BaseTestCase): - def test_badarg_count(self): h = kea.CalloutHandle(kea.CalloutManager()) self.assert_method_one_arg_no_keywords(h.getArgument) def test_badarg_type(self): h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match="argument 1 must be str, not int"): h.getArgument(3) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) def test_badarg_value(self): - h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(ValueError) as cm: - h.getArgument('foo') - self.assertEqual(("unknown argument",), cm.exception.args) + handle = kea.CalloutHandle(kea.CalloutManager()) + with pytest.raises(ValueError, match="unknown argument"): + handle.getArgument("foo") def test_ok(self): h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: - h.getArgument('query4') - self.assertEqual(("unable to find argument with name query4",), cm.exception.args) + with pytest.raises(TypeError) as cm: + h.getArgument("query4") + assert cm.value.args == ("unable to find argument with name query4",) class TestCalloutHandle_setArgument(utils.BaseTestCase): - def test_badarg_count(self): h = kea.CalloutHandle(kea.CalloutManager()) self.assert_method_two_args_no_keywords(h.setArgument) def test_badarg_type(self): h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: h.setArgument(3, 4) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) + assert cm.value.args == ("argument 1 must be str, not int",) def test_badarg_value(self): - h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(ValueError) as cm: - h.setArgument('foo', 3) - self.assertEqual(("unknown argument",), cm.exception.args) + handle = kea.CalloutHandle(kea.CalloutManager()) + with pytest.raises(ValueError, match="unknown argument"): + handle.setArgument("foo", 3) def test_lease4_ok(self): h = kea.CalloutHandle(kea.CalloutManager()) x = kea.Lease4() - x.addr = '1.2.3.4' - self.assertEqual(1, x.use_count) - self.assertIsNone(h.setArgument('lease4', x)) - self.assertEqual(2, x.use_count) - self.assertEqual('1.2.3.4', h.getArgument('lease4').addr) + x.addr = "1.2.3.4" + assert x.use_count == 1 + assert h.setArgument("lease4", x) is None + assert x.use_count == 2 + assert h.getArgument("lease4").addr == "1.2.3.4" def test_lease4_bad_type(self): h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: - h.setArgument('lease4', 3) - self.assertEqual(("expected Lease4 object",), cm.exception.args) + with pytest.raises(TypeError) as cm: + h.setArgument("lease4", 3) + assert cm.value.args == ("expected Lease4 object",) def test_query4_ok(self): h = kea.CalloutHandle(kea.CalloutManager()) x = kea.Pkt4(kea.DHCPACK, 42) - self.assertEqual(1, x.use_count) - self.assertIsNone(h.setArgument('query4', x)) - self.assertEqual(2, x.use_count) - self.assertEqual(kea.DHCPACK, h.getArgument('query4').getType()) + assert x.use_count == 1 + assert h.setArgument("query4", x) is None + assert x.use_count == 2 + assert h.getArgument("query4").getType() == kea.DHCPACK def test_query4_bad_type(self): h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: - h.setArgument('query4', 3) - self.assertEqual(("expected Pkt4 object",), cm.exception.args) + with pytest.raises(TypeError) as cm: + h.setArgument("query4", 3) + assert cm.value.args == ("expected Pkt4 object",) def test_response4_ok(self): h = kea.CalloutHandle(kea.CalloutManager()) x = kea.Pkt4(kea.DHCPACK, 42) - self.assertEqual(1, x.use_count) - self.assertIsNone(h.setArgument('response4', x)) - self.assertEqual(2, x.use_count) - self.assertEqual(kea.DHCPACK, h.getArgument('response4').getType()) + assert x.use_count == 1 + assert h.setArgument("response4", x) is None + assert x.use_count == 2 + assert h.getArgument("response4").getType() == kea.DHCPACK def test_response4_bad_type(self): h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: - h.setArgument('response4', 3) - self.assertEqual(("expected Pkt4 object",), cm.exception.args) + with pytest.raises(TypeError) as cm: + h.setArgument("response4", 3) + assert cm.value.args == ("expected Pkt4 object",) def test_command_ok(self): h = kea.CalloutHandle(kea.CalloutManager()) - self.assertIsNone(h.setArgument('command', {'foo': 42})) - self.assertEqual({'foo': 42}, h.getArgument('command')) + assert h.setArgument("command", {"foo": 42}) is None + assert {"foo": 42} == h.getArgument("command") def test_command_bad_type(self): h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: - h.setArgument('command', self) - self.assertEqual(("unhandled type TestCalloutHandle_setArgument",), cm.exception.args) + with pytest.raises(TypeError) as cm: + h.setArgument("command", self) + assert cm.value.args == ("unhandled type TestCalloutHandle_setArgument",) def test_response_ok(self): h = kea.CalloutHandle(kea.CalloutManager()) - self.assertIsNone(h.setArgument('response', [1, 'two', None])) - self.assertEqual([1, 'two', None], h.getArgument('response')) + assert h.setArgument("response", [1, "two", None]) is None + assert [1, "two", None] == h.getArgument("response") def test_response_bad_type(self): h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: - h.setArgument('response', self) - self.assertEqual(("unhandled type TestCalloutHandle_setArgument",), cm.exception.args) + with pytest.raises(TypeError) as cm: + h.setArgument("response", self) + assert cm.value.args == ("unhandled type TestCalloutHandle_setArgument",) class TestCalloutHandle_setContext(utils.BaseTestCase): - def test_badarg_count(self): h = kea.CalloutHandle(kea.CalloutManager()) self.assert_method_two_args_no_keywords(h.setContext) def test_badarg_type(self): h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: h.setContext(1, 2) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) + assert cm.value.args == ("argument 1 must be str, not int",) def test_ok(self): h = kea.CalloutHandle(kea.CalloutManager()) foo = utils.Logger() - self.assertIsNone(h.setContext('foo', foo)) - self.assertEqual(3, sys.getrefcount(foo)) + assert h.setContext("foo", foo) is None + assert sys.getrefcount(foo) == 3 class TestCalloutHandle_getContext(utils.BaseTestCase): - def test_badarg_count(self): h = kea.CalloutHandle(kea.CalloutManager()) self.assert_method_one_arg_no_keywords(h.getContext) def test_badarg_type(self): h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: h.getContext(1) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) + assert cm.value.args == ("argument 1 must be str, not int",) def test_ok(self): h = kea.CalloutHandle(kea.CalloutManager()) foo = utils.Logger() - h.setContext('foo', foo) - bar = h.getContext('foo') - self.assertIs(foo, bar) + h.setContext("foo", foo) + bar = h.getContext("foo") + assert foo is bar def test_notset(self): h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: - h.getContext('foo') - self.assertEqual(("unable to find callout context associated with the current" - " library index (-1)",), cm.exception.args) + with pytest.raises(TypeError) as cm: + h.getContext("foo") + assert cm.value.args == ("unable to find callout context associated with the current" " library index (-1)",) class TestCalloutHandle_deleteContext(utils.BaseTestCase): - def test_badarg_count(self): h = kea.CalloutHandle(kea.CalloutManager()) self.assert_method_one_arg_no_keywords(h.deleteContext) def test_badarg_type(self): h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: h.deleteContext(1) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) + assert cm.value.args == ("argument 1 must be str, not int",) def test_ok(self): h = kea.CalloutHandle(kea.CalloutManager()) foo = utils.Logger() - h.setContext('foo', foo) - self.assertEqual(3, sys.getrefcount(foo)) - self.assertIsNone(h.deleteContext('foo')) - self.assertEqual(2, sys.getrefcount(foo)) + h.setContext("foo", foo) + assert sys.getrefcount(foo) == 3 + assert h.deleteContext("foo") is None + assert sys.getrefcount(foo) == 2 def test_notset(self): h = kea.CalloutHandle(kea.CalloutManager()) - self.assertIsNone(h.deleteContext('foo')) + assert h.deleteContext("foo") is None class TestCalloutHandle_getStatus(utils.BaseTestCase): - def test_badarg_count(self): h = kea.CalloutHandle(kea.CalloutManager()) self.assert_method_no_arguments(h.getStatus) def test_ok(self): h = kea.CalloutHandle(kea.CalloutManager()) - self.assertEqual(kea.NEXT_STEP_CONTINUE, h.getStatus()) + assert h.getStatus() == kea.NEXT_STEP_CONTINUE class TestCalloutHandle_setStatus(utils.BaseTestCase): + def setUp(self): + self.handle = kea.CalloutHandle(kea.CalloutManager()) def test_badarg_count(self): - h = kea.CalloutHandle(kea.CalloutManager()) - self.assert_method_one_arg_no_keywords(h.setStatus) + self.assert_method_one_arg_no_keywords(self.handle.setStatus) def test_badarg_type(self): - h = kea.CalloutHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: - h.setStatus('foo') - self.assertEqual(("an integer is required (got type str)",), cm.exception.args) + with pytest.raises(TypeError, match="an integer is required|object cannot be interpreted as an integer"): + self.handle.setStatus("foo") def test_ok(self): - h = kea.CalloutHandle(kea.CalloutManager()) - self.assertIsNone(h.setStatus(kea.NEXT_STEP_SKIP)) - self.assertEqual(kea.NEXT_STEP_SKIP, h.getStatus()) + assert self.handle.setStatus(kea.NEXT_STEP_SKIP) is None + assert self.handle.getStatus() == kea.NEXT_STEP_SKIP diff --git a/keamodule/tests/test_callout_manager.py b/keamodule/tests/test_callout_manager.py index 0e5dd65..3d58ced 100644 --- a/keamodule/tests/test_callout_manager.py +++ b/keamodule/tests/test_callout_manager.py @@ -3,10 +3,9 @@ class TestCalloutManager_new(utils.BaseTestCase): - def test_badarg_count(self): self.assert_constructor_no_arguments(kea.CalloutManager) def test_ok(self): m = kea.CalloutManager() - self.assertEqual(1, m.use_count) + assert m.use_count == 1 diff --git a/keamodule/tests/test_cfg_mgr.py b/keamodule/tests/test_cfg_mgr.py index 075d588..b418de6 100644 --- a/keamodule/tests/test_cfg_mgr.py +++ b/keamodule/tests/test_cfg_mgr.py @@ -1,36 +1,81 @@ import kea -import utils +import pytest -class TestCfgMgr_new(utils.BaseTestCase): +@pytest.fixture() +def cfg_mgr(): + """Fixture to create a single instance of CfgMgr.""" + return kea.CfgMgr.instance() - def test_badarg_count(self): - self.assert_constructor_no_arguments(kea.CfgMgr) - def test_ok(self): - m = kea.CfgMgr() - self.assertIsInstance(m, kea.CfgMgr) +@pytest.mark.parametrize(("args", "kwargs"), [((42,), {}), ((), {"foo": 42})]) +def test_cfg_mgr_no_arguments_allowed(args, kwargs): + """Test to ensure that CfgMgr raises TypeError with incorrect arguments.""" + with pytest.raises(TypeError, match=r"takes no arguments"): + kea.CfgMgr(*args, **kwargs) -class TestCfgMgr_getCurrentCfg(utils.BaseTestCase): +def test_cfg_mgr_is_singleton(cfg_mgr): + """Test to ensure that CfgMgr follows singleton pattern.""" + assert isinstance(cfg_mgr, kea.CfgMgr), "The instance is not of type CfgMgr" + assert cfg_mgr is kea.CfgMgr(), "CfgMgr is not a singleton" - def test_badarg_count(self): - m = kea.CfgMgr() - self.assert_method_no_arguments(m.getCurrentCfg) - def test_ok(self): - m = kea.CfgMgr() - c = m.getCurrentCfg() - self.assertIsInstance(c, kea.SrvConfig) +def test_cfg_mgr_instance_is_singleton(cfg_mgr): + """Test to ensure that CfgMgr static method instance follows singleton pattern.""" + instance = kea.CfgMgr.instance() + assert isinstance(instance, kea.CfgMgr), "The instance is not of type CfgMgr" + assert instance is kea.CfgMgr.instance(), "CfgMgr.instance() is not a singleton" + assert instance is cfg_mgr, "CfgMgr and CfgMgr.instance() are not the same" -class TestCfgMgr_getStagingCfg(utils.BaseTestCase): +@pytest.mark.parametrize( + ("method_name", "args", "kwargs", "error_message"), + [ + ("instance", (1,), {}, r"takes no arguments"), + ("instance", (), {"foo": 1}, r"takes no keyword arguments"), + ("getDataDir", (1,), {}, r"takes no arguments"), + ("getDataDir", (), {"foo": 1}, r"takes no keyword arguments"), + ("setDataDir", (), {}, r"function takes at least 1 argument"), + ("setDataDir", (1,), {}, r"argument 1 must be str, not int"), + ("setDataDir", ("foo", "bar"), {}, r"an integer is required|object cannot be interpreted as an integer"), + ("setDataDir", ("foo", 1, "bar"), {}, r"function takes at most 2 arguments"), + ("setDataDir", (), {"foo": 1}, r"takes no keyword arguments"), + ("getCurrentCfg", (1,), {}, r"takes no arguments"), + ("getCurrentCfg", (), {"foo": 1}, r"takes no keyword arguments"), + ("getStagingCfg", (1,), {}, r"takes no arguments"), + ("getStagingCfg", (), {"foo": 1}, r"takes no keyword arguments"), + ], +) +def test_cfg_mgr_method_invalid_args(cfg_mgr, method_name, args, kwargs, error_message): + """Test to ensure HostMgr method methods raise TypeError with incorrect arguments.""" + method = getattr(cfg_mgr, method_name) + with pytest.raises(TypeError, match=error_message): + method(*args, **kwargs) - def test_badarg_count(self): - m = kea.CfgMgr() - self.assert_method_no_arguments(m.getStagingCfg) - def test_ok(self): - m = kea.CfgMgr() - c = m.getStagingCfg() - self.assertIsInstance(c, kea.SrvConfig) +def test_cfg_mgr_get_data_dir_returns_string(cfg_mgr): + """Test to ensure that HostMgr method getDataDir returns a string.""" + data_dir = cfg_mgr.getDataDir() + assert isinstance(data_dir, str), "HostMgr method getDataDir does not return a string" + assert len(data_dir) > 0, "HostMgr method getDataDir returns an empty string" + assert "\x00" not in data_dir, "HostMgr method getDataDir contains null character" + + +def test_cfg_mgr_set_data_dir_updates_directory(cfg_mgr): + """Test to ensure that HostMgr method setDataDir sets the data directory.""" + new_data_dir = "/new/data/dir" + cfg_mgr.setDataDir(new_data_dir) + assert cfg_mgr.getDataDir() == new_data_dir, "HostMgr method setDataDir does not set the data directory" + + +def test_cfg_mgr_get_current_cfg_returns_srv_config(cfg_mgr): + """Test to ensure that HostMgr method getCurrentCfg returns a SrvConfig object.""" + current_config = cfg_mgr.getCurrentCfg() + assert isinstance(current_config, kea.SrvConfig), "HostMgr method getCurrentCfg does not return a SrvConfig object" + + +def test_cfg_mgr_get_staging_cfg_returns_srv_config(cfg_mgr): + """Test to ensure that HostMgr method getStagingCfg returns a SrvConfig object.""" + staging_config = cfg_mgr.getStagingCfg() + assert isinstance(staging_config, kea.SrvConfig) diff --git a/keamodule/tests/test_cfg_subnets4.py b/keamodule/tests/test_cfg_subnets4.py index 3a32185..6763da1 100644 --- a/keamodule/tests/test_cfg_subnets4.py +++ b/keamodule/tests/test_cfg_subnets4.py @@ -1,57 +1,54 @@ import kea +import pytest import utils class TestCfgSubnets4_new(utils.BaseTestCase): - def test_cannot_construct(self): self.assert_cannot_construct(kea.CfgSubnets4) class TestCfgSubnets4_getAll(utils.BaseTestCase): - def test_badarg_count(self): n = kea.CfgMgr().getCurrentCfg().getCfgSubnets4() self.assert_method_no_arguments(n.getAll) def test_ok(self): n = kea.CfgMgr().getCurrentCfg().getCfgSubnets4() - self.assertEqual([], n.getAll()) - self.assertEqual(2, n.use_count) + assert [] == n.getAll() + assert n.use_count == 2 o = kea.CfgMgr().getCurrentCfg().getCfgSubnets4() - self.assertEqual(3, o.use_count) + assert o.use_count == 3 o = None - self.assertEqual(2, n.use_count) + assert n.use_count == 2 class TestCfgSubnets4_getSubnet(utils.BaseTestCase): - def test_badarg_count(self): n = kea.CfgMgr().getCurrentCfg().getCfgSubnets4() self.assert_method_one_arg_no_keywords(n.getSubnet) def test_badarg_type(self): n = kea.CfgMgr().getCurrentCfg().getCfgSubnets4() - with self.assertRaises(TypeError) as cm: - n.getSubnet('foo') - self.assertEqual(("argument 1 must be int, not str",), cm.exception.args) + with pytest.raises(TypeError) as cm: + n.getSubnet("foo") + assert cm.value.args == ("argument 1 must be int, not str",) def test_ok(self): n = kea.CfgMgr().getCurrentCfg().getCfgSubnets4() - self.assertIsNone(n.getSubnet(1)) + assert n.getSubnet(1) is None class TestCfgSubnets4_selectSubnet(utils.BaseTestCase): - def test_badarg_count(self): n = kea.CfgMgr().getCurrentCfg().getCfgSubnets4() self.assert_method_one_arg_no_keywords(n.selectSubnet) def test_badarg_type(self): n = kea.CfgMgr().getCurrentCfg().getCfgSubnets4() - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: n.selectSubnet(1) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) + assert cm.value.args == ("argument 1 must be str, not int",) # def test_ok(self): # n = kea.CfgMgr().getCurrentCfg().getCfgSubnets4() @@ -59,11 +56,10 @@ def test_badarg_type(self): class TestCfgSubnets4_toElement(utils.BaseTestCase): - def test_badarg_type(self): n = kea.CfgMgr().getCurrentCfg().getCfgSubnets4() self.assert_method_no_arguments(n.toElement) def test_ok(self): n = kea.CfgMgr().getCurrentCfg().getCfgSubnets4() - self.assertEqual([], n.toElement()) + assert [] == n.toElement() diff --git a/keamodule/tests/test_host.py b/keamodule/tests/test_host.py new file mode 100644 index 0000000..fcb010d --- /dev/null +++ b/keamodule/tests/test_host.py @@ -0,0 +1,50 @@ +import kea +import pytest + + +@pytest.fixture() +def host(): + """Fixture to create a single instance of Host""" + return kea.Host("cafecafe42", "hw-address", 0, "198.51.100.42") + + +def test_Host_getHostId(host): + # Call the getHostId function and check the result + host_id = host.getHostId() + assert isinstance(host_id, int), "Host ID should be an integer" + + +def test_Host_toElement(host): + # Call the toElement function and check the result + element = host.toElement() + assert isinstance(element, dict), "Element should be a dictionary" + assert element == { + "boot-file-name": "", + "client-classes": [], + "hostname": "", + "hw-address": "ca:fe:ca:fe:42", + "ip-address": "198.51.100.42", + "next-server": "0.0.0.0", + "option-data": [], + "server-hostname": "", + }, "Element should match expected dictionary" + + +def test_Host_getIdentifier(host): + # Call the getIdentifier function and check the result + identifier = host.getIdentifier() + assert isinstance(identifier, str), "Identifier should be a string" + assert "hwaddr=CAFECAFE42" in identifier, "String representation should contain identifier" + + +def test_Host_use_count(host): + # Call the use_count property and check the result + use_count = host.use_count + assert isinstance(use_count, int), "use_count should be an integer" + + +def test_Host_str(host): + # Call the __str__ function and check the result + str_representation = str(host) + assert isinstance(str_representation, str), "String representation should be a string" + assert "hwaddr=CAFECAFE42" in str_representation, "String representation should contain identifier" diff --git a/keamodule/tests/test_host_mgr.py b/keamodule/tests/test_host_mgr.py index 68dd47d..77351d4 100644 --- a/keamodule/tests/test_host_mgr.py +++ b/keamodule/tests/test_host_mgr.py @@ -1,34 +1,111 @@ import kea -import utils +import pytest -class TestHostMgr_new(utils.BaseTestCase): +@pytest.fixture() +def host_mgr(): + """Fixture to create a single instance of HostMgr.""" + return kea.HostMgr.instance() - def test_badarg_count(self): - self.assert_cannot_construct(kea.HostMgr) +@pytest.mark.parametrize(("args", "kwargs"), [((42,), {}), ((), {"foo": 42})]) +def test_host_mgr_no_arguments_allowed(args, kwargs): + """Test to ensure that HostMgr raises TypeError with incorrect arguments.""" + with pytest.raises(TypeError, match=r"takes no arguments"): + kea.HostMgr(*args, **kwargs) -class TestHostMgr_instance(utils.BaseTestCase): - def test_badarg_count(self): - self.assert_method_no_arguments(kea.HostMgr.instance) +def test_host_mgr_is_singleton(): + """Test to check if the kea.HostMgr.instance() is of type kea.HostMgr.""" + instance = kea.HostMgr() + assert isinstance(instance, kea.HostMgr), "The instance is not of type kea.HostMgr" + assert instance is kea.HostMgr(), "HostMgr is not a singleton" - def test_ok(self): - m = kea.HostMgr.instance() - self.assertIsInstance(m, kea.HostMgr) +def test_host_mgr_instance_issingleton(): + """Test to ensure that HostMgr follows singleton pattern.""" + instance = kea.HostMgr.instance() + assert instance is kea.HostMgr.instance(), "HostMgr.instance() is not a singleton" -class TestHostMgr_add(utils.BaseTestCase): - def test_badarg_count(self): - m = kea.HostMgr.instance() - with self.assertRaises(TypeError) as cm: - m.add(1) - with self.assertRaises(TypeError) as cm: - m.add(1, 2) +@pytest.mark.parametrize( + ("method_name", "args", "kwargs", "error_message"), + [ + ("add", (), {}, r"function takes at least 1 argument \(0 given\)"), + ("add", (), {"foo": 1}, r"takes no keyword arguments"), + ("add", ("foo",), {}, r"argument 1 must be kea.Host, not str"), + ("get", (), {}, r"function takes at least 2 arguments \(0 given\)"), + ("get", (), {"foo": 1}, r"takes no keyword arguments"), + ("get", ("foo", "foo"), {}, r"argument 1 must be int, not str"), + ("get", (42, 42), {}, r"argument 2 must be str, not int"), + ("get4", (), {}, r"function takes at least 2 arguments \(0 given\)"), + ("get4", (), {"foo": 1}, r"takes no keyword arguments"), + ("get4", ("foo", "foo"), {}, r"argument 1 must be int, not str"), + ("get4", (42, 42), {}, r"argument 2 must be str, not int"), + ("get4Any", (), {}, r"function takes at least 3 arguments \(0 given\)"), + ("get4Any", (), {"foo": 1}, r"takes no keyword arguments"), + ("get4Any", ("foo", "foo", "foo"), {}, r"argument 1 must be int, not str"), + ("get4Any", (42, 42, "foo"), {}, r"argument 2 must be str, not int"), + ("get4Any", (42, "foo", 42), {}, r"argument 3 must be str, not int"), + ("getAll4", (), {}, r"function takes at least 1 argument \(0 given\)"), + ("getAll4", (), {"foo": 1}, r"takes no keyword arguments"), + ("getAll4", ("foo",), {}, r"argument 1 must be int, not str"), + ("getPage4", (), {}, r"function takes exactly 4 arguments \(0 given\)"), + ("getPage4", (), {"foo": 1}, r"takes no keyword arguments"), + ("getPage4", ("foo", 0, 0, 10), {}, r"argument 1 must be int, not str"), + ("getPage4", (1, "foo", 0, 10), {}, r"argument 2 must be int, not str"), + ("getPage4", (1, 0, "foo", 10), {}, r"argument 3 must be int, not str"), + ("getPage4", (1, 0, 0, "foo"), {}, r"argument 4 must be int, not str"), + ("del_", (), {}, r"function takes at least 2 arguments \(0 given\)"), + ("del_", (), {"foo": 1}, r"takes no keyword arguments"), + ("del_", ("foo", "foo"), {}, r"argument 1 must be int, not str"), + ("del_", (1, 42), {}, r"argument 2 must be str, not int"), + ("del4", (), {}, r"function takes at least 3 arguments \(0 given\)"), + ("del4", (), {"foo": 1}, r"takes no keyword arguments"), + ("del4", ("foo", "foo", "foo"), {}, r"argument 1 must be int, not str"), + ("del4", (1, 42, "foo"), {}, r"argument 2 must be str, not int"), + ("del4", (1, "foo", 42), {}, r"argument 3 must be str, not int"), + ], +) +def test_host_mgr_method_invalid_args(host_mgr, method_name, args, kwargs, error_message): + """Test to ensure methods raise TypeError with incorrect arguments.""" + method = getattr(host_mgr, method_name) + with pytest.raises(TypeError, match=error_message): + method(*args, **kwargs) - def test_badarg_type(self): - m = kea.HostMgr.instance() - with self.assertRaises(TypeError) as cm: - m.add('foo') - self.assertEqual(("argument 1 must be kea.Host, not str",), cm.exception.args) + +def test_host_mgr_add_get_del(host_mgr): + """Test to ensure that add, get, and del methods work as expected.""" + subnet_id = 0 + target = kea.PRIMARY_SOURCE + + host = kea.Host("cafecafe42", "hw-address", subnet_id, "198.51.100.42") + + # Verify that the host list is initially empty + assert not host_mgr.getAll4(subnet_id), "Hosts not empty" + + host_mgr.add(host, target) + + # Verify that the host has been added + assert len(host_mgr.getAll4(subnet_id)) == 1, "Host not added" + + # Verify that the added host can be retrieved + assert host_mgr.get(subnet_id, "198.51.100.42") is not None, "Host not found" + assert host_mgr.get(subnet_id, "hw-address", "cafecafe42") is not None, "Host not found" + assert host_mgr.get4(subnet_id, "198.51.100.42") is not None, "Host not found" + assert host_mgr.get4Any(subnet_id, "hw-address", "cafecafe42") is not None, "Host not found" + + # Verify that fetching a non-existent host returns None + assert host_mgr.get(subnet_id, "254.254.254.254") is None, "Host found when it shouldn't be" + assert host_mgr.get(subnet_id, "hw-address", "deadbeef21") is None, "Host found when it shouldn't be" + assert host_mgr.get4(subnet_id, "254.254.254.254") is None, "Host found when it shouldn't be" + assert host_mgr.get4Any(subnet_id, "hw-address", "deadbeef21") is None, "Host found when it shouldn't be" + + assert host_mgr.del4(subnet_id, "hw-address", "cafecafe42", target), "Host not deleted" + assert not host_mgr.del4(subnet_id, "hw-address", "deadbeef21", target), "Host deleted when it shouldn't be" + + # Verify that the host has been deleted + assert host_mgr.get(subnet_id, "hw-address", "cafecafe42") is None, "Host not deleted" + assert host_mgr.get(subnet_id, "198.51.100.42") is None, "Host not deleted" + + assert not host_mgr.getAll4(subnet_id), "Hosts not empty after deletion" diff --git a/keamodule/tests/test_lease4.py b/keamodule/tests/test_lease4.py index 222bc7e..53909b2 100644 --- a/keamodule/tests/test_lease4.py +++ b/keamodule/tests/test_lease4.py @@ -1,257 +1,246 @@ import kea +import pytest import utils class TestLease4_new(utils.BaseTestCase): - def test_badarg_count(self): self.assert_constructor_no_arguments(kea.Lease4) def test_ok(self): x = kea.Lease4() - self.assertEqual(1, x.use_count) + assert x.use_count == 1 class TestLease4_addr(utils.BaseTestCase): - def test_getset(self): x = kea.Lease4() - self.assertEqual('0.0.0.0', x.addr) - x.addr = '192.168.0.1' - self.assertEqual('192.168.0.1', x.addr) + assert x.addr == "0.0.0.0" + x.addr = "192.168.0.1" + assert x.addr == "192.168.0.1" def test_bad_type(self): x = kea.Lease4() - with self.assertRaises(TypeError) as cm: - x.addr = 'bogus' - self.assertEqual(("Failed to convert string to address 'bogus': Invalid argument",), - cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: + x.addr = "bogus" + assert cm.value.args == ("Failed to convert string to address 'bogus': Invalid argument",) + with pytest.raises(TypeError) as cm: x.addr = 0 - self.assertEqual(('The addr attribute value must be a str',), cm.exception.args) + assert cm.value.args == ("The addr attribute value must be a str",) class TestLease4_valid_lft(utils.BaseTestCase): - def test_getset(self): x = kea.Lease4() - self.assertEqual(0, x.valid_lft) + assert x.valid_lft == 0 x.valid_lft = 3600 - self.assertEqual(3600, x.valid_lft) + assert x.valid_lft == 3600 def test_bad_type(self): x = kea.Lease4() - with self.assertRaises(TypeError) as cm: - x.valid_lft = 'bogus' - self.assertEqual(('The valid_lft attribute value must be an int',), cm.exception.args) + with pytest.raises(TypeError) as cm: + x.valid_lft = "bogus" + assert cm.value.args == ("The valid_lft attribute value must be an int",) class TestLease4_cltt(utils.BaseTestCase): - def test_getset(self): x = kea.Lease4() - self.assertEqual(0, x.cltt) + assert x.cltt == 0 x.cltt = 3600 - self.assertEqual(3600, x.cltt) + assert x.cltt == 3600 def test_bad_type(self): x = kea.Lease4() - with self.assertRaises(TypeError) as cm: - x.cltt = 'bogus' - self.assertEqual(('The cltt attribute value must be an int',), cm.exception.args) + with pytest.raises(TypeError) as cm: + x.cltt = "bogus" + assert cm.value.args == ("The cltt attribute value must be an int",) class TestLease4_subnet_id(utils.BaseTestCase): - def test_getset(self): x = kea.Lease4() - self.assertEqual(0, x.subnet_id) + assert x.subnet_id == 0 x.subnet_id = 5 - self.assertEqual(5, x.subnet_id) + assert x.subnet_id == 5 def test_bad_type(self): x = kea.Lease4() - with self.assertRaises(TypeError) as cm: - x.subnet_id = 'bogus' - self.assertEqual(('The subnet_id attribute value must be an int',), cm.exception.args) + with pytest.raises(TypeError) as cm: + x.subnet_id = "bogus" + assert cm.value.args == ("The subnet_id attribute value must be an int",) class TestLease4_hostname(utils.BaseTestCase): - def test_getset(self): x = kea.Lease4() - self.assertIsNone(x.hostname) - x.hostname = 'example.org' - self.assertEqual('example.org', x.hostname) + assert x.hostname is None + x.hostname = "example.org" + assert x.hostname == "example.org" x.hostname = None - self.assertIsNone(x.hostname) + assert x.hostname is None def test_bad_type(self): x = kea.Lease4() - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: x.hostname = 3 - self.assertEqual(('The hostname attribute value must be a str',), cm.exception.args) + assert cm.value.args == ("The hostname attribute value must be a str",) class TestLease4_fqdn_fwd(utils.BaseTestCase): - def test_getset(self): x = kea.Lease4() - self.assertEqual(False, x.fqdn_fwd) + assert False is x.fqdn_fwd x.fqdn_fwd = True - self.assertEqual(True, x.fqdn_fwd) + assert True is x.fqdn_fwd x.fqdn_fwd = False - self.assertEqual(False, x.fqdn_fwd) + assert False is x.fqdn_fwd def test_bad_type(self): x = kea.Lease4() - with self.assertRaises(TypeError) as cm: - x.fqdn_fwd = 'bogus' - self.assertEqual(('The fqdn_fwd attribute value must be a bool',), cm.exception.args) + with pytest.raises(TypeError) as cm: + x.fqdn_fwd = "bogus" + assert cm.value.args == ("The fqdn_fwd attribute value must be a bool",) class TestLease4_fqdn_rev(utils.BaseTestCase): - def test_getset(self): x = kea.Lease4() - self.assertEqual(False, x.fqdn_rev) + assert False is x.fqdn_rev x.fqdn_rev = True - self.assertEqual(True, x.fqdn_rev) + assert True is x.fqdn_rev x.fqdn_rev = False - self.assertEqual(False, x.fqdn_rev) + assert False is x.fqdn_rev def test_bad_type(self): x = kea.Lease4() - with self.assertRaises(TypeError) as cm: - x.fqdn_rev = 'bogus' - self.assertEqual(('The fqdn_rev attribute value must be a bool',), cm.exception.args) + with pytest.raises(TypeError) as cm: + x.fqdn_rev = "bogus" + assert cm.value.args == ("The fqdn_rev attribute value must be a bool",) class TestLease4_hwaddr(utils.BaseTestCase): - def test_getset(self): x = kea.Lease4() - self.assertIsNone(x.hwaddr) - x.hwaddr = '01:02:03:04:05:06' - self.assertEqual('01:02:03:04:05:06', x.hwaddr) + assert x.hwaddr is None + x.hwaddr = "01:02:03:04:05:06" + assert x.hwaddr == "01:02:03:04:05:06" def test_bad_type(self): x = kea.Lease4() - with self.assertRaises(TypeError) as cm: - x.hwaddr = 'bogus' - self.assertEqual(("invalid format of the decoded string 'bogus'",), cm.exception.args) + with pytest.raises(TypeError) as cm: + x.hwaddr = "bogus" + assert cm.value.args == ("invalid format of the decoded string 'bogus'",) class TestLease4_client_id(utils.BaseTestCase): - def test_getset(self): x = kea.Lease4() - self.assertIsNone(x.client_id) - x.client_id = '01:02:03:04:05:06' - self.assertEqual('01:02:03:04:05:06', x.client_id) + assert x.client_id is None + x.client_id = "01:02:03:04:05:06" + assert x.client_id == "01:02:03:04:05:06" def test_bad_type(self): x = kea.Lease4() - with self.assertRaises(TypeError) as cm: - x.client_id = 'bogus' - self.assertEqual(("'bogus' is not a valid string of hexadecimal digits",), - cm.exception.args) + with pytest.raises(TypeError) as cm: + x.client_id = "bogus" + assert cm.value.args == ("'bogus' is not a valid string of hexadecimal digits",) class TestLease4_state(utils.BaseTestCase): - def test_getset(self): x = kea.Lease4() - self.assertEqual(0, x.state) + assert x.state == 0 x.state = 5 - self.assertEqual(5, x.state) + assert x.state == 5 def test_bad_type(self): x = kea.Lease4() - with self.assertRaises(TypeError) as cm: - x.state = 'bogus' - self.assertEqual(('The state attribute value must be an int',), cm.exception.args) + with pytest.raises(TypeError) as cm: + x.state = "bogus" + assert cm.value.args == ("The state attribute value must be an int",) class TestLease4_setContext(utils.BaseTestCase): - def test_badarg_count(self): x = kea.Lease4() self.assert_method_one_arg_no_keywords(x.setContext) def test_ok(self): x = kea.Lease4() - self.assertIs(x, x.setContext('foo')) - self.assertIs(x, x.setContext(2)) - self.assertIs(x, x.setContext(True)) - self.assertIs(x, x.setContext([1, 'foo'])) - self.assertIs(x, x.setContext({'foo': 'bar'})) - self.assertIs(x, x.setContext(None)) + assert x is x.setContext("foo") + assert x is x.setContext(2) + assert x is x.setContext(True) + assert x is x.setContext([1, "foo"]) + assert x is x.setContext({"foo": "bar"}) + assert x is x.setContext(None) class TestLease4_getContext(utils.BaseTestCase): - def test_badarg_count(self): x = kea.Lease4() self.assert_method_no_arguments(x.getContext) def test_ok(self): x = kea.Lease4() - self.assertIsNone(x.getContext()) + assert x.getContext() is None x.setContext(None) - self.assertIsNone(x.getContext()) - x.setContext('foo') - self.assertEqual('foo', x.getContext()) + assert x.getContext() is None + x.setContext("foo") + assert x.getContext() == "foo" x.setContext(2) - self.assertEqual(2, x.getContext()) + assert x.getContext() == 2 x.setContext(True) - self.assertEqual(True, x.getContext()) - x.setContext([1, 'foo']) - self.assertEqual([1, 'foo'], x.getContext()) - x.setContext({'foo': 'bar'}) - self.assertEqual({'foo': 'bar'}, x.getContext()) + assert True is x.getContext() + x.setContext([1, "foo"]) + assert [1, "foo"] == x.getContext() + x.setContext({"foo": "bar"}) + assert {"foo": "bar"} == x.getContext() class TestLease4_toElement(utils.BaseTestCase): - def test_badarg_count(self): x = kea.Lease4() self.assert_method_no_arguments(x.toElement) def test_empty(self): x = kea.Lease4() - with self.assertRaises(RuntimeError) as cm: - self.assertEqual({}, x.toElement()) - self.assertIsInstance(cm.exception, RuntimeError) - self.assertEqual(("hwaddr must not be empty",), cm.exception.args) + with pytest.raises(RuntimeError) as cm: + assert {} == x.toElement() + assert isinstance(cm.value, RuntimeError) + assert cm.value.args == ("hwaddr must not be empty",) def test_ok(self): x = kea.Lease4() - x.hwaddr = '01:02:03:04:05:06' - self.assertEqual({'cltt': 0, - 'fqdn-fwd': False, - 'fqdn-rev': False, - 'hostname': '', - 'hw-address': '01:02:03:04:05:06', - 'ip-address': '0.0.0.0', - 'state': 0, - 'subnet-id': 0, - 'valid-lft': 0}, x.toElement()) + x.hwaddr = "01:02:03:04:05:06" + assert { + "cltt": 0, + "fqdn-fwd": False, + "fqdn-rev": False, + "hostname": "", + "hw-address": "01:02:03:04:05:06", + "ip-address": "0.0.0.0", + "state": 0, + "subnet-id": 0, + "valid-lft": 0, + } == x.toElement() x.cltt = 3600 x.fqdn_fwd = x.fqdn_rev = True - x.hostname = 'example.com' - x.addr = '192.168.0.1' + x.hostname = "example.com" + x.addr = "192.168.0.1" x.state = 3 x.subnet_id = 4 x.valid_lft = 1800 - x.client_id = '02:03:04:05:06:07' - self.assertEqual({'client-id': '02:03:04:05:06:07', - 'cltt': 3600, - 'fqdn-fwd': True, - 'fqdn-rev': True, - 'hostname': 'example.com', - 'hw-address': '01:02:03:04:05:06', - 'ip-address': '192.168.0.1', - 'state': 3, - 'subnet-id': 4, - 'valid-lft': 1800}, x.toElement()) + x.client_id = "02:03:04:05:06:07" + assert { + "client-id": "02:03:04:05:06:07", + "cltt": 3600, + "fqdn-fwd": True, + "fqdn-rev": True, + "hostname": "example.com", + "hw-address": "01:02:03:04:05:06", + "ip-address": "192.168.0.1", + "state": 3, + "subnet-id": 4, + "valid-lft": 1800, + } == x.toElement() diff --git a/keamodule/tests/test_lease_mgr.py b/keamodule/tests/test_lease_mgr.py index 3f5efb4..9bca1d0 100644 --- a/keamodule/tests/test_lease_mgr.py +++ b/keamodule/tests/test_lease_mgr.py @@ -1,13 +1,13 @@ import kea +import pytest import utils class TestLeaseMgr_new(utils.BaseTestCase): - def test_badarg_count(self): self.assert_constructor_no_arguments(kea.LeaseMgr) def test_ok(self): - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: kea.LeaseMgr() - self.assertEqual(("no current lease manager is available",), cm.exception.args) + assert cm.value.args == ("no current lease manager is available",) diff --git a/keamodule/tests/test_library_handle.py b/keamodule/tests/test_library_handle.py index 42c19a8..c9febf0 100644 --- a/keamodule/tests/test_library_handle.py +++ b/keamodule/tests/test_library_handle.py @@ -1,9 +1,9 @@ import kea +import pytest import utils class TestLibraryHandle_new(utils.BaseTestCase): - def test_badarg_count(self): self.assert_constructor_one_arg_no_keywords(kea.LibraryHandle) @@ -11,29 +11,29 @@ def test_ok(self): m = kea.CalloutManager() h = kea.LibraryHandle(m) # LibraryHandle has pointer to CalloutManager, not shared_ptr - self.assertEqual(1, m.use_count) - self.assertIsInstance(h, kea.LibraryHandle) + assert m.use_count == 1 + assert isinstance(h, kea.LibraryHandle) class TestLibraryHandle_registerCommandCallout(utils.BaseTestCase): - def test_badarg_count(self): h = kea.LibraryHandle(kea.CalloutManager()) self.assert_method_two_args_no_keywords(h.registerCommandCallout) def test_nadarg_type(self): h = kea.LibraryHandle(kea.CalloutManager()) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: h.registerCommandCallout(1, 42) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) - with self.assertRaises(TypeError) as cm: - h.registerCommandCallout('foo', 42) - self.assertEqual(("callout must be callable",), cm.exception.args) + assert cm.value.args == ("argument 1 must be str, not int",) + with pytest.raises(TypeError) as cm: + h.registerCommandCallout("foo", 42) + assert cm.value.args == ("callout must be callable",) def test_ok(self): def foo(): pass + h = kea.LibraryHandle(kea.CalloutManager()) - with self.assertRaises(RuntimeError) as cm: - h.registerCommandCallout('foo', foo) - self.assertEqual(("only supported in embedded mode",), cm.exception.args) + with pytest.raises(RuntimeError) as cm: + h.registerCommandCallout("foo", foo) + assert cm.value.args == ("only supported in embedded mode",) diff --git a/keamodule/tests/test_option.py b/keamodule/tests/test_option.py index ce54b6e..b6b5cc1 100644 --- a/keamodule/tests/test_option.py +++ b/keamodule/tests/test_option.py @@ -1,155 +1,144 @@ import codecs import kea +import pytest import utils class TestOption_new(utils.BaseTestCase): - def test_badarg_count(self): self.assert_constructor_one_arg_no_keywords(kea.Option) def test_badarg_type(self): - with self.assertRaises(TypeError) as cm: - kea.Option('foo') - self.assertEqual(("an integer is required (got type str)",), cm.exception.args) + with pytest.raises(TypeError, match="an integer is required|object cannot be interpreted as an integer"): + kea.Option("foo") + # self.assertEqual(("an integer is required (got type str)",), cm.value.args) def test_ok(self): o = kea.Option(42) - self.assertEqual(1, o.use_count) + assert o.use_count == 1 class TestOption_getType(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_no_arguments(o.getType) def test_ok(self): o = kea.Option(42) - self.assertIs(42, o.getType()) + assert o.getType() == 42 class TestOption_getBytes(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_no_arguments(o.getBytes) def test_ok(self): o = kea.Option(42) - o.setBytes(b'123') - self.assertEqual(b'123', o.getBytes()) + o.setBytes(b"123") + assert o.getBytes() == b"123" class TestOption_setBytes(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_one_arg_no_keywords(o.setBytes) def test_badarg_type(self): o = kea.Option(42) - with self.assertRaises(TypeError) as cm: - o.setBytes('foo') - self.assertEqual(("argument 1 must be bytes, not str",), cm.exception.args) + with pytest.raises(TypeError) as cm: + o.setBytes("foo") + assert cm.value.args == ("argument 1 must be bytes, not str",) def test_ok(self): o = kea.Option(42) - self.assertIs(o, o.setBytes(b'123')) + assert o is o.setBytes(b"123") class TestOption_getString(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_no_arguments(o.getString) def test_ok(self): o = kea.Option(42) - o.setString('Pokémon') - self.assertEqual('Pokémon', o.getString()) + o.setString("Pokémon") + assert o.getString() == "Pokémon" class TestOption_setString(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_one_arg_no_keywords(o.setString) def test_badarg_type(self): o = kea.Option(42) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: o.setString(1) - self.assertEqual(("a bytes-like object is required, not 'int'",), cm.exception.args) + assert cm.value.args == ("a bytes-like object is required, not 'int'",) def test_ok(self): o = kea.Option(42) - self.assertIs(o, o.setString('Pokémon')) + assert o is o.setString("Pokémon") class TestOption_getUint8(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_no_arguments(o.getUint8) def test_ok(self): o = kea.Option(42) - o.setUint8(0xfe) - self.assertEqual(0xfe, o.getUint8()) - self.assertEqual(b'\xfe', o.getBytes()) + o.setUint8(0xFE) + assert o.getUint8() == 254 + assert o.getBytes() == b"\xfe" class TestOption_setUint8(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_one_arg_no_keywords(o.setUint8) def test_badarg_type(self): o = kea.Option(42) - with self.assertRaises(TypeError) as cm: - o.setUint8('foo') - self.assertEqual(("an integer is required (got type str)",), cm.exception.args) + with pytest.raises(TypeError, match="an integer is required|object cannot be interpreted as an integer"): + o.setUint8("foo") def test_ok(self): o = kea.Option(42) - self.assertIs(o, o.setUint8(0xfe)) + assert o is o.setUint8(254) class TestOption_getUint16(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_no_arguments(o.getUint16) def test_ok(self): o = kea.Option(42) - o.setUint16(0xfeed) - self.assertEqual(0xfeed, o.getUint16()) - self.assertEqual(b'\xfe\xed', o.getBytes()) + o.setUint16(0xFEED) + assert o.getUint16() == 65261 + assert o.getBytes() == b"\xfe\xed" class TestOption_setUint16(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_one_arg_no_keywords(o.setUint16) def test_badarg_type(self): o = kea.Option(42) - with self.assertRaises(TypeError) as cm: - o.setUint16('foo') - self.assertEqual(("an integer is required (got type str)",), cm.exception.args) + with pytest.raises(TypeError, match="an integer is required|object cannot be interpreted as an integer"): + o.setUint16("foo") + # self.assertEqual(("an integer is required (got type str)",), cm.value.args) def test_ok(self): o = kea.Option(42) - self.assertIs(o, o.setUint16(0xfeed)) + assert o is o.setUint16(65261) class TestOption_getUint32(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_no_arguments(o.getUint32) @@ -157,98 +146,88 @@ def test_badarg_count(self): def test_ok(self): o = kea.Option(42) o.setUint32(0x01020304) - self.assertEqual(0x01020304, o.getUint32()) - self.assertEqual(b'\x01\x02\x03\x04', o.getBytes()) + assert o.getUint32() == 16909060 + assert o.getBytes() == b"\x01\x02\x03\x04" class TestOption_setUint32(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_one_arg_no_keywords(o.setUint32) def test_badarg_type(self): o = kea.Option(42) - with self.assertRaises(TypeError) as cm: - o.setUint32('foo') - self.assertEqual(("argument 1 must be int, not str",), cm.exception.args) + with pytest.raises(TypeError) as cm: + o.setUint32("foo") + assert cm.value.args == ("argument 1 must be int, not str",) def test_ok(self): o = kea.Option(42) - self.assertIs(o, o.setUint32(0x01020304)) + assert o is o.setUint32(16909060) class TestOption_addOption(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_one_arg_no_keywords(o.addOption) def test_badarg_type(self): o = kea.Option(42) - with self.assertRaises(TypeError) as cm: - o.addOption('foo') - self.assertEqual(("argument 1 must be kea.Option, not str",), cm.exception.args) + with pytest.raises(TypeError, match="argument 1 must be kea.Option"): + o.addOption("foo") def test_ok(self): o = kea.Option(42) - p = kea.Option(2).setUint8(0xef) - self.assertIs(o, o.addOption(p)) + p = kea.Option(2).setUint8(0xEF) + assert o is o.addOption(p) class TestOption_getOption(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_one_arg_no_keywords(o.getOption) def test_badarg_type(self): o = kea.Option(42) - with self.assertRaises(TypeError) as cm: - o.getOption('foo') - self.assertEqual(("an integer is required (got type str)",), cm.exception.args) + with pytest.raises(TypeError, match="an integer is required|object cannot be interpreted as an integer"): + o.getOption("foo") def test_ok(self): - o = kea.Option(42).addOption(kea.Option(2).setUint8(0xef)) + o = kea.Option(42).addOption(kea.Option(2).setUint8(0xEF)) p = o.getOption(2) - self.assertIsInstance(p, kea.Option) - self.assertEqual(2, p.getType()) - self.assertEqual(0xef, p.getUint8()) + assert isinstance(p, kea.Option) + assert p.getType() == 2 + assert p.getUint8() == 239 class TestOption_pack(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_no_arguments(o.pack) def test_ok(self): - o = kea.Option(42).addOption(kea.Option(2).setUint8(0xef)) + o = kea.Option(42).addOption(kea.Option(2).setUint8(0xEF)) wire = o.pack() - self.assertIsInstance(wire, bytes) - self.assertEqual(b'2a030201ef', codecs.encode(wire, 'hex')) + assert isinstance(wire, bytes) + assert codecs.encode(wire, "hex") == b"2a030201ef" class TestOption_toText(utils.BaseTestCase): - def test_badarg_count(self): o = kea.Option(42) self.assert_method_no_arguments(o.toText) def test_empty(self): o = kea.Option(42) - self.assertEqual('type=042, len=000: ', o.toText()) + assert o.toText() == "type=042, len=000: " def test_uint8(self): o = kea.Option(42).setUint8(5) - self.assertEqual('type=042, len=001: 05', o.toText()) + assert o.toText() == "type=042, len=001: 05" def test_nested(self): - o = kea.Option(42).addOption(kea.Option(4) - .setUint16(5)).addOption(kea.Option(6) - .setString('hello')) - self.assertEqual("""\ -type=042, len=011: , -options: - type=004, len=002: 00:05 - type=006, len=005: 68:65:6c:6c:6f""", o.toText()) + o = kea.Option(42).addOption(kea.Option(4).setUint16(5)).addOption(kea.Option(6).setString("hello")) + assert ( + o.toText() == "type=042, len=011: ,\noptions:\n type=004, len=002:" + " 00:05\n type=006, len=005: 68:65:6c:6c:6f" + ) diff --git a/keamodule/tests/test_pkt4.py b/keamodule/tests/test_pkt4.py index 899ce08..34f6b9a 100644 --- a/keamodule/tests/test_pkt4.py +++ b/keamodule/tests/test_pkt4.py @@ -1,458 +1,455 @@ -import textwrap from ipaddress import IPv4Network import kea +import pytest import utils +from utils import check_kea_version as keaver + +NL = "\n" # https://fossies.org/dox/kea-1.7.4/classisc_1_1dhcp_1_1Pkt4.html class TestPkt4_new(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): # 1 or 2 args - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: kea.Pkt4() - self.assertEqual(('function takes exactly 2 arguments (0 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + assert cm.value.args == ("function takes exactly 2 arguments (0 given)",) + with pytest.raises(TypeError) as cm: kea.Pkt4(1, 2, 3) - self.assertEqual(('function takes exactly 2 arguments (3 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + assert cm.value.args == ("function takes exactly 2 arguments (3 given)",) + with pytest.raises(TypeError) as cm: kea.Pkt4(x=1) - self.assertEqual(('keyword arguments are not supported',), cm.exception.args) + assert cm.value.args == ("keyword arguments are not supported",) def test_badarg_type(self): # 1 arg - bytes - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError) as cm: kea.Pkt4(42) - self.assertEqual(("argument 1 must be bytes, not int",), cm.exception.args) + assert cm.value.args == ("argument 1 must be bytes, not int",) # 2 args - type, trans_id - with self.assertRaises(TypeError) as cm: - kea.Pkt4('1', 42) - self.assertEqual(("an integer is required (got type str)",), cm.exception.args) - with self.assertRaises(TypeError) as cm: - kea.Pkt4(1, '42') - self.assertEqual(("argument 2 must be int, not str",), cm.exception.args) + with pytest.raises(TypeError, match="an integer is required|object cannot be interpreted as an integer"): + kea.Pkt4("1", 42) + with pytest.raises(TypeError) as cm: + kea.Pkt4(1, "42") + assert cm.value.args == ("argument 2 must be int, not str",) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertEqual(1, p.use_count) + assert self.packet4.use_count == 1 class TestPkt4_getType(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_no_arguments(p.getType) + self.assert_method_no_arguments(self.packet4.getType) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertEqual(kea.DHCPREQUEST, p.getType()) + assert self.packet4.getType() == kea.DHCPREQUEST class TestPkt4_setType(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_one_arg_no_keywords(p.setType) + self.assert_method_one_arg_no_keywords(self.packet4.setType) def test_badarg_type(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - with self.assertRaises(TypeError) as cm: - p.setType('foo') - self.assertEqual(("an integer is required (got type str)",), cm.exception.args) + with pytest.raises(TypeError, match="an integer is required|object cannot be interpreted as an integer"): + self.packet4.setType("foo") def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - p.setType(kea.DHCPNAK) - self.assertEqual(kea.DHCPNAK, p.getType()) + self.packet4.setType(kea.DHCPNAK) + assert self.packet4.getType() == kea.DHCPNAK class TestPkt4_getFlags(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_no_arguments(p.getFlags) + self.assert_method_no_arguments(self.packet4.getFlags) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertEqual(0, p.getFlags()) + assert self.packet4.getFlags() == 0 class TestPkt4_setFlags(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_one_arg_no_keywords(p.setFlags) + self.assert_method_one_arg_no_keywords(self.packet4.setFlags) def test_badarg_type(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - with self.assertRaises(TypeError) as cm: - p.setFlags('foo') - self.assertEqual(("an integer is required (got type str)",), cm.exception.args) + with pytest.raises(TypeError, match="an integer is required|object cannot be interpreted as an integer"): + self.packet4.setFlags("foo") def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - p.setFlags(0xbeef) - self.assertEqual(0xbeef, p.getFlags()) + self.packet4.setFlags(0xBEEF) + assert self.packet4.getFlags() == 48879 class TestPkt4_getLocalAddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_no_arguments(p.getLocalAddr) + self.assert_method_no_arguments(self.packet4.getLocalAddr) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertEqual('0.0.0.0', p.getLocalAddr()) + assert self.packet4.getLocalAddr() == "0.0.0.0" class TestPkt4_setLocalAddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_one_arg_no_keywords(p.setLocalAddr) + self.assert_method_one_arg_no_keywords(self.packet4.setLocalAddr) def test_badarg_type(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - with self.assertRaises(TypeError) as cm: - p.setLocalAddr(1) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) - with self.assertRaises(TypeError) as cm: - p.setLocalAddr('foo') - self.assertEqual(("Failed to convert string to address 'foo': Invalid argument",), - cm.exception.args) + with pytest.raises(TypeError) as cm: + self.packet4.setLocalAddr(1) + assert cm.value.args == ("argument 1 must be str, not int",) + with pytest.raises(TypeError) as cm: + self.packet4.setLocalAddr("foo") + assert cm.value.args == ("Failed to convert string to address 'foo': Invalid argument",) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertIs(p, p.setLocalAddr('1.2.3.4')) - self.assertEqual('1.2.3.4', p.getLocalAddr()) + assert self.packet4 is self.packet4.setLocalAddr("1.2.3.4") + assert self.packet4.getLocalAddr() == "1.2.3.4" class TestPkt4_getRemoteAddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_no_arguments(p.getRemoteAddr) + self.assert_method_no_arguments(self.packet4.getRemoteAddr) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertEqual('0.0.0.0', p.getRemoteAddr()) + assert self.packet4.getRemoteAddr() == "0.0.0.0" class TestPkt4_setRemoteAddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_one_arg_no_keywords(p.setRemoteAddr) + self.assert_method_one_arg_no_keywords(self.packet4.setRemoteAddr) def test_badarg_type(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - with self.assertRaises(TypeError) as cm: - p.setRemoteAddr(1) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) - with self.assertRaises(TypeError) as cm: - p.setRemoteAddr('foo') - self.assertEqual(("Failed to convert string to address 'foo': Invalid argument",), - cm.exception.args) + with pytest.raises(TypeError) as cm: + self.packet4.setRemoteAddr(1) + assert cm.value.args == ("argument 1 must be str, not int",) + with pytest.raises(TypeError) as cm: + self.packet4.setRemoteAddr("foo") + assert cm.value.args == ("Failed to convert string to address 'foo': Invalid argument",) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertIs(p, p.setRemoteAddr('1.2.3.4')) - self.assertEqual('1.2.3.4', p.getRemoteAddr()) + assert self.packet4 is self.packet4.setRemoteAddr("1.2.3.4") + assert self.packet4.getRemoteAddr() == "1.2.3.4" class TestPkt4_getCiaddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_no_arguments(p.getCiaddr) + self.assert_method_no_arguments(self.packet4.getCiaddr) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertEqual('0.0.0.0', p.getCiaddr()) + assert self.packet4.getCiaddr() == "0.0.0.0" class TestPkt4_setCiaddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_one_arg_no_keywords(p.setCiaddr) + self.assert_method_one_arg_no_keywords(self.packet4.setCiaddr) def test_badarg_type(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - with self.assertRaises(TypeError) as cm: - p.setCiaddr(1) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) - with self.assertRaises(TypeError) as cm: - p.setCiaddr('foo') - self.assertEqual(("Failed to convert string to address 'foo': Invalid argument",), - cm.exception.args) + with pytest.raises(TypeError) as cm: + self.packet4.setCiaddr(1) + assert cm.value.args == ("argument 1 must be str, not int",) + with pytest.raises(TypeError) as cm: + self.packet4.setCiaddr("foo") + assert cm.value.args == ("Failed to convert string to address 'foo': Invalid argument",) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertIs(p, p.setCiaddr('1.2.3.4')) - self.assertEqual('1.2.3.4', p.getCiaddr()) + assert self.packet4 is self.packet4.setCiaddr("1.2.3.4") + assert self.packet4.getCiaddr() == "1.2.3.4" class TestPkt4_getGiaddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_no_arguments(p.getGiaddr) + self.assert_method_no_arguments(self.packet4.getGiaddr) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertEqual('0.0.0.0', p.getGiaddr()) + assert self.packet4.getGiaddr() == "0.0.0.0" class TestPkt4_setGiaddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_one_arg_no_keywords(p.setGiaddr) + self.assert_method_one_arg_no_keywords(self.packet4.setGiaddr) def test_badarg_type(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - with self.assertRaises(TypeError) as cm: - p.setGiaddr(1) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) - with self.assertRaises(TypeError) as cm: - p.setGiaddr('foo') - self.assertEqual(("Failed to convert string to address 'foo': Invalid argument",), - cm.exception.args) + with pytest.raises(TypeError) as cm: + self.packet4.setGiaddr(1) + assert cm.value.args == ("argument 1 must be str, not int",) + with pytest.raises(TypeError) as cm: + self.packet4.setGiaddr("foo") + assert cm.value.args == ("Failed to convert string to address 'foo': Invalid argument",) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertIs(p, p.setGiaddr('1.2.3.4')) - self.assertEqual('1.2.3.4', p.getGiaddr()) + assert self.packet4 is self.packet4.setGiaddr("1.2.3.4") + assert self.packet4.getGiaddr() == "1.2.3.4" class TestPkt4_getSiaddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_no_arguments(p.getSiaddr) + self.assert_method_no_arguments(self.packet4.getSiaddr) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertEqual('0.0.0.0', p.getSiaddr()) + assert self.packet4.getSiaddr() == "0.0.0.0" class TestPkt4_setSiaddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_one_arg_no_keywords(p.setSiaddr) + self.assert_method_one_arg_no_keywords(self.packet4.setSiaddr) def test_badarg_type(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - with self.assertRaises(TypeError) as cm: - p.setSiaddr(1) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) - with self.assertRaises(TypeError) as cm: - p.setSiaddr('foo') - self.assertEqual(("Failed to convert string to address 'foo': Invalid argument",), - cm.exception.args) + with pytest.raises(TypeError) as cm: + self.packet4.setSiaddr(1) + assert cm.value.args == ("argument 1 must be str, not int",) + with pytest.raises(TypeError) as cm: + self.packet4.setSiaddr("foo") + assert cm.value.args == ("Failed to convert string to address 'foo': Invalid argument",) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertIs(p, p.setSiaddr('1.2.3.4')) - self.assertEqual('1.2.3.4', p.getSiaddr()) + assert self.packet4 is self.packet4.setSiaddr("1.2.3.4") + assert self.packet4.getSiaddr() == "1.2.3.4" class TestPkt4_getYiaddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_no_arguments(p.getYiaddr) + self.assert_method_no_arguments(self.packet4.getYiaddr) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertEqual('0.0.0.0', p.getYiaddr()) + assert self.packet4.getYiaddr() == "0.0.0.0" class TestPkt4_setYiaddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_one_arg_no_keywords(p.setYiaddr) + self.assert_method_one_arg_no_keywords(self.packet4.setYiaddr) def test_badarg_type(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - with self.assertRaises(TypeError) as cm: - p.setYiaddr(1) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) - with self.assertRaises(TypeError) as cm: - p.setYiaddr('foo') - self.assertEqual(("Failed to convert string to address 'foo': Invalid argument",), - cm.exception.args) + with pytest.raises(TypeError) as cm: + self.packet4.setYiaddr(1) + assert cm.value.args == ("argument 1 must be str, not int",) + with pytest.raises(TypeError) as cm: + self.packet4.setYiaddr("foo") + assert cm.value.args == ("Failed to convert string to address 'foo': Invalid argument",) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertIs(p, p.setYiaddr('1.2.3.4')) - self.assertEqual('1.2.3.4', p.getYiaddr()) + assert self.packet4 is self.packet4.setYiaddr("1.2.3.4") + assert self.packet4.getYiaddr() == "1.2.3.4" class TestPkt4_getHWAddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_no_arguments(p.getHWAddr) + self.assert_method_no_arguments(self.packet4.getHWAddr) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertEqual('', p.getHWAddr()) + assert self.packet4.getHWAddr() == "" class TestPkt4_setHWAddr(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_one_arg_no_keywords(p.setHWAddr) + self.assert_method_one_arg_no_keywords(self.packet4.setHWAddr) def test_badarg_type(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - with self.assertRaises(TypeError) as cm: - p.setHWAddr(1) - self.assertEqual(("argument 1 must be str, not int",), cm.exception.args) - with self.assertRaises(TypeError) as cm: - p.setHWAddr('foo') - self.assertEqual(("invalid format of the decoded string 'foo'",), - cm.exception.args) + with pytest.raises(TypeError) as cm: + self.packet4.setHWAddr(1) + assert cm.value.args == ("argument 1 must be str, not int",) + with pytest.raises(TypeError) as cm: + self.packet4.setHWAddr("foo") + assert cm.value.args == ("invalid format of the decoded string 'foo'",) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertIs(p, p.setHWAddr('01:02:03:04:05:06')) - self.assertEqual('01:02:03:04:05:06', p.getHWAddr()) + assert self.packet4 is self.packet4.setHWAddr("01:02:03:04:05:06") + assert self.packet4.getHWAddr() == "01:02:03:04:05:06" class TestPkt4_delOption(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_one_arg_no_keywords(p.delOption) + self.assert_method_one_arg_no_keywords(self.packet4.delOption) def test_badarg_type(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - with self.assertRaises(TypeError) as cm: - p.delOption('foo') - self.assertEqual(("an integer is required (got type str)",), cm.exception.args) + with pytest.raises(TypeError, match="an integer is required|object cannot be interpreted as an integer"): + self.packet4.delOption("foo") def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertFalse(p.delOption(42)) + assert not self.packet4.delOption(42) class TestPkt4_addOption(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_one_arg_no_keywords(p.addOption) + self.assert_method_one_arg_no_keywords(self.packet4.addOption) def test_badarg_type(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - with self.assertRaises(TypeError) as cm: - p.addOption('foo') - self.assertEqual(("argument 1 must be kea.Option, not str",), cm.exception.args) + with pytest.raises(TypeError) as cm: + self.packet4.addOption("foo") + assert cm.value.args == ("argument 1 must be kea.Option, not str",) def test_empty_option_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - o = kea.Option(25) - self.assertIs(p, p.addOption(o)) - self.assertEqual(2, o.use_count) + option = kea.Option(25) + assert self.packet4 is self.packet4.addOption(option) + assert option.use_count == 2 def test_bytes_option_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - o = kea.Option(25) - self.assertIs(p, p.addOption(o)) - self.assertEqual(2, o.use_count) + option = kea.Option(25) + assert self.packet4 is self.packet4.addOption(option) + assert option.use_count == 2 def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - o = kea.Option(kea.DHO_DHCP_AGENT_OPTIONS) - self.assertEqual(1, o.use_count) - self.assertIs(p, p.addOption(o)) - self.assertEqual(2, o.use_count) - n = p.getOption(kea.DHO_DHCP_AGENT_OPTIONS) - self.assertEqual(kea.DHO_DHCP_AGENT_OPTIONS, n.getType()) + option = kea.Option(kea.DHO_DHCP_AGENT_OPTIONS) + assert option.use_count == 1 + assert self.packet4 is self.packet4.addOption(option) + assert option.use_count == 2 + n = self.packet4.getOption(kea.DHO_DHCP_AGENT_OPTIONS) + assert n.getType() == kea.DHO_DHCP_AGENT_OPTIONS class TestPkt4_getOption(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_one_arg_no_keywords(p.getOption) + self.assert_method_one_arg_no_keywords(self.packet4.getOption) def test_badarg_type(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - with self.assertRaises(TypeError) as cm: - p.getOption('foo') - self.assertEqual(("an integer is required (got type str)",), cm.exception.args) + with pytest.raises(TypeError, match="an integer is required|object cannot be interpreted as an integer"): + self.packet4.getOption("foo") def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - o = p.getOption(kea.DHO_DHCP_MESSAGE_TYPE) - self.assertIsInstance(o, kea.Option) - self.assertEqual(bytes([kea.DHCPREQUEST]), o.getBytes()) + option = self.packet4.getOption(kea.DHO_DHCP_MESSAGE_TYPE) + assert isinstance(option, kea.Option) + assert bytes([kea.DHCPREQUEST]) == option.getBytes() class TestPkt4_pack(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_no_arguments(p.pack) + self.assert_method_no_arguments(self.packet4.pack) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - wire = p.pack() - self.assertIsInstance(wire, bytes) + wire = self.packet4.pack() + assert isinstance(wire, bytes) class TestPkt4_unpack(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_no_arguments(p.unpack) + self.assert_method_no_arguments(self.packet4.unpack) def test_ok(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - wire = p.pack() - p = kea.Pkt4(wire) - self.assertIsNone(p.unpack()) + wire = self.packet4.pack() + self.packet4 = kea.Pkt4(wire) + assert self.packet4.unpack() is None class TestPkt4_toText(utils.BaseTestCase): + def setUp(self): + self.packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) def test_badarg_count(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assert_method_no_arguments(p.toText) - - def test_empty(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) - self.assertEqual(textwrap.dedent("""\ - local_address=0.0.0.0:67, remote_address=0.0.0.0:68, msg_type=DHCPREQUEST (3), transid=0x2a, - options: - type=053, len=001: 3 (uint8)"""), p.toText()) # noqa: E501 - - def test_filled(self): - p = kea.Pkt4(kea.DHCPREQUEST, 42) # 53 - p.setLocalAddr('1.2.3.4') - p.setRemoteAddr('2.3.4.5') - subnet = IPv4Network('10.0.0.0/20') - p.addOption(kea.Option(kea.DHO_SUBNET_MASK).setBytes(subnet.netmask.packed)) # 1 - p.addOption(kea.Option(kea.DHO_ROUTERS).setBytes(subnet[1].packed)) # 3 - p.addOption(kea.Option(kea.DHO_DOMAIN_NAME).setString('test.org')) # 15 - p.addOption(kea.Option(kea.DHO_DHCP_LEASE_TIME).setUint32(7200)) # 51 - p.addOption(kea.Option(kea.DHO_DHCP_RENEWAL_TIME).setUint32(1800)) # 58 - p.addOption(kea.Option(kea.DHO_DHCP_REBINDING_TIME).setUint32(3600)) # 59 - self.assertEqual(textwrap.dedent("""\ - local_address=1.2.3.4:67, remote_address=2.3.4.5:68, msg_type=DHCPREQUEST (3), transid=0x2a, - options: - type=001, len=004: ff:ff:f0:00 - type=003, len=004: 0a:00:00:01 - type=015, len=008: 74:65:73:74:2e:6f:72:67 - type=051, len=004: 00:00:1c:20 - type=053, len=001: 3 (uint8) - type=058, len=004: 00:00:07:08 - type=059, len=004: 00:00:0e:10"""), p.toText()) # noqa: E501 + self.assert_method_no_arguments(self.packet4.toText) + + +def test_Pkt4_toText_empty(): + """Test to ensure that toText returns the correct string for an empty packet.""" + packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) + assert ( + packet4.toText() + == "local_address=0.0.0.0:67, remote_address=0.0.0.0:68," + + ( + "\nmsg_type=DHCPREQUEST (3), trans_id=0x2a,\n" + if keaver(">=2.6.0") + else " msg_type=DHCPREQUEST (3), transid=0x2a,\n" + ) + + "options:\n" + " type=053, len=001: 3 (uint8)" + ) # noqa: E501 + + +def test_Pkt4_toText_filled(): + """Test to ensure that toText returns the correct string for a filled packet.""" + packet4 = kea.Pkt4(kea.DHCPREQUEST, 42) + packet4.setLocalAddr("1.2.3.4") + packet4.setRemoteAddr("2.3.4.5") + subnet = IPv4Network("10.0.0.0/20") + packet4.addOption(kea.Option(kea.DHO_SUBNET_MASK).setBytes(subnet.netmask.packed)) # 1 + packet4.addOption(kea.Option(kea.DHO_ROUTERS).setBytes(subnet[1].packed)) # 3 + packet4.addOption(kea.Option(kea.DHO_DOMAIN_NAME).setString("test.org")) # 15 + packet4.addOption(kea.Option(kea.DHO_DHCP_LEASE_TIME).setUint32(7200)) # 51 + packet4.addOption(kea.Option(kea.DHO_DHCP_RENEWAL_TIME).setUint32(1800)) # 58 + packet4.addOption(kea.Option(kea.DHO_DHCP_REBINDING_TIME).setUint32(3600)) # 59 + assert ( + packet4.toText() + == "local_address=1.2.3.4:67, remote_address=2.3.4.5:68," + + ( + "\nmsg_type=DHCPREQUEST (3), trans_id=0x2a,\n" + if keaver(">=2.6.0") + else " msg_type=DHCPREQUEST (3), transid=0x2a,\n" + ) + + "options:\n" + " type=001, len=004: ff:ff:f0:00\n" + " type=003, len=004: 0a:00:00:01\n" + " type=015, len=008: 74:65:73:74:2e:6f:72:67\n" + " type=051, len=004: 00:00:1c:20\n" + " type=053, len=001: 3 (uint8)\n" + " type=058, len=004: 00:00:07:08\n" + " type=059, len=004: 00:00:0e:10" + ) # noqa: E501 diff --git a/keamodule/tests/test_srv_config.py b/keamodule/tests/test_srv_config.py index adada3d..03a47ff 100644 --- a/keamodule/tests/test_srv_config.py +++ b/keamodule/tests/test_srv_config.py @@ -1,17 +1,16 @@ import kea +import pytest import utils class TestSrvConfig_new(utils.BaseTestCase): - def test_cannot_construct(self): - with self.assertRaises(RuntimeError) as cm: + with pytest.raises(RuntimeError) as cm: kea.SrvConfig() - self.assertEqual(("cannot directly construct",), cm.exception.args) + assert cm.value.args == ("cannot directly construct",) class TestGetCurrentConfig(utils.BaseTestCase): - def test_badarg_count(self): m = kea.CfgMgr() self.assert_method_no_arguments(m.getCurrentCfg) @@ -19,14 +18,13 @@ def test_badarg_count(self): def test_ok(self): m = kea.CfgMgr() c = m.getCurrentCfg() - self.assertEqual(3, c.use_count) + assert c.use_count == 3 d = m.getCurrentCfg() - self.assertEqual(4, c.use_count) - self.assertEqual(4, d.use_count) + assert c.use_count == 4 + assert d.use_count == 4 class TestGetStagingConfig(utils.BaseTestCase): - def test_badarg_count(self): m = kea.CfgMgr() self.assert_method_no_arguments(m.getStagingCfg) @@ -34,16 +32,15 @@ def test_badarg_count(self): def test_ok(self): m = kea.CfgMgr() c = m.getStagingCfg() - self.assertEqual(2, c.use_count) + assert c.use_count == 2 d = m.getStagingCfg() - self.assertEqual(3, c.use_count) - self.assertEqual(3, d.use_count) + assert c.use_count == 3 + assert d.use_count == 3 d = None - self.assertEqual(2, c.use_count) + assert c.use_count == 2 class TestSrvConfig_getCfgSubnets4(utils.BaseTestCase): - def test_badarg_count(self): c = kea.CfgMgr().getStagingCfg() self.assert_method_no_arguments(c.getCfgSubnets4) @@ -51,11 +48,10 @@ def test_badarg_count(self): def test_ok(self): c = kea.CfgMgr().getStagingCfg() n = c.getCfgSubnets4() - self.assertEqual(2, n.use_count) + assert n.use_count == 2 class TestSrvConfig_toElement(utils.BaseTestCase): - def test_badarg_count(self): c = kea.CfgMgr().getStagingCfg() self.assert_method_no_arguments(c.toElement) @@ -63,4 +59,4 @@ def test_badarg_count(self): def test_ok(self): c = kea.CfgMgr().getStagingCfg() e = c.toElement() - self.assertIsInstance(e, dict) + assert isinstance(e, dict) diff --git a/keamodule/tests/utils.py b/keamodule/tests/utils.py index e0e5502..af537e1 100644 --- a/keamodule/tests/utils.py +++ b/keamodule/tests/utils.py @@ -1,91 +1,116 @@ +from __future__ import annotations + +import operator +import re import sys import unittest +from typing import Optional import kea +import pytest class Logger: - def error(self, msg): - sys.stderr.write(msg + '\n') + sys.stderr.write(msg + "\n") class BaseTestCase(unittest.TestCase): - def setUp(self): self.maxDiff = None kea.logger = Logger() def assert_cannot_construct(self, cls): - with self.assertRaises(RuntimeError) as cm: + with pytest.raises(RuntimeError, match=r"cannot directly construct"): cls() - self.assertEqual(("cannot directly construct",), cm.exception.args) def assert_constructor_no_arguments(self, cls): - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"function takes exactly 0 arguments \(1 given\)"): cls(1) - self.assertEqual(('function takes exactly 0 arguments (1 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"keyword arguments are not supported"): cls(x=1) - self.assertEqual(('keyword arguments are not supported',), cm.exception.args) def assert_constructor_one_arg_no_keywords(self, cls): - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"function takes exactly 1 argument \(0 given\)"): cls() - self.assertEqual(('function takes exactly 1 argument (0 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"function takes exactly 1 argument \(2 given\)"): cls(1, 2) - self.assertEqual(('function takes exactly 1 argument (2 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"keyword arguments are not supported"): cls(x=1) - self.assertEqual(('keyword arguments are not supported',), cm.exception.args) def assert_constructor_two_args_no_keywords(self, cls): - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"function takes exactly 2 arguments \(0 given\)"): cls() - self.assertEqual(('function takes exactly 2 arguments (0 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"function takes exactly 2 arguments \(1 given\)"): cls(1) - self.assertEqual(('function takes exactly 2 arguments (1 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"function takes exactly 2 arguments \(3 given\)"): cls(1, 2, 3) - self.assertEqual(('function takes exactly 2 arguments (3 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"keyword arguments are not supported"): cls(x=1) - self.assertEqual(('keyword arguments are not supported',), cm.exception.args) def assert_method_no_arguments(self, method): - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"takes no arguments \(1 given\)"): method(1) - self.assertEqual((f'{method.__name__}() takes no arguments (1 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"takes no keyword arguments"): method(x=1) - self.assertEqual((f'{method.__name__}() takes no keyword arguments',), cm.exception.args) def assert_method_one_arg_no_keywords(self, method): - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"function takes exactly 1 argument \(0 given\)"): method() - self.assertEqual(('function takes exactly 1 argument (0 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"function takes exactly 1 argument \(2 given\)"): method(1, 2) - self.assertEqual(('function takes exactly 1 argument (2 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"takes no keyword arguments"): method(x=1) - msg = '%s() takes no keyword arguments' % method.__name__ - self.assertEqual((msg,), cm.exception.args) def assert_method_two_args_no_keywords(self, method): - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"function takes exactly 2 arguments \(0 given\)"): method() - self.assertEqual(('function takes exactly 2 arguments (0 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"function takes exactly 2 arguments \(1 given\)"): method(1) - self.assertEqual(('function takes exactly 2 arguments (1 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"function takes exactly 2 arguments \(3 given\)"): method(1, 2, 3) - self.assertEqual(('function takes exactly 2 arguments (3 given)',), cm.exception.args) - with self.assertRaises(TypeError) as cm: + with pytest.raises(TypeError, match=r"takes no keyword arguments"): method(x=1) - msg = '%s() takes no keyword arguments' % method.__name__ - self.assertEqual((msg,), cm.exception.args) + +def check_kea_version(operator_and_version: str) -> Optional[bool]: + """ + Compare the current KEA version with the target version using the specified comparison operator. + + Args: + operator_and_version (Optional[str]): The comparison operator and target version in + the format "". If the operator is omitted, "==" is assumed. + Valid operators are "==", "!=", "<", "<=", ">", ">=", "^", and "~". If None, + no comparison is performed. + + Returns: + Optional[bool]: True if the comparison is satisfied, False if not + """ + + pattern = re.compile(r"^(==|!=|<=|>=|<|>|~|\^)?(.+)$") + match = pattern.match(operator_and_version) + + if not match: + raise ValueError("Input must be in the format ''") + + comparison_operator, target_version = match.groups() + + comparison_operators = { + "=": operator.eq, + "==": operator.eq, + "!": operator.ne, + "<": operator.lt, + "<=": operator.le, + ">": operator.gt, + ">=": operator.ge, + "^": lambda a, b: a.major == b.major and a.minor == b.minor, # Same major and minor version + "~": lambda a, b: a.major == b.major, # Same major version + } + + comparison_operator = operator.eq if not comparison_operator else comparison_operators[comparison_operator] + + from packaging.version import Version + + current_version = Version(kea.KEA_VERSION) + target_version_obj = Version(target_version) + return comparison_operator(current_version, target_version_obj) diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 0000000..636af37 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,116 @@ +# Exclude a variety of commonly ignored directories. +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", +] + +# Same as Flake8 +line-length = 120 +indent-width = 4 + +# Assume Python 3.8 +target-version = "py38" + +# jcruz: pre-commit +force-exclude = true + +show-fixes = true +[lint] +select = ["C", "E", "R", "W", "PL", # pylint, pycodestyle +"F", # Flake8 +"I", # isort, +"PL", +"B", "A", "BLE", # bugbear, otros errores que pueden causar bugs +"S", # bandit, seguridad +"DJ", # django +"ANN", "FA", "TCH", # type annotations +"C901", "SIM", # complejidad - simplificar +"RET", "PIE", # estilo de codigo - cosas innecesarias, +"FLY", # f-strings en vez de concatenacion de strings, .format o formato con % +"PT", # pytest +"RUF", # reglas personalizadas de ruff +"PTH" # usar pathlib!! es mucho más simple que os.path y más moderno +] + +ignore = [ +"ANN101", # argumentos self sin tipo, +"ANN102", # argumentos cls sin tipo +"ANN204", # retornos de __str__, __dict__, etc sin tipado +] + +# Allow fix for all enabled rules (when `--fix`) is provided. +fixable = ["ALL"] +unfixable = [] + +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + + +# custom: jcruz +[lint.flake8-annotations] +mypy-init-return = true # quitar que te pidan tipar el __init__ +suppress-none-returning = true # falta de tipado en el return en funciones que no retornan nada + +[lint.isort] +known-first-party = ["krill*", "kapi*", "*icinga*", "webapp"] + +# Ignores en los tests: +# S-Bandit (no le gustan los asserts) +# ANN-Anotaciones +# RUF-Ruff +# PLR-Pylint (no le gustan las comparaciones con valores hardcodeados) +[lint.per-file-ignores] +"test_*" = ["S", "ANN", "PLR", "RUF"] +"*_test*" = ["S", "ANN", "PLR", "RUF"] +"*test*" = ["S", "ANN", "PLR", "RUF"] + +[format] +# Like Black, use double quotes for strings. +quote-style = "double" + +# Like Black, indent with spaces, rather than tabs. +indent-style = "space" + +# Like Black, respect magic trailing commas. +skip-magic-trailing-comma = false + +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" + +# Enable auto-formatting of code examples in docstrings. Markdown, +# reStructuredText code/literal blocks and doctests are all supported. +# +# This is currently disabled by default, but it is planned for this +# to be opt-out in the future. +docstring-code-format = false + +# Set the line length limit used when formatting code snippets in +# docstrings. +# +# This only has an effect when the `docstring-code-format` setting is +# enabled. +docstring-code-line-length = "dynamic"