Add ringbuffer size to API
[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   cert_file_path     Path to client certificate file
71  * @param   key_file_path      Path to client key file
72  * @param   ca_info            Path to CA cert file
73  * @param   ca_file_path       Path to CA cert files
74  * @param   verify_peer        SSL verification of peer 0 or 1
75  * @param   verify_host        SSL verification of host 0 or 1
76  * @param   username  Username for Basic Authentication of requests.
77  * @param   password  Password for Basic Authentication of requests.
78  * @param   source_ip The ip of node we represent (NULL for default ip).
79  * @param   source_type The kind of node we represent.
80  * @param   role    The role this node undertakes.
81  * @param   verbosity  0 for normal operation, positive values for chattier
82  *                        logs.
83  *
84  * @returns Status code
85  * @retval  EVEL_SUCCESS      On success
86  * @retval  ::EVEL_ERR_CODES  On failure.
87  *****************************************************************************/
88 EVEL_ERR_CODES evel_initialize(const char * const fqdn,
89                                int port,
90                                const char * const path,
91                                const char * const topic,
92                                int ring_buf_size,
93                                int secure,
94                                const char * const cert_file_path,
95                                const char * const key_file_path,
96                                const char * const ca_info,
97                                const char * const ca_file_path,
98                                long verify_peer,
99                                long verify_host,
100                                const char * const username,
101                                const char * const password,
102                                const char * const source_ip,
103                                EVEL_SOURCE_TYPES source_type,
104                                const char * const role,
105                                int verbosity
106                                )
107 {
108   EVEL_ERR_CODES rc = EVEL_SUCCESS;
109   char base_api_url[EVEL_MAX_URL_LEN + 1] = {0};
110   char event_api_url[EVEL_MAX_URL_LEN + 1] = {0};
111   char throt_api_url[EVEL_MAX_URL_LEN + 1] = {0};
112   char path_url[EVEL_MAX_URL_LEN + 1] = {0};
113   char topic_url[EVEL_MAX_URL_LEN + 1] = {0};
114   char version_string[10] = {0};
115   int offset;
116
117   /***************************************************************************/
118   /* Check assumptions.                                                      */
119   /***************************************************************************/
120   assert(fqdn != NULL);
121   assert(port > 0 && port <= 65535);
122   assert(source_type < EVEL_MAX_SOURCE_TYPES);
123   assert(role != NULL);
124
125   /***************************************************************************/
126   /* Start logging so we can report on progress.                             */
127   /***************************************************************************/
128   log_initialize(verbosity == 0 ? EVEL_LOG_INFO : EVEL_LOG_DEBUG, "EVEL");
129   EVEL_INFO("EVEL started");
130   EVEL_INFO("API server is: %s", fqdn);
131   EVEL_INFO("API port is: %d", port);
132
133   if (path != NULL)
134   {
135     EVEL_INFO("API path is: %s", path);
136   }
137   else
138   {
139     EVEL_INFO("No API path");
140   }
141
142   if (topic != NULL)
143   {
144     EVEL_INFO("API topic is: %s", topic);
145   }
146   else
147   {
148     EVEL_INFO("No API topic");
149   }
150
151   EVEL_INFO("API transport is: %s", secure ? "HTTPS" : "HTTP");
152   if( secure ) {
153     assert( verify_peer >= 0 );
154     assert( verify_host >= 0 );
155     if (cert_file_path != NULL)
156     {
157       EVEL_INFO("Client cert is: %s", cert_file_path);
158     }
159     else
160     {
161       EVEL_INFO("No Client cert");
162     }
163     if (key_file_path != NULL)
164     {
165       EVEL_INFO("Key file is: %s", key_file_path);
166     }
167     else
168     {
169       EVEL_INFO("No Key file");
170     }
171     if (ca_file_path != NULL)
172     {
173       EVEL_INFO("Client CA certs path is: %s", ca_file_path);
174     }
175     else
176     {
177       EVEL_INFO("No CA certs path");
178     }
179     if (ca_info != NULL)
180     {
181       EVEL_INFO("Client CA cert file is: %s", ca_info);
182     }
183     else
184     {
185       EVEL_INFO("No CA cert file");
186     }
187   }
188   EVEL_INFO("Event Source Type is: %d", source_type);
189   EVEL_INFO("Functional Role is: %s", role);
190   EVEL_INFO("Log verbosity is: %d", verbosity);
191
192   /***************************************************************************/
193   /* Initialize event throttling to the default state.                       */
194   /***************************************************************************/
195   evel_throttle_initialize();
196
197   /***************************************************************************/
198   /* Save values we will need during operation.                              */
199   /***************************************************************************/
200   event_source_type = source_type;
201   functional_role = strdup(role);
202
203   /***************************************************************************/
204   /* Ensure there are no trailing zeroes and unnecessary decimal points in   */
205   /* the version.                                                            */
206   /***************************************************************************/
207   offset = sprintf(version_string, "%d", EVEL_API_MAJOR_VERSION);
208
209   if (EVEL_API_MINOR_VERSION != 0)
210   {
211     sprintf(version_string + offset, ".%d", EVEL_API_MINOR_VERSION);
212   }
213
214   /***************************************************************************/
215   /* Build a common base of the API URLs.                                    */
216   /***************************************************************************/
217   strcpy(path_url, "/");
218   snprintf(base_api_url,
219            EVEL_MAX_URL_LEN,
220            "%s://%s:%d%s/eventListener/v%s",
221            secure ? "https" : "http",
222            fqdn,
223            port,
224            (((path != NULL) && (strlen(path) > 0)) ?
225             strncat(path_url, path, EVEL_MAX_URL_LEN) : ""),
226            version_string);
227
228   /***************************************************************************/
229   /* Build the URL to the event API.                                         */
230   /***************************************************************************/
231   strcpy(topic_url, "/");
232   snprintf(event_api_url,
233            EVEL_MAX_URL_LEN,
234            "%s%s",
235            base_api_url,
236            (((topic != NULL) && (strlen(topic) > 0)) ?
237             strncat(topic_url, topic, EVEL_MAX_URL_LEN) : ""));
238   EVEL_INFO("Vendor Event Listener API is located at: %s", event_api_url);
239
240   /***************************************************************************/
241   /* Build the URL to the throttling API.                                    */
242   /***************************************************************************/
243   snprintf(throt_api_url,
244            EVEL_MAX_URL_LEN,
245            "%s/clientThrottlingState",
246            base_api_url);
247   EVEL_INFO("Vendor Event Throttling API is located at: %s", throt_api_url);
248
249   /***************************************************************************/
250   /* Spin-up the event-handler, which gets cURL readied for use.             */
251   /***************************************************************************/
252   rc = event_handler_initialize(event_api_url,
253                                 throt_api_url,
254                                 source_ip,
255                                 ring_buf_size,
256                                 secure,
257                                 cert_file_path,
258                                 key_file_path,
259                                 ca_info,
260                                 ca_file_path,
261                                 verify_peer,
262                                 verify_host,
263                                 username,
264                                 password,
265                                 verbosity);
266   if (rc != EVEL_SUCCESS)
267   {
268     log_error_state("Failed to initialize event handler (including cURL)");
269     goto exit_label;
270   }
271
272   /***************************************************************************/
273   /* Extract the metadata from OpenStack. If we fail to extract it, we       */
274   /* record that in the logs, but carry on, assuming we're in a test         */
275   /* without a metadata service.                                             */
276   /***************************************************************************/
277   rc = openstack_metadata(verbosity);
278   if (rc != EVEL_SUCCESS)
279   {
280     EVEL_INFO("Failed to load OpenStack metadata - assuming test environment");
281     rc = EVEL_SUCCESS;
282   }
283
284   /***************************************************************************/
285   /* Start the event handler thread.                                         */
286   /***************************************************************************/
287   rc = event_handler_run();
288   if (rc != EVEL_SUCCESS)
289   {
290     log_error_state("Failed to start event handler thread. "
291                     "Error code=%d", rc);
292     goto exit_label;
293   }
294
295 exit_label:
296   return(rc);
297 }
298
299 /**************************************************************************//**
300  * Clean up the EVEL library.
301  *
302  * @note that at present don't expect Init/Term cycling not to leak memory!
303  *
304  * @returns Status code
305  * @retval  EVEL_SUCCESS On success
306  * @retval  "One of ::EVEL_ERR_CODES" On failure.
307  *****************************************************************************/
308 EVEL_ERR_CODES evel_terminate(void)
309 {
310   int rc = EVEL_SUCCESS;
311
312   /***************************************************************************/
313   /* First terminate any pending transactions in the event-posting thread.   */
314   /***************************************************************************/
315   rc = event_handler_terminate();
316   if (rc != EVEL_SUCCESS)
317   {
318     log_error_state("Failed to terminate EVEL library cleanly!");
319   }
320
321   /***************************************************************************/
322   /* Shut down the Event Handler library in a tidy manner.                   */
323   /***************************************************************************/
324   curl_global_cleanup();
325
326   /***************************************************************************/
327   /* Clean up allocated memory.                                              */
328   /***************************************************************************/
329   free(functional_role);
330
331   /***************************************************************************/
332   /* Clean up event throttling.                                              */
333   /***************************************************************************/
334   evel_throttle_terminate();
335
336   EVEL_INFO("EVEL stopped");
337   return(rc);
338 }
339
340 /**************************************************************************//**
341  * Free an event.
342  *
343  * Free off the event supplied.  Will free all the contained allocated memory.
344  *
345  * @note  It is safe to free a NULL pointer.
346  *****************************************************************************/
347 void evel_free_event(void * event)
348 {
349   EVENT_HEADER * evt_ptr = event;
350   EVEL_ENTER();
351
352   if (event != NULL)
353   {
354     /*************************************************************************/
355     /* Work out what kind of event we're dealing with so we can cast it      */
356     /* appropriately.                                                        */
357     /*************************************************************************/
358     switch (evt_ptr->event_domain)
359     {
360     case EVEL_DOMAIN_INTERNAL:
361       EVEL_DEBUG("Event is an Internal event at %lp", evt_ptr);
362       evel_free_internal_event((EVENT_INTERNAL *) evt_ptr);
363       memset(evt_ptr, 0, sizeof(EVENT_INTERNAL));
364       free(evt_ptr);
365       break;
366
367     case EVEL_DOMAIN_HEARTBEAT:
368       EVEL_DEBUG("Event is a Heartbeat at %lp", evt_ptr);
369       evel_free_header(evt_ptr);
370       memset(evt_ptr, 0, sizeof(EVENT_HEADER));
371       free(evt_ptr);
372       break;
373
374     case EVEL_DOMAIN_FAULT:
375       EVEL_DEBUG("Event is a Fault at %lp", evt_ptr);
376       evel_free_fault((EVENT_FAULT *)evt_ptr);
377       memset(evt_ptr, 0, sizeof(EVENT_FAULT));
378       free(evt_ptr);
379       break;
380
381     case EVEL_DOMAIN_MEASUREMENT:
382       EVEL_DEBUG("Event is a Measurement at %lp", evt_ptr);
383       evel_free_measurement((EVENT_MEASUREMENT *)evt_ptr);
384       memset(evt_ptr, 0, sizeof(EVENT_MEASUREMENT));
385       free(evt_ptr);
386       break;
387
388     case EVEL_DOMAIN_MOBILE_FLOW:
389       EVEL_DEBUG("Event is a Mobile Flow at %lp", evt_ptr);
390       evel_free_mobile_flow((EVENT_MOBILE_FLOW *)evt_ptr);
391       memset(evt_ptr, 0, sizeof(EVENT_MOBILE_FLOW));
392       free(evt_ptr);
393       break;
394
395     case EVEL_DOMAIN_REPORT:
396       EVEL_DEBUG("Event is a Report at %lp", evt_ptr);
397       evel_free_report((EVENT_REPORT *)evt_ptr);
398       memset(evt_ptr, 0, sizeof(EVENT_REPORT));
399       free(evt_ptr);
400       break;
401
402     case EVEL_DOMAIN_HEARTBEAT_FIELD:
403       EVEL_DEBUG("Event is a Heartbeat Field Event at %lp", evt_ptr);
404       evel_free_hrtbt_field((EVENT_HEARTBEAT_FIELD *)evt_ptr);
405       memset(evt_ptr, 0, sizeof(EVENT_HEARTBEAT_FIELD));
406       free(evt_ptr);
407       break;
408
409     case EVEL_DOMAIN_SIPSIGNALING:
410       EVEL_DEBUG("Event is a Signaling at %lp", evt_ptr);
411       evel_free_signaling((EVENT_SIGNALING *)evt_ptr);
412       memset(evt_ptr, 0, sizeof(EVENT_SIGNALING));
413       free(evt_ptr);
414       break;
415
416     case EVEL_DOMAIN_STATE_CHANGE:
417       EVEL_DEBUG("Event is a State Change at %lp", evt_ptr);
418       evel_free_state_change((EVENT_STATE_CHANGE *)evt_ptr);
419       memset(evt_ptr, 0, sizeof(EVENT_STATE_CHANGE));
420       free(evt_ptr);
421       break;
422
423     case EVEL_DOMAIN_SYSLOG:
424       EVEL_DEBUG("Event is a Syslog at %lp", evt_ptr);
425       evel_free_syslog((EVENT_SYSLOG *)evt_ptr);
426       memset(evt_ptr, 0, sizeof(EVENT_SYSLOG));
427       free(evt_ptr);
428       break;
429
430     case EVEL_DOMAIN_OTHER:
431       EVEL_DEBUG("Event is an Other at %lp", evt_ptr);
432       evel_free_other((EVENT_OTHER *)evt_ptr);
433       memset(evt_ptr, 0, sizeof(EVENT_OTHER));
434       free(evt_ptr);
435       break;
436
437     case EVEL_DOMAIN_VOICE_QUALITY:
438       EVEL_DEBUG("Event is an VoiceQuality at %lp", evt_ptr);
439       evel_free_voice_quality((EVENT_VOICE_QUALITY *)evt_ptr);
440       memset(evt_ptr, 0, sizeof(EVENT_VOICE_QUALITY));
441       free(evt_ptr);
442       break;
443
444     case EVEL_DOMAIN_THRESHOLD_CROSS:
445       EVEL_DEBUG("Event is a Threshold crossing at %lp", evt_ptr);
446       evel_free_threshold_cross((EVENT_THRESHOLD_CROSS *)evt_ptr);
447       memset(evt_ptr, 0, sizeof(EVENT_THRESHOLD_CROSS));
448       free(evt_ptr);
449       break;
450
451     case EVEL_DOMAIN_BATCH:
452       EVEL_DEBUG("Event is a Batch at %lp", evt_ptr);
453       evel_free_batch((EVENT_HEADER *)evt_ptr);
454       memset(evt_ptr, 0, sizeof(EVENT_HEADER));
455       free(evt_ptr);
456       break;
457
458     default:
459       EVEL_ERROR("Unexpected event domain (%d)", evt_ptr->event_domain);
460       assert(0);
461     }
462   }
463   EVEL_EXIT();
464 }