metal/mtce-common/cgts-mtce-common-1.0/common/httpUtil.h
Eric MacDonald 08e66abb1b Mtce: Implement all token fetches as non-blocking operations.
Fetching a keystone token is seen to take a long time When the system
is overloaded. Such delay, due to overload, is most often seen over a
Swact in All-In-One Duplex (AIO-DX) configuration.

Any blocking call that takes a long time to complete can cause a process
stall. If that stall is sufficiently long then the command will either
finish on or before the timeout. The timeout is currently set to 15
seconds which is comparable to the SM monitored audit timeout.

Although rare, then race condition does exist and if there are 2
timeouts within 2 minutes then SM fails the process and triggers a
swact.

Rather than tune the timeouts, this update implements a more robust
fix by making all token fetches ; both 'initial token get' and
'runtime token refresh' as non-blocking.

The change applies to both mtcAgent and hwmond ; both of which need
to get and manage their own authentication token.

Change-Id: I2730b76ae78daec4b9edeaff5c1ca614b75ab52c
Signed-off-by: Eric MacDonald <eric.macdonald@windriver.com>
2018-06-27 15:00:23 -04:00

347 lines
11 KiB
C++

#ifndef __INCLUDE_HTTPUTIL_H__
#define __INCLUDE_HTTPUTIL_H__
/*
* Copyright (c) 2013, 2016 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*/
#include <iostream> /* for ... string */
#include <evhttp.h> /* for ... http libevent client */
#include <time.h>
#include <list>
using namespace std;
#include "nodeBase.h"
#include "timeUtil.h" /* for ... time_delta_type */
/* HTTP Error Codes with no specific existing define MACRO */
#define MTC_HTTP_BAD_REQUEST 400
#define MTC_HTTP_UNAUTHORIZED 401
#define MTC_HTTP_FORBIDDEN 403
#define MTC_HTTP_CONFLICT 409
#define MTC_HTTP_LENGTH_REQUIRED 411
#define MTC_HTTP_NORESPONSE 444
#define MTC_HTTP_UNPROCESSABLE_ENTITY 422
#define MTC_HTTP_ACCEPTED 202
#define EVENT_METHODS (EVHTTP_REQ_PATCH | \
EVHTTP_REQ_POST | \
EVHTTP_REQ_GET | \
EVHTTP_REQ_PUT | \
EVHTTP_REQ_DELETE)
/** Maximum libevent response message size in bytes. */
// #define MAX_EVENT_LEN (163840)
#define MAX_URL_LEN (200)
#define HTTP_VIM_TIMEOUT (20)
#define HTTP_MAX_RETRIES (3)
#define HTTP_SYSINV_CRIT_TIMEOUT (20)
#define HTTP_SYSINV_NONC_TIMEOUT (10)
#define HTTP_TOKEN_TIMEOUT (30)
#define HTTP_KEYSTONE_GET_TIMEOUT (10)
#define HTTP_SMGR_TIMEOUT (20)
#define HTTP_VIM_TIMEOUT (20)
#define SMGR_MAX_RETRIES (3)
#define CLIENT_HEADER "User-Agent"
#define CLIENT_SYSINV_1_0 "sysinv/1.0"
#define EVENT_SERVER "HTTP Event Server"
#define SMGR_EVENT_SIG "smgrEvent"
#define SYSINV_EVENT_SIG "sysinvEvent"
#define KEYSTONE_SIG "token"
#define SENSOR_SIG "sensor"
#define SYSINV_SIG "sysinv"
#define SMGR_SIG "smgr"
#define VIM_SIG "vim"
#define SYSINV_OPER__LOAD_HOST "load host"
#define SYSINV_OPER__UPDATE_TASK "update task"
#define SYSINV_OPER__FORCE_TASK "force task"
#define SYSINV_OPER__UPDATE_UPTIME "update uptime"
#define SYSINV_OPER__UPDATE_VALUE "update value"
#define SYSINV_OPER__UPDATE_STATE "update state"
#define SYSINV_OPER__UPDATE_STATES "update states"
#define SYSINV_OPER__FORCE_STATES "force states"
#define SYSINV_OPER__CONFIG_SHOW "config show"
#define SYSINV_OPER__CONFIG_MODIFY "config modify"
#define VIM_HOST__DISABLED "disabled"
#define VIM_HOST__ENABLED "enabled"
#define VIM_HOST__OFFLINE "offline"
#define VIM_HOST__FAILED "failed"
/** The workQueue_process FSM states */
typedef enum {
HTTP__TRANSMIT = 0,
HTTP__RECEIVE_WAIT = 1,
HTTP__RECEIVE = 2,
HTTP__FAILURE = 3,
HTTP__DONE_FAIL = 4,
HTTP__DONE_PASS = 5,
HTTP__STAGES = 6
} httpStages_enum ;
#define HTTP_RECEIVE_WAIT_MSEC (10)
typedef struct
{
string url ; /**< Keystone server URL string */
string issued ; /**< Timestamp token was issued */
string expiry ; /**< Timestamp when token is expired */
string token ; /**< The huge 3kb token */
bool refreshed; /**< set true when refreshed */
bool delay ; /**< trigger renew with small delay
error renewal - flood avoidance */
} keyToken_type ;
/** All supported Request Type Enums */
typedef enum {
SERVICE_NONE,
SYSINV_ADD,
SYSINV_GET,
SYSINV_HOST_QUERY,
SYSINV_UPDATE,
SYSINV_CONFIG_SHOW,
SYSINV_CONFIG_MODIFY,
SYSINV_SENSOR_LOAD,
SYSINV_SENSOR_LOAD_GROUPS,
SYSINV_SENSOR_LOAD_GROUP,
SYSINV_SENSOR_ADD,
SYSINV_SENSOR_ADD_GROUP,
SYSINV_SENSOR_DEL,
SYSINV_SENSOR_DEL_GROUP,
SYSINV_SENSOR_MOD,
SYSINV_SENSOR_MOD_GROUP,
SYSINV_SENSOR_GROUP_SENSORS,
VIM_UPDATE,
VIM_HOST_DISABLED,
VIM_HOST_ENABLED,
VIM_HOST_OFFLINE,
VIM_HOST_FAILED,
VIM_DPORT_FAILED,
VIM_DPORT_CLEARED,
VIM_DPORT_DEGRADED,
VIM_DPORT_OFFLINE,
VIM_HOST_QUERY,
VIM_HOST_STATE_QUERY,
VIM_HOST_INSTANCE_QUERY,
VIM_HOST_INSTANCE_FAILED,
VIM_HOST_INSTANCE_STATUS,
VIM_HOST_INSTANCE_NOTIFY,
SMGR_START_SWACT,
SMGR_QUERY_SWACT,
SMGR_HOST_UNLOCKED,
SMGR_HOST_LOCKED,
SMGR_HOST_ENABLED,
SMGR_HOST_DISABLED,
KEYSTONE_TOKEN,
KEYSTONE_GET_TOKEN,
KEYSTONE_GET_SERVICE_LIST,
KEYSTONE_GET_ENDPOINT_LIST,
TEST_WITH_NO_TOKEN,
TEST_WITH_TOKEN,
SERVICE_LAST
} libEvent_enum ;
/** Local event control structure for REST API services
*
* Nova, Neutron, Keystone and Inventory
*
*/
struct libEvent
{
/** Execution Controls */
httpStages_enum state ; /**< This http request FSM state */
int sequence ; /**< Event sequence number */
bool mutex ; /**< single operation at a time */
bool active ; /**< true if waiting on response */
int stuck ; /**< Count mutex active stuck state */
bool blocking ; /**< true if command is blocking */
bool found ; /**< true if query was found */
int timeout ; /**< Request timeout */
int count ; /**< retry recover counter */
int fails ; /**< fail counter */
int retries ; /**< number of retries on failure*/
int cur_retries ;
int max_retries ;
bool noncritical ; /**< true: event is non-ctitical */
int rx_retry_cnt ; /**< help avoid infinite rx retry*/
int rx_retry_max ; /**< each cmd can have a max */
/* HTTP request Info */
enum evhttp_cmd_type type; /**< HTTP Request Type ; PUT/GET */
struct event_base *base; /**< libEvent API service base */
struct evhttp_connection *conn; /**< HTTP connection ptr */
struct evhttp_request *req ; /**< HTTP request ptr */
struct evbuffer *buf ; /**< HTTP output buffer ptr */
struct evbuffer_ptr evp ; /**< HTTP output buffer ptr */
string log_prefix ; /**< log prefix for this event */
/** Service Specific Request Info */
libEvent_enum request ; /**< Specify the request command */
keyToken_type token ; /**< Copy of the active token */
string service ; /**< Service being executed */
string hostname ; /**< Target hostname */
string uuid ; /**< The UUID for this request */
string new_uuid ; /**< The UUID created & returned */
string ip ; /**< Server IP address */
int port ; /**< Server port number */
string operation ; /**< Specify the operation */
string information ;
string key ;
string value ;
string prefix_path ;
string label ; /**< typically a response label */
string entity_path ; /**< HTTP entity request string */
string entity_path_next ; /**< next entity request string */
string address ; /**< http url address */
string payload ; /**< the request's payload */
string user_agent ; /**< set the User-Agent header */
/** Result Info */
int status ; /**< Execution Status */
int http_status ; /**< raw http returned status */
int exec_time_msec ; /**< execution time in msec */
node_inv_type inv_info ;
size_t response_len ; /**< the json response length */
string response ; /**< the json response string */
string result ; /**< Command specific result str */
/* Endpoint strings */
string admin_url ;
string internal_url ;
string public_url ;
time_debug_type send_time ; /**< Request Dispatch Timestamp */
time_debug_type done_time ; /**< Response Handler Timestamp */
time_delta_type diff_time ; /**< how long the command handling took */
bool low_wm ;
bool med_wm ;
bool high_wm ;
int (*handler) (struct libEvent &) ;
char req_str[MAX_API_LOG_LEN] ;
unsigned long long prev_time ; /* latency log candidate start (prev) time */
unsigned long long this_time ; /* ... end (now or this) time */
} ;
typedef struct
{
struct event_base * base_ptr ;
struct libEvent * event_ptr ;
} event_base_pair_type ;
typedef struct
{
int elements ;
list<event_base_pair_type> pair_list ;
} event_base_list_type ;
/** Maximum number of headers that can be added to an HTTP message. */
#define MAX_HEADERS (10)
/** A header entry type. */
typedef struct
{
string key ; /**< the header label. */
string value ; /**< the header value. */
} http_header_entry_type;
/** The header entry table. */
typedef struct
{
int entries ; /**< Number of entries in the header table. */
http_header_entry_type entry[MAX_HEADERS]; /**< entry array. */
} http_headers_type ;
void httpUtil_init ( void );
int httpUtil_event_init ( libEvent * ptr ,
string hostname,
string service,
string ip,
int port );
/** Add payload to the HTTP message body. */
int httpUtil_payload_add ( libEvent & event );
/** Add all headers in header table to the HTTP connection message. */
int httpUtil_header_add ( libEvent * ptr, http_headers_type * hdrs_ptr );
/** Create an HTTP request. */
int httpUtil_request_make ( libEvent * ptr, enum evhttp_cmd_type type, string path );
/** Open a connection to an HTTP server. */
int httpUtil_connect ( libEvent & event );
/** Get a new HTTP request pointer. */
int httpUtil_request ( libEvent & event,
void(*hdlr)(struct evhttp_request *, void *));
/** Common REST API Request Utility */
int httpUtil_api_request ( libEvent & event );
/** Common REST API Request Utility */
int httpUtil_request ( libEvent & event , bool block,
void(*hdlr)(struct evhttp_request *, void *));
/** Common REST API Receive Utility for non-blocking requests */
int httpUtil_receive ( libEvent & event );
/** HTTP response status checker */
int httpUtil_status ( libEvent & event );
/** Free the libEvent */
void httpUtil_free_base ( libEvent & event );
/** Free the event lib connection */
void httpUtil_free_conn ( libEvent & event );
/** TODO: FIXME: Get the payload string length. */
string httpUtil_payload_len ( libEvent * ptr );
/** Get the length of the json response */
int httpUtil_get_length ( libEvent & event );
/** Load the json response into the event struct */
int httpUtil_get_response ( libEvent & event );
/** print event filtered event */
void httpUtil_log_event ( libEvent * event );
void httpUtil_event_info ( libEvent & event );
const char * getHttpCmdType_str ( evhttp_cmd_type type );
#endif /* __INCLUDE_HTTPUTIL_H__ */