/** * @file sw-management-rpc.c * @author Rastislav Szabo , Lukas Macko , * Milan Lenco * @brief Example usage of RPC API. * * @copyright * Copyright 2016 Cisco Systems, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include "sysrepo.h" #include "sysrepo/values.h" #include "utils.h" #define LINE_BUFSIZE 128 volatile int exit_application = 0; pthread_mutex_t lock; static int sw_download_error_count, sw_install_error_count, sw_activate_error_count; void call_software_management_script(char *script_name) { char line[LINE_BUFSIZE]; int linenr; FILE *pipe; /* Get a pipe where the output from the scripts comes in */ char script[200]; sprintf(script, "/opt/dev/%s", script_name); pipe = popen(script, "r"); if (pipe == NULL) { /* check for errors */ printf("Could not open script.\n"); return; /* return with exit code indicating error */ } /* Read script output from the pipe line by line */ linenr = 1; while (fgets(line, LINE_BUFSIZE, pipe) != NULL) { printf("Script output line %d: %s", linenr, line); ++linenr; } /* Once here, out of the loop, the script has ended. */ pclose(pipe); /* Close the pipe */ return; /* return with exit code indicating success. */ } struct sw_download_struct { sr_session_ctx_t *sess; char *filename; }; void* sw_download_notification_send(void *arguments) { // create the values to be sent in the notification struct sw_download_struct *args = (struct sw_download_struct *)arguments; int rc = SR_ERR_OK; sw_download_error_count++; sr_val_t *notif = NULL; size_t current_num_of_values_notif = 0; CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif); char *trunc_filename; trunc_filename = strrchr(args->filename, '/'); sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:download-event/file-name"); if (trunc_filename != NULL) { sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_STRING_T, trunc_filename + 1); if (strcmp(trunc_filename+1, "reset") == 0) { call_software_management_script("edit-config-demo-start.sh"); } else { call_software_management_script("edit-config-after-download.sh"); } } else { sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_STRING_T, args->filename); if (strcmp(args->filename, "reset") == 0) { call_software_management_script("edit-config-demo-start.sh"); } else { call_software_management_script("edit-config-after-download.sh"); } } if (args->filename != NULL) { free(args->filename); } CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif); sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:download-event/status"); //every 5 RPCs we send an error if (sw_download_error_count % 5 == 0) { sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_ENUM_T, "AUTHENTICATION_ERROR"); } else { sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_ENUM_T, "COMPLETED"); } // wait 5 seconds before sending the notification sleep(5); /* send notification for event_notif_sub(_tree)_example */ printf(">>> Sending event notification for '/o-ran-software-management:download-event'...\n"); rc = sr_event_notif_send(args->sess, "/o-ran-software-management:download-event", notif, current_num_of_values_notif, SR_EV_NOTIF_DEFAULT); if (SR_ERR_NOT_FOUND == rc) { printf("No application subscribed for '/o-ran-software-management:download-event', skipping.\n"); rc = SR_ERR_OK; } sr_free_values(notif, current_num_of_values_notif); return NULL; } struct sw_install_struct { sr_session_ctx_t *sess; char *slot_name; }; void* sw_install_notification_send(void *arguments) { // create the values to be sent in the notification struct sw_install_struct *args = (struct sw_install_struct *)arguments; int rc = SR_ERR_OK; sw_install_error_count++; sr_val_t *notif = NULL; size_t current_num_of_values_notif = 0; CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif); sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:install-event/slot-name"); sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_STRING_T, args->slot_name); if (args->slot_name != NULL) { free(args->slot_name); } CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif); sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:install-event/status"); //every 5 RPCs we send an error if (sw_install_error_count % 5 == 0) { sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_ENUM_T, "INTEGRITY_ERROR"); } else { sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_ENUM_T, "COMPLETED"); } // wait 5 seconds before sending the notification sleep(5); /* send notification for event_notif_sub(_tree)_example */ printf(">>> Sending event notification for '/o-ran-software-management:install-event'...\n"); rc = sr_event_notif_send(args->sess, "/o-ran-software-management:install-event", notif, current_num_of_values_notif, SR_EV_NOTIF_DEFAULT); if (SR_ERR_NOT_FOUND == rc) { printf("No application subscribed for '/o-ran-software-management:install-event', skipping.\n"); rc = SR_ERR_OK; } sr_free_values(notif, current_num_of_values_notif); return NULL; } struct sw_activate_struct { sr_session_ctx_t *sess; char *slot_name; }; void* sw_activate_notification_send(void *arguments) { // create the values to be sent in the notification struct sw_activate_struct *args = (struct sw_activate_struct *)arguments; int rc = SR_ERR_OK; sw_activate_error_count++; sr_val_t *notif = NULL; size_t current_num_of_values_notif = 0; CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif); sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:activation-event/slot-name"); sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_STRING_T, args->slot_name); if (args->slot_name != NULL) { free(args->slot_name); } CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif); sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:activation-event/status"); //every 5 RPCs we send an error if (sw_activate_error_count % 5 == 0) { sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_ENUM_T, "APPLICATION_ERROR"); } else { sr_val_set_str_data(¬if[current_num_of_values_notif - 1], SR_ENUM_T, "COMPLETED"); call_software_management_script("edit-config-after-activate.sh"); } CREATE_NEW_VALUE(rc, notif, current_num_of_values_notif); sr_val_build_xpath(¬if[current_num_of_values_notif - 1], "%s", "/o-ran-software-management:activation-event/return-code"); notif[current_num_of_values_notif - 1].type = SR_UINT8_T; notif[current_num_of_values_notif - 1].data.uint8_val = 200; // wait 5 seconds before sending the notification sleep(5); /* send notification for event_notif_sub(_tree)_example */ printf(">>> Sending event notification for '/o-ran-software-management:activation-event'...\n"); rc = sr_event_notif_send(args->sess, "/o-ran-software-management:activation-event", notif, current_num_of_values_notif, SR_EV_NOTIF_DEFAULT); if (SR_ERR_NOT_FOUND == rc) { printf("No application subscribed for '/o-ran-software-management:activation-event', skipping.\n"); rc = SR_ERR_OK; } sr_free_values(notif, current_num_of_values_notif); return NULL; } static int sw_download_rpc_cb(const char *xpath, const sr_val_t *input, const size_t input_cnt, sr_val_t **output, size_t *output_cnt, void *private_ctx) { int rc = SR_ERR_OK; sr_session_ctx_t *session = (sr_session_ctx_t *)private_ctx; /** * Here you would actually run the operation against the provided input values * and obtained the output values. */ /* allocate output values */ rc = sr_new_values(2, output); if (SR_ERR_OK != rc) { return rc; } rc = sr_val_set_xpath(&(*output)[0], "/o-ran-software-management:software-download/status"); if (SR_ERR_OK != rc) { return rc; } (*output)[0].type = SR_ENUM_T; (*output)[0].data.enum_val = "STARTED"; rc = sr_val_set_xpath(&(*output)[1], "/o-ran-software-management:software-download/notification-timeout"); if (SR_ERR_OK != rc) { return rc; } (*output)[1].type = SR_INT32_T; (*output)[1].data.int32_val = 10; /* inform sysrepo about the number of output values */ *output_cnt = 2; struct sw_download_struct *args = (struct sw_download_struct *)malloc(sizeof(struct sw_download_struct)); args->sess = session; args->filename = strdup(input[0].data.string_val); pthread_t sw_download_thread; if(pthread_create(&sw_download_thread, NULL, &sw_download_notification_send, (void *)args)) { fprintf(stderr, "Could not create thread for SW Download thread\n"); return SR_ERR_OPERATION_FAILED; } /** * Do not deallocate input values! * They will get freed automatically by sysrepo. */ return rc; } static int sw_install_rpc_cb(const char *xpath, const sr_val_t *input, const size_t input_cnt, sr_val_t **output, size_t *output_cnt, void *private_ctx) { int rc = SR_ERR_OK; sr_session_ctx_t *session = (sr_session_ctx_t *)private_ctx; /** * Here you would actually run the operation against the provided input values * and obtained the output values. */ /* allocate output values */ rc = sr_new_values(1, output); if (SR_ERR_OK != rc) { return rc; } rc = sr_val_set_xpath(&(*output)[0], "/o-ran-software-management:software-install/status"); if (SR_ERR_OK != rc) { return rc; } (*output)[0].type = SR_ENUM_T; (*output)[0].data.enum_val = "STARTED"; /* inform sysrepo about the number of output values */ *output_cnt = 1; struct sw_install_struct *args = (struct sw_install_struct *)malloc(sizeof(struct sw_install_struct)); args->sess = session; args->slot_name = strdup(input[0].data.string_val); pthread_t sw_install_thread; if(pthread_create(&sw_install_thread, NULL, &sw_install_notification_send, (void *)args)) { fprintf(stderr, "Could not create thread for SW Install thread\n"); return SR_ERR_OPERATION_FAILED; } /** * Do not deallocate input values! * They will get freed automatically by sysrepo. */ return rc; } static int sw_activate_rpc_cb(const char *xpath, const sr_val_t *input, const size_t input_cnt, sr_val_t **output, size_t *output_cnt, void *private_ctx) { int rc = SR_ERR_OK; sr_session_ctx_t *session = (sr_session_ctx_t *)private_ctx; /** * Here you would actually run the operation against the provided input values * and obtained the output values. */ /* allocate output values */ rc = sr_new_values(2, output); if (SR_ERR_OK != rc) { return rc; } rc = sr_val_set_xpath(&(*output)[0], "/o-ran-software-management:software-activate/status"); if (SR_ERR_OK != rc) { return rc; } (*output)[0].type = SR_ENUM_T; (*output)[0].data.enum_val = "STARTED"; rc = sr_val_set_xpath(&(*output)[1], "/o-ran-software-management:software-activate/notification-timeout"); if (SR_ERR_OK != rc) { return rc; } (*output)[1].type = SR_INT32_T; (*output)[1].data.int32_val = 10; /* inform sysrepo about the number of output values */ *output_cnt = 2; struct sw_activate_struct *args = (struct sw_activate_struct *)malloc(sizeof(struct sw_activate_struct)); args->sess = session; args->slot_name = strdup(input[0].data.string_val); pthread_t sw_activate_thread; if(pthread_create(&sw_activate_thread, NULL, &sw_activate_notification_send, (void *)args)) { fprintf(stderr, "Could not create thread for SW Activate thread\n"); return SR_ERR_OPERATION_FAILED; } /** * Do not deallocate input values! * They will get freed automatically by sysrepo. */ return rc; } static void sigint_handler(int signum) { exit_application = 1; } static int rpc_handler(sr_session_ctx_t *session) { sr_subscription_ctx_t *subscription = NULL; int rc = SR_ERR_OK; /* subscribe for handling software-download RPC */ rc = sr_rpc_subscribe(session, "/o-ran-software-management:software-download", sw_download_rpc_cb, (void *)session, SR_SUBSCR_DEFAULT, &subscription); if (SR_ERR_OK != rc) { fprintf(stderr, "Error by sr_rpc_subscribe: %s\n", sr_strerror(rc)); goto cleanup; } /* subscribe for handling software-install RPC */ rc = sr_rpc_subscribe(session, "/o-ran-software-management:software-install", sw_install_rpc_cb, (void *)session, SR_SUBSCR_DEFAULT, &subscription); if (SR_ERR_OK != rc) { fprintf(stderr, "Error by sr_rpc_subscribe: %s\n", sr_strerror(rc)); goto cleanup; } /* subscribe for handling software-activate RPC */ rc = sr_rpc_subscribe(session, "/o-ran-software-management:software-activate", sw_activate_rpc_cb, (void *)session, SR_SUBSCR_DEFAULT, &subscription); if (SR_ERR_OK != rc) { fprintf(stderr, "Error by sr_rpc_subscribe: %s\n", sr_strerror(rc)); goto cleanup; } printf("\n\n ========== SUBSCRIBED FOR HANDLING RPC ==========\n\n"); /* loop until ctrl-c is pressed / SIGINT is received */ signal(SIGINT, sigint_handler); signal(SIGPIPE, SIG_IGN); while (!exit_application) { sleep(1000); /* or do some more useful work... */ } printf("Application exit requested, exiting.\n"); cleanup: if (NULL != subscription) { sr_unsubscribe(session, subscription); } return rc; } int main(int argc, char **argv) { sr_conn_ctx_t *connection = NULL; sr_session_ctx_t *session = NULL; int rc = SR_ERR_OK; setbuf(stdout, NULL); if (pthread_mutex_init(&lock, NULL) != 0) { printf("Mutex init failed...\n"); goto cleanup; } /* connect to sysrepo */ rc = sr_connect("sw_management_rpc_app", SR_CONN_DEFAULT, &connection); if (SR_ERR_OK != rc) { fprintf(stderr, "Error by sr_connect: %s\n", sr_strerror(rc)); goto cleanup; } /* start session */ rc = sr_session_start(connection, SR_DS_RUNNING, SR_SESS_DEFAULT, &session); if (SR_ERR_OK != rc) { fprintf(stderr, "Error by sr_session_start: %s\n", sr_strerror(rc)); goto cleanup; } /* run as a RPC handler */ printf("This application will be an RPC handler for 'software-download' operation of 'o-ran-software-management'.\n"); rc = rpc_handler(session); cleanup: if (NULL != session) { sr_session_stop(session); } if (NULL != connection) { sr_disconnect(connection); } return rc; }