blob: 16e7991c82c9455e2d18c2bbe6604769268275de [file] [log] [blame]
Radek Krejcic61f0b42017-06-07 13:21:41 +02001/**
2 * @file netconf.c
3 * @author Radek Krejci <rkrejci@cesnet.cz>
4 * @brief Python3 bindings for libnetconf2 (client-side)
5 *
6 * Copyright (c) 2017 CESNET, z.s.p.o.
7 *
8 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * https://opensource.org/licenses/BSD-3-Clause
13 */
14
15/* Python API header */
16#include <Python.h>
17
18/* standard headers */
19#include <nc_client.h>
20#include <syslog.h>
21
22#include "netconf.h"
23
24PyObject *libnetconf2Error;
25PyObject *libnetconf2Warning;
26
27/* syslog usage flag */
28static int syslogEnabled = 0;
29
30static void
31clb_print(NC_VERB_LEVEL level, const char* msg)
32{
33 switch (level) {
34 case NC_VERB_ERROR:
35 PyErr_SetString(libnetconf2Error, msg);
36 if (syslogEnabled) {syslog(LOG_ERR, "%s", msg);}
37 break;
38 case NC_VERB_WARNING:
39 if (syslogEnabled) {syslog(LOG_WARNING, "%s", msg);}
40 PyErr_WarnEx(libnetconf2Warning, msg, 1);
41 break;
42 case NC_VERB_VERBOSE:
43 if (syslogEnabled) {syslog(LOG_INFO, "%s", msg);}
44 break;
45 case NC_VERB_DEBUG:
46 if (syslogEnabled) {syslog(LOG_DEBUG, "%s", msg);}
47 break;
48 }
49}
50
51static PyObject *
52setSyslog(PyObject *self, PyObject *args, PyObject *keywds)
53{
54 char* name = NULL;
55 static char* logname = NULL;
56 static int option = LOG_PID;
Radek Krejcib03ebe42017-07-04 14:00:33 +020057 static int facility = LOG_USER;
Radek Krejcic61f0b42017-06-07 13:21:41 +020058
59 static char *kwlist[] = {"enabled", "name", "option", "facility", NULL};
60
61 if (! PyArg_ParseTupleAndKeywords(args, keywds, "p|sii", kwlist, &syslogEnabled, &name, &option, &facility)) {
62 return NULL;
63 }
64
65 if (name) {
66 free(logname);
67 logname = strdup(name);
68 } else {
69 free(logname);
70 logname = NULL;
71 }
72 closelog();
73 openlog(logname, option, facility);
74
75 Py_RETURN_NONE;
76}
77
78static PyObject *
79setVerbosity(PyObject *self, PyObject *args, PyObject *keywds)
80{
81 int level = NC_VERB_ERROR; /* 0 */
82
83 static char *kwlist[] = {"level", NULL};
84
85 if (! PyArg_ParseTupleAndKeywords(args, keywds, "i", kwlist, &level)) {
86 return NULL;
87 }
88
89 /* normalize level value if not from the enum */
90 if (level < NC_VERB_ERROR) {
91 nc_verbosity(NC_VERB_ERROR);
92 } else if (level > NC_VERB_DEBUG) {
93 nc_verbosity(NC_VERB_DEBUG);
94 } else {
95 nc_verbosity(level);
96 }
97
98 Py_RETURN_NONE;
99}
100
Radek Krejci74ca4812017-09-21 13:03:33 +0200101static PyObject *
102setSearchpath(PyObject *self, PyObject *args, PyObject *keywds)
103{
104 char *path;
105 static char *kwlist[] = {"path", NULL};
106
107 if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", kwlist, &path)) {
108 return NULL;
109 }
110
111 if (nc_client_set_schema_searchpath(path)) {
112 return NULL;
113 }
114
115 Py_RETURN_NONE;
116}
117
Radek Krejcic61f0b42017-06-07 13:21:41 +0200118static PyMethodDef netconf2Methods[] = {
Radek Krejcib03ebe42017-07-04 14:00:33 +0200119 {"setVerbosity", (PyCFunction)setVerbosity, METH_VARARGS | METH_KEYWORDS,
120 "setVerbosity(level)\n--\n\n"
121 "Set verbose level\n\n"
122 ":param level: Verbosity level (0 - errors, 1 - warnings, 2 - verbose, 3 - debug)\n"
123 ":type level: int\n"
124 ":returns: None\n"},
125 {"setSyslog", (PyCFunction)setSyslog, METH_VARARGS | METH_KEYWORDS,
126 "setSyslog(enabled[, name=None][, option=LOG_PID][, facility=LOG_USER])\n--\n\n"
127 "Set application settings for syslog.\n\n"
128 ":param enabled: Flag to enable/disable logging into syslog.\n"
129 ":type enabled: bool\n"
130 ":param name: Identifier (program name is set by default).\n"
131 ":type name: string\n"
132 ":param option: ORed value of syslog options (LOG_PID by default).\n"
133 ":type option: int\n"
134 ":param facility: Type of the program logging the message (LOG_USER by default).\n"
135 ":type facility: int\n"
136 ":returns: None\n\n"
137 ".. seealso:: syslog.openlog\n"},
Radek Krejci74ca4812017-09-21 13:03:33 +0200138 {"setSearchpath", (PyCFunction)setSearchpath, METH_VARARGS | METH_KEYWORDS,
139 "setSearchpath(path)\n--\n\n"
140 "Set location where YANG/YIN schemas are searched and where the schemas\n"
141 "retrieved via <get-schema> opration are stored.\n\n"
142 ":param path: Search directory.\n"
143 ":type path: string\n"
144 ":returns: None\n"},
Radek Krejcic61f0b42017-06-07 13:21:41 +0200145 {NULL, NULL, 0, NULL}
146};
147
Radek Krejcib03ebe42017-07-04 14:00:33 +0200148static char netconf2Docs[] =
149 "NETCONF Protocol client-side implementation using libnetconf2\n"
150 "\n"
151 "netconf2 is a wrapper around libnetconf2 functions designed for NETCONF\n"
152 "clients. it provides a higher level API than the original libnetconf2 to\n"
153 "better fit the usage in Python.\n";
154
Radek Krejcic61f0b42017-06-07 13:21:41 +0200155static struct PyModuleDef ncModule = {
156 PyModuleDef_HEAD_INIT,
157 "netconf2",
Radek Krejcib03ebe42017-07-04 14:00:33 +0200158 netconf2Docs,
Radek Krejcic61f0b42017-06-07 13:21:41 +0200159 -1,
160 netconf2Methods,
161};
162
163/* module initializer */
164PyMODINIT_FUNC
165PyInit_netconf2(void)
166{
167 PyObject *nc;
168
169 /* initiate libnetconf2 client part */
170 nc_client_init();
171
172 /* set schema searchpath
173 * nc_client_set_schema_searchpath()
174 */
175
176 /* set print callback */
177 nc_set_print_clb(clb_print);
178
179 if (PyType_Ready(&ncSessionType) == -1) {
180 return NULL;
181 }
182
183 ncSSHType.tp_new = PyType_GenericNew;
184 if (PyType_Ready(&ncSSHType) == -1) {
185 return NULL;
186 }
187
188 ncTLSType.tp_new = PyType_GenericNew;
189 if (PyType_Ready(&ncTLSType) == -1) {
190 return NULL;
191 }
192
193 /* create netconf as the Python module */
194 nc = PyModule_Create(&ncModule);
195 if (nc == NULL) {
196 return NULL;
197 }
198
199 Py_INCREF(&ncSSHType);
200 PyModule_AddObject(nc, "SSH", (PyObject *)&ncSSHType);
201
202 Py_INCREF(&ncTLSType);
203 PyModule_AddObject(nc, "TLS", (PyObject *)&ncTLSType);
204
205 Py_INCREF(&ncSessionType);
206 PyModule_AddObject(nc, "Session", (PyObject *)&ncSessionType);
207
208/*
209 Py_INCREF(&ncTLSType);
210 PyModule_AddObject(nc, "TLS", (PyObject *)&ncTLSType);
211*/
212/*
213 PyModule_AddStringConstant(nc, "NETCONFv1_0", NETCONF_CAP_BASE10);
214 PyModule_AddStringConstant(nc, "NETCONFv1_1", NETCONF_CAP_BASE11);
215 PyModule_AddStringConstant(nc, "TRANSPORT_SSH", NETCONF_TRANSPORT_SSH);
216 PyModule_AddStringConstant(nc, "TRANSPORT_TLS", NETCONF_TRANSPORT_TLS);
217*/
Radek Krejcie0854c02017-10-10 21:11:29 +0200218 PyModule_AddIntConstant(nc, "DATASTORE_RUNNING", NC_DATASTORE_RUNNING);
219 PyModule_AddIntConstant(nc, "DATASTORE_STARTUP", NC_DATASTORE_STARTUP);
220 PyModule_AddIntConstant(nc, "DATASTORE_CANDIDATE", NC_DATASTORE_CANDIDATE);
Radek Krejcic61f0b42017-06-07 13:21:41 +0200221
222 /* init libnetconf exceptions for use in clb_print() */
223 libnetconf2Error = PyErr_NewExceptionWithDoc("netconf.Error",
224 "Error passed from the underlying libnetconf2 library.",
225 NULL, NULL);
226 Py_INCREF(libnetconf2Error);
227 PyModule_AddObject(nc, "Error", libnetconf2Error);
228
229 libnetconf2Warning = PyErr_NewExceptionWithDoc("netconf.Warning",
230 "Warning passed from the underlying libnetconf2 library.",
231 PyExc_Warning, NULL);
232 Py_INCREF(libnetconf2Warning);
233 PyModule_AddObject(nc, "Warning", libnetconf2Warning);
234
235 return nc;
236}