Skip to content

Commit

Permalink
Parse AWS configuration with support for profile section
Browse files Browse the repository at this point in the history
  • Loading branch information
mannreis committed Aug 7, 2024
1 parent 150db23 commit b05e95e
Show file tree
Hide file tree
Showing 6 changed files with 187 additions and 8 deletions.
37 changes: 30 additions & 7 deletions libdispatch/ds3util.c
Original file line number Diff line number Diff line change
Expand Up @@ -603,13 +603,18 @@ NC_getactives3profile(NCURI* uri, const char** profilep)
int stat = NC_NOERR;
const char* profile = NULL;
struct AWSprofile* ap = NULL;
struct NCglobalstate* gs = NC_getglobalstate();

profile = ncurifragmentlookup(uri,"aws.profile");
if(profile == NULL)
profile = NC_rclookupx(uri,"AWS.PROFILE");
if (uri != NULL) {
profile = ncurifragmentlookup(uri,"aws.profile");
if(profile == NULL)
profile = NC_rclookupx(uri,"AWS.PROFILE");
}

if(profile == NULL)
profile = NC_getglobalstate()->aws.profile;
if(profile == NULL && gs->aws.profile != NULL) {
if((stat=NC_authgets3profile(gs->aws.profile,&ap))) goto done;
if(ap) profile = nulldup(gs->aws.profile);
}

if(profile == NULL) {
if((stat=NC_authgets3profile("default",&ap))) goto done;
Expand Down Expand Up @@ -837,13 +842,19 @@ awsparse(const char* text, NClist* profiles)
if(token == AWS_EOF) break; /* finished */
if(token == AWS_EOL) {continue;} /* blank line */
if(token != LBR) {stat = NCTHROW(NC_EINVAL); goto done;}
/* parse [profile name] */
/* parse [profile name] or [name] */
token = awslex(parser);
if(token != AWS_WORD) {stat = NCTHROW(NC_EINVAL); goto done;}
assert(profile == NULL);
if((profile = (struct AWSprofile*)calloc(1,sizeof(struct AWSprofile)))==NULL)
{stat = NC_ENOMEM; goto done;}
profile->name = ncbytesextract(parser->yytext);
if(strncmp("profile", profile->name, sizeof("profile")) == 0 ) {
token = awslex(parser);
if(token != AWS_WORD) {stat = NCTHROW(NC_EINVAL); goto done;}
nullfree(profile->name);
profile->name = ncbytesextract(parser->yytext);
}
profile->entries = nclistnew();
token = awslex(parser);
if(token != RBR) {stat = NCTHROW(NC_EINVAL); goto done;}
Expand Down Expand Up @@ -881,10 +892,22 @@ fprintf(stderr,">>> parse: entry=(%s,%s)\n",entry->key,entry->value);
{stat = NCTHROW(NC_EINVAL); goto done;}
}

/* If this profile already exists, then replace old one */
/* If this profile already exists, then overwrite old one */
for(size_t i=0;i<nclistlength(profiles);i++) {
struct AWSprofile* p = (struct AWSprofile*)nclistget(profiles,i);
if(strcasecmp(p->name,profile->name)==0) {
// Keep unique parameters from previous (incomplete!?) profile
for (size_t j=0;j<nclistlength(p->entries);j++){
struct AWSentry* old = (struct AWSentry*)nclistget(p->entries,j);
int add = 1;
for (size_t z=0;z<nclistlength(profile->entries);z++){
struct AWSentry* new = (struct AWSentry*)nclistget(profile->entries,z);
add &= (strcasecmp(old->key,new->key)!=0);
}
if(add){
nclistpush(profile->entries, nclistremove(p->entries,j--));
}
}
nclistset(profiles,i,profile);
profile = NULL;
/* reclaim old one */
Expand Down
15 changes: 15 additions & 0 deletions unit_test/.aws/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[uni]
region = somewhere-1
endpoint_url = https://example.com/bucket/prefix/1
key = value
extrakey = willbepropagated

[profile unidata]
region = us-east-1
endpoint_url = https://play.min.io/
dummy_key = dummy_value

[profile play]
region = us-east-1
endpoint_url = https://play.min.io/

8 changes: 8 additions & 0 deletions unit_test/.aws/credentials
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[play]
aws_access_key_id = DummyKeys
aws_secret_access_key = DummySecret

[uni]
region = somewhere-2
endpoint_url = https://example.com/bucket/prefix/2
key = value2
5 changes: 4 additions & 1 deletion unit_test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,15 @@ IF(NETCDF_BUILD_UTILITIES)
# SDK Test
build_bin_test(test_s3sdk ${XGETOPTSRC})
add_sh_test(unit_test run_s3sdk)
#AWS Configuration test
build_bin_test(aws_config)
add_sh_test(unit_test run_aws_config)
ENDIF()
ENDIF()

# Performance tests
add_bin_test(unit_test tst_exhash timer_utils.c)
add_bin_test(unit_test tst_xcache timer_utils.c)

FILE(GLOB COPY_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.sh)
FILE(GLOB COPY_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.sh ${CMAKE_CURRENT_SOURCE_DIR}/\.aws)
FILE(COPY ${COPY_FILES} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ FILE_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE)
96 changes: 96 additions & 0 deletions unit_test/aws_config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*********************************************************************
* Copyright 2018, UCAR/Unidata
* See netcdf/COPYRIGHT file for copying and redistribution conditions.
*********************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "netcdf.h"
#include "ncrc.h"
#include "ncpathmgr.h"
#include "ncs3sdk.h"
#include "ncuri.h"
#include "nc4internal.h"

NCS3INFO s3info;
void* s3client = NULL;

/* Forward */
static void cleanup(void);

#define STR(p) p?p:"NULL"
#define CHECK(code) do {stat = check(code,__func__,__LINE__); if(stat) {goto done;}} while(0)

static int
check(int code, const char* fcn, int line)
{
if(code == NC_NOERR) return code;
fprintf(stderr,"***FAIL: (%d) %s @ %s:%d\n",code,nc_strerror(code),fcn,line);
abort();
}

static void
cleanup(void)
{
if(s3client)
NC_s3sdkclose(s3client, &s3info, 0/*deleteit*/, NULL);
s3client = NULL;
NC_s3clear(&s3info);
}

int
main(int argc, char** argv)
{
int c = 0,stat = NC_NOERR;

/* Load RC and .aws/config */
CHECK(nc_initialize());
CHECK(NC_s3sdkinitialize());
NCglobalstate* gs = NC_getglobalstate();
//Not checking, aborts if ~/.aws/config doesn't exist
//int notloaded = NC_aws_load_credentials(gs);
//fprintf(stderr,"RETCODE: %d\n", notloaded);
CHECK(NC_aws_load_credentials(gs));

// Lets ensure the active profile is loaded
// from the configurtion files instead of an URL
const char* activeprofile = NULL;
CHECK(NC_getactives3profile(NULL, &activeprofile));

//if (notloaded) { // If not loaded, we'll use profile "no"
// CHECK(strncmp(activeprofile, "no", sizeof("no")));
// // And we passed this test...
//} else {
fprintf(stderr, "Active profile:%s\n", STR(activeprofile));
// ARGV contains should contain "key[=[value]]" pairs to verify
// if parsed when loading the aws config on the respective profile

for(int i = 1; i < argc; i++) {
const char *argkey = strtok(argv[i],"=");
const char *argvalue = strtok(NULL,"=");
const char* value = NULL;

NC_s3profilelookup(activeprofile,argkey,&value);
fprintf(stderr, "%s\t%s -> %s\n",value?"":"*** FAIL:", argv[i],value?value:"NOT DEFINED!");
if ( value == NULL
|| (argvalue != NULL
&& strncmp(value, argvalue, strlen(value)))
){
c++;
stat |= NC_ERCFILE;
}
}
//}

done:
cleanup();
if(stat)
printf("*** FAIL: a total of %d keys were not found on the profile %s\n", c, STR(activeprofile));
else
printf("***PASS\n");
(void)NC_s3sdkfinalize();
(void)nc_finalize();
exit(stat?:0);
}
34 changes: 34 additions & 0 deletions unit_test/run_aws_config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#!/bin/sh

if test "x$srcdir" = x ; then srcdir=`pwd`; fi
. ../test_common.sh

set -e

#CMD="valgrind --leak-check=full"

isolate "testdir_ut_aws_config"

THISDIR=`pwd`
cd $ISOPATH

echo -e "Testing loading AWS configuration in ${THISDIR}/.aws/config"
env NC_TEST_AWS_DIR=${THISDIR} AWS_PROFILE=unidata ${CMD} ${execdir}/aws_config endpoint_url region dummy_key
echo "Status: $?"

env NC_TEST_AWS_DIR=${THISDIR} AWS_PROFILE=play ${CMD} ${execdir}/aws_config endpoint_url region
echo "Status: $?"

env NC_TEST_AWS_DIR=${THISDIR} AWS_PROFILE=uni ${CMD} ${execdir}/aws_config endpoint_url region key
echo "Status: $?"

env NC_TEST_AWS_DIR=${THISDIR} AWS_PROFILE=uni ${CMD} ${execdir}/aws_config region=somewhere-2 endpoint_url=https://example.com/bucket/prefix/2 key=value2 extrakey=willbepropagated
echo "Status: $?"

echo ${CMD} ${execdir}/aws_config
${CMD} ${execdir}/aws_config
echo "Status: $? [this is expected]"
echo -e "Finished"

exit

0 comments on commit b05e95e

Please sign in to comment.