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

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

C++初心者がMacでAWS SDK for C++を利用してAmazon DynamoDBにアクセスする – Qiita
https://cloudpack.media/45913

C++初心者がDockerで開発環境をつくってみた – Qiita
https://cloudpack.media/46001

S3互換のオブジェクトストレージ MinioをDocker Composeで利用する – Qiita
https://cloudpack.media/46077

実装

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://cloudpack.media/45913

C++初心者がDockerで開発環境をつくってみた – Qiita
https://cloudpack.media/46001

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://cloudpack.media/46077

元記事はこちら

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