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