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

[S3] Parse AWS configuration with support for profile section #2969

Merged
merged 4 commits into from
Aug 20, 2024
Merged
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: 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
3 changes: 3 additions & 0 deletions unit_test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ 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()

Expand Down
2 changes: 2 additions & 0 deletions unit_test/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ if NETCDF_ENABLE_S3_TESTALL
check_PROGRAMS += test_s3sdk
TESTS += run_s3sdk.sh
endif
check_PROGRAMS += aws_config
TESTS += run_aws_config.sh
endif

EXTRA_DIST = CMakeLists.txt run_s3sdk.sh run_reclaim_tests.sh
Expand Down
90 changes: 90 additions & 0 deletions unit_test/aws_config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*********************************************************************
* 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
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));

fprintf(stderr, "Active profile:%s\n", STR(activeprofile));

// ARGV contains should contain "key[=value]" to verify
// if key was parsed when loading the aws config and if it's
// value is updated in case it's redefined on the .aws/credentials
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);
}
69 changes: 69 additions & 0 deletions unit_test/run_aws_config.sh
mannreis marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#!/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

mkdir -p $THISDIR/.aws/

test_cleanup() {
rm -rfv $THISDIR/.aws/
}
trap test_cleanup EXIT

cat << 'EOF' > $THISDIR/.aws/config
[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://s3.example.domain/
dummy_key = dummy_value

[profile play]
region = us-east-1
endpoint_url = https://endpoint.example.com/
EOF

cat << 'EOF' > $THISDIR/.aws/credentials
[play]
aws_access_key_id = DummyKeys
aws_secret_access_key = DummySecret

[uni]
region = somewhere-2
endpoint_url = https://example.com/bucket/prefix/2
key = value-overwritten
EOF

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

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

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

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

# Will use profile=no
NC_TEST_AWS_DIR=${THISDIR} ${CMD} ${execdir}/aws_config 2>&1 | grep -q 'Active profile:no'
echo "Status: $?"
echo -e "Finished"

exit

Loading