【发布时间】:2021-01-12 14:34:47
【问题描述】:
是否可以通过 cloudformation 模板创建 Athena 视图。我可以使用 Athena Dashboard 创建视图,但我想使用 CF 模板以编程方式执行此操作。在 AWS 文档中找不到任何详细信息,因此不确定是否支持。
谢谢。
【问题讨论】:
标签: amazon-web-services amazon-athena
是否可以通过 cloudformation 模板创建 Athena 视图。我可以使用 Athena Dashboard 创建视图,但我想使用 CF 模板以编程方式执行此操作。在 AWS 文档中找不到任何详细信息,因此不确定是否支持。
谢谢。
【问题讨论】:
标签: amazon-web-services amazon-athena
通常,CloudFormation 用于以可重复的方式部署基础架构。这不适用于数据库内部的数据,数据库通常单独保存到其他基础设施。
对于 Amazon Athena,AWS CloudFormation 仅支持:
最接近您要求的是命名查询,它(我认为)可以存储可以创建视图的查询(例如CREATE VIEW...)。
见:AWS::Athena::NamedQuery - AWS CloudFormation
更新:@Theo 指出 AWS CloudFormation 还具有 AWS Glue 功能,包括:
这显然可以用来创建视图。请参阅下面的 cmets。
【讨论】:
可以使用 CloudFormation 创建视图,只是非常、非常、复杂。 Athena 视图存储在 Glue 数据目录中,就像数据库和表一样。实际上,Athena 视图是 Glue Data Catalog 中的表,只是内容略有不同。
有关如何以编程方式创建视图的完整说明,请参阅此答案,您将对复杂性有所了解:Create AWS Athena view programmatically – 可以将其映射到 CloudFormation,但我不建议这样做。
如果要使用 CloudFormation 创建数据库和表,资源为 AWS::Glue::Database 和 AWS::Glue::Table。
【讨论】:
我认为目前从 CloudFormation 模板创建 Athena 视图的最佳方法是使用自定义资源和 Lambda。我们必须提供视图创建和删除的方法。例如,使用 crhelper 库 Lambda 可以定义:
from __future__ import print_function
from crhelper import CfnResource
import logging
import os
import boto3
logger = logging.getLogger(__name__)
helper = CfnResource(json_logging=False, log_level='DEBUG', boto_level='CRITICAL', sleep_on_delete=120)
try:
client = boto3.client('athena')
ATHENA_WORKGROUP = os.environ['athena_workgroup']
DATABASE = os.environ['database']
QUERY_CREATE = os.environ['query_create']
QUERY_DROP = os.environ['query_drop']
except Exception as e:
helper.init_failure(e)
@helper.create
@helper.update
def create(event, context):
logger.info("View creation started")
try:
executionResponse = client.start_query_execution(
QueryString=QUERY_CREATE,
QueryExecutionContext={'Database': DATABASE},
WorkGroup='AudienceAthenaWorkgroup'
)
logger.info(executionResponse)
response = client.get_query_execution(QueryExecutionId=executionResponse['QueryExecutionId'])
logger.info(response)
if response['QueryExecution']['Status']['State'] == 'FAILED':
logger.error("Query failed")
raise ValueError("Query failed")
helper.Data['success'] = True
helper.Data['id'] = executionResponse['QueryExecutionId']
helper.Data['message'] = 'query is running'
except Exception as e:
print(f"An exception occurred: {e}")
if not helper.Data.get("success"):
raise ValueError("Creating custom resource failed.")
return
@helper.delete
def delete(event, context):
logger.info("View deletion started")
try:
executionResponse = client.start_query_execution(
QueryString=QUERY_DROP,
QueryExecutionContext={'Database': DATABASE},
WorkGroup='AudienceAthenaWorkgroup'
)
logger.info(executionResponse)
except Exception as e:
print("An exception occurred")
print(e)
@helper.poll_create
def poll_create(event, context):
logger.info("Pol creation")
response = client.get_query_execution(QueryExecutionId=event['CrHelperData']['id'])
logger.info(f"Poll response: {response}")
# There are 3 types of state of query
# if state is failed - we stop and fail creation
# if state is queued - we continue polling in 2 minutes
# if state is succeeded - we stop and succeed creation
if 'FAILED' == response['QueryExecution']['Status']['State']:
logger.error("Query failed")
raise ValueError("Query failed")
if 'SUCCEEDED' == response['QueryExecution']['Status']['State']:
logger.error("Query SUCCEEDED")
return True
if 'QUEUED' == response['QueryExecution']['Status']['State']:
logger.error("Query QUEUED")
return False
# Return a resource id or True to indicate that creation is complete. if True is returned an id
# will be generated
# Return false to indicate that creation is not complete and we need to poll again
return False
def handler(event, context):
helper(event, context)
用于视图创建/更新/删除的 Athena 查询作为环境参数传递给 Lambda。
在CloudFormation 模板中,我们必须定义调用提到的Python 代码并创建/更新/删除Athena 视图的Lambda。例如
AthenaCommonViewLambda:
Type: 'AWS::Lambda::Function'
DependsOn: [CreateAthenaViewLayer, CreateAthenaViewLambdaRole]
Properties:
Environment:
Variables:
athena_workgroup: !Ref AudienceAthenaWorkgroup
database:
Ref: DatabaseName
query_create: !Sub >-
CREATE OR REPLACE VIEW ${TableName}_view AS
SELECT field1, field2, ...
FROM ${DatabaseName}.${TableName}
query_drop: !Sub DROP VIEW IF EXISTS ${TableName}_common_view
Code:
S3Bucket: !Ref SourceS3Bucket
S3Key: createview.zip
FunctionName: !Sub '${AWS::StackName}_create_common_view'
Handler: createview.handler
MemorySize: 128
Role: !GetAtt CreateAthenaViewLambdaRole.Arn
Runtime: python3.8
Timeout: 60
Layers:
- !Ref CreateAthenaViewLayer
AthenaCommonView:
Type: 'Custom::AthenaCommonView'
Properties:
ServiceToken: !GetAtt AthenaCommonViewLambda.Arn
【讨论】: