Edited at

S3互換のオブジェクトストレージ MinioにAWS SDK for C++でアクセスするのにハマるポイント

AWS SDK for C++を利用した開発でMinioを利用する際にハマったのでメモ。

AWS SDK for C++とMinioについては下記をご参考ください。

C++初心者がMacでAWS SDK for C++を利用してAmazon DynamoDBにアクセスする - Qiita

https://qiita.com/kai_kou/items/fe9e3525d2023dc955a5

C++初心者がDockerで開発環境をつくってみた - Qiita

https://qiita.com/kai_kou/items/1f4b9a45a5d4d6788649

S3互換のオブジェクトストレージ MinioをDocker Composeで利用する - Qiita

https://qiita.com/kai_kou/items/9fe06d4d24928d9efa2a


実装

AWS SDK for C++のバージョンは1.6.0となります。(2019/02/18時点)

aws/aws-sdk-cpp: AWS SDK for C++

https://github.com/aws/aws-sdk-cpp

下記のサンプルのエンドポイントをMinioに変更して動作するようにします。

C++ Code Samples for Amazon S3 - AWS Code Sample

https://docs.aws.amazon.com/ja_jp/code-samples/latest/catalog/code-catalog-cpp-example_code-s3.html

put_object.cpp - AWS Code Sample

https://docs.aws.amazon.com/ja_jp/code-samples/latest/catalog/cpp-s3-put_object.cpp.html


put_object.cpp

/*

Copyright 2010-2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.

This file is licensed under the Apache License, Version 2.0 (the "License").
You may not use this file except in compliance with the License. A copy of
the License is located at

http://aws.amazon.com/apache2.0/

This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
*/
#include <aws/core/Aws.h>
#include <aws/s3/S3Client.h>
#include <aws/s3/model/PutObjectRequest.h>
#include <iostream>
#include <fstream>

/**
* Put an object from an Amazon S3 bucket.
*/

int main(int argc, char** argv)
{
if (argc < 4)
{
std::cout << std::endl <<
"To run this example, supply the name of an S3 bucket, destination key, and file to upload."
<< std::endl << std::endl <<
"Ex: put_object <bucketname> <keyname> <filename> <optional:region>" << std::endl;
exit(1);
}

Aws::SDKOptions options;
Aws::InitAPI(options);
{
const Aws::String bucket_name = argv[1];
const Aws::String key_name = argv[2];
const Aws::String file_name = argv[3];
const Aws::String region(argc > 4 ? argv[4] : "");

std::cout << "Uploading " << file_name << " to S3 bucket " <<
bucket_name << " at key " << key_name << std::endl;

Aws::Client::ClientConfiguration clientConfig;
if (!region.empty())
clientConfig.region = region;
Aws::S3::S3Client s3_client(clientConfig);

Aws::S3::Model::PutObjectRequest object_request;
object_request.WithBucket(bucket_name).WithKey(key_name);

// Binary files must also have the std::ios_base::bin flag or'ed in
auto input_data = Aws::MakeShared<Aws::FStream>("PutObjectInputStream",
file_name.c_str(), std::ios_base::in | std::ios_base::binary);

object_request.SetBody(input_data);

auto put_object_outcome = s3_client.PutObject(object_request);

if (put_object_outcome.IsSuccess())
{
std::cout << "Done!" << std::endl;
}
else
{
std::cout << "PutObject error: " <<
put_object_outcome.GetError().GetExceptionName() << " " <<
put_object_outcome.GetError().GetMessage() << std::endl;
}
}
Aws::ShutdownAPI(options);
}


上記サンプルで、Minioへアクセスするようにエンドポイントを指定してやればよいわけですが、いろいろとハマったのでポイントです。


エンドポイントの指定はendpointOverrideschemeを利用する

Aws::Client::ClientConfiguration にあるendpointOverride でエンドポイントが指定できます。HTTPアクセスの場合、scheme の指定も必要です。

AWS SDK for C++: Aws::Client::ClientConfiguration Struct Reference

https://sdk.amazonaws.com/cpp/api/LATEST/struct_aws_1_1_client_1_1_client_configuration.html


put_object.cpp_一部抜粋

    Aws::Client::ClientConfiguration clientConfig;

if (!region.empty())
clientConfig.region = region;
clientConfig.scheme = Aws::Http::Scheme::HTTP;
clientConfig.endpointOverride = endpoint;

公式のドキュメントをみるとauthenticationRegion の指定も必要とありますが、最新バージョン1.6.0 (2019/02/18時点)では定義されていませんので気をつけましょう。

古いドキュメント

AWS Client Configuration - AWS SDK for C++

https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/client-config.html

古いドキュメント

AWS SDK for C++: Aws::Client::ClientConfiguration Struct Reference

https://sdk.amazonaws.com/cpp/api/0.12.9/df/d19/struct_aws_1_1_client_1_1_client_configuration.html


S3Client 作成時にuseVirtualAdressing を無効にする

Minioのエンドポイントがlocalhost:9000 となり、useVirtualAdressing が有効の場合、アクセスすることができません。

useVirtualAdressing を指定するコンストラクタではCredentials などを渡す必要があるため、Aws::Auth::EnvironmentAWSCredentialsProvider().GetAWSCredentials()を利用します。アクセスキーとシークレットをパラメータにCredentials を作成してもOKです。

AWS SDK for C++: Aws::S3::S3Client Class Reference

https://sdk.amazonaws.com/cpp/api/LATEST/class_aws_1_1_s3_1_1_s3_client.html#ac8168b12d0e630dcdc5cd912d38d8787

VirtualAdressing (仮想ホスト形式)については下記が参考になります。

S3のバケットURL(仮想ホスト形式とパス形式) - Qiita

https://qiita.com/ryo0301/items/48120379b240ab071028

AWS CLIのS3接続先の選択動作とaddressing_styleオプション - おぎろぐはてブロ

https://iogi.hatenablog.com/entry/s3-addressing-style


put_object.cpp_一部抜粋

#include <aws/core/auth/AWSCredentialsProvider.h>

#include <aws/core/auth/AWSAuthSigner.h>

()

// 環境変数などから認証情報を取得する
Aws::Auth::AWSCredentials cred = Aws::Auth::EnvironmentAWSCredentialsProvider().GetAWSCredentials();
// useVirtualAdressingをfalseにする
Aws::S3::S3Client s3_client(cred, clientConfig, Aws::Client::AWSAuthV4Signer::PayloadSigningPolicy::Never, false);


こちらも過去バージョンだとS3Clientコストラクタのパラメータが一部異なるので注意しましょう。

古いドキュメント

AWS SDK for C++: Aws::S3::S3Client Class Reference

https://sdk.amazonaws.com/cpp/api/0.12.9/d7/db7/class_aws_1_1_s3_1_1_s3_client.html


まとめ

AWS SDK for C++のバージョンによって仕様が異なり、ネットで検索して得られる情報では解決できない可能性がありますので、最終的には実装や最新のドキュメントを確認するようにしましょう。


参考

C++初心者がMacでAWS SDK for C++を利用してAmazon DynamoDBにアクセスする - Qiita

https://qiita.com/kai_kou/items/fe9e3525d2023dc955a5

C++初心者がDockerで開発環境をつくってみた - Qiita

https://qiita.com/kai_kou/items/1f4b9a45a5d4d6788649

aws/aws-sdk-cpp: AWS SDK for C++

https://github.com/aws/aws-sdk-cpp

C++ Code Samples for Amazon S3 - AWS Code Sample

https://docs.aws.amazon.com/ja_jp/code-samples/latest/catalog/code-catalog-cpp-example_code-s3.html

put_object.cpp - AWS Code Sample

https://docs.aws.amazon.com/ja_jp/code-samples/latest/catalog/cpp-s3-put_object.cpp.html

AWS SDK for C++: Aws::Client::ClientConfiguration Struct Reference

https://sdk.amazonaws.com/cpp/api/LATEST/struct_aws_1_1_client_1_1_client_configuration.html

AWS SDK for C++: Aws::S3::S3Client Class Reference

https://sdk.amazonaws.com/cpp/api/LATEST/class_aws_1_1_s3_1_1_s3_client.html#ac8168b12d0e630dcdc5cd912d38d8787

S3のバケットURL(仮想ホスト形式とパス形式) - Qiita

https://qiita.com/ryo0301/items/48120379b240ab071028

AWS CLIのS3接続先の選択動作とaddressing_styleオプション - おぎろぐはてブロ

https://iogi.hatenablog.com/entry/s3-addressing-style

S3互換のオブジェクトストレージ MinioをDocker Composeで利用する - Qiita

https://qiita.com/kai_kou/items/9fe06d4d24928d9efa2a