Refactor folder structure.
[sim/o1-interface.git] / ntsimulator / src / software-management-xran / sw-management-rpc.c
1 /**
2  * @file sw-management-rpc.c
3  * @author Rastislav Szabo <raszabo@cisco.com>, Lukas Macko <lmacko@cisco.com>,
4  *         Milan Lenco <milan.lenco@pantheon.tech>
5  * @brief Example usage of RPC API.
6  *
7  * @copyright
8  * Copyright 2016 Cisco Systems, Inc.
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  *    http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <signal.h>
27 #include <string.h>
28
29 #include <pthread.h>
30
31 #include "sysrepo.h"
32 #include "sysrepo/values.h"
33
34 #include "utils.h"
35
36 #define LINE_BUFSIZE 128
37
38 volatile int exit_application = 0;
39
40 pthread_mutex_t lock;
41
42 static int sw_download_error_count, sw_install_error_count, sw_activate_error_count;
43
44 void call_software_management_script(char *script_name)
45 {
46     char line[LINE_BUFSIZE];
47         int linenr;
48         FILE *pipe;
49
50         /* Get a pipe where the output from the scripts comes in */
51         char script[200];
52         sprintf(script, "/opt/dev/%s", script_name);
53
54         pipe = popen(script, "r");
55         if (pipe == NULL) {  /* check for errors */
56                 printf("Could not open script.\n");
57                 return;        /* return with exit code indicating error */
58         }
59
60         /* Read script output from the pipe line by line */
61         linenr = 1;
62         while (fgets(line, LINE_BUFSIZE, pipe) != NULL) {
63                 printf("Script output line %d: %s", linenr, line);
64                 ++linenr;
65         }
66
67         /* Once here, out of the loop, the script has ended. */
68         pclose(pipe); /* Close the pipe */
69         return;     /* return with exit code indicating success. */
70 }
71
72 struct sw_download_struct
73 {
74     sr_session_ctx_t *sess;
75     char *filename;
76 };
77
78 void* sw_download_notification_send(void *arguments)
79 {
80     // create the values to be sent in the notification
81     struct sw_download_struct *args = (struct sw_download_struct *)arguments;
82     int rc = SR_ERR_OK;
83
84     sw_download_error_count++;
85
86     sr_val_t *notif = NULL;
87     size_t current_num_of_values_notif = 0;
88
89     CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
90
91     char *trunc_filename;
92     trunc_filename = strrchr(args->filename, '/');
93
94     sr_val_build_xpath(&notif[current_num_of_values_notif - 1], "%s", "/xran-software-management:download-event/file-name");
95     if (trunc_filename != NULL)
96     {
97         sr_val_set_str_data(&notif[current_num_of_values_notif - 1], SR_STRING_T, trunc_filename + 1);
98
99         if (strcmp(trunc_filename+1, "reset") == 0)
100         {
101             call_software_management_script("edit-config-demo-start.sh");
102         }
103         else
104         {
105             call_software_management_script("edit-config-after-download.sh");
106         }
107     }
108     else
109     {
110         sr_val_set_str_data(&notif[current_num_of_values_notif - 1], SR_STRING_T, args->filename);
111         if (strcmp(args->filename, "reset") == 0)
112         {
113             call_software_management_script("edit-config-demo-start.sh");
114         }
115         else
116         {
117             call_software_management_script("edit-config-after-download.sh");
118         }
119     }
120
121     if (args->filename != NULL)
122     {
123         free(args->filename);
124     }
125
126     CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
127
128         sr_val_build_xpath(&notif[current_num_of_values_notif - 1], "%s", "/xran-software-management:download-event/status");
129     //every 5 RPCs we send an error
130     if (sw_download_error_count % 5 == 0)
131     {
132             sr_val_set_str_data(&notif[current_num_of_values_notif - 1], SR_ENUM_T, "AUTHENTICATION_ERROR");
133     }
134     else
135     {
136         sr_val_set_str_data(&notif[current_num_of_values_notif - 1], SR_ENUM_T, "COMPLETED");
137     }
138     
139
140     // wait 5 seconds before sending the notification
141     sleep(5);
142
143     /* send notification for event_notif_sub(_tree)_example */
144     printf(">>> Sending event notification for '/xran-software-management:download-event'...\n");
145     rc = sr_event_notif_send(args->sess, "/xran-software-management:download-event", notif, current_num_of_values_notif, SR_EV_NOTIF_DEFAULT);
146     if (SR_ERR_NOT_FOUND == rc) {
147         printf("No application subscribed for '/xran-software-management:download-event', skipping.\n");
148         rc = SR_ERR_OK;
149     }
150     sr_free_values(notif, current_num_of_values_notif);
151
152     return NULL;
153 }
154
155 struct sw_install_struct
156 {
157     sr_session_ctx_t *sess;
158     char *slot_name;
159 };
160
161 void* sw_install_notification_send(void *arguments)
162 {
163     // create the values to be sent in the notification
164     struct sw_install_struct *args = (struct sw_install_struct *)arguments;
165     int rc = SR_ERR_OK;
166     sw_install_error_count++;
167
168     sr_val_t *notif = NULL;
169     size_t current_num_of_values_notif = 0;
170
171     CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
172
173     sr_val_build_xpath(&notif[current_num_of_values_notif - 1], "%s", "/xran-software-management:install-event/slot-name");
174     sr_val_set_str_data(&notif[current_num_of_values_notif - 1], SR_STRING_T, args->slot_name);
175
176     if (args->slot_name != NULL)
177     {
178         free(args->slot_name);
179     }
180
181     CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
182
183         sr_val_build_xpath(&notif[current_num_of_values_notif - 1], "%s", "/xran-software-management:install-event/status");
184
185         //every 5 RPCs we send an error
186     if (sw_install_error_count % 5 == 0)
187     {
188             sr_val_set_str_data(&notif[current_num_of_values_notif - 1], SR_ENUM_T, "INTEGRITY_ERROR");
189     }
190     else
191     {
192         sr_val_set_str_data(&notif[current_num_of_values_notif - 1], SR_ENUM_T, "COMPLETED");
193     }
194
195     // wait 5 seconds before sending the notification
196     sleep(5);
197
198     /* send notification for event_notif_sub(_tree)_example */
199     printf(">>> Sending event notification for '/xran-software-management:install-event'...\n");
200     rc = sr_event_notif_send(args->sess, "/xran-software-management:install-event", notif, current_num_of_values_notif, SR_EV_NOTIF_DEFAULT);
201     if (SR_ERR_NOT_FOUND == rc) {
202         printf("No application subscribed for '/xran-software-management:install-event', skipping.\n");
203         rc = SR_ERR_OK;
204     }
205     sr_free_values(notif, current_num_of_values_notif);
206
207     return NULL;
208 }
209
210 struct sw_activate_struct
211 {
212     sr_session_ctx_t *sess;
213     char *slot_name;
214 };
215
216 void* sw_activate_notification_send(void *arguments)
217 {
218     // create the values to be sent in the notification
219     struct sw_activate_struct *args = (struct sw_activate_struct *)arguments;
220     int rc = SR_ERR_OK;
221     sw_activate_error_count++;
222
223     sr_val_t *notif = NULL;
224     size_t current_num_of_values_notif = 0;
225
226     CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
227
228     sr_val_build_xpath(&notif[current_num_of_values_notif - 1], "%s", "/xran-software-management:activation-event/slot-name");
229     sr_val_set_str_data(&notif[current_num_of_values_notif - 1], SR_STRING_T, args->slot_name);
230
231     if (args->slot_name != NULL)
232     {
233         free(args->slot_name);
234     }
235
236     CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
237
238         sr_val_build_xpath(&notif[current_num_of_values_notif - 1], "%s", "/xran-software-management:activation-event/status");
239         //every 5 RPCs we send an error
240     if (sw_activate_error_count % 5 == 0)
241     {
242             sr_val_set_str_data(&notif[current_num_of_values_notif - 1], SR_ENUM_T, "APPLICATION_ERROR");
243     }
244     else
245     {
246         sr_val_set_str_data(&notif[current_num_of_values_notif - 1], SR_ENUM_T, "COMPLETED");
247
248         call_software_management_script("edit-config-after-activate.sh");
249     }
250
251     CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
252
253         sr_val_build_xpath(&notif[current_num_of_values_notif - 1], "%s", "/xran-software-management:activation-event/return-code");
254     notif[current_num_of_values_notif - 1].type = SR_UINT8_T;
255     notif[current_num_of_values_notif - 1].data.uint8_val = 200;
256
257     // wait 5 seconds before sending the notification
258     sleep(5);
259
260     /* send notification for event_notif_sub(_tree)_example */
261     printf(">>> Sending event notification for '/xran-software-management:activation-event'...\n");
262     rc = sr_event_notif_send(args->sess, "/xran-software-management:activation-event", notif, current_num_of_values_notif, SR_EV_NOTIF_DEFAULT);
263     if (SR_ERR_NOT_FOUND == rc) {
264         printf("No application subscribed for '/xran-software-management:activation-event', skipping.\n");
265         rc = SR_ERR_OK;
266     }
267     sr_free_values(notif, current_num_of_values_notif);
268
269     return NULL;
270 }
271
272 static int
273 sw_download_rpc_cb(const char *xpath, const sr_val_t *input, const size_t input_cnt,
274        sr_val_t **output, size_t *output_cnt, void *private_ctx)
275 {
276     int rc = SR_ERR_OK;
277     sr_session_ctx_t *session = (sr_session_ctx_t *)private_ctx;
278
279     /**
280      * Here you would actually run the operation against the provided input values
281      * and obtained the output values.
282      */
283
284     /* allocate output values */
285     rc = sr_new_values(2, output);
286     if (SR_ERR_OK != rc) {
287         return rc;
288     }
289
290     rc = sr_val_set_xpath(&(*output)[0], "/xran-software-management:software-download/status");
291     if (SR_ERR_OK != rc) {
292         return rc;
293     }
294     (*output)[0].type = SR_ENUM_T;
295     (*output)[0].data.enum_val = "STARTED";
296
297     rc = sr_val_set_xpath(&(*output)[1], "/xran-software-management:software-download/notification-timeout");
298     if (SR_ERR_OK != rc) {
299         return rc;
300     }
301     (*output)[1].type = SR_INT32_T;
302     (*output)[1].data.int32_val = 10;
303
304     /* inform sysrepo about the number of output values */
305     *output_cnt = 2;
306
307     struct sw_download_struct *args = (struct sw_download_struct *)malloc(sizeof(struct sw_download_struct));
308     args->sess = session;
309     args->filename = strdup(input[0].data.string_val);
310
311     pthread_t sw_download_thread;
312         if(pthread_create(&sw_download_thread, NULL, &sw_download_notification_send, (void *)args))
313         {
314                 fprintf(stderr, "Could not create thread for SW Download thread\n");
315                 return SR_ERR_OPERATION_FAILED;
316         }
317
318     /**
319      * Do not deallocate input values!
320      * They will get freed automatically by sysrepo.
321      */
322     return rc;
323 }
324
325 static int
326 sw_install_rpc_cb(const char *xpath, const sr_val_t *input, const size_t input_cnt,
327        sr_val_t **output, size_t *output_cnt, void *private_ctx)
328 {
329     int rc = SR_ERR_OK;
330     sr_session_ctx_t *session = (sr_session_ctx_t *)private_ctx;
331
332     /**
333      * Here you would actually run the operation against the provided input values
334      * and obtained the output values.
335      */
336
337     /* allocate output values */
338     rc = sr_new_values(1, output);
339     if (SR_ERR_OK != rc) {
340         return rc;
341     }
342
343     rc = sr_val_set_xpath(&(*output)[0], "/xran-software-management:software-install/status");
344     if (SR_ERR_OK != rc) {
345         return rc;
346     }
347     (*output)[0].type = SR_ENUM_T;
348     (*output)[0].data.enum_val = "STARTED";
349
350     /* inform sysrepo about the number of output values */
351     *output_cnt = 1;
352
353     struct sw_install_struct *args = (struct sw_install_struct *)malloc(sizeof(struct sw_install_struct));
354     args->sess = session;
355     args->slot_name = strdup(input[0].data.string_val);
356
357     pthread_t sw_install_thread;
358         if(pthread_create(&sw_install_thread, NULL, &sw_install_notification_send, (void *)args))
359         {
360                 fprintf(stderr, "Could not create thread for SW Install thread\n");
361                 return SR_ERR_OPERATION_FAILED;
362         }
363
364     /**
365      * Do not deallocate input values!
366      * They will get freed automatically by sysrepo.
367      */
368     return rc;
369 }
370
371 static int
372 sw_activate_rpc_cb(const char *xpath, const sr_val_t *input, const size_t input_cnt,
373        sr_val_t **output, size_t *output_cnt, void *private_ctx)
374 {
375     int rc = SR_ERR_OK;
376     sr_session_ctx_t *session = (sr_session_ctx_t *)private_ctx;
377
378     /**
379      * Here you would actually run the operation against the provided input values
380      * and obtained the output values.
381      */
382
383     /* allocate output values */
384     rc = sr_new_values(2, output);
385     if (SR_ERR_OK != rc) {
386         return rc;
387     }
388
389     rc = sr_val_set_xpath(&(*output)[0], "/xran-software-management:software-activate/status");
390     if (SR_ERR_OK != rc) {
391         return rc;
392     }
393     (*output)[0].type = SR_ENUM_T;
394     (*output)[0].data.enum_val = "STARTED";
395
396     rc = sr_val_set_xpath(&(*output)[1], "/xran-software-management:software-activate/notification-timeout");
397     if (SR_ERR_OK != rc) {
398         return rc;
399     }
400     (*output)[1].type = SR_INT32_T;
401     (*output)[1].data.int32_val = 10;
402
403     /* inform sysrepo about the number of output values */
404     *output_cnt = 2;
405
406     struct sw_activate_struct *args = (struct sw_activate_struct *)malloc(sizeof(struct sw_activate_struct));
407     args->sess = session;
408     args->slot_name = strdup(input[0].data.string_val);
409
410     pthread_t sw_activate_thread;
411         if(pthread_create(&sw_activate_thread, NULL, &sw_activate_notification_send, (void *)args))
412         {
413                 fprintf(stderr, "Could not create thread for SW Activate thread\n");
414                 return SR_ERR_OPERATION_FAILED;
415         }
416
417     /**
418      * Do not deallocate input values!
419      * They will get freed automatically by sysrepo.
420      */
421     return rc;
422 }
423
424 static void
425 sigint_handler(int signum)
426 {
427     exit_application = 1;
428 }
429
430 static int
431 rpc_handler(sr_session_ctx_t *session)
432 {
433     sr_subscription_ctx_t *subscription = NULL;
434     int rc = SR_ERR_OK;
435
436     /* subscribe for handling software-download RPC */
437     rc = sr_rpc_subscribe(session, "/xran-software-management:software-download", sw_download_rpc_cb,
438             (void *)session, SR_SUBSCR_DEFAULT, &subscription);
439     if (SR_ERR_OK != rc) {
440         fprintf(stderr, "Error by sr_rpc_subscribe: %s\n", sr_strerror(rc));
441         goto cleanup;
442     }
443
444     /* subscribe for handling software-install RPC */
445     rc = sr_rpc_subscribe(session, "/xran-software-management:software-install", sw_install_rpc_cb,
446             (void *)session, SR_SUBSCR_DEFAULT, &subscription);
447     if (SR_ERR_OK != rc) {
448         fprintf(stderr, "Error by sr_rpc_subscribe: %s\n", sr_strerror(rc));
449         goto cleanup;
450     }
451
452         /* subscribe for handling software-activate RPC */
453     rc = sr_rpc_subscribe(session, "/xran-software-management:software-activate", sw_activate_rpc_cb,
454             (void *)session, SR_SUBSCR_DEFAULT, &subscription);
455     if (SR_ERR_OK != rc) {
456         fprintf(stderr, "Error by sr_rpc_subscribe: %s\n", sr_strerror(rc));
457         goto cleanup;
458     }
459
460     printf("\n\n ========== SUBSCRIBED FOR HANDLING RPC ==========\n\n");
461
462     /* loop until ctrl-c is pressed / SIGINT is received */
463     signal(SIGINT, sigint_handler);
464     signal(SIGPIPE, SIG_IGN);
465     while (!exit_application) {
466         sleep(1000);  /* or do some more useful work... */
467     }
468
469     printf("Application exit requested, exiting.\n");
470
471 cleanup:
472     if (NULL != subscription) {
473         sr_unsubscribe(session, subscription);
474     }
475     return rc;
476 }
477
478 int
479 main(int argc, char **argv)
480 {
481     sr_conn_ctx_t *connection = NULL;
482     sr_session_ctx_t *session = NULL;
483     int rc = SR_ERR_OK;
484
485     setbuf(stdout, NULL);
486
487     if (pthread_mutex_init(&lock, NULL) != 0)
488         {
489                 printf("Mutex init failed...\n");
490                 goto cleanup;
491         }
492
493     /* connect to sysrepo */
494     rc = sr_connect("sw_management_rpc_app", SR_CONN_DEFAULT, &connection);
495     if (SR_ERR_OK != rc) {
496         fprintf(stderr, "Error by sr_connect: %s\n", sr_strerror(rc));
497         goto cleanup;
498     }
499
500     /* start session */
501     rc = sr_session_start(connection, SR_DS_RUNNING, SR_SESS_DEFAULT, &session);
502     if (SR_ERR_OK != rc) {
503         fprintf(stderr, "Error by sr_session_start: %s\n", sr_strerror(rc));
504         goto cleanup;
505     }
506
507     /* run as a RPC handler */
508     printf("This application will be an RPC handler for 'software-download' operation of 'xran-software-management'.\n");
509     rc = rpc_handler(session);
510
511 cleanup:
512     if (NULL != session) {
513         sr_session_stop(session);
514     }
515     if (NULL != connection) {
516         sr_disconnect(connection);
517     }
518     return rc;
519 }