[アップデート] Amazon QuickSight でアセットのインポート・エクスポートジョブを実行することが出来るようになりました

2023.05.24

いわさです。

先日 AWS QuickSight API のアップデートでアセットバンドル周りの API がサポートされるようになりました。

ここでいうアセットというのはダッシュボードや分析・データセットなどの QuickSight 上のオブジェクトリソースを指しています。
以前に、このアセットを管理するための機能がリリースされています。

その際にはアセットを作成したりインポートしたりするような機能は備わっていませんでした。
今回のアップデートで QuickSight のアセットを特定のフォーマットの JSON ファイルにエクスポートしたり、そのファイルを再びインポートすることが出来るようになりました。

まだ公式ドキュメントや What's New at AWS で情報が確認出来ていないのですが、AWS CLI のリファレンスは更新されていて、v1.27.139 以上であればもうこの機能を利用することが出来ます。
本日は AWS CLI のリファレンスなどを頼りに使ってみましたので紹介します。

(2023.06.08 追記) 公式アナウンスも出ていました

早すぎてまだマネジメントコンソールで触れないのかなという予想もしていたのですが、そうではなくて API のみで利用出来る機能で間違いなさそうです。

追加された API

今回新たに実装された API は次の 6 つです。

今回の API で操作出来るのはインポートとエクスポートのジョブです。

describe-asset-bundle-xxx-jobを使うことでジョブの実行状況をポーリングすることが出来ます。
ジョブの停止コマンドは用意されていないようです。

続いて、エクスポートとインポートの手順を解説します。

エクスポートジョブの実行手順

エクスポートにあたって事前にアセットが存在している必要があります。
エクスポートジョブでエクスポート対象のアセットの ARN を指定する必要があるためです。

また、本日時点でエクスポート可能なリソースは以下となっています。

  • Analysis
  • Dashboard
  • DataSet
  • DataSource
  • RefreshSchedule
  • Theme
  • VPCConnection

一見すると必要なリソースにはほとんど対応してそうに見えます。
しかし、厳密にはサポートしていないデータソースがあったり、データソースに S3 パラメータで指定するマニフェストファイルなどが出力されていないようにも見えたのでサポートされていないデータソースがあるような気がしています。このあたりは採用前に評価したほうが良いと思います。

start-asset-bundle-export-jobでエクスポートジョブを実行することが出来ます。
おそらく以下が最小構成でのエクスポートです。

% cat start-asset-bundle-export-job.json
{
    "AwsAccountId": "123456789012",
    "AssetBundleExportJobId": "hoge-export-1",
    "ResourceArns": [
        "arn:aws:quicksight:ap-northeast-1:123456789012:dashboard/912c7f7b-94f6-46ef-844f-25aa69d6ec4e"
    ],
    "IncludeAllDependencies": true,
    "ExportFormat": "QUICKSIGHT_JSON"
}
% aws-v1 quicksight start-asset-bundle-export-job --cli-input-json file://start-asset-bundle-export-job.json         
{
    "Status": 202,
    "Arn": "arn:aws:quicksight:ap-northeast-1:123456789012:asset-bundle-export-job/hoge-export-1",
    "AssetBundleExportJobId": "hoge-export-1",
    "RequestId": "1844d07c-d12a-4af9-ab99-c0960609054a"
}

IncludeAllDependenciesフラグを有効化することで依存アセットもまとめてエクスポート出来ます。
例えば、分析をエクスポートした時に使用しているデータセットなどもエクスポート出来るイメージです。

ExportFormatは本日時点では 2 種類用意されていてQUICKSIGHT_JSONという独自形式の他に CloudFormation テンプレートの形式でもエクスポートが可能です(すごい)

あとはResourceArnsでエクスポート対象のアセット ARN を指定する感じですね。
エクスポート時に上書きするパラメータとかも設定出来るのですが、ちょっと高度だと思うので今日は割愛します。

エクスポート ジョブは非同期で実行され、最大 10 個のエクスポート ジョブを同時に実行できます。

ジョブが正常に完了するとdescribe-asset-bundle-export-jobでエクスポートされたアセットを含むダウンロード URL を取得することが出来ますので試してみましょう。

% aws-v1 quicksight describe-asset-bundle-export-job --cli-input-json file://describe-asset-bundle-export-job.json   
{
    "Status": 200,
    "JobStatus": "SUCCESSFUL",
    "DownloadUrl": "https://quicksight-asset-bundle-export-job-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/123456789012/hoge-export-2/a6699217-5e5b-42d6-a89f-db2c02296d54/assetbundle-hoge-export-2.qs
    "Arn": "arn:aws:quicksight:ap-northeast-1:550669467088:asset-bundle-export-job/hoge-export-2",
    "CreatedTime": 1684902303.0,
    "AssetBundleExportJobId": "hoge-export-2",
    "AwsAccountId": "550669467088",
    "ResourceArns": [
        "arn:aws:quicksight:ap-northeast-1:550669467088:dashboard/df48ede9-5225-4c1d-b593-a6e4d1c57064"
    ],
    "IncludeAllDependencies": true,
    "ExportFormat": "QUICKSIGHT_JSON",
    "RequestId": "9e7d2e4b-0265-49d1-9ab9-808ce8601af7"
}

上記 URL (DownloadUrl) へアクセスするとエクスポートされたアセットファイルを取得出来ます。
なお、URL は 5 分間有効で、describe-asset-bundle-export-jobの実行ごとに有効期間が更新されるそうです。呼び出しごとに一時トークンを払い出しているようなイメージのようです。QuickSight の埋め込み URL に似ていますね。

% ls -lh
total 41816
-rw-r--r--  1 iwasa.takahito  staff   2.6K May 24 13:25 assetbundle-hoge-export-2.qs

S3 がデータソースなシンプルなダッシュボードを、依存アセット込みでエクスポートしてみました。
サイズは 2.6 KB。

なお、ダウンロードしたバイナリファイルは Zip 形式で圧縮されており、展開するとエクスポート時に指定したフォーマットのファイルにアクセスすることが出来ます。
やってみましょう。

% unzip assetbundle-hoge-export-2.qs -d assets                                                                                                   
Archive:  assetbundle-hoge-export-2.qs
  inflating: assets/datasource/760415a1-3cdf-45f0-806a-78590a5ad2df.json  
  inflating: assets/refreshSchedule/3dd18763-ba70-4ff0-87af-725977fce402--refresh-schedule--7c2d3db0-713a-46b7-8870-771ab68879f8.json  
  inflating: assets/dataset/3dd18763-ba70-4ff0-87af-725977fce402.json  
  inflating: assets/dashboard/df48ede9-5225-4c1d-b593-a6e4d1c57064.json

アセットファイル一式にデータソースとスケジュール、データセット、ダッシュボードの定義ファイルが含まれていることがわかりますね。

ちなみにダッシュボードは次のような JSON ファイルでした。

% cat assets/dashboard/df48ede9-5225-4c1d-b593-a6e4d1c57064.json | jq
{
  "resourceType": "dashboard",
  "dashboardId": "df48ede9-5225-4c1d-b593-a6e4d1c57064",
  "name": "hoge0323",
  "definition": {
    "dataSetIdentifierDeclarations": [
      {
        "identifier": "hoge0323",
        "dataSetArn": "arn:aws:quicksight:ap-northeast-1:123456789012:dataset/3dd18763-ba70-4ff0-87af-725977fce402"
      }
    ],
    "sheets": [
      {
        "sheetId": "df48ede9-5225-4c1d-b593-a6e4d1c57064_56a1cc61-458a-4583-b822-62d0fa2c4212",
        "name": "シート 1",
        "visuals": [
          {
            "tableVisual": {
              "visualId": "df48ede9-5225-4c1d-b593-a6e4d1c57064_d0ec34c5-175a-41be-8b6c-c09cf7153b51",
              "title": {
                "visibility": "VISIBLE"
              },
              "subtitle": {
                "visibility": "VISIBLE"
              },
              "chartConfiguration": {
                "fieldWells": {
                  "tableAggregatedFieldWells": {
                    "groupBy": [
                      {
                        "categoricalDimensionField": {
                          "fieldId": "be7222a6-97fd-4aac-bfd8-89bc20ca05b9.hoge1.0.1679553974895",
                          "column": {
                            "dataSetIdentifier": "hoge0323",
                            "columnName": "hoge1"
                          }
                        }
                      }
                    ],
                    "values": [
                      {
                        "numericalMeasureField": {
                          "fieldId": "be7222a6-97fd-4aac-bfd8-89bc20ca05b9.hoge2.1.1679553975477",
                          "column": {
                            "dataSetIdentifier": "hoge0323",
                            "columnName": "hoge2"
                          },
                          "aggregationFunction": {
                            "simpleNumericalAggregation": "SUM"
                          }
                        }
                      },
                      {
                        "numericalMeasureField": {
                          "fieldId": "be7222a6-97fd-4aac-bfd8-89bc20ca05b9.hoge3.2.1679553976010",
                          "column": {
                            "dataSetIdentifier": "hoge0323",
                            "columnName": "hoge3"
                          },
                          "aggregationFunction": {
                            "simpleNumericalAggregation": "SUM"
                          }
                        }
                      }
                    ]
                  }
                },
                "sortConfiguration": {},
                "tableOptions": {
                  "headerStyle": {
                    "visibility": "VISIBLE"
                  }
                }
              },
              "actions": []
            }
          }
        ],
        "layouts": [
          {
            "configuration": {
              "gridLayout": {
                "elements": [
                  {
                    "elementId": "df48ede9-5225-4c1d-b593-a6e4d1c57064_d0ec34c5-175a-41be-8b6c-c09cf7153b51",
                    "elementType": "VISUAL",
                    "columnSpan": 18,
                    "rowSpan": 12
                  }
                ]
              }
            }
          }
        ],
        "contentType": "INTERACTIVE"
      }
    ],
    "calculatedFields": [],
    "parameterDeclarations": [],
    "filterGroups": [],
    "analysisDefaults": {
      "defaultNewSheetConfiguration": {
        "interactiveLayoutConfiguration": {
          "grid": {
            "canvasSizeOptions": {
              "screenCanvasSizeOptions": {
                "resizeOption": "FIXED",
                "optimizedViewPortWidth": "1600px"
              }
            }
          }
        },
        "sheetContentType": "INTERACTIVE"
      }
    }
  },
  "dashboardPublishOptions": {
    "adHocFilteringOption": {
      "availabilityStatus": "DISABLED"
    },
    "exportToCSVOption": {
      "availabilityStatus": "ENABLED"
    },
    "sheetControlsOption": {
      "visibilityState": "COLLAPSED"
    },
    "sheetLayoutElementMaximizationOption": {
      "availabilityStatus": "ENABLED"
    },
    "visualMenuOption": {
      "availabilityStatus": "ENABLED"
    },
    "visualAxisSortOption": {
      "availabilityStatus": "ENABLED"
    },
    "exportWithHiddenFieldsOption": {
      "availabilityStatus": "DISABLED"
    },
    "dataPointDrillUpDownOption": {
      "availabilityStatus": "ENABLED"
    },
    "dataPointMenuLabelOption": {
      "availabilityStatus": "ENABLED"
    },
    "dataPointTooltipOption": {
      "availabilityStatus": "ENABLED"
    }
  }
}

お気づきの方もいるかもしれませんが、これは次のアップデートで使えるようになったアセットの定義ファイルと同じもののようですね。

ファイルアップロードによって作成されたデータセットは対象外っぽい

今回いくつかのアセットで試してみたところ、ファイルアップロードで作成されたデータセットについてはエクスポート出来ないことがわかりました。
次のようにジョブステータスが FAILED になっておりますね。

% aws-v1 quicksight describe-asset-bundle-export-job --cli-input-json file://describe-asset-bundle-export-job.json  
{
    "Status": 200,
    "JobStatus": "FAILED",
    "Errors": [
        {
            "Arn": "arn:aws:quicksight:ap-northeast-1:123456789012:dataset/fa4725c7-f57c-448c-b231-cc314a6c9029",
            "Type": "com.amazonaws.services.quicksight.model.InvalidParameterValueException",
            "Message": "The data set type is not supported through API yet"
        }
    ],
    "Arn": "arn:aws:quicksight:ap-northeast-1:123456789012:asset-bundle-export-job/hoge-export-1",
    "CreatedTime": 1684901862.0,
    "AssetBundleExportJobId": "hoge-export-1",
    "AwsAccountId": "123456789012",
    "ResourceArns": [
        "arn:aws:quicksight:ap-northeast-1:123456789012:dashboard/912c7f7b-94f6-46ef-844f-25aa69d6ec4e"
    ],
    "IncludeAllDependencies": true,
    "ExportFormat": "QUICKSIGHT_JSON",
    "RequestId": "5b34d5df-86bb-4a7c-8ab5-65ddd592808f"
}

上記エラーメッセージに見覚えのある方いますかね。そうなのです本日時点では AWS CLI など QuickSight API を通してファイルアップロードで作成されたデータセットにはアクセス出来ないのです。
S3 や Athena など何かしらのデータソースである必要があります。

これは API がサポートされることによって使えるようになってほしいですね。
yetって言ってるくらいなので、信じてます。

インポート手順

アセットのエクスポートが出来ましたね。続いてインポートです。
インポートはstart-asset-bundle-import-jobで先程ダウンロードしたアセットデータを渡してあげれば良いです。

アセットデータの渡しかたは S3 に配置して URL を指定することも出来ますし、base64 形式でバイナリデータを指定することも出来ます。
ここではasset-bundle-import-source-bytesオプションに fileb で指定してみます。

fileb の使い方は以下も参考にしてください。

% aws-v1 quicksight start-asset-bundle-import-job --aws-account-id 123456789012 --asset-bundle-import-job-id hoge-import-1 --asset-bundle-import-source-bytes fileb://assetbundle-hoge-export-5.qs
{
    "Status": 202,
    "Arn": "arn:aws:quicksight:ap-northeast-1:123456789012:asset-bundle-import-job/hoge-import-1",
    "AssetBundleImportJobId": "hoge-import-1",
    "RequestId": "2a6d2b79-7462-4a09-934b-f498543c20dc"
}

インポートジョブ開始出来ました。
エクスポートのときと同じようにジョブの状況をポーリングしてみましょう。

% aws-v1 quicksight describe-asset-bundle-import-job --aws-account-id 123456789012 --asset-bundle-import-job-id hoge-import-1  
{
    "Status": 200,
    "JobStatus": "SUCCESSFUL",
    "Arn": "arn:aws:quicksight:ap-northeast-1:123456789012:asset-bundle-import-job/hoge-import-1",
    "CreatedTime": 1684904831.0,
    "AssetBundleImportJobId": "hoge-import-1",
    "AwsAccountId": "123456789012",
    "AssetBundleImportSource": {
        "Body": "https://quicksight-asset-bundle-import-job-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/123456789012/hoge-import-1/2a6d2b79-7462-4a09-934b-f498543c20dc/body.zip
    },
    "FailureAction": "ROLLBACK",
    "RequestId": "3347b770-744f-4203-9907-67aa03db941d"
}

上記は成功パターンです。
以上がエクスポート・インポートの基本的な使い方になります。

A アカウントからエクスポートしたアセットを B アカウントにインポートする

まずは A アカウントでエクスポートした先程のアセットを別の AWS アカウントである B の QuickSight でインポートしてみます。
結論としては今回は成功しませんでした。

内部の ID 指定や依存関係の解決が結構大変そうで、そのあたりはエクスポートやインポートのオーバーライドなどを駆使する必要がありそうです。
今回は成功しなかったのですが、ひとまず簡単に誰でもアカウント間でインポート・エクスポートが出来るという温度感ではないということがわかりました。それなりに考慮事項が多そうです。

% aws-v1 quicksight start-asset-bundle-import-job --aws-account-id 111111111111 --asset-bundle-import-job-id hoge-import-1 --asset-bundle-import-source-bytes fileb://assetbundle-hoge-export-2.qs --profile hogeadmin
{
    "Status": 202,
    "Arn": "arn:aws:quicksight:ap-northeast-1:111111111111:asset-bundle-import-job/hoge-import-1",
    "AssetBundleImportJobId": "hoge-import-1",
    "RequestId": "91e4ea63-c95c-45f1-b32d-2b3a15f077ba"
}

上記のようにインポート実行まではいけました。
しかし、ジョブを確認してみると次のように失敗していました。

% aws-v1 quicksight describe-asset-bundle-import-job --aws-account-id 111111111111 --asset-bundle-import-job-id hoge-import-1 --profile hogeadmin
{
    "Status": 200,
    "JobStatus": "FAILED_ROLLBACK_COMPLETED",
    "Errors": [
        {
            "Arn": "arn:aws:quicksight:ap-northeast-1:111111111111:datasource/760415a1-3cdf-45f0-806a-78590a5ad2df",
            "Type": "com.amazonaws.services.quicksight.model.InvalidParameterValueException",
            "Message": "DataSourceParameters field is incorrectly set"
        }
    ],
    "Arn": "arn:aws:quicksight:ap-northeast-1:111111111111:asset-bundle-import-job/hoge-import-1",
    "CreatedTime": 1684902780.0,
    "AssetBundleImportJobId": "hoge-import-1",
    "AwsAccountId": "111111111111",
    "AssetBundleImportSource": {
        "Body": "https://quicksight-asset-bundle-import-job-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/111111111111/hoge-import-1/91e4ea63-c95c-45f1-b32d-2b3a15f077ba/body.zip
    },
    "FailureAction": "ROLLBACK",
    "RequestId": "4e137001-b57c-45a8-a03c-98ffbe87ed1f"
}

同一 ID や構成のデータセットが既に存在している状態でダッシュボードのみインポートとか、シンプルであれば成功すると思います。
複雑な構成での一括インポートは今後検証を重ねて、いつかもっとうまくやれる方法を案内したいと思ってます。

A アカウントからエクスポートしたアセットを A アカウントにインポートする

ということで、本日はとりあえず一通りの流れを成功させたいので、同一アカウント上でダッシュボードだけをエクスポートしてインポートするというのをやってみます。
シナリオとしては、次のようなダッシュボードをエクスポートして、そのダッシュボードを削除します。その後インポートすることで復元出来るのかを試してみます。

エクスポートしたアセットを展開してみるとダッシュボード定義しか含まれていないシンプルなものが取得出来ました。

% unzip assetbundle-hoge-export-5.qs -d hoge-export-5
Archive:  assetbundle-hoge-export-5.qs
  inflating: hoge-export-5/dashboard/b7069228-45d0-4b49-910f-352eb2c8b0a8.json

続いてダッシュボードを削除します。

完全に削除されました。

インポートジョブを実行し、ステータスが成功になっていることを確認しました。

% aws-v1 quicksight describe-asset-bundle-import-job --aws-account-id 123456789012 --asset-bundle-import-job-id hoge-import-1  
{
    "Status": 200,
    "JobStatus": "SUCCESSFUL",
    "Arn": "arn:aws:quicksight:ap-northeast-1:123456789012:asset-bundle-import-job/hoge-import-1",
    "CreatedTime": 1684904831.0,
    "AssetBundleImportJobId": "hoge-import-1",
    "AwsAccountId": "123456789012",
    "AssetBundleImportSource": {
        "Body": "https://quicksight-asset-bundle-import-job-ap-northeast-1.s3.ap-northeast-1.amazonaws.com/123456789012/hoge-import-1/2a6d2b79-7462-4a09-934b-f498543c20dc/body.zip
    },
    "FailureAction": "ROLLBACK",
    "RequestId": "3347b770-744f-4203-9907-67aa03db941d"
}

しかし、QuickSight のダッシュボード一覧上は確認することが出来ません。

今回わかったのですが、インポートしても権限は付与されないのでそこは別の方法で権限付与が必要だということです。
今回はアセット管理機能から権限を付与します。

インポートされたダッシュボードがアセット管理で確認出来ました。

所有者権限を追加します。

対象ユーザーのダッシュボード一覧にインポートされたダッシュボードが表示されました。

ダッシュボードを開いてみると削除前のものが復元されていますね。やった。

さいごに

本日は Amazon QuickSight でアセットのインポート・エクスポートジョブを実行することが出来るようになったので、使ってみました。

これ中々すごくないですか?顧客が本当に必要だったものというやつではないだろうか。

現時点でバックアップと復元の用途であれば全く問題なく使えますね。
移行の用途でも考慮しなければいけない点はありますが使えそうです。もう少し検証したいところ。

本日時点ではマネジメントコンソール上では利用出来ないですが、QuickSight は通常 API が更新されてから 数日 ~ 1 週間くらいしてから UI に新機能が反映されるケースが多いので、そのうち GUI でも操作出来るようになるかもしれません。