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