## Addendum [5/9/23]

It turns out that attempting to test S3 using a github action secret is a very complex process. So, this was disabled for github actions. However, a new *run_tests_s3.yml* action file was added that will eventually encapsulate S3 testing.
This commit is contained in:
Dennis Heimbigner 2023-05-09 21:13:49 -06:00
parent d79f08176a
commit 98477b9f25
30 changed files with 1030 additions and 1017 deletions

View File

@ -7,7 +7,7 @@
name: Run macOS-based netCDF Tests
on: [pull_request,workflow_dispatch]
on: [push,pull_request,workflow_dispatch]
jobs:

153
.github/workflows/run_tests_s3.yml vendored Normal file
View File

@ -0,0 +1,153 @@
###
# Test S3 Support
# -- derived from run_tests_ubuntu.yml
###
###
# Build hdf5 dependencies and cache them in a combined directory.
###
name: Run S3 netCDF Tests (under Ubuntu Linux)
on: [push,pull_request, workflow_dispatch]
jobs:
build-deps-serial:
runs-on: ubuntu-latest
strategy:
matrix:
hdf5: [ 1.10.8, 1.12.2, 1.14.0 ]
steps:
- uses: actions/checkout@v3
- name: Install System dependencies
shell: bash -l {0}
run: sudo apt update && sudo apt install -y libaec-dev zlib1g-dev automake autoconf libcurl4-openssl-dev libjpeg-dev wget curl bzip2 m4 flex bison cmake libzip-dev
###
# Installing libhdf5
###
- name: Cache libhdf5-${{ matrix.hdf5 }}
id: cache-hdf5
uses: actions/cache@v3
with:
path: ~/environments/${{ matrix.hdf5 }}
key: hdf5-${{ runner.os }}-${{ matrix.hdf5 }}
- name: Build libhdf5-${{ matrix.hdf5 }}
if: steps.cache-hdf5.outputs.cache-hit != 'true'
run: |
set -x
wget https://support.hdfgroup.org/ftp/HDF5/releases/hdf5-$(echo ${{ matrix.hdf5 }} | cut -d. -f 1,2)/hdf5-${{ matrix.hdf5 }}/src/hdf5-${{ matrix.hdf5 }}.tar.bz2
tar -jxf hdf5-${{ matrix.hdf5 }}.tar.bz2
pushd hdf5-${{ matrix.hdf5 }}
./configure --disable-static --enable-shared --prefix=${HOME}/environments/${{ matrix.hdf5 }} --enable-hl --with-szlib
make -j
make install -j
popd
#####
# S3 Autotools-based tests.
#####
##
# Serial
##
nc-ac-tests-s3-serial:
needs: build-deps-serial
runs-on: ubuntu-latest
strategy:
matrix:
hdf5: [ 1.14.0 ]
steps:
- uses: actions/checkout@v3
- name: Install System dependencies
shell: bash -l {0}
run: sudo apt update && sudo apt install -y libaec-dev zlib1g-dev automake autoconf libcurl4-openssl-dev libjpeg-dev wget curl bzip2 m4 flex bison cmake libzip-dev openssl libssl-dev
###
# Set Environmental Variables
###
- run: echo "CFLAGS=-I${HOME}/environments/${{ matrix.hdf5 }}/include" >> $GITHUB_ENV
- run: echo "LDFLAGS=-L${HOME}/environments/${{ matrix.hdf5 }}/lib" >> $GITHUB_ENV
- run: echo "LD_LIBRARY_PATH=${HOME}/environments/${{ matrix.hdf5 }}/lib" >> $GITHUB_ENV
###
# Fetch Cache
###
- name: Fetch HDF Cache
id: cache-hdf
uses: actions/cache@v3
with:
path: ~/environments/${{ matrix.hdf5 }}
key: hdf5-${{ runner.os }}-${{ matrix.hdf5 }}
- name: Check Cache
shell: bash -l {0}
run: ls ${HOME}/environments && ls ${HOME}/environments/${{ matrix.hdf5 }} && ls ${HOME}/environments/${{ matrix.hdf5}}/lib
###
# Configure and build
###
- name: Run autoconf
shell: bash -l {0}
run: autoreconf -if
- name: Configure
shell: bash -l {0}
run: CFLAGS=${CFLAGS} LDFLAGS=${LDFLAGS} LD_LIBRARY_PATH=${LD_LIBRARY_PATH} ./configure --enable-hdf5 --disable-dap --enable-external-server-tests --enable-s3 --enable-s3-internal --with-s3-testing=public
if: ${{ success() }}
- name: Look at config.log if error
shell: bash -l {0}
run: cat config.log
if: ${{ failure() }}
- name: Print Summary
shell: bash -l {0}
run: cat libnetcdf.settings
- name: Build Library and Utilities
shell: bash -l {0}
run: CFLAGS=${CFLAGS} LDFLAGS=${LDFLAGS} LD_LIBRARY_PATH=${LD_LIBRARY_PATH} make -j
if: ${{ success() }}
- name: Build Tests
shell: bash -l {0}
run: CFLAGS=${CFLAGS} LDFLAGS=${LDFLAGS} LD_LIBRARY_PATH=${LD_LIBRARY_PATH} make check TESTS="" -j
if: ${{ success() }}
- name: Run Tests
shell: bash -l {0}
env:
AWS_PROFILE: ${{ secrets.DEFAULT_PROFILE }}
run: |
mkdir -p ~/.aws
echo "" > ~/.aws/config
chmod go-x ~/.aws/config
echo "${AWS_PROFILE}" >> ~/.aws/config
LD_LIBRARY_PATH="/home/runner/work/netcdf-c/netcdf-c/liblib/.libs:${LD_LIBRARY_PATH}"
CFLAGS=${CFLAGS} LDFLAGS=${LDFLAGS} LD_LIBRARY_PATH=${LD_LIBRARY_PATH} make check -j
if: ${{ success() }}
#####
# S3 CMake-based tests.
#####
##
# Serial
##
# T.B.D. nc-cmake-tests-s3-serial:

View File

@ -4,7 +4,7 @@
name: Run Ubuntu/Linux netCDF Tests
on: [pull_request, workflow_dispatch]
on: [push,pull_request, workflow_dispatch]
jobs:
@ -167,7 +167,7 @@ jobs:
- name: Configure
shell: bash -l {0}
run: CFLAGS=${CFLAGS} LDFLAGS=${LDFLAGS} LD_LIBRARY_PATH=${LD_LIBRARY_PATH} ./configure --enable-hdf5 --enable-dap --disable-dap-remote-tests --enable-doxygen --enable-external-server-tests --disable-s3
run: CFLAGS=${CFLAGS} LDFLAGS=${LDFLAGS} LD_LIBRARY_PATH=${LD_LIBRARY_PATH} ./configure --enable-hdf5 --enable-dap --disable-dap-remote-tests --enable-doxygen --enable-external-server-tests
if: ${{ success() }}
- name: Look at config.log if error

View File

@ -1,6 +1,6 @@
name: Run Cygwin-based tests
on: [pull_request,workflow_dispatch]
on: [push,pull_request,workflow_dispatch]
env:
SHELLOPTS: igncr
@ -43,7 +43,7 @@ jobs:
run: >-
/bin/dash ./configure --enable-hdf5 --enable-shared
--disable-static --enable-dap --disable-dap-remote-tests
--enable-plugins --enable-nczarr --disable-s3
--enable-plugins --enable-nczarr
- name: Look at config.log if error
if: ${{ failure() }}

View File

@ -9,7 +9,7 @@ name: Run MSYS2, MinGW64-based Tests
env:
CPPFLAGS: "-D_BSD_SOURCE"
on: [pull_request,workflow_dispatch]
on: [push,pull_request,workflow_dispatch]
jobs:

View File

@ -1272,7 +1272,17 @@ ENDIF()
OPTION(ENABLE_S3 "Enable S3 support." OFF)
OPTION(ENABLE_S3_INTERNAL "Enable S3 Internal support." OFF)
OPTION(ENABLE_NCZARR_S3 "Enable NCZarr S3 support; Deprecated in favor of ENABLE_S3" OFF)
OPTION(ENABLE_NCZARR_S3_TESTS "Enable NCZarr S3 tests." OFF)
# Control S3 Testing: Multi-valued option
SET(WITH_S3_TESTING OFF CACHE STRING "Control S3 Testing: ON (i.e. all) OFF (i.e. none) PUBLIC")
SET_PROPERTY(CACHE WITH_S3_TESTING PROPERTY STRINGS ON OFF PUBLIC) #
IF(WITH_S3_TESTING STREQUAL "")
SET(WITH_S3_TESTING OFF CACHE STRING "") # Default
ENDIF()
IF(WITH_S3_TESTING)
message(WARNING "**** DO NOT USE WITH_S3_TESTING=ON UNLESS YOU HAVE ACCESS TO THE UNIDATA S3 BUCKET! ***")
ENDIF()
# ENABLE_NCZARR_S3 is now an alias for ENABLE_S3 (but...)
if (NOT ENABLE_S3 AND ENABLE_NCZARR_S3)
@ -1284,14 +1294,16 @@ UNSET(ENABLE_NCZARR_S3)
# because for some reason this screws up if we unconditionally test for sdk
# and it is not available. Fix someday
IF(ENABLE_S3)
# See if aws-s3-sdk is available
find_package(AWSSDK REQUIRED COMPONENTS s3;core)
IF(AWSSDK_FOUND)
SET(service s3;core)
AWSSDK_DETERMINE_LIBS_TO_LINK(service AWS_LINK_LIBRARIES)
SET(ENABLE_S3_AWS ON CACHE BOOL "S3 AWS" FORCE)
ELSE()
SET(ENABLE_S3_AWS OFF CACHE BOOL "S3 AWS" FORCE)
IF(NOT ENABLE_S3_INTERNAL)
# See if aws-s3-sdk is available
find_package(AWSSDK REQUIRED COMPONENTS s3;core)
IF(AWSSDK_FOUND)
SET(service s3;core)
AWSSDK_DETERMINE_LIBS_TO_LINK(service AWS_LINK_LIBRARIES)
SET(ENABLE_S3_AWS ON CACHE BOOL "S3 AWS" FORCE)
ELSE()
SET(ENABLE_S3_AWS OFF CACHE BOOL "S3 AWS" FORCE)
ENDIF()
ENDIF()
ELSE()
SET(ENABLE_S3_AWS OFF CACHE BOOL "S3 AWS" FORCE)
@ -1313,13 +1325,11 @@ IF(ENABLE_S3)
ENDIF()
ENDIF()
IF(ENABLE_NCZARR_S3_TESTS AND NOT ENABLE_S3)
message(FATAL_ERROR "S3 support is disabled; please specify option -DENABLE_NCZARR_S3_TESTS=NO")
SET(ENABLE_NCZARR_S3_TESTS OFF CACHE BOOL "NCZARR S3 TESTS" FORCE)
IF(NOT ENABLE_S3)
IF(WITH_S3_TESTING STREQUAL "PUBLIC" OR WITH_S3_TESTING)
message(WARNING "S3 support is disabled => WITH_S3_TESTING=OFF")
SET(WITH_S3_TESTING OFF CACHE STRING "" FORCE)
ENDIF()
IF(ENABLE_NCZARR_S3_TESTS)
message(WARNING "**** DO NOT ENABLE_NCZARR_S3_TESTS UNLESS YOU HAVE ACCESS TO THE UNIDATA S3 BUCKET! ***")
ENDIF()
# Start disabling if curl not found
@ -2558,7 +2568,6 @@ is_enabled(ENABLE_S3_AWS HAS_S3_AWS)
is_enabled(ENABLE_S3_INTERNAL HAS_S3_INTERNAL)
is_enabled(HAS_HDF5_ROS3 HAS_HDF5_ROS3)
is_enabled(ENABLE_NCZARR HAS_NCZARR)
is_enabled(ENABLE_NCZARR_S3_TESTS DO_NCZARR_S3_TESTS)
is_enabled(ENABLE_NCZARR_ZIP HAS_NCZARR_ZIP)
is_enabled(ENABLE_MULTIFILTERS HAS_MULTIFILTERS)
is_enabled(ENABLE_NCZARR_ZIP DO_NCZARR_ZIP_TESTS)
@ -2570,17 +2579,26 @@ is_enabled(HAVE_SZ HAS_SZLIB_WRITE)
is_enabled(HAVE_ZSTD HAS_ZSTD)
is_enabled(HAVE_BLOSC HAS_BLOSC)
is_enabled(HAVE_BZ2 HAS_BZ2)
if(ENABLE_S3_AWS)
SET(WHICH_S3_SDK "aws-sdk-cpp")
SET(NC_WHICH_S3_SDK "aws-sdk-cpp")
else()
if(ENABLE_S3_AWS)
if(ENABLE_S3_INTERNAL)
SET(WHICH_S3_SDK "internal")
SET(NC_WHICH_S3_SDK "internal")
elseif(ENABLE_S3_AWS)
SET(WHICH_S3_SDK "aws-sdk-cpp")
SET(NC_WHICH_S3_SDK "aws-sdk-cpp")
else()
SET(WHICH_S3_SDK "none")
SET(NC_WHICH_S3_SDK "none")
endif()
if(WITH_S3_TESTING STREQUAL PUBLIC)
SET(DO_S3_TESTING "public")
elseif(WITH_S3_TESTING)
SET(DO_S3_TESTING "yes")
elseif(NOT WITH_S3_TESTING)
SET(DO_S3_TESTING "no")
else()
SET(DO_S3_TESTING "no")
endif()
# Generate file from template.

View File

@ -142,9 +142,6 @@ are set when opening a binary file on Windows. */
/* if true, enable nczarr filter support */
#cmakedefine ENABLE_NCZARR_FILTERS 1
/* if true, enable S3 testing*/
#cmakedefine ENABLE_NCZARR_S3_TESTS 1
/* if true, enable nczarr zip support */
#cmakedefine ENABLE_NCZARR_ZIP 1
@ -160,6 +157,9 @@ are set when opening a binary file on Windows. */
/* if true, Force use of S3 internal library */
#cmakedefine ENABLE_S3_INTERNAL 1
/* if true, enable S3 testing*/
#cmakedefine WITH_S3_TESTING "PUBLIC"
/* if true, run extra tests which may not work yet */
#cmakedefine EXTRA_TESTS 1

View File

@ -855,18 +855,18 @@ fi
fi
# Check for enabling S3 testing
AC_MSG_CHECKING([whether netcdf zarr S3 testing should be enabled])
AC_ARG_ENABLE([nczarr-s3-tests],
[AS_HELP_STRING([--enable-nczarr-s3-tests],
[enable netcdf zarr S3 testing])])
test "x$enable_nczarr_s3_tests" = xyes || enable_nczarr_s3_tests=no
AC_MSG_RESULT($enable_nczarr_s3_tests)
AC_MSG_CHECKING([what level of netcdf S3 testing should be enabled])
AC_ARG_WITH([s3-testing],
[AS_HELP_STRING([--with-s3-testing=yes|no|public],
[control netcdf S3 testing])],
[], [with_s3_testing=public])
AC_MSG_RESULT($with_s3_testing)
# Disable S3 tests if S3 support is disabled
if test "x$enable_nczarr_s3_tests" = xyes ; then
if test "x$enable_s3" = xno ; then
AC_MSG_ERROR([S3 support is disabled => no testing])
enable_nczarr_s3_tests=no
if test "x$enable_s3" = xno ; then
if test "x$with_s3_testing" != xno ; then
AC_MSG_WARN([S3 support is disabled => no testing])
with_s3_testing=no
fi
fi
@ -882,12 +882,10 @@ if test "x$enable_s3_internal" = xyes ; then
AC_DEFINE([ENABLE_S3_INTERNAL], [1], [If true, then use internal S3 library])
fi
if test "x$enable_nczarr_s3_tests" = xyes ; then
AC_DEFINE([ENABLE_NCZARR_S3_TESTS], [1], [if true, build libnczarr with S3 tests enabled])
fi
AC_DEFINE_UNQUOTED([WITH_S3_TESTING], [$with_s3_testing], [control S3 testing.])
if test "x$enable_nczarr_s3_tests" = xyes ; then
AC_MSG_WARN([*** DO NOT ENABLE_NCZARR_S3_TESTS UNLESS YOU HAVE ACCESS TO THE UNIDATA S3 BUCKET! ***])
if test "x$with_s3_testing" = xyes ; then
AC_MSG_WARN([*** DO NOT SPECIFY WITH_S3_TESTING=YES UNLESS YOU HAVE ACCESS TO THE UNIDATA S3 BUCKET! ***])
fi
# Set default
@ -1855,7 +1853,8 @@ AM_CONDITIONAL(ENABLE_S3, [test "x$enable_s3" = xyes])
AM_CONDITIONAL(ENABLE_S3_AWS, [test "x$enable_s3_aws" = xyes])
AM_CONDITIONAL(ENABLE_S3_INTERNAL, [test "x$enable_s3_internal" = xyes])
AM_CONDITIONAL(ENABLE_NCZARR, [test "x$enable_nczarr" = xyes])
AM_CONDITIONAL(ENABLE_NCZARR_S3_TESTS, [test "x$enable_nczarr_s3_tests" = xyes])
AM_CONDITIONAL(ENABLE_S3_TESTPUB, [test "x$with_s3_testing" != xno]) # all => public
AM_CONDITIONAL(ENABLE_S3_TESTALL, [test "x$with_s3_testing" = xyes])
AM_CONDITIONAL(ENABLE_NCZARR_ZIP, [test "x$enable_nczarr_zip" = xyes])
AM_CONDITIONAL(HAS_MULTIFILTERS, [test "x$has_multifilters" = xyes])
AM_CONDITIONAL(HAVE_SZ, [test "x$have_sz" = xyes])
@ -1965,7 +1964,7 @@ AC_SUBST(HAS_S3_AWS,[$enable_s3_aws])
AC_SUBST(HAS_S3_INTERNAL,[$enable_s3_internal])
AC_SUBST(HAS_HDF5_ROS3,[$has_hdf5_ros3])
AC_SUBST(HAS_NCZARR,[$enable_nczarr])
AC_SUBST(DO_NCZARR_S3_TESTS,[$enable_nczarr_s3_tests])
AC_SUBST(DO_S3_TESTING,[$with_s3_testing])
AC_SUBST(HAS_NCZARR_ZIP,[$enable_nczarr_zip])
AC_SUBST(HAS_MULTIFILTERS,[$has_multifilters])
AC_SUBST(DO_NCZARR_ZIP_TESTS,[$enable_nczarr_zip])
@ -2075,7 +2074,7 @@ AC_SUBST([NOUNDEFINED])
# example: AX_SET_META([NC_HAS_NC2],[$nc_build_v2],[]) # Because it checks for no.
# AX_SET_META([NC_HAS_HDF4],[$enable_hdf4],[yes])
AC_DEFUN([AX_SET_META],[
if [ test "x$2" = x$3 ]; then
if [ test "x$2" = "x$3" ]; then
AC_SUBST([$1]) $1=1
else
AC_SUBST([$1]) $1=0
@ -2103,10 +2102,10 @@ AX_SET_META([NC_HAS_CDF5],[$enable_cdf5],[yes])
AX_SET_META([NC_HAS_ERANGE_FILL], [$enable_erange_fill],[yes])
AX_SET_META([NC_HAS_PAR_FILTERS], [$hdf5_supports_par_filters],[yes])
AX_SET_META([NC_HAS_BYTERANGE],[$enable_byterange],[yes])
AX_SET_META([NC_HAS_S3],[$enable_s3],[no])
AX_SET_META([NC_HAS_S3_AWS],[$enable_s3_aws],[no])
AX_SET_META([HAS_HAS_S3_INTERNAL],[$enable_s3_internal],[no])
AX_SET_META([HAS_HDF5_ROS3],[$has_hdf5_ros3],[no])
AX_SET_META([NC_HAS_S3],[$enable_s3],[yes])
AX_SET_META([NC_HAS_S3_AWS],[$enable_s3_aws],[yes])
AX_SET_META([NC_HAS_S3_INTERNAL],[$enable_s3_internal],[yes])
AX_SET_META([NC_HAS_HDF5_ROS3],[$has_hdf5_ros3],[yes])
AX_SET_META([NC_HAS_NCZARR],[$enable_nczarr],[yes])
AX_SET_META([NC_HAS_MULTIFILTERS],[$has_multifilters],[yes])
AX_SET_META([NC_HAS_LOGGING],[$enable_logging],[yes])

View File

@ -1,3 +1,4 @@
Cloud Storage Access Using The NetCDF-C Library
============================
<!-- double header is needed to workaround doxygen bug -->
@ -98,11 +99,12 @@ Currently the following build cases are known to work.
## Automake
There are several options relevant to NCZarr support and to Amazon S3 support.
There are several options relevant to Amazon S3 support.
These are as follows.
1. _--enable-s3_ -- Enable S3 support.
2. _--enable-s3-internal_ -- Force use of the *nch5s3comms* SDK instead of the *aws-cpp-sdk* (assuming it is available).
3. _--with-s3-testing_=yes|no|public -- "yes" means do all S3 tests, "no" means do no S3 testing, "public" means do only those tests that involve publically accessible S3 data.
__A note about using S3 with Automake.__
If S3 support is desired, and using the Amazon "aws-sdk-cpp" SDK, and using Automake, then LDFLAGS must be properly set, namely to this.
@ -117,8 +119,9 @@ Note also that if S3 support is enabled, then you need to have a C++ compiler in
The necessary CMake flags are as follows (with defaults)
1. -DENABLE_S3 -- Enable S3 support, including NCZarr support if NCZarr is enabled
2. -DENABLE_S3_INTERNAL -- Force use of the *nch5s3comms* SDK instead of the *aws-cpp-sdk*.
1. *-DENABLE_S3* -- Controll S3 support
2. *-DENABLE_S3_INTERNAL* -- Force use of the *nch5s3comms* SDK instead of the *aws-cpp-sdk*.
3. *-DWITH-S3-TESTING_=ON|OFF|PUBLIC -- "ON" means do all S3 tests, "OFF" means do no S3 testing, "PUBLIC" means do only those tests that involve publically accessible S3 data.
Note that unlike Automake, CMake can properly locate C++ libraries, so it should not be necessary to specify _-laws-cpp-sdk-s3_ assuming that the aws s3 libraries are installed in the default location.
For CMake with Visual Studio, the default location is here:
@ -167,7 +170,7 @@ has a number of properties of interest:
For linux, the following context works. Of course your mileage may vary.
* OS: ubuntu 21
* aws-sdk-cpp version 1.9.96 (or later)
* Dependencies: openssl, libcurl, cmake, ninja (ninja-build in apt)
* Dependencies: openssl, libcurl, cmake, ninja (ninja-build using *apt-get*)
#### AWS-SDK-CPP CMake Build Recipe
````
@ -249,14 +252,13 @@ Then the following options must be specified for cmake.
-DAWSSDK_ROOT_DIR=${AWSSDK_ROOT_DIR}
-DAWSSDK_DIR=${AWSSDK_ROOT_DIR}/lib/cmake/AWSSDK"
````
## Building ``nch5s3comms''
This is an experimental SDK provided internally in the netcdf-c library.
* It is written in C
* It provides the minimum functionality necessary to read/write/search an Amazon S3 bucket.
* It was constructed by heavily modifying the HDF5 *H5FDros3* Virtual File Driver and combining it with crypto code wrappers provided by libcurl.
* It was constructed by heavily modifying the HDF5 *H5FDros3* Virtual File Driver and combining it with crypto code wrappers provided by libcurl. The resulting file was then modified to fit into the netcdf coding style.
* The resulting code is rather ugly, but appears to work under at least Linux and under Windows (using Visual C++).
### Dependencies
@ -303,12 +305,12 @@ The algorithm for choosing the active profile to use is as follows:
https://...#mode=nczarr,s3&aws.profile=xxx
````
2. If the "AWS.PROFILE" entry in the .rc file (i.e. .netrc or .dodsrc) is set, then it is used.
3. Otherwise the profile "default" is used.
3. If defined, then profile "default" is used.
4. Otherwise the profile "no" is used.
The profile named "none" is a special profile that the netcdf-c library automatically defines.
The profile named "no" is a special profile that the netcdf-c library automatically defines.
It should not be defined anywhere else. It signals to the library that no credentialas are to used.
It is equivalent to the "--no-sign-request" option in the AWS CLI.
Also, it must be explicitly specified by name. Otherwise "default" will be used.
## Region Selection
@ -332,7 +334,7 @@ The algorithm for picking an region is as follows.
Picking an access-key/secret-key pair is always determined
by the current active profile. To choose to not use keys
requires that the active profile must be "none".
requires that the active profile must be "no".
# Change Log {#nccloud_changelog}
[Note: minor text changes are not included.]

View File

@ -46,7 +46,7 @@ filters](./md_filters.html "filters") for details.
Briefly, the data model supported by NCZarr is netcdf-4 minus
the user-defined types. However, a restricted form of String type
is supported (see Appendix H).
is supported (see Appendix E).
As with netcdf-4 chunking is supported. Filters and compression
are also [supported](./md_filters.html "filters").
@ -455,11 +455,10 @@ Here are a couple of examples using the _ncgen_ and _ncdump_ utilities.
```
ncgen -4 -lb -o "s3://datasetbucket/rootkey#mode=nczarr,awsprofile=unidata" dataset.cdl
```
Note that the URLis internally translated to this
Note that the URL is internally translated to this
````
https://s2.&lt;region&gt.amazonaws.com/datasetbucket/rootkey#mode=nczarr,awsprofile=unidata" dataset.cdl
````
The region is from the algorithm described in Appendix E1.
# References {#nczarr_bib}
@ -499,153 +498,37 @@ A separate tabulation of S3 support is in the document cloud.md.
The relevant ./configure options are as follows.
1. *--disable-nczarr* -- disable the NCZarr support.
2. *--enable-nczarr-s3-tests* -- the NCZarr S3 tests are currently only usable by Unidata personnel, so they are disabled by default.
### A note about using S3 with Automake.
If S3 support is desired, and using Automake, then LDFLAGS must be properly set, namely to this.
````
LDFLAGS="$LDFLAGS -L/usr/local/lib -laws-cpp-sdk-s3"
````
The above assumes that these libraries were installed in '/usr/local/lib', so the above requires modification if they were installed elsewhere.
## CMake
The relevant CMake flags are as follows.
1. *-DENABLE_NCZARR=off* -- equivalent to the Automake *--disable-nczarr* option.
2. *-DENABLE_NCZARR_S3_TESTS=off* -- equivalent to the Automake *--enable-nczarr-s3-tests* option.
Note that unlike Automake, CMake can properly locate C++ libraries, so it should not be necessary to specify *-laws-cpp-sdk-s3*, assuming that the aws s3 libraries are installed in the default location.
For CMake with Visual Studio, the default location is here:
````
C:/Program Files (x86)/aws-cpp-sdk-all
````
It is possible to install the sdk library in another location.
In this case, one must add the following flag to the cmake command.
````
cmake ... -DAWSSDK_DIR=\<awssdkdir\>
````
where "awssdkdir" is the path to the sdk installation.
For example, this might be as follows.
````
cmake ... -DAWSSDK_DIR="c:\tools\aws-cpp-sdk-all"
````
This can be useful if blanks in path names cause problems in your build environment.
## Testing S3 Support {#nczarr_testing_S3_support}
## Testing NCZarr S3 Support {#nczarr_testing_S3_support}
The relevant tests for S3 support are in the _nczarr_test_ directory.
Currently, by default, testing of S3 with NCZarr is supported only for Unidata members of the NetCDF Development Group.
This is because it uses a Unidata-specific bucket is inaccessible to the general user.
# Appendix B. Building aws-sdk-cpp {#nczarr_s3sdk}
In order to use the S3 storage driver, it is necessary to install the Amazon [aws-sdk-cpp library](https://github.com/aws/aws-sdk-cpp.git).
Building this package from scratch has proven to be a formidable task.
This appears to be due to dependencies on very specific versions of,
for example, openssl.
## *\*nix\** Build
For linux, the following context works. Of course your mileage may vary.
* OS: ubuntu 21
* aws-sdk-cpp version 1.9.96 (or later?)
* Required installed libraries: openssl, libcurl, cmake, ninja (ninja-build in apt)
### AWS-SDK-CPP Build Recipe
````
git clone --recurse-submodules https://www.github.com/aws/aws-sdk-cpp.git
cd aws-sdk-cpp
mkdir build
cd build
PREFIX=/usr/local
FLAGS="-DCMAKE_INSTALL_PREFIX=${PREFIX} \
-DCMAKE_INSTALL_LIBDIR=lib \
-DCMAKE_MODULE_PATH=${PREFIX}/lib/cmake \
-DCMAKE_POLICY_DEFAULT_CMP0075=NEW \
-DBUILD_ONLY=s3 \
-DENABLE_UNITY_BUILD=ON \
-DENABLE_TESTING=OFF \
-DCMAKE_BUILD_TYPE=$CFG \
-DSIMPLE_INSTALL=ON \
_DMY_ASSEMBLER_IS_TOO_OLD_FOR_AVX=ON"
cmake -GNinja $FLAGS ..
ninja all
sudo ninja install
cd ..
cd ..
````
This is because it uses a Unidata-specific bucket that is inaccessible to the general user.
### NetCDF Build
In order to build netcdf-c with S3 sdk support,
the following options must be specified for ./configure.
````
--enable-nczarr-s3
--enable-s3
````
If you have access to the Unidata bucket on Amazon, then you can
also test S3 support with this option.
````
--enable-nczarr-s3-tests
--with-s3-testing=yes
````
## Windows build
It is possible to build and install aws-sdk-cpp. It is also possible
to build netcdf-c using cmake. Unfortunately, testing currently fails.
For Windows, the following context work. Of course your mileage may vary.
* OS: Windows 10 64-bit with Visual Studio community edition 2019.
* aws-sdk-cpp version 1.9.96 (or later?)
* Required installed libraries: openssl, libcurl, cmake
### AWS-SDK-CPP Build Recipe
This command-line build assumes one is using Cygwin or Mingw to provide
tools such as bash.
````
git clone --recurse-submodules https://www.github.com/aws/aws-sdk-cpp
pushd aws-sdk-cpp
mkdir build
cd build
CFG="Release"
PREFIX="c:/tools/aws-sdk-cpp"
FLAGS="-DCMAKE_INSTALL_PREFIX=${PREFIX} \
-DCMAKE_INSTALL_LIBDIR=lib" \
-DCMAKE_MODULE_PATH=${PREFIX}/cmake \
-DCMAKE_POLICY_DEFAULT_CMP0075=NEW \
-DBUILD_ONLY=s3 \
-DENABLE_UNITY_BUILD=ON \
-DCMAKE_BUILD_TYPE=$CFG \
-DSIMPLE_INSTALL=ON"
rm -fr build
mkdir -p build
cd build
cmake -DCMAKE_BUILD_TYPE=${CFG} $FLAGS ..
cmake --build . --config ${CFG}
cmake --install . --config ${CFG}
cd ..
popd
````
Notice that the sdk is being installed in the directory "c:\tools\aws-sdk-cpp"
rather than the default location "c:\Program Files (x86)/aws-sdk-cpp-all"
This is because when using a command line, an install path that contains
blanks may not work.
### NetCDF CMake Build
Enabling S3 support is controlled by these two cmake options:
Enabling S3 support is controlled by this cmake option:
````
-DENABLE_NCZARR_S3=ON
-DENABLE_NCZARR_S3_TESTS=OFF
-DENABLE_S3=ON
````
However, to find the aws sdk libraries,
the following environment variables must be set:
````
@ -658,7 +541,7 @@ Then the following options must be specified for cmake.
-DAWSSDK_ROOT_DIR=${AWSSDK_ROOT_DIR}
-DAWSSDK_DIR=${AWSSDK_ROOT_DIR}/lib/cmake/AWSSDK"
````
# Appendix C. Amazon S3 Imposed Limits {#nczarr_s3limits}
# Appendix B. Amazon S3 Imposed Limits {#nczarr_s3limits}
The Amazon S3 cloud storage imposes some significant limits that are inherited by NCZarr (and Zarr also, for that matter).
@ -668,7 +551,7 @@ Some of the relevant limits are as follows:
Note that the limit is defined in terms of bytes and not (Unicode) characters.
This affects the depth to which groups can be nested because the key encodes the full path name of a group.
# Appendix F. NCZarr Version 1 Meta-Data Representation. {#nczarr_version1}
# Appendix C. NCZarr Version 1 Meta-Data Representation. {#nczarr_version1}
In NCZarr Version 1, the NCZarr specific metadata was represented using new objects rather than as keys in existing Zarr objects.
Due to conflicts with the Zarr specification, that format is deprecated in favor of the one described above.
@ -683,7 +566,7 @@ The content of these objects is the same as the contents of the corresponding ke
* ''.nczarray <=> ''_nczarr_array_''
* ''.nczattr <=> ''_nczarr_attr_''
# Appendix G. JSON Attribute Convention. {#nczarr_json}
# Appendix D. JSON Attribute Convention. {#nczarr_json}
The Zarr V2 specification is somewhat vague on what is a legal
value for an attribute. The examples all show one of two cases:
@ -771,7 +654,7 @@ actions "read-write-read" is equivalent to a single "read" and "write-read-write
The "almost" caveat is necessary because (1) whitespace may be added or lost during the sequence of operations,
and (2) numeric precision may change.
# Appendix H. Support for string types
# Appendix E. Support for string types
Zarr supports a string type, but it is restricted to
fixed size strings. NCZarr also supports such strings,
@ -839,7 +722,7 @@ It is necessary to use the 'git diff' command.
accepted for back compatibility.
2. The legal values of an attribute has been extended to
include arbitrary JSON expressions; see Appendix G for more details.
include arbitrary JSON expressions; see Appendix D for more details.
# Point of Contact {#nczarr_poc}

View File

@ -50,7 +50,7 @@ endif # ENABLE_BYTERANGE
if ENABLE_S3
if ENABLE_S3_INTERNAL
# Renamed to avoid conflicts with the HDF5 files
libdispatch_la_SOURCES += ncs3sdk_h5.c nch5s3comms.c nch5s3comms.h nccurl_setup.h \
libdispatch_la_SOURCES += ncs3sdk_h5.c nch5s3comms.c nch5s3comms.h ncutil.h nccurl_setup.h \
nccurl_sha256.c nccurl_sha256.h nccurl_hmac.c nccurl_hmac.h
AM_CPPFLAGS += -I$(top_srcdir)/libncxml
libdispatch_la_CPPFLAGS += ${AM_CPPFLAGS}

View File

@ -94,6 +94,7 @@ NC_authsetup(NCauth** authp, NCURI* uri)
int ret = NC_NOERR;
char* uri_hostport = NULL;
NCauth* auth = NULL;
struct AWSprofile* ap = NULL;
if(uri != NULL)
uri_hostport = NC_combinehostport(uri);
@ -175,8 +176,15 @@ NC_authsetup(NCauth** authp, NCURI* uri)
nullfree(user);
nullfree(pwd);
}
/* Get the Default profile */
auth->s3profile = strdup("default");
if((ret=NC_authgets3profile("no",&ap))) goto done;
if(ap == NULL)
if((ret=NC_authgets3profile("default",&ap))) goto done;
if(ap != NULL)
auth->s3profile = strdup(ap->name);
else
auth->s3profile = NULL;
if(authp) {*authp = auth; auth = NULL;}
done:

View File

@ -155,9 +155,11 @@ nc_http_close(NC_HTTP_STATE* state)
break;
#ifdef ENABLE_S3
case HTTPS3: {
NC_s3sdkclose(state->s3.s3client, state->s3.info, 0, &state->errmsg);
if(state->s3.s3client)
NC_s3sdkclose(state->s3.s3client, state->s3.info, 0, NULL);
NC_s3clear(state->s3.info);
nullfree(state->s3.info);
state->s3.s3client = NULL;
} break;
#endif
default: stat = NCTHROW(NC_ENOTBUILT); goto done;

View File

@ -762,6 +762,7 @@ Get the current active profile. The priority order is as follows:
1. aws.profile key in mode flags
2. aws.profile in .rc entries
4. "default"
5. "no" -- meaning do not use any profile => no secret key
@param uri uri with mode flags, may be NULL
@param profilep return profile name here or NULL if none found
@ -774,16 +775,27 @@ NC_getactives3profile(NCURI* uri, const char** profilep)
{
int stat = NC_NOERR;
const char* profile = NULL;
struct AWSprofile* ap = NULL;
profile = ncurifragmentlookup(uri,"aws.profile");
if(profile == NULL)
profile = NC_rclookupx(uri,"AWS.PROFILE");
if(profile == NULL)
profile = "default";
if(profile == NULL) {
if((stat=NC_authgets3profile("default",&ap))) goto done;
if(ap) profile = "default";
}
if(profile == NULL) {
if((stat=NC_authgets3profile("no",&ap))) goto done;
if(ap) profile = "no";
}
#ifdef AWSDEBUG
fprintf(stderr,">>> activeprofile = %s\n",(profile?profile:"null"));
#endif
if(profilep) *profilep = profile;
done:
return stat;
}
@ -811,7 +823,7 @@ NC_getdefaults3region(NCURI* uri, const char** regionp)
if(region == NULL)
region = NC_rclookupx(uri,"AWS.REGION");
if(region == NULL) {/* See if we can find a profile */
if((stat = NC_getactives3profile(uri,&profile))==NC_NOERR) {
if(NC_getactives3profile(uri,&profile)==NC_NOERR) {
if(profile)
(void)NC_s3profilelookup(profile,"aws_region",&region);
}
@ -1122,6 +1134,14 @@ aws_load_credentials(NCglobalstate* gstate)
NCbytes* buf = ncbytesnew();
char path[8192];
/* add a "no" credentials */
{
struct AWSprofile* noprof = (struct AWSprofile*)calloc(1,sizeof(struct AWSprofile));
noprof->name = strdup("no");
noprof->entries = nclistnew();
nclistpush(profiles,noprof); noprof = NULL;
}
for(;*awscfg;awscfg++) {
/* Construct the path ${HOME}/<file> or Windows equivalent. */
const char* cfg = *awscfg;
@ -1140,14 +1160,6 @@ aws_load_credentials(NCglobalstate* gstate)
}
}
/* add a "none" credentials */
{
struct AWSprofile* noprof = (struct AWSprofile*)calloc(1,sizeof(struct AWSprofile));
noprof->name = strdup("none");
noprof->entries = nclistnew();
nclistpush(profiles,noprof); noprof = NULL;
}
if(gstate->rcinfo->s3profiles)
freeprofilelist(gstate->rcinfo->s3profiles);
gstate->rcinfo->s3profiles = profiles; profiles = NULL;
@ -1177,6 +1189,13 @@ done:
return stat;
}
/* Lookup a profile by name;
@param profilename to lookup
@param profilep return the matching profile; null if profile not found
@return NC_NOERR if no error
@return other error
*/
int
NC_authgets3profile(const char* profilename, struct AWSprofile** profilep)
{
@ -1197,25 +1216,23 @@ done:
/**
@param profile name of profile
@param key key to search for in profile
@param valup place to store the value if key is found.
@return NC_NOERR if key is found, NC_NOOBJECT if key is not found, or other error.
@param value place to store the value if key is found; NULL if not found
@return NC_NOERR if key is found, Some other error otherwise.
*/
int
NC_s3profilelookup(const char* profile, const char* key, const char** valuep)
{
int i,stat = NC_ENOOBJECT;
int i,stat = NC_NOERR;
struct AWSprofile* awsprof = NULL;
const char* value = NULL;
if(profile == NULL) return NC_ES3;
stat = NC_authgets3profile(profile,&awsprof);
if(stat == NC_NOERR && awsprof != NULL) {
if((stat=NC_authgets3profile(profile,&awsprof))==NC_NOERR && awsprof != NULL) {
for(i=0;i<nclistlength(awsprof->entries);i++) {
struct AWSentry* entry = (struct AWSentry*)nclistget(awsprof->entries,i);
if(strcasecmp(entry->key,key)==0) {
value = entry->value;
stat = NC_NOERR;
break;
}
}

View File

@ -214,7 +214,7 @@ NC_s3urlprocess(NCURI* url, NCS3INFO* s3)
{stat = NC_EURL; goto done;}
/* Get current profile */
if((stat = NC_getactives3profile(url,&profile0))) goto done;
if(profile0 == NULL) profile0 = "none";
if(profile0 == NULL) profile0 = "no";
s3->profile = strdup(profile0);
/* Rebuild the URL to path format and get a usable region and optional bucket*/

File diff suppressed because it is too large Load Diff

View File

@ -74,6 +74,7 @@
/* Opaque Handles */
struct CURL;
struct NCURI;
struct VString;
/*****************
* PUBLIC MACROS *
@ -184,11 +185,11 @@ struct NCURI;
*---------------------------------------------------------------------------
*/
#define S3COMMS_FORMAT_CREDENTIAL(dest, access, iso8601_date, region, service) \
ncbytescat((dest),(access)); ncbytescat((dest),"/"); \
ncbytescat((dest),(iso8601_date)); ncbytescat((dest),"/"); \
ncbytescat((dest),(region)); ncbytescat((dest),"/"); \
ncbytescat((dest),(service)); ncbytescat((dest),"/"); \
ncbytescat((dest),"aws4_request");
vscat((dest),(access)); vscat((dest),"/"); \
vscat((dest),(iso8601_date)); vscat((dest),"/"); \
vscat((dest),(region)); vscat((dest),"/"); \
vscat((dest),(service)); vscat((dest),"/"); \
vscat((dest),"aws4_request");
#if 0
snprintf((dest), S3COMMS_MAX_CREDENTIAL_SIZE, "%s/%s/%s/%s/aws4_request", (access), (iso8601_date), \
@ -274,11 +275,6 @@ struct NCURI;
* as the field would appear in an HTTP request.
* e.g., "Range: bytes=0-9"
*
* `next` (hrb_node_t *)
*
* Pointers to next node in the list, or NULL sentinel as end of list.
* Next node must have a greater `lowername` as determined by strcmp().
*
*----------------------------------------------------------------------------
*/
typedef struct hrb_node_t {
@ -358,12 +354,11 @@ typedef struct hrb_node_t {
*----------------------------------------------------------------------------
*/
typedef struct {
unsigned long magic;
char *body;
size_t body_len;
hrb_node_t *first_header;
char *resource;
char *version;
unsigned long magic;
struct VString *body;
struct VList *headers;
char *resource;
char *version;
} hrb_t;
#define S3COMMS_HRB_MAGIC 0x6DCC84UL
@ -466,12 +461,19 @@ typedef struct {
char *accessid;
char *accesskey;
char httpverb[S3COMMS_VERB_MAX];
unsigned char signing_key[SHA256_DIGEST_LENGTH];
unsigned char *signing_key; /*|signing_key| = SHA256_DIGEST_LENGTH*/
char iso8601now[ISO8601_SIZE];
char *reply;
struct curl_slist *curlheaders;
} s3r_t;
/* Combined storage for space + size */
typedef struct s3r_buf_t {
unsigned long long count; /* |content| */
void* content;
} s3r_buf_t;
#define S3COMMS_S3R_MAGIC 0x44d8d79
typedef enum HTTPVerb {
@ -492,7 +494,7 @@ EXTERNL int NCH5_s3comms_hrb_node_set(hrb_node_t **L, const char *name, const ch
* DECLARATION OF HTTP REQUEST BUFFER ROUTINES *
***********************************************/
EXTERNL int NCH5_s3comms_hrb_destroy(hrb_t **buf);
EXTERNL int NCH5_s3comms_hrb_destroy(hrb_t *buf);
EXTERNL hrb_t *NCH5_s3comms_hrb_init_request(const char *resource, const char *host);
@ -504,13 +506,11 @@ EXTERNL s3r_t *NCH5_s3comms_s3r_open(const char* root, const char* region, const
EXTERNL int NCH5_s3comms_s3r_close(s3r_t *handle);
EXTERNL int NCH5_s3comms_s3r_read(s3r_t *handle, const char* url, size_t offset, size_t len, NCbytes* dest);
EXTERNL int NCH5_s3comms_s3r_read(s3r_t *handle, const char* url, size_t offset, size_t len, s3r_buf_t* data);
EXTERNL int NCH5_s3comms_s3r_write(s3r_t *handle, const char* url, NCbytes* data);
EXTERNL int NCH5_s3comms_s3r_write(s3r_t *handle, const char* url, const s3r_buf_t* data);
EXTERNL int NCH5_s3comms_s3r_getkeys(s3r_t *handle, const char* url, NCbytes* response);
EXTERNL int NCH5_s3comms_s3r_execute(s3r_t *handle, const char* url, HTTPVerb verb, const char* byterange, const char* header, const char** otherheaders, long* httpcodep, NCbytes* data);
EXTERNL int NCH5_s3comms_s3r_getkeys(s3r_t *handle, const char* url, s3r_buf_t* response);
EXTERNL int NCH5_s3comms_s3r_getsize(s3r_t *handle, const char* url, long long * sizep);
@ -524,8 +524,8 @@ EXTERNL int NCH5_s3comms_s3r_head(s3r_t *handle, const char* url, const char* he
EXTERNL struct tm *gmnow(void);
EXTERNL int NCH5_s3comms_aws_canonical_request(NCbytes* canonical_request_dest,
NCbytes* signed_headers_dest,
EXTERNL int NCH5_s3comms_aws_canonical_request(struct VString* canonical_request_dest,
struct VString* signed_headers_dest,
HTTPVerb verb,
const char* query,
const char* payloadsha256,
@ -544,15 +544,15 @@ EXTERNL int NCH5_s3comms_nlowercase(char *dest, const char *s, size_t len);
EXTERNL int NCH5_s3comms_percent_encode_char(char *repr, const unsigned char c, size_t *repr_len);
EXTERNL int NCH5_s3comms_signing_key(unsigned char *md, const char *secret, const char *region,
EXTERNL int NCH5_s3comms_signing_key(unsigned char **mdp, const char *secret, const char *region,
const char *iso8601now);
EXTERNL int NCH5_s3comms_tostringtosign(NCbytes* dest, const char *req_str, const char *now,
EXTERNL int NCH5_s3comms_tostringtosign(struct VString* dest, const char *req_str, const char *now,
const char *region);
EXTERNL int NCH5_s3comms_trim(char *dest, char *s, size_t s_len, size_t *n_written);
EXTERNL int NCH5_s3comms_uriencode(NCbytes* dest, const char *s, size_t s_len, int encode_slash, size_t *n_written);
EXTERNL int NCH5_s3comms_uriencode(char** destp, const char *s, size_t s_len, int encode_slash, size_t *n_written);
#ifdef __cplusplus
}

View File

@ -89,7 +89,7 @@ static int ncs3_finalized = 0;
static void s3client_destroy(NCS3CLIENT* s3client);
static char* makes3rooturl(NCS3INFO* info);
static int makes3fullpath(const char* pathkey, const char* bucket, const char* prefix, const char* key, NCbytes* url);
static int parse_listbucketresult(char* xml, size_t xmllen, struct LISTOBJECTSV2**);
static int parse_listbucketresult(char* xml, unsigned long long xmllen, struct LISTOBJECTSV2**);
static int parse_object(ncxml_t root, NClist* objects);
static int parse_owner(ncxml_t root, struct Owner* ownerp);
static int parse_prefix(ncxml_t root, NClist* prefixes);
@ -103,7 +103,7 @@ static int makes3prefix(const char* prefix, char** prefixdirp);
static int s3objectsinfo(NClist* contents, NClist* keys, NClist* lens);
static int s3commonprefixes(NClist* list, NClist* keys);
static int mergekeysets(NClist*,NClist*,NClist*);
static int rawtokeys(NCbytes* response, NClist* keys, NClist* lengths, struct LISTOBJECTSV2** listv2p);
static int rawtokeys(s3r_buf_t* response, NClist* keys, NClist* lengths, struct LISTOBJECTSV2** listv2p);
static int queryadd(NClist* query, const char* key, const char* value);
static int queryend(NClist* query, char** querystring);
@ -172,7 +172,8 @@ NC_s3sdkcreateclient(NCS3INFO* info)
char* urlroot = NULL;
NCS3CLIENT* s3client = NULL;
NCTRACE(11,NULL);
NCTRACE(11,"info=%s",NC_s3dumps3info(info));
s3client = (NCS3CLIENT*)calloc(1,sizeof(NCS3CLIENT));
if(s3client == NULL) goto done;
if(info->profile != NULL) {
@ -281,23 +282,18 @@ NC_s3sdkread(void* s3client0, const char* bucket, const char* pathkey, size64_t
int stat = NC_NOERR;
NCS3CLIENT* s3client = (NCS3CLIENT*)s3client0;
NCbytes* url = ncbytesnew();
NCbytes* wrap = ncbytesnew();
struct s3r_buf_t data = {0,NULL};
NCTRACE(11,"bucket=%s pathkey=%s start=%llu count=%llu content=%p",bucket,pathkey,start,count,content);
if((stat = makes3fullpath(s3client->rooturl,bucket,pathkey,NULL,url))) goto done;
/* Wrap contents as a byte buffer */
ncbytessetcontents(wrap,content,count);
ncbytessetlength(wrap,0); /* prepare for writing */
/* Read the data */
if((stat = NCH5_s3comms_s3r_read(s3client->h5s3client,ncbytescontents(url),(size_t)start,(size_t)count,wrap))) goto done;
assert(ncbyteslength(wrap) == count);
data.count = count;
data.content = content;
if((stat = NCH5_s3comms_s3r_read(s3client->h5s3client,ncbytescontents(url),(size_t)start,(size_t)count,&data))) goto done;
done:
(void)ncbytesextract(wrap); /* reset the wrapper */
ncbytesfree(wrap);
ncbytesfree(url);
return NCUNTRACE(stat);
}
@ -312,21 +308,18 @@ NC_s3sdkwriteobject(void* s3client0, const char* bucket, const char* pathkey, s
int stat = NC_NOERR;
NCS3CLIENT* s3client = (NCS3CLIENT*)s3client0;
NCbytes* url = ncbytesnew();
NCbytes* wrap = ncbytesnew();
s3r_buf_t data;
NCTRACE(11,"bucket=%s pathkey=%s count=%llu content=%p",bucket,pathkey,count,content);
if((stat = makes3fullpath(s3client->rooturl,bucket,pathkey,NULL,url))) goto done;
/* Wrap contents as a byte buffer */
ncbytessetcontents(wrap,(void*)content,count);
/* Write the data */
if((stat = NCH5_s3comms_s3r_write(s3client->h5s3client,ncbytescontents(url),wrap))) goto done;
data.count = count;
data.content = (void*)content;
if((stat = NCH5_s3comms_s3r_write(s3client->h5s3client,ncbytescontents(url),&data))) goto done;
done:
(void)ncbytesextract(wrap); /* reset the wrapper */
ncbytesfree(wrap);
ncbytesfree(url);
return NCUNTRACE(stat);
}
@ -337,7 +330,7 @@ NC_s3sdkclose(void* s3client0, NCS3INFO* info, int deleteit, char** errmsgp)
int stat = NC_NOERR;
NCS3CLIENT* s3client = (NCS3CLIENT*)s3client0;
NCTRACE(11,"info=%s rootkey=%s deleteit=%d",NC_s3dumps3info(info),deleteit);
NCTRACE(11,"info=%s deleteit=%d",NC_s3dumps3info(info),deleteit);
if(deleteit) {
/* Delete the root key; ok it if does not exist */
@ -347,7 +340,6 @@ NC_s3sdkclose(void* s3client0, NCS3INFO* info, int deleteit, char** errmsgp)
default: break;
}
}
stat = NCH5_s3comms_s3r_close(s3client->h5s3client);
s3client_destroy(s3client);
return NCUNTRACE(stat);
}
@ -363,7 +355,6 @@ getkeys(void* s3client0, const char* bucket, const char* prefixkey0, const char*
{
int stat = NC_NOERR;
NCS3CLIENT* s3client = (NCS3CLIENT*)s3client0;
NCbytes* response = ncbytesnew();
char* prefixdir = NULL;
NClist* query = NULL;
char* querystring = NULL;
@ -373,6 +364,7 @@ getkeys(void* s3client0, const char* bucket, const char* prefixkey0, const char*
struct LISTOBJECTSV2* listv2 = NULL;
int istruncated = 0;
char* continuetoken = NULL;
s3r_buf_t response = {0,NULL};
NCTRACE(11,"bucket=%s prefixkey0=%s",bucket,prefixkey0);
@ -385,7 +377,7 @@ getkeys(void* s3client0, const char* bucket, const char* prefixkey0, const char*
nullfree(querystring);
querystring = NULL;
ncbytesclear(listurl);
ncbytesclear(response);
nullfree(response.content); response.content = NULL; response.count = 0;
/* Make sure order is sorted (after encoding) */
if((stat = queryadd(query,"list-type","2"))) goto done;
if((stat = queryadd(query,"prefix",prefixdir))) goto done;
@ -403,9 +395,8 @@ getkeys(void* s3client0, const char* bucket, const char* prefixkey0, const char*
ncbytescat(listurl,"?");
ncbytescat(listurl,querystring);
if((stat = NCH5_s3comms_s3r_getkeys(s3client->h5s3client, ncbytescontents(listurl), response))) goto done;
ncbytesnull(response);
if((stat = rawtokeys(response,allkeys,NULL,&listv2))) goto done;
if((stat = NCH5_s3comms_s3r_getkeys(s3client->h5s3client, ncbytescontents(listurl), &response))) goto done;
if((stat = rawtokeys(&response,allkeys,NULL,&listv2))) goto done;
istruncated = (strcasecmp(listv2->istruncated,"true")==0?1:0);
nullfree(continuetoken);
continuetoken = nulldup(listv2->nextcontinuationtoken);
@ -422,7 +413,7 @@ done:
nullfree(querystring);
ncurifree(purl);
ncbytesfree(listurl);
ncbytesfree(response);
nullfree(response.content);
if(prefixdir) free(prefixdir);
return NCUNTRACEX(stat,"nkeys=%u",PTRVAL(unsigned,nkeysp,0));
}
@ -459,7 +450,7 @@ NC_s3sdkdeletekey(void* s3client0, const char* bucket, const char* pathkey, char
NCbytes* url = ncbytesnew();
long httpcode = 0;
NCTRACE(11,"bucket=%s pathkey=%s",bucket,pathkey);
NCTRACE(11,"s3client0=%p bucket=%s pathkey=%s",s3client0,bucket,pathkey);
if((stat = makes3fullpath(s3client->rooturl,bucket,pathkey,NULL,url))) goto done;
@ -477,14 +468,14 @@ done:
Convert raw getkeys response to vector of keys
*/
static int
rawtokeys(NCbytes* response, NClist* allkeys, NClist* lengths, struct LISTOBJECTSV2** listv2p)
rawtokeys(s3r_buf_t* response, NClist* allkeys, NClist* lengths, struct LISTOBJECTSV2** listv2p)
{
int stat = NC_NOERR;
struct LISTOBJECTSV2* listv2 = NULL;
NClist* realkeys = nclistnew();
NClist* commonkeys = nclistnew();
if((stat = parse_listbucketresult(ncbytescontents(response),ncbyteslength(response),&listv2))) goto done;
if((stat = parse_listbucketresult(response->content,response->count,&listv2))) goto done;
if(nclistlength(listv2->contents) > 0) {
if((stat = s3objectsinfo(listv2->contents,realkeys,lengths))) goto done;
@ -589,6 +580,7 @@ s3client_destroy(NCS3CLIENT* s3client)
{
if(s3client) {
nullfree(s3client->rooturl);
(void)NCH5_s3comms_s3r_close(s3client->h5s3client);
free(s3client);
}
}
@ -636,7 +628,7 @@ HTTP/1.1 200
*/
static int
parse_listbucketresult(char* xml, size_t xmllen, struct LISTOBJECTSV2** resultp)
parse_listbucketresult(char* xml, unsigned long long xmllen, struct LISTOBJECTSV2** resultp)
{
int stat = NC_NOERR;
ncxml_doc_t doc = NULL;
@ -990,19 +982,14 @@ static int
queryadd(NClist* query, const char* key, const char* value)
{
int stat = NC_NOERR;
NCbytes* buf = NULL;
char* ekey = NULL;
char* evalue = NULL;
if(key == NULL) {stat = NC_EINVAL; goto done;}
buf = ncbytesnew();
if((stat = NCH5_s3comms_uriencode(buf, key, strlen(key), 1/*true*/, NULL))) goto done;
ekey = ncbytesextract(buf);
if((stat = NCH5_s3comms_uriencode(&ekey, key, strlen(key), 1/*true*/, NULL))) goto done;
evalue = NULL;
if(value != NULL) {
ncbytesclear(buf);
if((stat = NCH5_s3comms_uriencode(buf, value, strlen(value), 1/*true*/, NULL))) goto done;
evalue = ncbytesextract(buf);
if((stat = NCH5_s3comms_uriencode(&evalue, value, strlen(value), 1/*true*/, NULL))) goto done;
}
/* Insert encoded key+value keeping sorted order */
if((stat = queryinsert(query, ekey, evalue))) goto done;
@ -1011,7 +998,6 @@ queryadd(NClist* query, const char* key, const char* value)
done:
nullfree(ekey);
nullfree(evalue);
ncbytesfree(buf);
return NCTHROW(stat);
}

242
libdispatch/ncutil.h Normal file
View File

@ -0,0 +1,242 @@
/* Copyright 2018, UCAR/Unidata and OPeNDAP, Inc.
See the COPYRIGHT file for more information. */
#ifndef UTILS_H
#define UTILS_H 1
/* Define a header-only simple version of a dynamically expandable list and byte buffer */
/* To be used in code that should be independent of libnetcdf */
typedef struct VList {
unsigned alloc;
unsigned length;
void** content;
} VList;
typedef struct VString {
int nonextendible; /* 1 => fail if an attempt is made to extend this string*/
unsigned int alloc;
unsigned int length;
char* content;
} VString;
/* VString has a fixed expansion size */
#define VSTRALLOC 64
#if defined(_CPLUSPLUS_) || defined(__CPLUSPLUS__)
#define EXTERNC extern "C"
#else
#define EXTERNC extern
#endif
static int util_initialized = 0;
static void util_initialize(void);
static VList*
vlistnew(void)
{
VList* l;
if(!util_initialized) util_initialize();
l = (VList*)calloc(1,sizeof(VList));
assert(l != NULL);
return l;
}
static void
vlistfree(VList* l)
{
if(l == NULL) return;
if(l->content != NULL) {free(l->content); l->content = NULL;}
free(l);
}
static void
vlistexpand(VList* l)
{
void** newcontent = NULL;
size_t newsz;
if(l == NULL) return;
newsz = (l->length * 2) + 1; /* basically double allocated space */
if(l->alloc >= newsz) return; /* space already allocated */
newcontent=(void**)calloc(newsz,sizeof(void*));
assert(newcontent != NULL);
if(l->alloc > 0 && l->length > 0 && l->content != NULL) { /* something to copy */
memcpy((void*)newcontent,(void*)l->content,sizeof(void*)*l->length);
}
if(l->content != NULL) free(l->content);
l->content=newcontent;
l->alloc=newsz;
/* size is the same */
}
static void*
vlistget(VList* l, unsigned index) /* Return the ith element of l */
{
if(l == NULL || l->length == 0) return NULL;
assert(index < l->length);
return l->content[index];
}
static void
vlistpush(VList* l, void* elem)
{
if(l == NULL) return;
while(l->length >= l->alloc) vlistexpand(l);
l->content[l->length] = elem;
l->length++;
}
static void*
vlistfirst(VList* l) /* remove first element */
{
unsigned i,len;
void* elem;
if(l == NULL || l->length == 0) return NULL;
elem = l->content[0];
len = l->length;
for(i=1;i<len;i++) l->content[i-1] = l->content[i];
l->length--;
return elem;
}
static void
vlistfreeall(VList* l) /* call free() on each list element*/
{
unsigned i;
if(l == NULL || l->length == 0) return;
for(i=0;i<l->length;i++) if(l->content[i] != NULL) {free(l->content[i]);}
vlistfree(l);
}
static VString*
vsnew(void)
{
VString* vs = NULL;
if(!util_initialized) util_initialize();
vs = (VString*)calloc(1,sizeof(VString));
assert(vs != NULL);
return vs;
}
static void
vsfree(VString* vs)
{
if(vs == NULL) return;
if(vs->content != NULL) free(vs->content);
free(vs);
}
static void
vsexpand(VString* vs)
{
char* newcontent = NULL;
size_t newsz;
if(vs == NULL) return;
assert(vs->nonextendible == 0);
newsz = (vs->alloc + VSTRALLOC); /* basically double allocated space */
if(vs->alloc >= newsz) return; /* space already allocated */
newcontent=(char*)calloc(1,newsz+1);/* always room for nul term */
assert(newcontent != NULL);
if(vs->alloc > 0 && vs->length > 0 && vs->content != NULL) /* something to copy */
memcpy((void*)newcontent,(void*)vs->content,vs->length);
newcontent[vs->length] = '\0'; /* ensure null terminated */
if(vs->content != NULL) free(vs->content);
vs->content=newcontent;
vs->alloc=newsz;
/* length is the same */
}
static void
vsappendn(VString* vs, const char* elem, unsigned n)
{
size_t need;
assert(vs != NULL && elem != NULL);
if(n == 0) {n = strlen(elem);}
need = vs->length + n;
if(vs->nonextendible) {
/* Space must already be available */
assert(vs->alloc >= need);
} else {
while(vs->alloc < need)
vsexpand(vs);
}
memcpy(&vs->content[vs->length],elem,n);
vs->length += n;
if(!vs->nonextendible)
vs->content[vs->length] = '\0';
}
static void
vsappend(VString* vs, char elem)
{
char s[2];
s[0] = elem;
s[1] = '\0';
vsappendn(vs,s,1);
}
/* Set unexpandible contents */
static void
vssetcontents(VString* vs, char* contents, unsigned alloc)
{
assert(vs != NULL && contents != NULL);
vs->length = 0;
if(!vs->nonextendible && vs->content != NULL) free(vs->content);
vs->content = contents;
vs->length = alloc;
vs->alloc = alloc;
vs->nonextendible = 1;
}
/* Extract the content and leave content null */
static char*
vsextract(VString* vs)
{
char* x = NULL;
if(vs == NULL || vs->content == NULL) return NULL;
x = vs->content;
vs->content = NULL;
vs->length = 0;
vs->alloc = 0;
return x;
}
static void
util_initialize(void)
{
/* quiet compiler */
void* f = NULL;
f = f;
f = (void*)vlistnew;
f = (void*)vlistfree;
f = (void*)vlistexpand;
f = (void*)vlistget;
f = (void*)vlistpush;
f = (void*)vlistfirst;
f = (void*)vlistfreeall;
f = (void*)vsnew;
f = (void*)vsfree;
f = (void*)vsexpand;
f = (void*)vssetcontents;
f = (void*)vsappendn;
f = (void*)vsappend;
f = (void*)vsextract;
util_initialized = 1;
}
/* Following are always "in-lined"*/
#define vlistcontents(l) ((l)==NULL?NULL:(l)->content)
#define vlistlength(l) ((l)==NULL?0:(int)(l)->length)
#define vlistclear(l) vlistsetlength(l,0)
#define vlistsetlength(l,len) do{if((l)!=NULL) (l)->length=len;} while(0)
#define vscontents(vs) ((vs)==NULL?NULL:(vs)->content)
#define vslength(vs) ((vs)==NULL?0:(int)(vs)->length)
#define vscat(vs,s) vsappendn(vs,s,0)
#define vsclear(vs) vssetlength(vs,0)
#define vssetlength(vs,len) do{if((vs)!=NULL) (vs)->length=len;} while(0)
#endif /*UTILS_H*/

View File

@ -12,15 +12,17 @@ if test "x$FEATURE_THREDDSTEST" = x1 ; then
URL3="https://thredds-test.unidata.ucar.edu/thredds/fileServer/pointData/cf_dsg/example/point.nc#mode=bytes"
URL4b="https://thredds-test.unidata.ucar.edu/thredds/fileServer/irma/metar/files/METAR_20170910_0000.nc#bytes"
fi
if test "x$FEATURE_S3TESTS" = xyes ; then
if test "x$FEATURE_S3TESTS" != xno ; then
URL4a="https://s3.us-east-1.amazonaws.com/noaa-goes16/ABI-L1b-RadC/2017/059/03/OR_ABI-L1b-RadC-M3C13_G16_s20170590337505_e20170590340289_c20170590340316.nc#mode=bytes"
URL4c="s3://noaa-goes16/ABI-L1b-RadC/2017/059/03/OR_ABI-L1b-RadC-M3C13_G16_s20170590337505_e20170590340289_c20170590340316.nc#mode=bytes"
# Test alternate URL with no specified region
URL4e="http://noaa-goes16.s3.amazonaws.com/ABI-L1b-RadF/2022/001/18/OR_ABI-L1b-RadF-M6C01_G16_s20220011800205_e20220011809513_c20220011809562.nc#mode=bytes,s3"
fi
if test "x$FEATURE_S3TESTS" = xyes ; then
# Requires auth
URL3b="s3://unidata-zarr-test-data/byterangefiles/upload3.nc#bytes"
# Requires auth
URL4d="s3://unidata-zarr-test-data/byterangefiles/upload4.nc#bytes&aws.profile=unidata"
# Test alternate URL with no specified region
URL4e="http://noaa-goes16.s3.amazonaws.com/ABI-L1b-RadF/2022/001/18/OR_ABI-L1b-RadF-M6C01_G16_s20220011800205_e20220011809513_c20220011809562.nc#mode=bytes,s3"
fi
URL4f="https://crudata.uea.ac.uk/cru/data/temperature/HadCRUT.4.6.0.0.median.nc#mode=bytes"
@ -33,7 +35,6 @@ echo ""
testsetup() {
U=$1
# Create and upload test files
if test "x$FEATURE_S3TESTS" = xyes ; then
rm -f upload4.nc upload3.nc
${execdir}/../nczarr_test/s3util -u ${U} -k /byterangefiles clear
${NCGEN} -lb -3 ${srcdir}/nc_enddef.cdl
@ -44,16 +45,13 @@ ${NCGEN} -lb -4 ${srcdir}/nc_enddef.cdl
mv nc_enddef.nc upload4.nc
${execdir}/../nczarr_test/s3util -u ${U} -k /byterangefiles/upload4.nc -f upload4.nc upload
fi
fi
rm -f tst_http_nc3.cdl tst_http_nc4?.cdl
}
testcleanup() {
U=$1
rm -f upload4.nc upload3.nc
if test "x$FEATURE_S3TESTS" = xyes ; then
${execdir}/../nczarr_test/s3util -u ${U} -k /byterangefiles clear
fi
}
testbytes() {
@ -105,23 +103,31 @@ if test "x$FEATURE_HDF5" = xyes ; then
testbytes nc4f netCDF-4 "$URL4f"
fi
if test "x$FEATURE_S3" = xyes ; then
if test "x$URL3B" != x ; then
echo "***Test remote netcdf-3 file: s3 auth"
tests3auth nc3b classic "$URL3b"
fi
if test "x$FEATURE_S3" = xyes && test "x$FEATURE_HDF5" = xyes ; then
if test "x$URL4a" != x ; then
echo "***Test remote netdf-4 file: s3"
testbytes nc4a netCDF-4 "$URL4a"
fi
if test "x$URL4c" != x ; then
echo "***Test remote netcdf-4 file: s3"
testbytes nc4c netCDF-4 "$URL4c"
fi
if test "x$URL4d" != x ; then
echo "***Test remote netcdf-4 file: s3 auth"
tests3auth nc4d netCDF-4 "$URL4d"
fi
if test "x$URL4e" != x ; then
echo "***Test remote netcdf-4 file: s3 noauth"
testbytes nc4e netCDF-4 "$URL4e"
fi
# Cleanup
if test "x$FEATURE_S3TESTS" = xyes ; then
testcleanup https://s3.us-east-1.amazonaws.com/unidata-zarr-test-data
fi
exit

View File

@ -76,16 +76,18 @@ IF(ENABLE_TESTS)
TARGET_INCLUDE_DIRECTORIES(tst_fillonlyz PUBLIC ../libnczarr)
# Helper programs for testing
BUILD_BIN_TEST(zmapio ${COMMONSRC})
TARGET_INCLUDE_DIRECTORIES(zmapio PUBLIC ../libnczarr)
BUILD_BIN_TEST(zhex)
BUILD_BIN_TEST(zisjson ${COMMONSRC})
TARGET_INCLUDE_DIRECTORIES(zisjson PUBLIC ../libnczarr)
BUILD_BIN_TEST(zs3parse ${COMMONSRC})
TARGET_INCLUDE_DIRECTORIES(zs3parse PUBLIC ../libnczarr)
if(ENABLE_S3)
BUILD_BIN_TEST(s3util ${COMMONSRC})
TARGET_INCLUDE_DIRECTORIES(s3util PUBLIC ../libnczarr)
BUILD_BIN_TEST(zmapio ${COMMONSRC})
TARGET_INCLUDE_DIRECTORIES(zmapio PUBLIC ../libnczarr)
IF(ENABLE_S3 AND NOT WITH_S3_TESTING STREQUAL "NO")
# Helper programs for testing
BUILD_BIN_TEST(s3util ${COMMONSRC})
TARGET_INCLUDE_DIRECTORIES(s3util PUBLIC ../libnczarr)
endif()
SET(ncdumpchunks_SOURCE ncdumpchunks.c)

View File

@ -113,12 +113,12 @@ endif #ENABLE_FILTER_TESTING
endif #BUILD_UTILITIES
# These programs are used by the test cases
noinst_PROGRAMS = zmapio
zmapio_SOURCES = zmapio.c
noinst_PROGRAMS += zhex
noinst_PROGRAMS = zhex
zhex_SOURCES = zhex.c
noinst_PROGRAMS += zisjson
zisjson_SOURCES = zisjson.c
noinst_PROGRAMS += zmapio
zmapio_SOURCES = zmapio.c
noinst_PROGRAMS += zs3parse
zs3parse_SOURCES = zs3parse.c

View File

@ -131,8 +131,6 @@ echo "Test miscellaneous 1"
makefile tmp_misc1
rm -f tmp_misc1_${zext}.txt tmp_misc1_${zext}.cdl
$TC -d 6,12,4 -c 2,3,1 -f 0,0,0 -e 6,1,4 -Ow $F
ls
ls -1 ${execdir}
if test "x$FEATURE_S3TESTS" = xyes ; then
${S3UTIL} -u 'https://s3.us-east-1.amazonaws.com/unidata-zarr-test-data' -k '/netcdf-c' list
fi

View File

@ -90,4 +90,3 @@ if test "x$FEATURE_NCZARR_ZIP" = xyes ; then testallcases zip; fi
if test "x$FEATURE_S3TESTS" = xyes ; then testallcases s3; fi
if test "x$FEATURE_S3TESTS" = xyes ; then s3sdkdelete "/${S3ISOPATH}" ; fi # Cleanup

View File

@ -182,6 +182,8 @@ atexit() {
trap atexit_cleanup EXIT
}
GDBB="gdb -batch -ex r -ex bt -ex q --args"
resetrc
atexit

View File

@ -286,6 +286,7 @@ rootpathfor(const char* path)
case NCZM_ZIP:
rootpath = strdup("/"); /*constant*/
break;
#ifdef ENABLE_S3
case NCZM_S3:
/* Split the path part */
if((stat = nczm_split(uri->path,segments))) goto done;
@ -295,6 +296,7 @@ rootpathfor(const char* path)
/* Put it back together */
if((stat = nczm_join(segments,&rootpath))) goto done;
break;
#endif
default:
stat = NC_EINVAL;
goto done;

View File

@ -38,7 +38,7 @@ FEATURE_S3_AWS=@HAS_S3_AWS@
FEATURE_S3_INTERNAL=@HAS_S3_INTERNAL@
FEATURE_S3=@HAS_S3@
FEATURE_NCZARR=@HAS_NCZARR@
FEATURE_S3TESTS=@DO_NCZARR_S3_TESTS@
FEATURE_S3TESTS=@DO_S3_TESTING@
FEATURE_NCZARR_ZIP=@DO_NCZARR_ZIP_TESTS@
FEATURE_LARGE_TESTS=@DO_LARGE_TESTS@

View File

@ -33,7 +33,7 @@ ENDFOREACH()
add_bin_test(unit_test test_pathcvt)
IF(BUILD_UTILITIES)
IF(ENABLE_S3)
IF(ENABLE_S3 AND WITH_S3_TESTING)
# SDK Test
BUILD_BIN_TEST(test_s3sdk ${XGETOPTSRC})
ADD_SH_TEST(unit_test run_s3sdk)

View File

@ -8,9 +8,9 @@
# Ed Hartnett 8/9/19
SH_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver-verbose
sh_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver-verbose
LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver-verbose
#SH_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver-verbose
#sh_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver-verbose
#LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver-verbose
#TESTS_ENVIRONMENT = export SETX=1;
# Put together AM_CPPFLAGS and AM_LDFLAGS.
@ -38,9 +38,11 @@ TESTS += tst_nc4internal
endif # USE_NETCDF4
if ENABLE_S3
if ENABLE_S3_TESTALL
check_PROGRAMS += test_s3sdk
TESTS += run_s3sdk.sh
endif
endif
EXTRA_DIST = CMakeLists.txt run_s3sdk.sh
EXTRA_DIST += nctest_netcdf4_classic.nc

View File

@ -362,7 +362,6 @@ testsearch(void)
done:
cleanup();
NC_s3sdkclose(s3client,&s3info,0,NULL); s3client = NULL;
for(i=0;i<nkeys;i++) nullfree(keys[i]);
nullfree(keys);
return stat;