Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merging #1

Open
wants to merge 1 commit into
base: ecs-provider-compare
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions include/fluent-bit/flb_aws_credentials.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@
#define AWS_SECRET_ACCESS_KEY "AWS_SECRET_ACCESS_KEY"
#define AWS_SESSION_TOKEN "AWS_SESSION_TOKEN"

/* HTTP Credentials Endpoints have a standard set of JSON Keys */
#define AWS_HTTP_RESPONSE_ACCESS_KEY "AccessKeyId"
#define AWS_HTTP_RESPONSE_SECRET_KEY "SecretAccessKey"
#define AWS_HTTP_RESPONSE_TOKEN "Token"
#define AWS_HTTP_RESPONSE_EXPIRATION "Expiration"

#define ECS_CREDENTIALS_HOST "169.254.170.2"
#define ECS_CREDENTIALS_HOST_LEN 13
#define ECS_CREDENTIALS_PATH_ENV_VAR "AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"

/*
* A structure that wraps the sensitive data needed to sign an AWS request
*/
Expand Down Expand Up @@ -143,6 +153,33 @@ struct aws_credentials_provider *new_sts_provider(struct flb_config *config,
*/
struct aws_credentials_provider *new_environment_provider();


/*
* New http provider - retrieve credentials from a local http server.
* Equivalent to:
* https://github.com/aws/aws-sdk-go/tree/master/aws/credentials/endpointcreds
*
* Calling aws_provider_destroy on this provider frees the memory
* used by host and path.
*/
struct aws_credentials_provider *new_http_provider(struct flb_config *config,
flb_sds_t host,
flb_sds_t path,
struct
aws_http_client_generator
*generator);

/*
* ECS Provider
* The ECS Provider is just a wrapper around the HTTP Provider
* with the ECS credentials endpoint.
*/

struct aws_credentials_provider *new_ecs_provider(struct flb_config *config,
struct
aws_http_client_generator
*generator);

/*
* Helper functions
*/
Expand Down
229 changes: 229 additions & 0 deletions plugins/out_stdout/stdout.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,233 @@

#include "stdout.h"

#include <fluent-bit/flb_sds.h>
#include <fluent-bit/flb_aws_credentials.h>
#include <fluent-bit/flb_mem.h>
#include <fluent-bit/flb_info.h>
#include <fluent-bit/flb_http_client.h>

#include <monkey/mk_core.h>
#include <string.h>
#include <unistd.h>

#define ACCESS_KEY_HTTP "http_akid"
#define SECRET_KEY_HTTP "http_skid"
#define TOKEN_HTTP "http_token"

#define HTTP_CREDENTIALS_RESPONSE "{\n\
\"AccessKeyId\": \"http_akid\",\n\
\"Expiration\": \"2014-10-24T23:00:23Z\",\n\
\"RoleArn\": \"TASK_ROLE_ARN\",\n\
\"SecretAccessKey\": \"http_skid\",\n\
\"Token\": \"http_token\"\n\
}"

/*
* Unexpected/invalid HTTP response. The goal of this is not to test anything
* that might happen in production, but rather to test the error handling
* code for the providers. This helps ensure all code paths are tested and
* the error handling code does not introduce memory leaks.
*/
#define HTTP_RESPONSE_MALFORMED "{\n\
\"AccessKeyId\": \"http_akid\",\n\
\"partially-correct\": \"json\",\n\
\"RoleArn\": \"TASK_ROLE_ARN\",\n\
\"but incomplete\": \"and not terminated with a closing brace\",\n\
\"Token\": \"http_token\""


/*
* Global Variable that allows us to check the number of calls
* made in each test
*/
int g_request_count;

int request_happy_case(struct aws_http_client *aws_client,
int method, const char *uri)
{
flb_debug("[test-check] %d", method == FLB_HTTP_GET);

flb_debug("[test-check] %d", strstr(uri, "happy-case") != NULL);

/* free client from previous request */
if (aws_client->c) {
flb_http_client_destroy(aws_client->c);
}
/* create an http client so that we can set the response */
aws_client->c = flb_calloc(1, sizeof(struct flb_http_client));
if (!aws_client->c) {
flb_errno();
return -1;
}
mk_list_init(&aws_client->c->headers);

aws_client->c->resp.status = 200;
aws_client->c->resp.payload = HTTP_CREDENTIALS_RESPONSE;
aws_client->c->resp.payload_size = strlen(HTTP_CREDENTIALS_RESPONSE);
aws_client->error_type = NULL;

return 0;
}

/* unexpected output test- see description for HTTP_RESPONSE_MALFORMED */
int request_malformed(struct aws_http_client *aws_client,
int method, const char *uri)
{
flb_debug("[test-check] %d", method == FLB_HTTP_GET);

flb_debug("[test-check] %d", strstr(uri, "malformed") != NULL);

/* free client from previous request */
if (aws_client->c) {
flb_http_client_destroy(aws_client->c);
}
/* create an http client so that we can set the response */
aws_client->c = flb_calloc(1, sizeof(struct flb_http_client));
if (!aws_client->c) {
flb_errno();
return -1;
}
mk_list_init(&aws_client->c->headers);

aws_client->c->resp.status = 200;
aws_client->c->resp.payload = HTTP_RESPONSE_MALFORMED;
aws_client->c->resp.payload_size = strlen(HTTP_RESPONSE_MALFORMED);
aws_client->error_type = NULL;

return 0;
}

int request_error_case(struct aws_http_client *aws_client,
int method, const char *uri)
{
flb_debug("[test-check] %d", method == FLB_HTTP_GET);

flb_debug("[test-check] %d", strstr(uri, "error-case") != NULL);

/* free client from previous request */
if (aws_client->c) {
flb_http_client_destroy(aws_client->c);
}
/* create an http client so that we can set the response */
aws_client->c = flb_calloc(1, sizeof(struct flb_http_client));
if (!aws_client->c) {
flb_errno();
return -1;
}
mk_list_init(&aws_client->c->headers);

aws_client->c->resp.status = 400;
aws_client->c->resp.payload = NULL;
aws_client->c->resp.payload_size = 0;
aws_client->error_type = NULL;

return 0;
}

/* test/mock version of the aws_http_client request function */
int test_http_client_request(struct aws_http_client *aws_client,
int method, const char *uri,
const char *body, size_t body_len,
struct aws_http_header *dynamic_headers,
size_t dynamic_headers_len)
{
g_request_count++;
/*
* route to the correct test case fn using the uri
*/
if (strstr(uri, "happy-case") != NULL) {
return request_happy_case(aws_client, method, uri);
} else if (strstr(uri, "error-case") != NULL) {
return request_error_case(aws_client, method, uri);
} else if (strstr(uri, "malformed") != NULL) {
return request_malformed(aws_client, method, uri);
}

/* uri should match one of the above conditions */
flb_errno();
return -1;

}

/* Test/mock aws_http_client */
static struct aws_http_client_vtable test_vtable = {
.request = test_http_client_request,
};

struct aws_http_client *test_http_client_create()
{
struct aws_http_client *client = flb_calloc(1,
sizeof(struct aws_http_client));
if (!client) {
flb_errno();
return NULL;
}
client->client_vtable = &test_vtable;
return client;
}

/* Generator that returns clients with the test vtable */
static struct aws_http_client_generator test_generator = {
.new = test_http_client_create,
};

struct aws_http_client_generator *generator_in_test()
{
return &test_generator;
}

static void test_http_provider_malformed_response()
{
struct aws_credentials_provider *provider;
struct aws_credentials *creds;
int ret;
struct flb_config *config;
flb_sds_t host;
flb_sds_t path;

g_request_count = 0;

config = flb_malloc(sizeof(struct flb_config));
if (!config) {
flb_errno();
return;
}

host = flb_sds_create("127.0.0.1");
path = flb_sds_create("/malformed");

provider = new_http_provider(config, host, path,
generator_in_test());

if (!provider) {
flb_errno();
return;
}

/* get_credentials will fail */
creds = provider->provider_vtable->get_credentials(provider);
flb_debug("[test-check] %d", creds == NULL);

creds = provider->provider_vtable->get_credentials(provider);
flb_debug("[test-check] %d", creds == NULL);

/* refresh should return -1 (failure) */
ret = provider->provider_vtable->refresh(provider);
flb_debug("[test-check] %d", ret < 0);

/*
* Request count should be 3:
* - Each call to get_credentials and refresh invokes the client's
* request method and returns a request failure.
*/
flb_debug("[test-check] %d", g_request_count == 3);

flb_sds_destroy(path);
flb_sds_destroy(host);
aws_provider_destroy(provider);
}

static int cb_stdout_init(struct flb_output_instance *ins,
struct flb_config *config, void *data)
{
Expand Down Expand Up @@ -100,6 +327,8 @@ static void cb_stdout_flush(const void *data, size_t bytes,
struct flb_time tmp;
msgpack_object *p;

test_http_provider_malformed_response();

if (ctx->out_format != FLB_PACK_JSON_FORMAT_NONE) {
json = flb_pack_msgpack_to_json_format(data, bytes,
ctx->out_format,
Expand Down
Loading