41 #include <curl/curl.h> 52 static const char * OPENSTACK_METADATA_URL =
53 "http://169.254.169.254/openstack/latest/meta_data.json";
59 static const int OPENSTACK_METADATA_TIMEOUT = 2;
64 #define MAX_METADATA_STRING 64 79 static const int MAX_METADATA_TOKENS = 128;
84 static EVEL_ERR_CODES json_get_top_level_string(
const char * json_string,
94 static int jsoneq(
const char *json,
const jsmntok_t *tok,
const char *s);
108 CURLcode curl_rc = CURLE_OK;
109 CURL * curl_handle = NULL;
111 char curl_err_string[CURL_ERROR_SIZE] =
"<NULL>";
114 int json_token_count = 0;
127 curl_handle = curl_easy_init();
128 if (curl_handle == NULL)
138 curl_rc = curl_easy_setopt(curl_handle,
141 if (curl_rc != CURLE_OK)
144 EVEL_ERROR(
"Failed to initialize libcurl to provide friendly errors. " 145 "Error code=%d", curl_rc);
152 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_URL, OPENSTACK_METADATA_URL);
153 if (curl_rc != CURLE_OK)
156 EVEL_ERROR(
"Failed to initialize libcurl with the API URL. " 157 "Error code=%d (%s)", curl_rc, curl_err_string);
164 curl_rc = curl_easy_setopt(curl_handle,
165 CURLOPT_WRITEFUNCTION,
167 if (curl_rc != CURLE_OK)
170 EVEL_ERROR(
"Failed to initialize libcurl with the write callback. " 171 "Error code=%d (%s)", curl_rc, curl_err_string);
179 curl_rc = curl_easy_setopt(curl_handle,
181 "libcurl-agent/1.0");
182 if (curl_rc != CURLE_OK)
185 EVEL_ERROR(
"Failed to initialize libcurl to upload. Error code=%d (%s)",
186 curl_rc, curl_err_string);
193 curl_rc = curl_easy_setopt(curl_handle,
195 OPENSTACK_METADATA_TIMEOUT);
196 if (curl_rc != CURLE_OK)
199 EVEL_ERROR(
"Failed to initialize libcurl to set timeout. " 200 "Error code=%d (%s)", curl_rc, curl_err_string);
208 rx_chunk.
memory = malloc(1);
209 assert(rx_chunk.
memory != NULL);
215 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (
void *)&rx_chunk);
216 if (curl_rc != CURLE_OK)
219 EVEL_ERROR(
"Failed to initialize libcurl to receive metadata. " 220 "Error code=%d (%s)", curl_rc, curl_err_string);
230 curl_rc = curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
231 if (curl_rc != CURLE_OK)
235 "Error code=%d", curl_rc);
243 curl_rc = curl_easy_perform(curl_handle);
244 if (curl_rc != CURLE_OK)
247 EVEL_ERROR(
"Failed to transfer the data from metadata service. " 248 "Error code=%d (%s)", curl_rc, curl_err_string);
260 tokens, MAX_METADATA_TOKENS);
265 if (json_token_count < 0 || tokens[0].type !=
JSMN_OBJECT)
268 EVEL_ERROR(
"Failed to parse received JSON OpenStack metadata. " 269 "Error code=%d", json_token_count);
274 EVEL_DEBUG(
"Extracted %d tokens from the JSON OpenStack metadata. ",
281 if (json_get_string(rx_chunk.
memory,
288 EVEL_ERROR(
"Failed to extract UUID from OpenStack metadata");
294 if (json_get_top_level_string(rx_chunk.
memory,
301 EVEL_ERROR(
"Failed to extract VM Name from OpenStack metadata");
314 if (curl_handle != NULL)
316 curl_easy_cleanup(curl_handle);
331 "Dummy VM UUID - No Metadata available",
334 "Dummy VM name - No Metadata available",
361 int json_token_count,
374 assert(json_string != NULL);
375 assert(tokens != NULL);
376 assert(json_token_count >= 0);
378 assert(value != NULL);
380 for (token_num = 0; token_num < json_token_count; token_num++)
382 switch(tokens[token_num].type)
396 if (jsoneq(json_string, &tokens[token_num], key) == 0)
398 token_len = tokens[token_num + 1].
end - tokens[token_num + 1].
start;
399 EVEL_DEBUG(
"Token %d len %d matches at %d to %d", token_num,
400 tokens[token_num + 1].start,
401 tokens[token_num + 1].end);
402 strncpy(value, json_string + tokens[token_num + 1].start, token_len);
403 value[token_len] =
'\0';
404 EVEL_DEBUG(
"Extracted key: \"%s\" Value: \"%s\"", key, value);
426 EVEL_ERROR(
"Unexpected JSON format at token %d (%d)",
428 tokens[token_num].type);
457 static EVEL_ERR_CODES json_get_top_level_string(
const char * json_string,
459 int json_token_count,
466 int bracket_count = 0;
467 int string_index = 0;
475 assert(json_string != NULL);
476 assert(tokens != NULL);
477 assert(json_token_count >= 0);
479 assert(value != NULL);
481 for (token_num = 0; token_num < json_token_count; token_num++)
483 switch(tokens[token_num].type)
497 if (jsoneq(json_string, &tokens[token_num], key) == 0)
505 increment = ((string_index < tokens[token_num].
start) ? 1 : -1);
507 while (string_index != tokens[token_num].start)
509 if (json_string[string_index] ==
'{')
511 bracket_count += increment;
513 else if (json_string[string_index] ==
'}')
515 bracket_count -= increment;
518 string_index += increment;
521 if (bracket_count == 1)
523 token_len = tokens[token_num + 1].
end - tokens[token_num + 1].
start;
524 EVEL_DEBUG(
"Token %d len %d matches at top level at %d to %d",
526 tokens[token_num + 1].start,
527 tokens[token_num + 1].end);
528 strncpy(value, json_string + tokens[token_num + 1].start, token_len);
529 value[token_len] =
'\0';
530 EVEL_DEBUG(
"Extracted key: \"%s\" Value: \"%s\"", key, value);
536 EVEL_DEBUG(
"String key did match, but not at top level");
557 EVEL_ERROR(
"Unexpected JSON format at token %d (%d)",
559 tokens[token_num].type);
581 static int jsoneq(
const char *json,
const jsmntok_t *tok,
const char *s) {
#define EVEL_DEBUG(FMT,...)
OpenStack metadata invalid format.
#define EVEL_INFO(FMT,...)
A chunk of memory used in the cURL functions.
size_t evel_write_callback(void *contents, size_t size, size_t nmemb, void *userp)
Callback function to provide returned data.
#define EVEL_ERROR(FMT,...)
EVEL_ERR_CODES
Error codes.
int jsmn_parse(jsmn_parser *parser, const char *js, size_t len, jsmntok_t *tokens, unsigned int num_tokens)
Parse JSON string and fill tokens.
void log_error_state(char *format,...)
void jsmn_init(jsmn_parser *parser)
Creates a new parser based over a given buffer with an array of tokens available. ...
Failed to retrieve OpenStack metadata.
EVEL internal definitions.
Attempt to raise event when inactive.
JSON failed to parse correctly.