MochiuWiki : SUSE, EC, PCB
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
Qtの応用 - AWS Lambdaのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
Qtの応用 - AWS Lambda
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == <br><br> == AWS SDK for C++のインストール == [[Qtの応用_-_AWS|Qtの応用_-_AWS#AWS_SDK_for_C++のインストール]]のページを参照すること。<br> <br><br> ==== AWS認証情報 ==== AWS SDKのメソッドを使用する前に、以下に示すいずれかの方法でAWS認証情報を設定する必要がある。<br> <br> * 環境変数 ** AWS_ACCESS_KEY_ID **: AWSアクセスキーID ** AWS_SECRET_ACCESS_KEY **: AWSシークレットアクセスキー ** AWS_SESSION_TOKEN **: 一時認証情報を使用する場合のセッショントークン *: <br> * AWS認証情報ファイル<br>~/.aws/credentialsファイル *: <syntaxhighlight lang="ini"> [default] aws_access_key_id = <アクセスキーID> aws_secret_access_key = <シークレットアクセスキー> </syntaxhighlight> *: <br> * IAMロール ** EC2インスタンスやLambda関数内で実行する場合 ** IAMロールが自動的にアタッチされ、認証情報の管理が不要 *: <br> * AWS SDK設定ファイル<br>~/.aws/configファイル *: <syntaxhighlight lang="ini"> [default] region = <リージョン名 例 : us-east-1> output = json </syntaxhighlight> <br><br> == Lambdaクライアントの初期化 == 指定されたリージョンでLambdaクライアントを初期化する。<br> <br> <syntaxhighlight lang="c++"> #include <aws/lambda/LambdaClient.h> QString region = "<リージョン名>" // Aws::Client::ClientConfiguration // AWS SDKのクライアント設定を保持するオブジェクト // リージョン、エンドポイント、タイムアウト、リトライ設定などを指定できる Aws::Client::ClientConfiguration clientConfig; // clientConfig.region // Lambda関数が配置されているAWSリージョンを指定する // 例 : "us-east-1", "ap-northeast-1", "eu-west-1" clientConfig.region = region.toStdString(); // Aws::Lambda::LambdaClient // AWS Lambda APIとの通信を行うクライアントクラス // 全てのLambda操作 (Invoke, ListFunctions等) はこのクライアントを通じて実行される auto lambdaClient = std::make_unique<Aws::Lambda::LambdaClient>(clientConfig); </syntaxhighlight> <br><br> == Lambda関数の呼び出し == Lambda関数を呼び出し、レスポンスを取得する。<br> <br> 以下の例では、同期呼び出し、非同期呼び出し、ドライランに対応している。<br> <br> <syntaxhighlight lang="c++"> #include <aws/lambda/LambdaClient.h> #include <aws/lambda/model/InvokeRequest.h> // Aws::Lambda::Model::InvokeRequest // Lambda関数呼び出しリクエストを表すクラス // 関数名、ペイロード、呼び出しタイプ、ログタイプ等を設定する Aws::Lambda::Model::InvokeRequest request; // SetFunctionName() // 呼び出すLambda関数の名前またはARN(Amazon Resource Name)を指定する // 例 : "my-function" または "arn:aws:lambda:us-east-1:123456789012:function:my-function" request.SetFunctionName(functionName.toStdString()); // InvocationType (呼び出しタイプ) の設定 // Lambda関数の呼び出し方法を指定する列挙型 if (invocationType == "RequestResponse") { // RequestResponse - 同期呼び出し // 関数の実行完了を待ち、結果(レスポンスペイロード)を返す // リアルタイムで結果が必要な場合に使用 request.SetInvocationType(Aws::Lambda::Model::InvocationType::RequestResponse); } else if (invocationType == "Event") { // Event - 非同期呼び出し // 関数をイベントキューに追加し、すぐに制御を返す(結果は返らない) // 処理の完了を待つ必要がない場合に使用 request.SetInvocationType(Aws::Lambda::Model::InvocationType::Event); } else if (invocationType == "DryRun") { // DryRun - テスト呼び出し // 実際には関数を実行せず、アクセス許可のみを検証する // 本番実行前の権限チェックに使用 request.SetInvocationType(Aws::Lambda::Model::InvocationType::DryRun); } // LogType(ログタイプ)の設定 // 実行ログの取得方法を指定する列挙型 if (logType == "Tail") { // Tail - 最後の4KBの実行ログをBase64エンコードして返す // デバッグ時に関数の実行状況を確認する場合に使用 request.SetLogType(Aws::Lambda::Model::LogType::Tail); } else { // None - ログを返さない // ログが不要な場合に使用 (デフォルト) request.SetLogType(Aws::Lambda::Model::LogType::None); } // SetBody() - ペイロード (入力データ) の設定 // Lambda関数に渡すデータを設定する (JSON形式が一般的) // Aws::MakeShared // AWS SDKのメモリアロケータを使用してshared_ptrを作成する関数 // 第1引数は識別用のタグ (メモリトラッキング用) std::shared_ptr<Aws::IOStream> payload_stream = Aws::MakeShared<Aws::StringStream>("PayloadStream"); *payload_stream << payload.toStdString(); request.SetBody(payload_stream); // Invoke() - Lambda関数を実際に呼び出すメソッド // 戻り値はOutcomeオブジェクト (成功 / 失敗の結果を保持) // // Outcome // AWS SDK for C++の結果を表すテンプレートクラス // 成功時はGetResult(), 失敗時はGetError()でアクセスする auto outcome = m_lambdaClient->Invoke(request); // IsSuccess() - 呼び出しが成功したかをチェック if (outcome.IsSuccess()) { // GetResult() - 成功時の結果オブジェクトを取得 const auto& result = outcome.GetResult(); // GetStatusCode() // HTTPステータスコードを取得 // 通常、成功時は200が返る int statusCode = result.GetStatusCode(); // GetFunctionError() // Lambda関数内でエラーが発生した場合、エラータイプを返す // "Handled" - 関数コード内でキャッチされたエラー // "Unhandled" - 関数コードでキャッチされなかったエラー // 空文字列 - エラーなし std::string functionError = result.GetFunctionError(); // GetPayload() // Lambda関数から返されたレスポンスデータのストリームを取得 // 通常、JSON形式のデータが返される auto& payload_stream = result.GetPayload(); std::stringstream ss; ss << payload_stream.rdbuf(); std::string response_payload = ss.str(); // GetLogResult() // 実行ログ (Base64エンコード済み) を取得 // LogType::Tailを指定した場合のみ利用可能 // デコードすることで関数の実行ログ (print文やエラーメッセージ等) を確認できる std::string logResult = result.GetLogResult(); return true; } else { // GetError() - 失敗時のエラー情報を取得 // GetMessage() - エラーメッセージを取得 std::cerr << "✗ 呼び出し失敗: " << outcome.GetError().GetMessage() << std::endl; return false; } </syntaxhighlight> <br><br> == Lambda関数の一覧の取得 == アカウント内に存在するLambda関数の一覧を取得する。<br> 関数の基本情報 (ランタイム、メモリ、タイムアウト等) も同時に取得することができる。<br> <br> <syntaxhighlight lang="c++"> #include <aws/lambda/LambdaClient.h> #include <aws/lambda/model/ListFunctionsRequest.h> // Aws::Lambda::Model::ListFunctionsRequest // Lambda関数一覧取得リクエストを表すクラス // オプションで最大取得数 (MaxItems) や ページネーショントークン (Marker) を設定できる Aws::Lambda::Model::ListFunctionsRequest request; // ListFunctions() // アカウント内のLambda関数一覧を取得するメソッド // 指定したリージョン内の全ての関数情報を返す auto outcome = m_lambdaClient->ListFunctions(request); // IsSuccess() : 呼び出しが成功したかをチェック if (outcome.IsSuccess()) { // GetResult() - 成功時の結果オブジェクトを取得 const auto& result = outcome.GetResult(); // GetFunctions() // Lambda関数設定のベクトル (std::vector) を返す // 各要素はFunctionConfigurationオブジェクト (個々のLambda関数の設定情報) const auto& functions = result.GetFunctions(); // 各関数の情報を取得 for (const auto& func : functions) { // GetFunctionName() // Lambda関数の名前を取得 // 例 : "my-function", "data-processor", "api-handler" std::string functionName = func.GetFunctionName(); // GetHandler() // Lambda関数のハンドラを取得 // ハンドラは関数のエントリーポイントを指定する // 例 : "index.handler" (Node.js), "lambda_function.lambda_handler" (Python) std::string handler = func.GetHandler(); // GetRuntime() // Lambda関数のランタイム環境を列挙型で取得 // 例 : Python3_9, nodejs18_x, java17, dotnet6, go1_x, ruby3_2 Aws::Lambda::Model::Runtime runtime = func.GetRuntime(); // RuntimeMapper::GetNameForRuntime() // Runtime列挙型を文字列表現に変換するユーティリティメソッド // 例 : Runtime::Python3_9 → "python3.9" std::string runtimeName = Aws::Lambda::Model::RuntimeMapper::GetNameForRuntime(runtime); // GetMemorySize() // Lambda関数に割り当てられたメモリサイズ (MB単位) を取得 // 設定可能範囲 : 128[MB]~10,240[MB] (10[GB]) // メモリサイズに比例してCPUパワーも増加する int memorySize = func.GetMemorySize(); // GetTimeout() // Lambda関数のタイムアウト時間 (秒単位) を取得 // 設定可能範囲: 1秒~900秒 (15分) // この時間を超えると関数の実行が強制終了される int timeout = func.GetTimeout(); // GetLastModified() // 関数が最後に更新された日時をISO 8601形式で取得 // 例 : "2024-01-15T10:30:45.123+0000" std::string lastModified = func.GetLastModified(); // GetFunctionArn() // Lambda関数のAmazon Resource Name (ARN) を取得 // ARNは関数を一意に識別するグローバル識別子 // 例 : "arn:aws:lambda:us-east-1:123456789012:function:my-function" std::string functionArn = func.GetFunctionArn(); // GetDescription() // Lambda関数の説明文を取得 // コンソールやCLIで設定した関数の説明を返す std::string description = func.GetDescription(); // その他にも取得可能な情報: // - GetCodeSize() : 関数コードのサイズ (バイト単位) // - GetRole() : 関数に関連付けられたIAMロールのARN // - GetVersion() : 関数のバージョン番号 // - GetLayers() : 関数にアタッチされたレイヤーの情報 // - GetEnvironment() : 環境変数の設定 } return true; } else { // GetError() - 失敗時のエラー情報を取得 std::cerr << "✗ 取得失敗: " << outcome.GetError().GetMessage() << std::endl; return false; } </syntaxhighlight> <br><br> == エラーハンドリング == 全ての操作はOutcomeオブジェクトを返すため、必ず <code>IsSuccess</code> メソッドで確認する。<br> <br> <syntaxhighlight lang="c++"> auto outcome = m_lambdaClient->Invoke(request); // 必ず成功 / 失敗を確認 if (!outcome.IsSuccess()) { // GetError() : エラー情報オブジェクトを取得 auto error = outcome.GetError(); // GetErrorType() : エラーの種類を列挙型で取得 // 例 : INVALID_PARAMETER_VALUE, RESOURCE_NOT_FOUND, ACCESS_DENIED std::cerr << "エラーコード: " << error.GetErrorType() << std::endl; // GetMessage() : エラーの詳細メッセージを取得 // ユーザーに表示可能な分かりやすいエラー説明 std::cerr << "メッセージ: " << error.GetMessage() << std::endl; // GetExceptionName() : AWS APIが返した例外の名前を取得 // 例 : "ResourceNotFoundException", "InvalidParameterValueException" std::cerr << "例外名: " << error.GetExceptionName() << std::endl; } </syntaxhighlight> <br><br> == サンプルコード == 以下の例では、AWS Lambdaの関数呼び出しとレスポンスの取得を行っている。<br> 全ての設定 (リージョン、関数名、ペイロード) を任意の設定ファイルから読み込んでいる。<br> <br> * 呼び出しタイプ ** RequestResponse **: 同期呼び出し **: 関数の実行結果を待ってレスポンスを返す。 ** Event **: 非同期呼び出し **: 関数をキューに入れてすぐに制御を返す。 ** DryRun **: テスト呼び出し **: 関数を実行せずにアクセス許可を検証する。 *: <br> * ログタイプ ** Tail **: 最後の4KBの実行ログをBase64エンコードして返す。 ** None **: ログを返さない。 *: <br> * ペイロード形式 *: ペイロードは有効なJSON形式である必要がある。 *: <syntaxhighlight lang="json"> # 例 : { "body": { "message": "Hello Lambda!" }, "queryStringParameters": { "param1": "value1" } } </syntaxhighlight> <br> <syntaxhighlight lang="ini"> # config.iniファイル [AWS] # AWSリージョン (必須) region=us-east-1 [Lambda] # Lambda関数名 (必須) function_name=my-lambda-function # 呼び出しタイプ (RequestResponse, Event, DryRun) invocation_type=RequestResponse # ペイロード (JSON形式) payload={"key1": "value1", "key2": "value2"} # ログタイプ (None または Tail) log_type=Tail </syntaxhighlight> <br> <syntaxhighlight lang="cmake"> # CMakeLists.txtファイル cmake_minimum_required(VERSION 3.16) project(<プロジェクト名> VERSION 1.0 LANGUAGES CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Qt設定 set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_AUTOUIC ON) # Qtの検索 find_package(Qt6 COMPONENTS Core QUIET) if (NOT Qt6_FOUND) find_package(Qt5 5.15 REQUIRED COMPONENTS Core) endif() # AWS SDK for C++の検索 find_package(AWSSDK REQUIRED COMPONENTS lambda) # 実行ファイル add_executable(<プロジェクト名> main.cpp ) # Qt6とQt5の両方に対応 if (Qt6_FOUND) target_link_libraries(<プロジェクト名> Qt6::Core ${AWSSDK_LINK_LIBRARIES} ) else() target_link_libraries(<プロジェクト名> Qt5::Core ${AWSSDK_LINK_LIBRARIES} ) endif() # インストール install(TARGETS <プロジェクト名> RUNTIME DESTINATION bin ) </syntaxhighlight> <br> <syntaxhighlight lang="c++"> #include <QCoreApplication> #include <QCommandLineParser> #include <QSettings> #include <QFileInfo> #include <QDebug> #include <QJsonDocument> #include <QJsonObject> #include <iostream> #include <aws/core/Aws.h> #include <aws/lambda/LambdaClient.h> #include <aws/lambda/model/InvokeRequest.h> #include <aws/lambda/model/ListFunctionsRequest.h> // 設定情報を保持する構造体 struct LambdaConfig { QString region; QString functionName; QString invocationType; QString payload; QString logType; }; // 設定ファイルを読み込む関数 bool loadConfig(const QString& configPath, LambdaConfig& config) { QFileInfo fileInfo(configPath); if (!fileInfo.exists()) { std::cerr << "エラー: 設定ファイルが見つかりません: " << configPath.toStdString() << std::endl; return false; } QSettings settings(configPath, QSettings::IniFormat); settings.setIniCodec("UTF-8"); // AWS設定 settings.beginGroup("AWS"); config.region = settings.value("region").toString(); settings.endGroup(); // Lambda設定 settings.beginGroup("Lambda"); config.functionName = settings.value("function_name").toString(); config.invocationType = settings.value("invocation_type", "RequestResponse").toString(); config.payload = settings.value("payload", "{}").toString(); config.logType = settings.value("log_type", "None").toString(); settings.endGroup(); // 必須項目のチェック if (config.region.isEmpty()) { std::cerr << "エラー: [AWS] region が設定されていません" << std::endl; return false; } if (config.functionName.isEmpty()) { std::cerr << "エラー: [Lambda] function_name が設定されていません" << std::endl; return false; } std::cout << "設定ファイル読み込み完了: " << configPath.toStdString() << std::endl; std::cout << " リージョン: " << config.region.toStdString() << std::endl; std::cout << " 関数名: " << config.functionName.toStdString() << std::endl; std::cout << " 呼び出しタイプ: " << config.invocationType.toStdString() << std::endl; return true; } class LambdaManager { private: std::unique_ptr<Aws::Lambda::LambdaClient> m_lambdaClient; public: LambdaManager(const QString& region) { Aws::Client::ClientConfiguration clientConfig; clientConfig.region = region.toStdString(); m_lambdaClient = std::make_unique<Aws::Lambda::LambdaClient>(clientConfig); std::cout << "Lambdaクライアント初期化完了 (リージョン: " << region.toStdString() << ")" << std::endl; } bool invokeFunction(const QString& functionName, const QString& payload, const QString& invocationType, const QString& logType) { std::cout << "\n=== Lambda関数呼び出し開始 ===" << std::endl; std::cout << " 関数名: " << functionName.toStdString() << std::endl; std::cout << " ペイロード: " << payload.toStdString() << std::endl; // ペイロードのJSON検証 QJsonParseError parseError; QJsonDocument jsonDoc = QJsonDocument::fromJson(payload.toUtf8(), &parseError); if (parseError.error != QJsonParseError::NoError) { std::cerr << "エラー: ペイロードが有効なJSONではありません: " << parseError.errorString().toStdString() << std::endl; return false; } Aws::Lambda::Model::InvokeRequest request; request.SetFunctionName(functionName.toStdString()); // 呼び出しタイプの設定 if (invocationType == "RequestResponse") { request.SetInvocationType(Aws::Lambda::Model::InvocationType::RequestResponse); } else if (invocationType == "Event") { request.SetInvocationType(Aws::Lambda::Model::InvocationType::Event); } else if (invocationType == "DryRun") { request.SetInvocationType(Aws::Lambda::Model::InvocationType::DryRun); } // ログタイプの設定 if (logType == "Tail") { request.SetLogType(Aws::Lambda::Model::LogType::Tail); } else { request.SetLogType(Aws::Lambda::Model::LogType::None); } // ペイロードの設定 std::shared_ptr<Aws::IOStream> payload_stream = Aws::MakeShared<Aws::StringStream>("PayloadStream"); *payload_stream << payload.toStdString(); request.SetBody(payload_stream); auto outcome = m_lambdaClient->Invoke(request); if (outcome.IsSuccess()) { const auto& result = outcome.GetResult(); std::cout << "✓ 呼び出し成功!" << std::endl; std::cout << "\n--- レスポンス ---" << std::endl; std::cout << " ステータスコード: " << result.GetStatusCode() << std::endl; // 関数エラーの確認 if (!result.GetFunctionError().empty()) { std::cout << " 関数エラー: " << result.GetFunctionError() << std::endl; } // レスポンスペイロードの取得 auto& payload_stream = result.GetPayload(); std::stringstream ss; ss << payload_stream.rdbuf(); std::string response_payload = ss.str(); if (!response_payload.empty()) { std::cout << " ペイロード: " << response_payload << std::endl; // JSONの整形表示 QJsonDocument responseDoc = QJsonDocument::fromJson(QString::fromStdString(response_payload).toUtf8()); if (!responseDoc.isNull()) { std::cout << " 整形済みペイロード:\n" << responseDoc.toJson(QJsonDocument::Indented).toStdString() << std::endl; } } // ログの表示 (LogType=Tailの場合) if (!result.GetLogResult().empty()) { std::cout << "\n--- 実行ログ (Base64デコード済み) ---" << std::endl; // Base64デコード QByteArray logData = QByteArray::fromBase64(QByteArray::fromStdString(result.GetLogResult())); std::cout << logData.toStdString() << std::endl; } return true; } else { std::cerr << "✗ 呼び出し失敗: " << outcome.GetError().GetMessage() << std::endl; return false; } } bool listFunctions() { std::cout << "\n=== Lambda関数一覧取得 ===" << std::endl; Aws::Lambda::Model::ListFunctionsRequest request; auto outcome = m_lambdaClient->ListFunctions(request); if (outcome.IsSuccess()) { const auto& result = outcome.GetResult(); const auto& functions = result.GetFunctions(); std::cout << "✓ 取得成功! (" << functions.size() << "個の関数)" << std::endl; if (functions.empty()) { std::cout << " 登録されている関数がありません" << std::endl; } else { std::cout << "\n--- 関数一覧 ---" << std::endl; for (const auto& func : functions) { std::cout << " • " << func.GetFunctionName() << std::endl; std::cout << " ランタイム: " << Aws::Lambda::Model::RuntimeMapper::GetNameForRuntime(func.GetRuntime()) << std::endl; std::cout << " ハンドラ: " << func.GetHandler() << std::endl; std::cout << " メモリ: " << func.GetMemorySize() << " MB" << std::endl; std::cout << " タイムアウト: " << func.GetTimeout() << " 秒" << std::endl; std::cout << " 最終更新: " << func.GetLastModified() << std::endl; std::cout << std::endl; } } return true; } else { std::cerr << "✗ 取得失敗: " << outcome.GetError().GetMessage() << std::endl; return false; } } }; int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); QCoreApplication::setApplicationName("AWS Lambda Manager"); QCoreApplication::setApplicationVersion("1.0"); // コマンドライン引数のパーサーを設定 QCommandLineParser parser; parser.setApplicationDescription("AWS Lambda関数呼び出しツール (設定ファイルベース)"); parser.addHelpOption(); parser.addVersionOption(); // オプション定義 QCommandLineOption invokeOption(QStringList() << "i" << "invoke", "Lambda関数を呼び出し"); parser.addOption(invokeOption); QCommandLineOption listOption(QStringList() << "l" << "list", "Lambda関数の一覧を取得"); parser.addOption(listOption); QCommandLineOption configOption(QStringList() << "c" << "config", "設定ファイルのパス (デフォルト: config.ini)", "config", "config.ini"); parser.addOption(configOption); parser.process(app); // AWS SDKの初期化 Aws::SDKOptions options; Aws::InitAPI(options); int result = 0; { // 設定ファイルのパスを取得 QString configPath = parser.value(configOption); // 設定を読み込む LambdaConfig config; if (!loadConfig(configPath, config)) { std::cerr << "\n設定ファイルの例:" << std::endl; std::cerr << " [AWS]" << std::endl; std::cerr << " region=ap-northeast-1" << std::endl; std::cerr << " " << std::endl; std::cerr << " [Lambda]" << std::endl; std::cerr << " function_name=my-function" << std::endl; std::cerr << " invocation_type=RequestResponse" << std::endl; std::cerr << " payload={\"key\": \"value\"}" << std::endl; std::cerr << " log_type=Tail" << std::endl; Aws::ShutdownAPI(options); return 1; } // Lambdaマネージャーを初期化 LambdaManager lambdaManager(config.region); if (parser.isSet(invokeOption)) { // Lambda関数呼び出し if (!lambdaManager.invokeFunction(config.functionName, config.payload, config.invocationType, config.logType)) { result = 1; } } else if (parser.isSet(listOption)) { // Lambda関数一覧取得 if (!lambdaManager.listFunctions()) { result = 1; } } else { std::cerr << "エラー: --invoke または --list を指定してください" << std::endl; parser.showHelp(1); } } // AWS SDKのクリーンアップ Aws::ShutdownAPI(options); return result; } </syntaxhighlight> <br> <syntaxhighlight lang="sh"> # 実行例 # Lambda関数を呼び出し ./lambda-manager --invoke --config config.ini # Lambda関数の一覧を取得 ./lambda-manager --list --config config.ini # 別の設定ファイルを使用 ./lambda-manager --invoke --config /path/to/custom-config.ini </syntaxhighlight> <br><br> __FORCETOC__ [[カテゴリ:Qt]]
Qtの応用 - AWS Lambda
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse