dbaf58adffa0115039358195a624211f594a2088
[demo.git] / vnfs / VES5.0 / evel / evel-library / code / evel_library / evel.c
1 /*************************************************************************//**
2  *
3  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
4  *
5  * Unless otherwise specified, all software contained herein is
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
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
19 /**************************************************************************//**
20  * @file
21  * Source module isolating the ECOMP Vendor Event Listener (EVEL) API.
22  *
23  * This file implements the EVEL library which is intended to provide a
24  * simple wrapper around the complexity of AT&T's Vendor Event Listener API so
25  * that VNFs can use it without worrying about details of:
26  *
27  *  *   The API's encoding into JSON.
28  *  *   The API's transport over HTTP/HTTPS.
29  *
30  ****************************************************************************/
31
32 #include <string.h>
33 #include <assert.h>
34 #include <stdlib.h>
35 #include <sys/time.h>
36 #include <curl/curl.h>
37
38 #include "evel.h"
39 #include "evel_internal.h"
40 #include "evel_throttle.h"
41 #include "metadata.h"
42
43 /**************************************************************************//**
44  * The type of equipment represented by this VNF.
45  *****************************************************************************/
46 EVEL_SOURCE_TYPES event_source_type = EVEL_SOURCE_OTHER;
47
48 /**************************************************************************//**
49  * The Functional Role of the equipment represented by this VNF.
50  *****************************************************************************/
51 char *functional_role = NULL;
52
53 /**************************************************************************//**
54  * Library initialization.
55  *
56  * Initialize the EVEL library.
57  *
58  * @note  This function initializes the cURL library.  Applications making use
59  *        of libcurl may need to pull the initialization out of here.  Note
60  *        also that this function is not threadsafe as a result - refer to
61  *        libcurl's API documentation for relevant warnings.
62  *
63  * @sa  Matching Term function.
64  *
65  * @param   fqdn    The API's FQDN or IP address.
66  * @param   port    The API's port.
67  * @param   path    The optional path (may be NULL).
68  * @param   topic   The optional topic part of the URL (may be NULL).
69  * @param   secure  Whether to use HTTPS (0=HTTP, 1=HTTPS)
70  * @param   username  Username for Basic Authentication of requests.
71  * @param   password  Password for Basic Authentication of requests.
72  * @param   source_type The kind of node we represent.
73  * @param   role    The role this node undertakes.
74  * @param   verbosity  0 for normal operation, positive values for chattier
75  *                        logs.
76  *
77  * @returns Status code
78  * @retval  EVEL_SUCCESS      On success
79  * @retval  ::EVEL_ERR_CODES  On failure.
80  *****************************************************************************/
81 EVEL_ERR_CODES evel_initialize(const char * const fqdn,
82                                int port,
83                                const char * const path,
84                                const char * const topic,
85                                int secure,
86                                const char * const username,
87                                const char * const password,
88                                EVEL_SOURCE_TYPES source_type,
89                                const char * const role,
90                                int verbosity
91                                )
92 {
93   EVEL_ERR_CODES rc = EVEL_SUCCESS;
94   char base_api_url[EVEL_MAX_URL_LEN + 1] = {0};
95   char event_api_url[EVEL_MAX_URL_LEN + 1] = {0};
96   char throt_api_url[EVEL_MAX_URL_LEN + 1] = {0};
97   char path_url[EVEL_MAX_URL_LEN + 1] = {0};
98   char topic_url[EVEL_MAX_URL_LEN + 1] = {0};
99   char version_string[10] = {0};
100   int offset;
101
102   /***************************************************************************/
103   /* Check assumptions.                                                      */
104   /***************************************************************************/
105   assert(fqdn != NULL);
106   assert(port > 0 && port <= 65535);
107   assert(source_type < EVEL_MAX_SOURCE_TYPES);
108   assert(role != NULL);
109
110   /***************************************************************************/
111   /* Start logging so we can report on progress.                             */
112   /***************************************************************************/
113   log_initialize(verbosity == 0 ? EVEL_LOG_INFO : EVEL_LOG_DEBUG, "EVEL");
114   EVEL_INFO("EVEL started");
115   EVEL_INFO("API server is: %s", fqdn);
116   EVEL_INFO("API port is: %d", port);
117
118   if (path != NULL)
119   {
120     EVEL_INFO("API path is: %s", path);
121   }
122   else
123   {
124     EVEL_INFO("No API path");
125   }
126
127   if (topic != NULL)
128   {
129     EVEL_INFO("API topic is: %s", topic);
130   }
131   else
132   {
133     EVEL_INFO("No API topic");
134   }
135
136   EVEL_INFO("API transport is: %s", secure ? "HTTPS" : "HTTP");
137   EVEL_INFO("Event Source Type is: %d", source_type);
138   EVEL_INFO("Functional Role is: %s", role);
139   EVEL_INFO("Log verbosity is: %d", verbosity);
140
141   /***************************************************************************/
142   /* Initialize event throttling to the default state.                       */
143   /***************************************************************************/
144   evel_throttle_initialize();
145
146   /***************************************************************************/
147   /* Save values we will need during operation.                              */
148   /***************************************************************************/
149   event_source_type = source_type;
150   functional_role = strdup(role);
151
152   /***************************************************************************/
153   /* Ensure there are no trailing zeroes and unnecessary decimal points in   */
154   /* the version.                                                            */
155   /***************************************************************************/
156   offset = sprintf(version_string, "%d", EVEL_API_MAJOR_VERSION);
157
158   if (EVEL_API_MINOR_VERSION != 0)
159   {
160     sprintf(version_string + offset, ".%d", EVEL_API_MINOR_VERSION);
161   }
162
163   /***************************************************************************/
164   /* Build a common base of the API URLs.                                    */
165   /***************************************************************************/
166   strcpy(path_url, "/");
167   snprintf(base_api_url,
168            EVEL_MAX_URL_LEN,
169            "%s://%s:%d%s/eventListener/v%s",
170            secure ? "https" : "http",
171            fqdn,
172            port,
173            (((path != NULL) && (strlen(path) > 0)) ?
174             strncat(path_url, path, EVEL_MAX_URL_LEN) : ""),
175            version_string);
176
177   /***************************************************************************/
178   /* Build the URL to the event API.                                         */
179   /***************************************************************************/
180   strcpy(topic_url, "/");
181   snprintf(event_api_url,
182            EVEL_MAX_URL_LEN,
183            "%s%s",
184            base_api_url,
185            (((topic != NULL) && (strlen(topic) > 0)) ?
186             strncat(topic_url, topic, EVEL_MAX_URL_LEN) : ""));
187   EVEL_INFO("Vendor Event Listener API is located at: %s", event_api_url);
188
189   /***************************************************************************/
190   /* Build the URL to the throttling API.                                    */
191   /***************************************************************************/
192   snprintf(throt_api_url,
193            EVEL_MAX_URL_LEN,
194            "%s/clientThrottlingState",
195            base_api_url);
196   EVEL_INFO("Vendor Event Throttling API is located at: %s", throt_api_url);
197
198   /***************************************************************************/
199   /* Spin-up the event-handler, which gets cURL readied for use.             */
200   /***************************************************************************/
201   rc = event_handler_initialize(event_api_url,
202                                 throt_api_url,
203                                 username,
204                                 password,
205                                 verbosity);
206   if (rc != EVEL_SUCCESS)
207   {
208     log_error_state("Failed to initialize event handler (including cURL)");
209     goto exit_label;
210   }
211
212   /***************************************************************************/
213   /* Extract the metadata from OpenStack. If we fail to extract it, we       */
214   /* record that in the logs, but carry on, assuming we're in a test         */
215   /* without a metadata service.                                             */
216   /***************************************************************************/
217   rc = openstack_metadata(verbosity);
218   if (rc != EVEL_SUCCESS)
219   {
220     EVEL_INFO("Failed to load OpenStack metadata - assuming test environment");
221     rc = EVEL_SUCCESS;
222   }
223
224   /***************************************************************************/
225   /* Start the event handler thread.                                         */
226   /***************************************************************************/
227   rc = event_handler_run();
228   if (rc != EVEL_SUCCESS)
229   {
230     log_error_state("Failed to start event handler thread. "
231                     "Error code=%d", rc);
232     goto exit_label;
233   }
234
235 exit_label:
236   return(rc);
237 }
238
239 /**************************************************************************//**
240  * Clean up the EVEL library.
241  *
242  * @note that at present don't expect Init/Term cycling not to leak memory!
243  *
244  * @returns Status code
245  * @retval  EVEL_SUCCESS On success
246  * @retval  "One of ::EVEL_ERR_CODES" On failure.
247  *****************************************************************************/
248 EVEL_ERR_CODES evel_terminate(void)
249 {
250   int rc = EVEL_SUCCESS;
251
252   /***************************************************************************/
253   /* First terminate any pending transactions in the event-posting thread.   */
254   /***************************************************************************/
255   rc = event_handler_terminate();
256   if (rc != EVEL_SUCCESS)
257   {
258     log_error_state("Failed to terminate EVEL library cleanly!");
259   }
260
261   /***************************************************************************/
262   /* Shut down the Event Handler library in a tidy manner.                   */
263   /***************************************************************************/
264   curl_global_cleanup();
265
266   /***************************************************************************/
267   /* Clean up allocated memory.                                              */
268   /***************************************************************************/
269   free(functional_role);
270
271   /***************************************************************************/
272   /* Clean up event throttling.                                              */
273   /***************************************************************************/
274   evel_throttle_terminate();
275
276   EVEL_INFO("EVEL stopped");
277   return(rc);
278 }
279
280 /**************************************************************************//**
281  * Free an event.
282  *
283  * Free off the event supplied.  Will free all the contained allocated memory.
284  *
285  * @note  It is safe to free a NULL pointer.
286  *****************************************************************************/
287 void evel_free_event(void * event)
288 {
289   EVENT_HEADER * evt_ptr = event;
290   EVEL_ENTER();
291
292   if (event != NULL)
293   {
294     /*************************************************************************/
295     /* Work out what kind of event we're dealing with so we can cast it      */
296     /* appropriately.                                                        */
297     /*************************************************************************/
298     switch (evt_ptr->event_domain)
299     {
300     case EVEL_DOMAIN_INTERNAL:
301       EVEL_DEBUG("Event is an Internal event at %lp", evt_ptr);
302       evel_free_internal_event((EVENT_INTERNAL *) evt_ptr);
303       memset(evt_ptr, 0, sizeof(EVENT_INTERNAL));
304       free(evt_ptr);
305       break;
306
307     case EVEL_DOMAIN_HEARTBEAT:
308       EVEL_DEBUG("Event is a Heartbeat at %lp", evt_ptr);
309       evel_free_header(evt_ptr);
310       memset(evt_ptr, 0, sizeof(EVENT_HEADER));
311       free(evt_ptr);
312       break;
313
314     case EVEL_DOMAIN_FAULT:
315       EVEL_DEBUG("Event is a Fault at %lp", evt_ptr);
316       evel_free_fault((EVENT_FAULT *)evt_ptr);
317       memset(evt_ptr, 0, sizeof(EVENT_FAULT));
318       free(evt_ptr);
319       break;
320
321     case EVEL_DOMAIN_MEASUREMENT:
322       EVEL_DEBUG("Event is a Measurement at %lp", evt_ptr);
323       evel_free_measurement((EVENT_MEASUREMENT *)evt_ptr);
324       memset(evt_ptr, 0, sizeof(EVENT_MEASUREMENT));
325       free(evt_ptr);
326       break;
327
328     case EVEL_DOMAIN_MOBILE_FLOW:
329       EVEL_DEBUG("Event is a Mobile Flow at %lp", evt_ptr);
330       evel_free_mobile_flow((EVENT_MOBILE_FLOW *)evt_ptr);
331       memset(evt_ptr, 0, sizeof(EVENT_MOBILE_FLOW));
332       free(evt_ptr);
333       break;
334
335     case EVEL_DOMAIN_REPORT:
336       EVEL_DEBUG("Event is a Report at %lp", evt_ptr);
337       evel_free_report((EVENT_REPORT *)evt_ptr);
338       memset(evt_ptr, 0, sizeof(EVENT_REPORT));
339       free(evt_ptr);
340       break;
341
342     case EVEL_DOMAIN_HEARTBEAT_FIELD:
343       EVEL_DEBUG("Event is a Heartbeat Field Event at %lp", evt_ptr);
344       evel_free_hrtbt_field((EVENT_HEARTBEAT_FIELD *)evt_ptr);
345       memset(evt_ptr, 0, sizeof(EVENT_HEARTBEAT_FIELD));
346       free(evt_ptr);
347       break;
348
349     case EVEL_DOMAIN_SIPSIGNALING:
350       EVEL_DEBUG("Event is a Signaling at %lp", evt_ptr);
351       evel_free_signaling((EVENT_SIGNALING *)evt_ptr);
352       memset(evt_ptr, 0, sizeof(EVENT_SIGNALING));
353       free(evt_ptr);
354       break;
355
356     case EVEL_DOMAIN_STATE_CHANGE:
357       EVEL_DEBUG("Event is a State Change at %lp", evt_ptr);
358       evel_free_state_change((EVENT_STATE_CHANGE *)evt_ptr);
359       memset(evt_ptr, 0, sizeof(EVENT_STATE_CHANGE));
360       free(evt_ptr);
361       break;
362
363     case EVEL_DOMAIN_SYSLOG:
364       EVEL_DEBUG("Event is a Syslog at %lp", evt_ptr);
365       evel_free_syslog((EVENT_SYSLOG *)evt_ptr);
366       memset(evt_ptr, 0, sizeof(EVENT_SYSLOG));
367       free(evt_ptr);
368       break;
369
370     case EVEL_DOMAIN_OTHER:
371       EVEL_DEBUG("Event is an Other at %lp", evt_ptr);
372       evel_free_other((EVENT_OTHER *)evt_ptr);
373       memset(evt_ptr, 0, sizeof(EVENT_OTHER));
374       free(evt_ptr);
375       break;
376
377     case EVEL_DOMAIN_VOICE_QUALITY:
378       EVEL_DEBUG("Event is an VoiceQuality at %lp", evt_ptr);
379       evel_free_voice_quality((EVENT_VOICE_QUALITY *)evt_ptr);
380       memset(evt_ptr, 0, sizeof(EVENT_VOICE_QUALITY));
381       free(evt_ptr);
382       break;
383
384     case EVEL_DOMAIN_THRESHOLD_CROSS:
385       EVEL_DEBUG("Event is a Threshold crossing at %lp", evt_ptr);
386       evel_free_threshold_cross((EVENT_THRESHOLD_CROSS *)evt_ptr);
387       memset(evt_ptr, 0, sizeof(EVENT_THRESHOLD_CROSS));
388       free(evt_ptr);
389       break;
390
391     default:
392       EVEL_ERROR("Unexpected event domain (%d)", evt_ptr->event_domain);
393       assert(0);
394     }
395   }
396   EVEL_EXIT();
397 }