aboutsummaryrefslogtreecommitdiffstats
path: root/VES5.0/evel/evel-library/code/evel_library/metadata.c
diff options
context:
space:
mode:
Diffstat (limited to 'VES5.0/evel/evel-library/code/evel_library/metadata.c')
-rw-r--r--VES5.0/evel/evel-library/code/evel_library/metadata.c607
1 files changed, 0 insertions, 607 deletions
diff --git a/VES5.0/evel/evel-library/code/evel_library/metadata.c b/VES5.0/evel/evel-library/code/evel_library/metadata.c
deleted file mode 100644
index dfdca052..00000000
--- a/VES5.0/evel/evel-library/code/evel_library/metadata.c
+++ /dev/null
@@ -1,607 +0,0 @@
-/**************************************************************************//**
- * @file
- * Wrap the OpenStack metadata service.
- *
- * License
- * -------
- *
- * Copyright(c) <2016>, AT&T Intellectual Property. All other rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement: This product includes
- * software developed by the AT&T.
- * 4. Neither the name of AT&T nor the names of its contributors may be used to
- * endorse or promote products derived from this software without specific
- * prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY AT&T INTELLECTUAL PROPERTY ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AT&T INTELLECTUAL PROPERTY BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *****************************************************************************/
-
-#include <string.h>
-#include <assert.h>
-#include <malloc.h>
-
-#include <curl/curl.h>
-
-#include "evel.h"
-#include "evel_internal.h"
-#include "jsmn.h"
-#include "metadata.h"
-
-/**************************************************************************//**
- * URL on the link-local IP address where we can get the metadata in
- * machine-friendly format.
- *****************************************************************************/
-static const char * OPENSTACK_METADATA_URL =
- "http://169.254.169.254/openstack/latest/meta_data.json";
-
-/**************************************************************************//**
- * How long we're prepared to wait for the metadata service to respond in
- * seconds.
- *****************************************************************************/
-static const int OPENSTACK_METADATA_TIMEOUT = 2;
-
-/**************************************************************************//**
- * Size of fields extracted from metadata service.
- *****************************************************************************/
-#define MAX_METADATA_STRING 64
-
-/**************************************************************************//**
- * UUID of the VM extracted from the OpenStack metadata service.
- *****************************************************************************/
-static char vm_uuid[MAX_METADATA_STRING+1] = {0};
-
-/**************************************************************************//**
- * Name of the VM extracted from the OpenStack metadata service.
- *****************************************************************************/
-static char vm_name[MAX_METADATA_STRING+1] = {0};
-
-/**************************************************************************//**
- * How many metadata elements we allow for in the retrieved JSON.
- *****************************************************************************/
-static const int MAX_METADATA_TOKENS = 128;
-
-/*****************************************************************************/
-/* Local prototypes. */
-/*****************************************************************************/
-static EVEL_ERR_CODES json_get_top_level_string(const char * json_string,
- const jsmntok_t *tokens,
- int json_token_count,
- const char * key,
- char * value);
-static EVEL_ERR_CODES json_get_string(const char * json_string,
- const jsmntok_t *tokens,
- int json_token_count,
- const char * key,
- char * value);
-static int jsoneq(const char *json, const jsmntok_t *tok, const char *s);
-
-/**************************************************************************//**
- * Download metadata from the OpenStack metadata service.
- *
- * @param verbosity Controls whether to generate debug to stdout. Zero:
- * none. Non-zero: generate debug.
- * @returns Status code
- * @retval EVEL_SUCCESS On success
- * @retval ::EVEL_ERR_CODES On failure.
- *****************************************************************************/
-EVEL_ERR_CODES openstack_metadata(int verbosity)
-{
- int rc = EVEL_SUCCESS;
- CURLcode curl_rc = CURLE_OK;
- CURL * curl_handle = NULL;
- MEMORY_CHUNK rx_chunk;
- char curl_err_string[CURL_ERROR_SIZE] = "<NULL>";
- jsmn_parser json_parser;
- jsmntok_t tokens[MAX_METADATA_TOKENS];
- int json_token_count = 0;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Initialize dummy values for the metadata - needed for test */
- /* environments. */
- /***************************************************************************/
- openstack_metadata_initialize();
-
- /***************************************************************************/
- /* Get a curl handle which we'll use for accessing the metadata service. */
- /***************************************************************************/
- curl_handle = curl_easy_init();
- if (curl_handle == NULL)
- {
- rc = EVEL_CURL_LIBRARY_FAIL;
- EVEL_ERROR("Failed to get libcurl handle");
- goto exit_label;
- }
-
- /***************************************************************************/
- /* Prime the library to give friendly error codes. */
- /***************************************************************************/
- curl_rc = curl_easy_setopt(curl_handle,
- CURLOPT_ERRORBUFFER,
- curl_err_string);
- if (curl_rc != CURLE_OK)
- {
- rc = EVEL_CURL_LIBRARY_FAIL;
- EVEL_ERROR("Failed to initialize libcurl to provide friendly errors. "
- "Error code=%d", curl_rc);
- goto exit_label;
- }
-
- /***************************************************************************/
- /* Set the URL for the metadata API. */
- /***************************************************************************/
- curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, OPENSTACK_METADATA_URL);
- if (curl_rc != CURLE_OK)
- {
- rc = EVEL_CURL_LIBRARY_FAIL;
- EVEL_ERROR("Failed to initialize libcurl with the API URL. "
- "Error code=%d (%s)", curl_rc, curl_err_string);
- goto exit_label;
- }
-
- /***************************************************************************/
- /* send all data to this function. */
- /***************************************************************************/
- curl_rc = curl_easy_setopt(curl_handle,
- CURLOPT_WRITEFUNCTION,
- evel_write_callback);
- if (curl_rc != CURLE_OK)
- {
- rc = EVEL_CURL_LIBRARY_FAIL;
- EVEL_ERROR("Failed to initialize libcurl with the write callback. "
- "Error code=%d (%s)", curl_rc, curl_err_string);
- goto exit_label;
- }
-
- /***************************************************************************/
- /* some servers don't like requests that are made without a user-agent */
- /* field, so we provide one. */
- /***************************************************************************/
- curl_rc = curl_easy_setopt(curl_handle,
- CURLOPT_USERAGENT,
- "libcurl-agent/1.0");
- if (curl_rc != CURLE_OK)
- {
- rc = EVEL_CURL_LIBRARY_FAIL;
- EVEL_ERROR("Failed to initialize libcurl to upload. Error code=%d (%s)",
- curl_rc, curl_err_string);
- goto exit_label;
- }
-
- /***************************************************************************/
- /* Set the timeout for the operation. */
- /***************************************************************************/
- curl_rc = curl_easy_setopt(curl_handle,
- CURLOPT_TIMEOUT,
- OPENSTACK_METADATA_TIMEOUT);
- if (curl_rc != CURLE_OK)
- {
- rc = EVEL_NO_METADATA;
- EVEL_ERROR("Failed to initialize libcurl to set timeout. "
- "Error code=%d (%s)", curl_rc, curl_err_string);
- goto exit_label;
- }
-
- /***************************************************************************/
- /* Create the memory chunk to be used for the response to the post. The */
- /* will be realloced. */
- /***************************************************************************/
- rx_chunk.memory = malloc(1);
- assert(rx_chunk.memory != NULL);
- rx_chunk.size = 0;
-
- /***************************************************************************/
- /* Point to the data to be received. */
- /***************************************************************************/
- curl_rc = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&rx_chunk);
- if (curl_rc != CURLE_OK)
- {
- rc = EVEL_CURL_LIBRARY_FAIL;
- EVEL_ERROR("Failed to initialize libcurl to receive metadata. "
- "Error code=%d (%s)", curl_rc, curl_err_string);
- goto exit_label;
- }
- EVEL_DEBUG("Initialized data to receive");
-
- /***************************************************************************/
- /* If running in verbose mode generate more output. */
- /***************************************************************************/
- if (verbosity > 0)
- {
- curl_rc = curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
- if (curl_rc != CURLE_OK)
- {
- rc = EVEL_CURL_LIBRARY_FAIL;
- log_error_state("Failed to initialize libcurl to be verbose. "
- "Error code=%d", curl_rc);
- goto exit_label;
- }
- }
-
- /***************************************************************************/
- /* Now run off and do what you've been told! */
- /***************************************************************************/
- curl_rc = curl_easy_perform(curl_handle);
- if (curl_rc != CURLE_OK)
- {
- rc = EVEL_CURL_LIBRARY_FAIL;
- EVEL_ERROR("Failed to transfer the data from metadata service. "
- "Error code=%d (%s)", curl_rc, curl_err_string);
- }
- else
- {
- /*************************************************************************/
- /* We have some metadata available, so break it out into tokens. */
- /*************************************************************************/
- EVEL_DEBUG("Received metadata size = %d", rx_chunk.size);
- EVEL_INFO("Received metadata = %s", rx_chunk.memory);
- jsmn_init(&json_parser);
- json_token_count = jsmn_parse(&json_parser,
- rx_chunk.memory, rx_chunk.size,
- tokens, MAX_METADATA_TOKENS);
-
- /*************************************************************************/
- /* Check that we parsed some data and that the top level is as expected. */
- /*************************************************************************/
- if (json_token_count < 0 || tokens[0].type != JSMN_OBJECT)
- {
- rc = EVEL_BAD_METADATA;
- EVEL_ERROR("Failed to parse received JSON OpenStack metadata. "
- "Error code=%d", json_token_count);
- goto exit_label;
- }
- else
- {
- EVEL_DEBUG("Extracted %d tokens from the JSON OpenStack metadata. ",
- json_token_count);
- }
-
- /*************************************************************************/
- /* Find the keys we want from the metadata. */
- /*************************************************************************/
- if (json_get_string(rx_chunk.memory,
- tokens,
- json_token_count,
- "uuid",
- vm_uuid) != EVEL_SUCCESS)
- {
- rc = EVEL_BAD_METADATA;
- EVEL_ERROR("Failed to extract UUID from OpenStack metadata");
- }
- else
- {
- EVEL_DEBUG("UUID: %s", vm_uuid);
- }
- if (json_get_top_level_string(rx_chunk.memory,
- tokens,
- json_token_count,
- "name",
- vm_name) != EVEL_SUCCESS)
- {
- rc = EVEL_BAD_METADATA;
- EVEL_ERROR("Failed to extract VM Name from OpenStack metadata");
- }
- else
- {
- EVEL_DEBUG("VM Name: %s", vm_name);
- }
- }
-
-exit_label:
-
- /***************************************************************************/
- /* Shut down the cURL library in a tidy manner. */
- /***************************************************************************/
- if (curl_handle != NULL)
- {
- curl_easy_cleanup(curl_handle);
- curl_handle = NULL;
- }
- free(rx_chunk.memory);
-
- EVEL_EXIT();
- return rc;
-}
-
-/**************************************************************************//**
- * Initialize default values for vm_name and vm_uuid - for testing purposes.
- *****************************************************************************/
-void openstack_metadata_initialize()
-{
- strncpy(vm_uuid,
- "Dummy VM UUID - No Metadata available",
- MAX_METADATA_STRING);
- strncpy(vm_name,
- "Dummy VM name - No Metadata available",
- MAX_METADATA_STRING);
-}
-
-/**************************************************************************//**
- * Get a string value from supplied JSON by matching the key.
- *
- * As the structure of the metadata we're looking at is pretty straightforward
- * we don't do anything complex (a la XPath) to extract nested keys with the
- * same leaf name, for example. Simply walk the structure until we find a
- * string with the correct value.
- *
- * @param[in] json_string The string which contains the JSON and has already
- * been parsed.
- * @param[in] tokens The tokens which the JSON parser found in the JSON.
- * @param[in] json_token_count How many tokens were found.
- * @param[in] key The key we're looking for.
- * @param[out] value The string we found at @p key.
- *
- * @returns Status code
- * @retval EVEL_SUCCESS On success - contents of @p value updated.
- * @retval EVEL_JSON_KEY_NOT_FOUND Key not found - @p value not updated.
- * @retval EVEL_BAD_JSON Parser hit unexpected data - @p value not
- * updated.
- *****************************************************************************/
-static EVEL_ERR_CODES json_get_string(const char * json_string,
- const jsmntok_t * tokens,
- int json_token_count,
- const char * key,
- char * value)
-{
- EVEL_ERR_CODES rc = EVEL_JSON_KEY_NOT_FOUND;
- int token_num = 0;
- int token_len = 0;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check assumptions. */
- /***************************************************************************/
- assert(json_string != NULL);
- assert(tokens != NULL);
- assert(json_token_count >= 0);
- assert(key != NULL);
- assert(value != NULL);
-
- for (token_num = 0; token_num < json_token_count; token_num++)
- {
- switch(tokens[token_num].type)
- {
- case JSMN_OBJECT:
- EVEL_DEBUG("Skipping object");
- break;
-
- case JSMN_ARRAY:
- EVEL_DEBUG("Skipping array");
- break;
-
- case JSMN_STRING:
- /***********************************************************************/
- /* This is a string, so may be what we want. Compare keys. */
- /***********************************************************************/
- if (jsoneq(json_string, &tokens[token_num], key) == 0)
- {
- token_len = tokens[token_num + 1].end - tokens[token_num + 1].start;
- EVEL_DEBUG("Token %d len %d matches at %d to %d", token_num,
- tokens[token_num + 1].start,
- tokens[token_num + 1].end);
- strncpy(value, json_string + tokens[token_num + 1].start, token_len);
- value[token_len] = '\0';
- EVEL_DEBUG("Extracted key: \"%s\" Value: \"%s\"", key, value);
- rc = EVEL_SUCCESS;
- goto exit_label;
- }
- else
- {
- EVEL_DEBUG("String key did not match");
- }
-
- /***********************************************************************/
- /* Step over the value, whether we used it or not. */
- /***********************************************************************/
- token_num++;
- break;
-
- case JSMN_PRIMITIVE:
- EVEL_INFO("Skipping primitive");
- break;
-
- case JSMN_UNDEFINED:
- default:
- rc = EVEL_BAD_JSON_FORMAT;
- EVEL_ERROR("Unexpected JSON format at token %d (%d)",
- token_num,
- tokens[token_num].type);
- goto exit_label;
- }
- }
-
-exit_label:
- EVEL_EXIT();
- return rc;
-}
-
-/**************************************************************************//**
- * Get a top-level string value from supplied JSON by matching the key.
- *
- * Unlike json_get_string, this only returns a value that is in the top-level
- * JSON object.
- *
- * @param[in] json_string The string which contains the JSON and has already
- * been parsed.
- * @param[in] tokens The tokens which the JSON parser found in the JSON.
- * @param[in] json_token_count How many tokens were found.
- * @param[in] key The key we're looking for.
- * @param[out] value The string we found at @p key.
- *
- * @returns Status code
- * @retval EVEL_SUCCESS On success - contents of @p value updated.
- * @retval EVEL_JSON_KEY_NOT_FOUND Key not found - @p value not updated.
- * @retval EVEL_BAD_JSON Parser hit unexpected data - @p value not
- * updated.
- *****************************************************************************/
-static EVEL_ERR_CODES json_get_top_level_string(const char * json_string,
- const jsmntok_t * tokens,
- int json_token_count,
- const char * key,
- char * value)
-{
- EVEL_ERR_CODES rc = EVEL_JSON_KEY_NOT_FOUND;
- int token_num = 0;
- int token_len = 0;
- int bracket_count = 0;
- int string_index = 0;
- int increment = 0;
-
- EVEL_ENTER();
-
- /***************************************************************************/
- /* Check assumptions. */
- /***************************************************************************/
- assert(json_string != NULL);
- assert(tokens != NULL);
- assert(json_token_count >= 0);
- assert(key != NULL);
- assert(value != NULL);
-
- for (token_num = 0; token_num < json_token_count; token_num++)
- {
- switch(tokens[token_num].type)
- {
- case JSMN_OBJECT:
- EVEL_DEBUG("Skipping object");
- break;
-
- case JSMN_ARRAY:
- EVEL_DEBUG("Skipping array");
- break;
-
- case JSMN_STRING:
- /***********************************************************************/
- /* This is a string, so may be what we want. Compare keys. */
- /***********************************************************************/
- if (jsoneq(json_string, &tokens[token_num], key) == 0)
- {
- /*********************************************************************/
- /* Count the difference in the number of opening and closing */
- /* brackets up to this token. This needs to be 1 for a top-level */
- /* string. Let's just hope we don't have any strings containing */
- /* brackets. */
- /*********************************************************************/
- increment = ((string_index < tokens[token_num].start) ? 1 : -1);
-
- while (string_index != tokens[token_num].start)
- {
- if (json_string[string_index] == '{')
- {
- bracket_count += increment;
- }
- else if (json_string[string_index] == '}')
- {
- bracket_count -= increment;
- }
-
- string_index += increment;
- }
-
- if (bracket_count == 1)
- {
- token_len = tokens[token_num + 1].end - tokens[token_num + 1].start;
- EVEL_DEBUG("Token %d len %d matches at top level at %d to %d",
- token_num,
- tokens[token_num + 1].start,
- tokens[token_num + 1].end);
- strncpy(value, json_string + tokens[token_num + 1].start, token_len);
- value[token_len] = '\0';
- EVEL_DEBUG("Extracted key: \"%s\" Value: \"%s\"", key, value);
- rc = EVEL_SUCCESS;
- goto exit_label;
- }
- else
- {
- EVEL_DEBUG("String key did match, but not at top level");
- }
- }
- else
- {
- EVEL_DEBUG("String key did not match");
- }
-
- /***********************************************************************/
- /* Step over the value, whether we used it or not. */
- /***********************************************************************/
- token_num++;
- break;
-
- case JSMN_PRIMITIVE:
- EVEL_INFO("Skipping primitive");
- break;
-
- case JSMN_UNDEFINED:
- default:
- rc = EVEL_BAD_JSON_FORMAT;
- EVEL_ERROR("Unexpected JSON format at token %d (%d)",
- token_num,
- tokens[token_num].type);
- goto exit_label;
- }
- }
-
-exit_label:
- EVEL_EXIT();
- return rc;
-}
-
-/**************************************************************************//**
- * Compare a JSON string token with a value.
- *
- * @param[in] json The string which contains the JSON and has already been
- * parsed.
- * @param[in] tok The token which the JSON parser found in the JSON.
- * @param[in] s The string we're looking for.
- *
- * @returns Whether the token matches the string or not.
- * @retval 0 Value matches
- * @retval -1 Value does not match.
- *****************************************************************************/
-static int jsoneq(const char *json, const jsmntok_t *tok, const char *s) {
- if (tok->type == JSMN_STRING && (int) strlen(s) == tok->end - tok->start &&
- strncmp(json + tok->start, s, tok->end - tok->start) == 0) {
- return 0;
- }
- return -1;
-}
-
-/**************************************************************************//**
- * Get the VM name provided by the metadata service.
- *
- * @returns VM name
- *****************************************************************************/
-const char *openstack_vm_name()
-{
- return vm_name;
-}
-
-/**************************************************************************//**
- * Get the VM UUID provided by the metadata service.
- *
- * @returns VM UUID
- *****************************************************************************/
-const char *openstack_vm_uuid()
-{
- return vm_uuid;
-}