この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、CX 事業本部 IoT 事業部の若槻です。
前回のエントリでは Amazon QuickSight のコンソールから Athena の Dataset を作成してみました。(そして数々のエラーに遭遇しとてもハマりました。)
今回は、AWS CDKで QuickSight の Athena の Dataset を作成してみました。また作成するのは前回と同様既存のユーザーがアクセスがアクセス可能な Dataset とします。
やってみた
ざっくりと次のような手順で実装を行いました。
- データソースとなる Resource の CDK Deploy
- データソースとなる Resource のアクセス権限を既存のユーザーに手動設定
- QuickSight の Dataset となる Resource の CDK Deploy
実装
AWS CDK v2(TypeScript)で Stack の記述を作成します。
まずデータソースとなる Glue Table およびデータ格納用 S3 Bucket を作成する Stack です。
lib/aws-app-stack.ts
import { Construct } from 'constructs';
import { aws_s3, Stack, StackProps, RemovalPolicy } from 'aws-cdk-lib';
import * as glue_alpha from '@aws-cdk/aws-glue-alpha';
export class AwsAppStack extends Stack {
public readonly glueDatabase: glue_alpha.Database;
public readonly glueTable: glue_alpha.Table;
constructor(scope: Construct, id: string, props: StackProps) {
super(scope, id, props);
// データ格納バケット
const dataBucket = new aws_s3.Bucket(this, 'dataBucket', {
removalPolicy: RemovalPolicy.DESTROY,
});
// Glueデータベース
const glueDatabase = new glue_alpha.Database(this, 'glueDatabase', {
databaseName: 'glue_database',
});
this.glueDatabase = glueDatabase;
// Glueテーブル
const glueTable = new glue_alpha.Table(this, 'glueTable', {
tableName: 'glue_table',
database: glueDatabase,
bucket: dataBucket,
s3Prefix: 'data/',
dataFormat: glue_alpha.DataFormat.JSON,
columns: [
{
name: 'id',
type: glue_alpha.Schema.STRING,
},
{
name: 'count',
type: glue_alpha.Schema.FLOAT,
},
{
name: 'area',
type: glue_alpha.Schema.STRING,
},
],
});
this.glueTable = glueTable;
}
}
次に、QuickSight の Datasource および Dataset を作成する Stack です。Dataset の Resource にはpermissions
を設定し、既存のユーザーが Dataset にコンソールからアクセスできるようにしています。
lib/process-stack.ts
import { Construct } from 'constructs';
import { aws_quicksight, Stack, StackProps } from 'aws-cdk-lib';
import * as glue_alpha from '@aws-cdk/aws-glue-alpha';
interface ProcessStackProps extends StackProps {
userName: string;
glueDatabase: glue_alpha.Database;
glueTable: glue_alpha.Table;
}
export class ProcessStack extends Stack {
constructor(scope: Construct, id: string, props: ProcessStackProps) {
super(scope, id, props);
// QuickSightデータソース
const quickSightAthenaDataSource = new aws_quicksight.CfnDataSource(
this,
'quickSightAthenaDataSource',
{
awsAccountId: this.account,
dataSourceId: 'quickSightAthenaDataSource',
name: 'quickSightAthenaDataSource',
type: 'ATHENA',
dataSourceParameters: {
athenaParameters: {
workGroup: 'primary',
},
},
}
);
// QuickSightデータセット
new aws_quicksight.CfnDataSet(this, 'quickSightAthenaDataSet', {
name: 'quickSightAthenaDataSet',
awsAccountId: this.account,
dataSetId: 'quickSightAthenaDataSet',
physicalTableMap: {
quickSightAthenaDataSetPhysicalTableMap: {
relationalTable: {
dataSourceArn: quickSightAthenaDataSource.attrArn,
catalog: 'AwsDataCatalog',
schema: props.glueDatabase.databaseName,
name: props.glueTable.tableName,
inputColumns: [
{
name: 'id',
type: 'STRING',
},
{
name: 'count',
type: 'DECIMAL',
},
{
name: 'area',
type: 'STRING',
},
],
},
},
},
logicalTableMap: {
quickSightAthenaDataSetPhysicalTableMap: {
alias: props.glueTable.tableName,
source: {
physicalTableId: 'quickSightAthenaDataSetPhysicalTableMap',
},
},
},
importMode: 'SPICE',
permissions: [
{
principal: `arn:aws:quicksight:${this.region}:${this.account}:user/default/${props.userName}`,
actions: [
'quicksight:PassDataSet',
'quicksight:DescribeIngestion',
'quicksight:CreateIngestion',
'quicksight:UpdateDataSet',
'quicksight:DeleteDataSet',
'quicksight:DescribeDataSet',
'quicksight:CancelIngestion',
'quicksight:DescribeDataSetPermissions',
'quicksight:ListIngestions',
'quicksight:UpdateDataSetPermissions',
],
},
],
});
}
}
App 層ではAwsAppStack
からProcessStack
へ Glue の Resource を渡しています。
bin/aws-cdk-v2-project.ts
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { ProcessStack } from '../lib/process-stack';
import { AwsAppStack } from '../lib/aws-app-stack';
const app = new cdk.App();
const userName = app.node.tryGetContext('userName');
const awsAppStack = new AwsAppStack(app, 'AwsAppStack', {});
new ProcessStack(app, 'ProcessStack', {
userName: userName,
glueDatabase: awsAppStack.glueDatabase,
glueTable: awsAppStack.glueTable,
});
まずデータソース側の Stack を CDK Deploy します。
cdk deploy AwsAppStack
デプロイに成功したら、QuickSight access to AWS servicesを開きます。
[Amazon Athena]が未チェックであればチェックを入れます。
[Amazon Athena permissions]のダイアログが出たら[Skip]をクリックして閉じます。
[Select S3 buckets]をクリック。
先程 CDK Deploy で作成した Bucket にチェックを入れ、[Finish]をクリック。
[Save]をクリックしてアクセス権限の変更を保存します。
ここでManage usersコンソールにて Dataset を利用可能としたい既存のユーザーの Username を確認します。
Context に Username を指定して、QuickSight の Datasource および Dataset を CDK Deploy で作成します。
cdk deploy ProcessStack -c userName=${USER_NAME}
デプロイに成功したら、コンソールのDatasetsを見ると、Dataset が作成されていることが確認できました!
ここでデータソースの Bucket に次の JSON ファイルをアップロードします。
data1.json
{"id":"u001","count":3,"area":"Shinjuku"}
{"id":"u001","count":1,"area":"Akihabara"}
{"id":"u002","count":5,"area":"Ikebukuro"}
{"id":"u002","count":2,"area":"Akihabara"}
{"id":"u003","count":4,"area":"Shinjuku"}
aws s3 cp data1.json s3://${BUCKET_NAME}/data/data1.json
Dataset を開いて Refresh すると、レコードが読み込めています!
おわりに
AWS CDK で QuickSight の Athena の Dataset を作成して、既存のユーザーで使えるようにしてみました。
最初 CDK Stack で Dataset の Permission を設定していなかったため、作成されたはずの Dataset が既存のユーザーでコンソールから見れなくて焦りました。QuickSight ではコンソールにサインインするユーザーに権限を明示的に付与するということを CDK で実装する場合は意識する必要がありました。
以上