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.
8 * Copyright 2016 Cisco Systems, Inc.
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
14 * http://www.apache.org/licenses/LICENSE-2.0
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.
32 #include "sysrepo/values.h"
36 #define LINE_BUFSIZE 128
38 volatile int exit_application = 0;
42 static int sw_download_error_count, sw_install_error_count, sw_activate_error_count;
44 void call_software_management_script(char *script_name)
46 char line[LINE_BUFSIZE];
50 /* Get a pipe where the output from the scripts comes in */
52 sprintf(script, "/opt/dev/%s", script_name);
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 */
60 /* Read script output from the pipe line by line */
62 while (fgets(line, LINE_BUFSIZE, pipe) != NULL) {
63 printf("Script output line %d: %s", linenr, line);
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. */
72 struct sw_download_struct
74 sr_session_ctx_t *sess;
78 void* sw_download_notification_send(void *arguments)
80 // create the values to be sent in the notification
81 struct sw_download_struct *args = (struct sw_download_struct *)arguments;
84 sw_download_error_count++;
86 sr_val_t *notif = NULL;
87 size_t current_num_of_values_notif = 0;
89 CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
92 trunc_filename = strrchr(args->filename, '/');
94 sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:download-event/file-name");
95 if (trunc_filename != NULL)
97 sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_STRING_T, trunc_filename + 1);
99 if (strcmp(trunc_filename+1, "reset") == 0)
101 call_software_management_script("edit-config-demo-start.sh");
105 call_software_management_script("edit-config-after-download.sh");
110 sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_STRING_T, args->filename);
111 if (strcmp(args->filename, "reset") == 0)
113 call_software_management_script("edit-config-demo-start.sh");
117 call_software_management_script("edit-config-after-download.sh");
121 if (args->filename != NULL)
123 free(args->filename);
126 CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
128 sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:download-event/status");
129 //every 5 RPCs we send an error
130 if (sw_download_error_count % 5 == 0)
132 sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_ENUM_T, "AUTHENTICATION_ERROR");
136 sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_ENUM_T, "COMPLETED");
140 // wait 5 seconds before sending the notification
143 /* send notification for event_notif_sub(_tree)_example */
144 printf(">>> Sending event notification for '/o-ran-software-management:download-event'...\n");
145 rc = sr_event_notif_send(args->sess, "/o-ran-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 '/o-ran-software-management:download-event', skipping.\n");
150 sr_free_values(notif, current_num_of_values_notif);
155 struct sw_install_struct
157 sr_session_ctx_t *sess;
161 void* sw_install_notification_send(void *arguments)
163 // create the values to be sent in the notification
164 struct sw_install_struct *args = (struct sw_install_struct *)arguments;
166 sw_install_error_count++;
168 sr_val_t *notif = NULL;
169 size_t current_num_of_values_notif = 0;
171 CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
173 sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:install-event/slot-name");
174 sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_STRING_T, args->slot_name);
176 if (args->slot_name != NULL)
178 free(args->slot_name);
181 CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
183 sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:install-event/status");
185 //every 5 RPCs we send an error
186 if (sw_install_error_count % 5 == 0)
188 sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_ENUM_T, "INTEGRITY_ERROR");
192 sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_ENUM_T, "COMPLETED");
195 // wait 5 seconds before sending the notification
198 /* send notification for event_notif_sub(_tree)_example */
199 printf(">>> Sending event notification for '/o-ran-software-management:install-event'...\n");
200 rc = sr_event_notif_send(args->sess, "/o-ran-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 '/o-ran-software-management:install-event', skipping.\n");
205 sr_free_values(notif, current_num_of_values_notif);
210 struct sw_activate_struct
212 sr_session_ctx_t *sess;
216 void* sw_activate_notification_send(void *arguments)
218 // create the values to be sent in the notification
219 struct sw_activate_struct *args = (struct sw_activate_struct *)arguments;
221 sw_activate_error_count++;
223 sr_val_t *notif = NULL;
224 size_t current_num_of_values_notif = 0;
226 CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
228 sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:activation-event/slot-name");
229 sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_STRING_T, args->slot_name);
231 if (args->slot_name != NULL)
233 free(args->slot_name);
236 CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
238 sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:activation-event/status");
239 //every 5 RPCs we send an error
240 if (sw_activate_error_count % 5 == 0)
242 sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_ENUM_T, "APPLICATION_ERROR");
246 sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_ENUM_T, "COMPLETED");
248 call_software_management_script("edit-config-after-activate.sh");
251 CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif);
253 sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-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;
257 // wait 5 seconds before sending the notification
260 /* send notification for event_notif_sub(_tree)_example */
261 printf(">>> Sending event notification for '/o-ran-software-management:activation-event'...\n");
262 rc = sr_event_notif_send(args->sess, "/o-ran-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 '/o-ran-software-management:activation-event', skipping.\n");
267 sr_free_values(notif, current_num_of_values_notif);
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)
277 sr_session_ctx_t *session = (sr_session_ctx_t *)private_ctx;
280 * Here you would actually run the operation against the provided input values
281 * and obtained the output values.
284 /* allocate output values */
285 rc = sr_new_values(2, output);
286 if (SR_ERR_OK != rc) {
290 rc = sr_val_set_xpath(&(*output)[0], "/o-ran-software-management:software-download/status");
291 if (SR_ERR_OK != rc) {
294 (*output)[0].type = SR_ENUM_T;
295 (*output)[0].data.enum_val = "STARTED";
297 rc = sr_val_set_xpath(&(*output)[1], "/o-ran-software-management:software-download/notification-timeout");
298 if (SR_ERR_OK != rc) {
301 (*output)[1].type = SR_INT32_T;
302 (*output)[1].data.int32_val = 10;
304 /* inform sysrepo about the number of output values */
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);
311 pthread_t sw_download_thread;
312 if(pthread_create(&sw_download_thread, NULL, &sw_download_notification_send, (void *)args))
314 fprintf(stderr, "Could not create thread for SW Download thread\n");
315 return SR_ERR_OPERATION_FAILED;
319 * Do not deallocate input values!
320 * They will get freed automatically by sysrepo.
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)
330 sr_session_ctx_t *session = (sr_session_ctx_t *)private_ctx;
333 * Here you would actually run the operation against the provided input values
334 * and obtained the output values.
337 /* allocate output values */
338 rc = sr_new_values(1, output);
339 if (SR_ERR_OK != rc) {
343 rc = sr_val_set_xpath(&(*output)[0], "/o-ran-software-management:software-install/status");
344 if (SR_ERR_OK != rc) {
347 (*output)[0].type = SR_ENUM_T;
348 (*output)[0].data.enum_val = "STARTED";
350 /* inform sysrepo about the number of output values */
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);
357 pthread_t sw_install_thread;
358 if(pthread_create(&sw_install_thread, NULL, &sw_install_notification_send, (void *)args))
360 fprintf(stderr, "Could not create thread for SW Install thread\n");
361 return SR_ERR_OPERATION_FAILED;
365 * Do not deallocate input values!
366 * They will get freed automatically by sysrepo.
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)
376 sr_session_ctx_t *session = (sr_session_ctx_t *)private_ctx;
379 * Here you would actually run the operation against the provided input values
380 * and obtained the output values.
383 /* allocate output values */
384 rc = sr_new_values(2, output);
385 if (SR_ERR_OK != rc) {
389 rc = sr_val_set_xpath(&(*output)[0], "/o-ran-software-management:software-activate/status");
390 if (SR_ERR_OK != rc) {
393 (*output)[0].type = SR_ENUM_T;
394 (*output)[0].data.enum_val = "STARTED";
396 rc = sr_val_set_xpath(&(*output)[1], "/o-ran-software-management:software-activate/notification-timeout");
397 if (SR_ERR_OK != rc) {
400 (*output)[1].type = SR_INT32_T;
401 (*output)[1].data.int32_val = 10;
403 /* inform sysrepo about the number of output values */
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);
410 pthread_t sw_activate_thread;
411 if(pthread_create(&sw_activate_thread, NULL, &sw_activate_notification_send, (void *)args))
413 fprintf(stderr, "Could not create thread for SW Activate thread\n");
414 return SR_ERR_OPERATION_FAILED;
418 * Do not deallocate input values!
419 * They will get freed automatically by sysrepo.
425 sigint_handler(int signum)
427 exit_application = 1;
431 rpc_handler(sr_session_ctx_t *session)
433 sr_subscription_ctx_t *subscription = NULL;
436 /* subscribe for handling software-download RPC */
437 rc = sr_rpc_subscribe(session, "/o-ran-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));
444 /* subscribe for handling software-install RPC */
445 rc = sr_rpc_subscribe(session, "/o-ran-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));
452 /* subscribe for handling software-activate RPC */
453 rc = sr_rpc_subscribe(session, "/o-ran-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));
460 printf("\n\n ========== SUBSCRIBED FOR HANDLING RPC ==========\n\n");
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... */
469 printf("Application exit requested, exiting.\n");
472 if (NULL != subscription) {
473 sr_unsubscribe(session, subscription);
479 main(int argc, char **argv)
481 sr_conn_ctx_t *connection = NULL;
482 sr_session_ctx_t *session = NULL;
485 setbuf(stdout, NULL);
487 if (pthread_mutex_init(&lock, NULL) != 0)
489 printf("Mutex init failed...\n");
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));
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));
507 /* run as a RPC handler */
508 printf("This application will be an RPC handler for 'software-download' operation of 'o-ran-software-management'.\n");
509 rc = rpc_handler(session);
512 if (NULL != session) {
513 sr_session_stop(session);
515 if (NULL != connection) {
516 sr_disconnect(connection);