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