Add supoprt for D release use-case.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / utils / nc_client.c
1 /*************************************************************************
2 *
3 * Copyright 2020 highstreet technologies GmbH and others
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 ***************************************************************************/
17
18 #define _GNU_SOURCE
19
20 #include "nc_client.h"
21 #include "utils/log_utils.h"
22 #include "utils/sys_utils.h"
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <assert.h>
26
27 #include "core/session.h"
28 #include "core/nc_config.h"
29
30 #include <libnetconf2/session.h>
31 #include <libnetconf2/session_client.h>
32 #include <libnetconf2/messages_client.h>
33
34 static char *nc_client_pass_cb(const char *username, const char *hostname, void *priv) {
35     nc_client_t *client = (nc_client_t *)priv;
36     return strdup(client->password);
37 }
38
39 static int nc_client_auth_hostkey_check(const char *hostname, ssh_session session, void *priv) {
40     return 0;   //auto-authorize
41 }
42
43 nc_client_t *nc_client_ssh_connect(const char *host, uint16_t port, const char *username, const char *password) {
44     assert(host);
45     assert(port > 20);
46     assert(username);
47     assert(password);
48
49     nc_client_t *client = (nc_client_t *)malloc(sizeof(nc_client_t));
50     if(client == 0) {
51         return 0;
52     }
53
54     client->edit_batch_root = 0;
55
56     nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PASSWORD, 3);
57     nc_client_ssh_set_auth_pref(NC_SSH_AUTH_PUBLICKEY, -1);
58     nc_client_ssh_set_auth_pref(NC_SSH_AUTH_INTERACTIVE, -1);
59
60     nc_client_ssh_set_username(username);
61     client->password = strdup(password);
62     if(client->password == 0) {
63         log_error("strdup failed\n");
64         free(client);
65         return 0;
66     }
67
68     nc_client_ssh_set_auth_password_clb(nc_client_pass_cb, client);
69     nc_client_ssh_set_auth_hostkey_check_clb(nc_client_auth_hostkey_check, 0);
70
71     client->session = nc_connect_ssh(host, port, 0);
72     if(client->session == 0) {
73         log_error("nc_connect_ssh failed\n");
74         free(client->password);
75         free(client);
76         return 0;
77     }
78
79     return client;
80 }
81
82 nc_client_t *nc_client_tls_connect(const char *host, uint16_t port) {
83     assert(host);
84     assert(port > 20);
85
86     nc_client_t *client = (nc_client_t *)malloc(sizeof(nc_client_t));
87     if(client == 0) {
88         return 0;
89     }
90
91     client->edit_batch_root = 0;
92     client->password = 0;
93     int rc = nc_client_tls_set_cert_key_paths(CLIENT_CERT_PATH, CLIENT_KEY_PATH);
94     if(rc != 0) {
95         log_error("nc_client_tls_set_cert_key_paths failed\n");
96         return 0;
97     }
98
99     rc = nc_client_tls_set_trusted_ca_paths(CLIENT_CA_FILE, 0);
100     if(rc != 0) {
101         log_error("nc_client_tls_set_trusted_ca_paths failed\n");
102         return 0;
103     }
104
105     client->session = nc_connect_tls(host, port, 0);
106     if(client->session == 0) {
107         log_error("nc_connect_tls failed\n");
108         free(client);
109         return 0;
110     }
111
112     return client;
113 }
114
115 int nc_client_disconnect(nc_client_t *client) {
116     assert(client);
117     
118     nc_session_free(client->session, 0);
119     free(client->password);
120     free(client);
121
122     return NTS_ERR_OK;
123 }
124
125 struct lyd_node *nc_client_send_rpc(nc_client_t *client, struct lyd_node *data, int timeout) {
126     assert(client);
127     assert(data);
128
129     struct nc_rpc *rpc;
130     struct nc_reply *reply;
131     NC_MSG_TYPE send_ret;
132     NC_MSG_TYPE reply_ret;
133     uint64_t msg_id;
134
135     char *xmldata = 0;
136     if(lyd_print_mem(&xmldata, data, LYD_XML, 0) != 0) {
137         log_error("lyd_print_mem failed\n");
138         return 0;
139     }
140
141     rpc = nc_rpc_act_generic_xml(xmldata, NC_PARAMTYPE_CONST);
142     if(rpc == 0) {
143         log_error("could not create rpc\n");
144         free(xmldata);
145         return 0;
146     }
147
148     msg_id = 0;
149     send_ret = nc_send_rpc(client->session, rpc, timeout, &msg_id);
150     if(send_ret != NC_MSG_RPC) {
151         log_error("could not send rpc\n");
152         free(xmldata);
153         nc_rpc_free(rpc);
154         return 0;
155     }
156
157     repeat_nc_recv_reply:
158     reply_ret = nc_recv_reply(client->session, rpc, msg_id, timeout, LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS, &reply);
159     if(reply_ret != NC_MSG_REPLY) {
160         if(reply_ret == NC_MSG_NOTIF) {
161             goto repeat_nc_recv_reply;
162         }
163
164         log_error("could not get rpc reply\n");
165         free(xmldata);
166         nc_rpc_free(rpc);
167         return 0;
168     }
169
170     if(reply->type != NC_RPL_DATA) {
171         log_error("reply has no data\n");
172         free(xmldata);
173         nc_rpc_free(rpc);
174         nc_reply_free(reply);
175         return 0;
176     }
177
178     char *ret_data_xml = strdup("");    //libyang does not support having the parent RPC in XML
179     struct lyd_node *chd = 0;
180     LY_TREE_FOR(((struct nc_reply_data *)reply)->data->child, chd) {
181         char *temp_xml = 0;
182         if(lyd_print_mem(&temp_xml, chd, LYD_XML, 0) != 0) {
183             log_error("lyd_print_mem failed\n");
184             free(ret_data_xml);
185             free(xmldata);
186             nc_rpc_free(rpc);
187             nc_reply_free(reply);
188             return 0;
189         }
190
191         ret_data_xml = (char *)realloc(ret_data_xml, sizeof(char) * (strlen(ret_data_xml) + strlen(temp_xml) + 1));
192         strcat(ret_data_xml, temp_xml);
193         free(temp_xml);
194     }
195     
196     free(xmldata);
197     nc_reply_free(reply);
198     nc_rpc_free(rpc);
199
200     struct lyd_node *ret_data = lyd_parse_mem(session_context, ret_data_xml, LYD_XML, LYD_OPT_RPCREPLY | LYD_OPT_NOEXTDEPS, data, 0);
201     free(ret_data_xml);
202     return ret_data;
203 }
204
205 struct lyd_node *nc_client_get_batch(nc_client_t *client, const char *xpath, int timeout) {
206     assert(client);
207     assert(xpath);
208
209     struct nc_rpc *rpc;
210     struct nc_reply *reply;
211     NC_MSG_TYPE send_ret;
212     NC_MSG_TYPE reply_ret;
213     uint64_t msg_id;
214
215     rpc = nc_rpc_get(xpath, NC_WD_UNKNOWN, NC_PARAMTYPE_CONST);
216     if(rpc == 0) {
217         log_error("could not create rpc\n");
218         return 0;
219     }
220
221     msg_id = 0;
222     send_ret = nc_send_rpc(client->session, rpc, timeout, &msg_id);
223     if(send_ret != NC_MSG_RPC) {
224         log_error("could not send rpc\n");
225         nc_rpc_free(rpc);
226         return 0;
227     }
228
229     repeat_nc_recv_reply:
230     reply_ret = 0;
231     reply_ret = nc_recv_reply(client->session, rpc, msg_id, timeout, LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS, &reply);
232     if(reply_ret != NC_MSG_REPLY) {
233         if(reply_ret == NC_MSG_NOTIF) {
234             goto repeat_nc_recv_reply;
235         }
236
237         log_error("could not get rpc reply\n");
238         nc_rpc_free(rpc);
239         return 0;
240     }
241
242     if(reply->type != NC_RPL_DATA) {
243         log_error("reply has no data\n");
244         nc_rpc_free(rpc);
245         nc_reply_free(reply);
246         return 0;
247     }
248
249     char *ret_data_xml = 0;
250     if(lyd_print_mem(&ret_data_xml, ((struct nc_reply_data *)reply)->data, LYD_XML, 0) != 0) {
251         log_error("lyd_print_mem failed\n");
252         nc_reply_free(reply);
253         nc_rpc_free(rpc);
254         return 0;
255     }
256     
257     nc_reply_free(reply);
258     nc_rpc_free(rpc);
259
260     struct lyd_node *ret_data = lyd_parse_mem(session_context, ret_data_xml, LYD_XML, LYD_OPT_DATA | LYD_OPT_NOSIBLINGS);
261     free(ret_data_xml);
262     return ret_data;
263 }
264
265 int nc_client_edit_batch(nc_client_t *client, struct lyd_node *data, int timeout) {
266     assert(client);
267     assert(data);
268
269     struct nc_rpc *rpc;
270     struct nc_reply *reply;
271     NC_MSG_TYPE send_ret;
272     NC_MSG_TYPE reply_ret;
273     uint64_t msg_id;
274
275     char *content = 0;
276     int rc = lyd_print_mem(&content, data, LYD_XML, 0);
277     if(rc != 0) {
278         log_error("lyd_print_mem failed\n");
279         return NTS_ERR_FAILED;
280     }
281
282     rpc = nc_rpc_edit(NC_DATASTORE_RUNNING, NC_RPC_EDIT_DFLTOP_MERGE, NC_RPC_EDIT_TESTOPT_SET, NC_RPC_EDIT_ERROPT_STOP, content, NC_PARAMTYPE_CONST);
283     if(rpc == 0) {
284         log_error("could not create rpc\n");
285         free(content);
286         return NTS_ERR_FAILED;
287     }
288     
289     msg_id = 0;
290     send_ret = nc_send_rpc(client->session, rpc, timeout, &msg_id);
291     if(send_ret != NC_MSG_RPC) {
292         log_error("could not send rpc\n");
293         free(content);
294         nc_rpc_free(rpc);
295         return NTS_ERR_FAILED;
296     }
297
298     reply_ret = nc_recv_reply(client->session, rpc, msg_id, timeout, LYD_OPT_DESTRUCT | LYD_OPT_NOSIBLINGS, &reply);
299     if((reply_ret != NC_MSG_REPLY) || (reply->type != NC_RPL_OK)) {
300         log_error("could not get rpc reply\n");
301
302         free(content);
303         nc_rpc_free(rpc);
304         return NTS_ERR_FAILED;
305     }
306     
307     free(content);
308     nc_reply_free(reply);
309     nc_rpc_free(rpc);
310
311     return NTS_ERR_OK;
312 }
313
314 int nc_client_set_item_str(nc_client_t *client, const char *xpath, const char *value) {
315     assert(client);
316     assert(xpath);
317     assert(value);
318
319     if(client->edit_batch_root) {
320         struct lyd_node *n = lyd_new_path(client->edit_batch_root, 0, xpath, (void*)value, LYD_ANYDATA_CONSTSTRING, 0);
321         if(n == 0) {
322             log_error("lyd_new_path error\n");
323             return NTS_ERR_FAILED;
324         }
325     }
326     else {
327         client->edit_batch_root = lyd_new_path(0, session_context, xpath, (void*)value, LYD_ANYDATA_CONSTSTRING, 0);
328         if(client->edit_batch_root == 0) {
329             log_error("lyd_new_path error\n");
330             return NTS_ERR_FAILED;
331         }
332     }
333
334     return NTS_ERR_OK;
335 }
336
337 int nc_client_edit_apply_changes(nc_client_t *client, int timeout) {
338     assert(client);
339     assert(client->edit_batch_root);
340
341     int rc = nc_client_edit_batch(client, client->edit_batch_root, timeout);
342     lyd_free_withsiblings(client->edit_batch_root);
343     client->edit_batch_root = 0;
344     return rc;
345 }
346
347 int lyd_utils_dup(sr_session_ctx_t *session, const char *xpath_s, const char *xpath_d, struct lyd_node **tree) {
348     assert(session);
349     assert(xpath_s);
350     assert(xpath_d);
351     assert(tree);
352
353     if(*tree == 0) {
354         *tree = lyd_new_path(0, session_context, xpath_d, 0, LYD_ANYDATA_CONSTSTRING, 0);
355         if(*tree == 0) {
356             return NTS_ERR_FAILED;
357         }
358     }
359
360     struct lyd_node *data_s = 0;
361     int rc = sr_get_data(session, xpath_s, 0, 0, 0, &data_s);
362     if(rc != SR_ERR_OK) {
363         log_error("could not get value for xPath=%s from the datastore\n", xpath_s);
364         lyd_free(*tree);
365         return NTS_ERR_FAILED;
366     }
367
368     struct lyd_node *next = 0;
369     struct lyd_node *snode = 0;
370     LY_TREE_DFS_BEGIN(data_s, next, snode) {
371         char *xpath_c = lyd_path(snode);
372         if((snode->schema->nodetype == LYS_LEAF) || (snode->schema->nodetype == LYS_LEAFLIST)) {
373             const char *value = ((struct lyd_node_leaf_list*)snode)->value_str;
374             char *new_xpath = str_replace(xpath_c, xpath_s, xpath_d);
375             
376             // ly_log_options(0);
377             ly_verb(LY_LLERR);  //checkAL
378             lyd_new_path(*tree, 0, new_xpath, (void*)value, LYD_ANYDATA_CONSTSTRING, 0);
379             free(xpath_c);
380             free(new_xpath);
381         }
382         LY_TREE_DFS_END(data_s, next, snode);
383     }
384
385     lyd_free(data_s);
386     return NTS_ERR_OK;
387 }