FEATURE initial python3 bindings commit
- integration into build system
- basic functionality to connect to the server and provide information
about the NETCONF session
- no NETCONF operation (except the implicit close-session) supported yet
diff --git a/python/netconf.c b/python/netconf.c
new file mode 100644
index 0000000..4f38241
--- /dev/null
+++ b/python/netconf.c
@@ -0,0 +1,185 @@
+/**
+ * @file netconf.c
+ * @author Radek Krejci <rkrejci@cesnet.cz>
+ * @brief Python3 bindings for libnetconf2 (client-side)
+ *
+ * Copyright (c) 2017 CESNET, z.s.p.o.
+ *
+ * This source code is licensed under BSD 3-Clause License (the "License").
+ * You may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://opensource.org/licenses/BSD-3-Clause
+ */
+
+/* Python API header */
+#include <Python.h>
+
+/* standard headers */
+#include <nc_client.h>
+#include <syslog.h>
+
+#include "netconf.h"
+
+PyObject *libnetconf2Error;
+PyObject *libnetconf2Warning;
+
+/* syslog usage flag */
+static int syslogEnabled = 0;
+
+static void
+clb_print(NC_VERB_LEVEL level, const char* msg)
+{
+ switch (level) {
+ case NC_VERB_ERROR:
+ PyErr_SetString(libnetconf2Error, msg);
+ if (syslogEnabled) {syslog(LOG_ERR, "%s", msg);}
+ break;
+ case NC_VERB_WARNING:
+ if (syslogEnabled) {syslog(LOG_WARNING, "%s", msg);}
+ PyErr_WarnEx(libnetconf2Warning, msg, 1);
+ break;
+ case NC_VERB_VERBOSE:
+ if (syslogEnabled) {syslog(LOG_INFO, "%s", msg);}
+ break;
+ case NC_VERB_DEBUG:
+ if (syslogEnabled) {syslog(LOG_DEBUG, "%s", msg);}
+ break;
+ }
+}
+
+static PyObject *
+setSyslog(PyObject *self, PyObject *args, PyObject *keywds)
+{
+ char* name = NULL;
+ static char* logname = NULL;
+ static int option = LOG_PID;
+ static int facility = LOG_DAEMON;
+
+ static char *kwlist[] = {"enabled", "name", "option", "facility", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, keywds, "p|sii", kwlist, &syslogEnabled, &name, &option, &facility)) {
+ return NULL;
+ }
+
+ if (name) {
+ free(logname);
+ logname = strdup(name);
+ } else {
+ free(logname);
+ logname = NULL;
+ }
+ closelog();
+ openlog(logname, option, facility);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+setVerbosity(PyObject *self, PyObject *args, PyObject *keywds)
+{
+ int level = NC_VERB_ERROR; /* 0 */
+
+ static char *kwlist[] = {"level", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, keywds, "i", kwlist, &level)) {
+ return NULL;
+ }
+
+ /* normalize level value if not from the enum */
+ if (level < NC_VERB_ERROR) {
+ nc_verbosity(NC_VERB_ERROR);
+ } else if (level > NC_VERB_DEBUG) {
+ nc_verbosity(NC_VERB_DEBUG);
+ } else {
+ nc_verbosity(level);
+ }
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef netconf2Methods[] = {
+ {"setVerbosity", (PyCFunction)setVerbosity, METH_VARARGS | METH_KEYWORDS, "Set verbose level (0-3)."},
+ {"setSyslog", (PyCFunction)setSyslog, METH_VARARGS | METH_KEYWORDS, "Set application settings for syslog."},
+ {NULL, NULL, 0, NULL}
+};
+
+static struct PyModuleDef ncModule = {
+ PyModuleDef_HEAD_INIT,
+ "netconf2",
+ "NETCONF Protocol implementation using libnetconf2",
+ -1,
+ netconf2Methods,
+};
+
+/* module initializer */
+PyMODINIT_FUNC
+PyInit_netconf2(void)
+{
+ PyObject *nc;
+
+ /* initiate libnetconf2 client part */
+ nc_client_init();
+
+ /* set schema searchpath
+ * nc_client_set_schema_searchpath()
+ */
+
+ /* set print callback */
+ nc_set_print_clb(clb_print);
+
+ if (PyType_Ready(&ncSessionType) == -1) {
+ return NULL;
+ }
+
+ ncSSHType.tp_new = PyType_GenericNew;
+ if (PyType_Ready(&ncSSHType) == -1) {
+ return NULL;
+ }
+
+ ncTLSType.tp_new = PyType_GenericNew;
+ if (PyType_Ready(&ncTLSType) == -1) {
+ return NULL;
+ }
+
+ /* create netconf as the Python module */
+ nc = PyModule_Create(&ncModule);
+ if (nc == NULL) {
+ return NULL;
+ }
+
+ Py_INCREF(&ncSSHType);
+ PyModule_AddObject(nc, "SSH", (PyObject *)&ncSSHType);
+
+ Py_INCREF(&ncTLSType);
+ PyModule_AddObject(nc, "TLS", (PyObject *)&ncTLSType);
+
+ Py_INCREF(&ncSessionType);
+ PyModule_AddObject(nc, "Session", (PyObject *)&ncSessionType);
+
+/*
+ Py_INCREF(&ncTLSType);
+ PyModule_AddObject(nc, "TLS", (PyObject *)&ncTLSType);
+*/
+/*
+ PyModule_AddStringConstant(nc, "NETCONFv1_0", NETCONF_CAP_BASE10);
+ PyModule_AddStringConstant(nc, "NETCONFv1_1", NETCONF_CAP_BASE11);
+ PyModule_AddStringConstant(nc, "TRANSPORT_SSH", NETCONF_TRANSPORT_SSH);
+ PyModule_AddStringConstant(nc, "TRANSPORT_TLS", NETCONF_TRANSPORT_TLS);
+*/
+
+ /* init libnetconf exceptions for use in clb_print() */
+ libnetconf2Error = PyErr_NewExceptionWithDoc("netconf.Error",
+ "Error passed from the underlying libnetconf2 library.",
+ NULL, NULL);
+ Py_INCREF(libnetconf2Error);
+ PyModule_AddObject(nc, "Error", libnetconf2Error);
+
+ libnetconf2Warning = PyErr_NewExceptionWithDoc("netconf.Warning",
+ "Warning passed from the underlying libnetconf2 library.",
+ PyExc_Warning, NULL);
+ Py_INCREF(libnetconf2Warning);
+ PyModule_AddObject(nc, "Warning", libnetconf2Warning);
+
+ return nc;
+}