こんにちは、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', {
bucketName: '220817databucket',
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で実装する場合は意識する必要がありました。
以上