[docs]@attr.sclassBotoMan:""" Simple wrapper around boto3 API. """bsm:BSM=attr.ib()@propertydefdefault_s3_bucket_artifacts(self)->str:""" The default s3 bucket that stores the temporary artifacts. """returnf"{self.bsm.aws_account_id}-{self.bsm.aws_region}-aws-stepfunction-python-sdk"@propertydefdefault_s3_bucket_artifacts_prefix(self)->str:return"aws-stepfunction-python-sdk"@propertydefdefault_iam_role_magic_task(self)->str:""" The default iam role for magic task lambda function. """return"aws-stepfunction-python-sdk-magic-task-role"@propertydefdefault_iam_role_arn_magic_task(self)->str:""" The default iam role arn for magic task lambda function. """returnf"arn:aws:iam::{self.bsm.aws_account_id}:role/{self.default_iam_role_magic_task}"@propertydefsfn_client(self):returnself.bsm.get_client(AwsServiceEnum.SFN)@propertydefs3_client(self):returnself.bsm.get_client(AwsServiceEnum.S3)@propertydefiam_client(self):returnself.bsm.get_client(AwsServiceEnum.IAM)@propertydefcf_client(self):returnself.bsm.get_client(AwsServiceEnum.CloudFormation)@propertydeflbd_client(self):returnself.bsm.get_client(AwsServiceEnum.Lambda)# ------------------------------------------------------------------------------# S3# ------------------------------------------------------------------------------defis_s3_bucket_exists(self,name:str)->bool:try:self.s3_client.head_bucket(Bucket=name)returnTrueexceptExceptionase:if"Not Found"instr(e):returnFalseelse:raiseedefget_s3_bucket_tags(self,name:str)->dict:try:response=self.s3_client.get_bucket_tagging(Bucket=name)return{dct["Key"]:dct["Value"]fordctinresponse.get("TagSet",[])}exceptExceptionase:if"The specified bucket does not exist"instr(e):raiseBucketNotExistelse:raisee# ------------------------------------------------------------------------------# IAM Role# ------------------------------------------------------------------------------_iam_role_not_exists_message_pattern="cannot be found"defis_iam_role_exists(self,name:str)->bool:try:self.iam_client.get_role(RoleName=name)returnTrueexceptExceptionase:ifself._iam_role_not_exists_message_patterninstr(e):returnFalseelse:raiseedefget_iam_role_tags(self,name:str)->dict:try:response=self.iam_client.get_role(RoleName=name)return{dct["Key"]:dct["Value"]fordctinresponse["Role"].get("Tags",[])}exceptExceptionase:ifself._iam_role_not_exists_message_patterninstr(e):raiseIamRoleNotExistelse:raisee# ------------------------------------------------------------------------------# Lambda Function# ------------------------------------------------------------------------------_lbd_func_not_exists_message_pattern="Function not found"defis_lbd_func_exists(self,name:str)->bool:try:self.lbd_client.get_function(FunctionName=name)returnTrueexceptExceptionase:ifself._lbd_func_not_exists_message_patterninstr(e):returnFalseelse:raiseedefget_lbd_func_tags(self,name:str)->dict:try:response=self.lbd_client.get_function(FunctionName=name)returnresponse.get("Tags",{})exceptExceptionase:ifself._lbd_func_not_exists_message_patterninstr(e):raiseLambdaFunctionNotExistelse:raisee# ------------------------------------------------------------------------------# CloudFormation Stack# ------------------------------------------------------------------------------_cloudformation_stack_not_exists_message_pattern="does not exist"defis_cloudformation_stack_exists(self,name:str)->bool:try:self.cf_client.describe_stacks(StackName=name)returnTrueexceptExceptionase:ifself._cloudformation_stack_not_exists_message_patterninstr(e):returnFalseelse:raiseedefget_cloudformation_stack_tags(self,name:str)->dict:try:response=self.cf_client.describe_stacks(StackName=name)return{dct["Key"]:dct["Value"]fordctinresponse["Stacks"][0].get("Tags",[])}exceptExceptionase:ifself._cloudformation_stack_not_exists_message_patterninstr(e):raiseCloudFormationStackNotExistelse:raisee
[docs]defget_cloudformation_stack_status(self,name:str)->str:""" Get CloudFormation stack status. possible status: 'CREATE_IN_PROGRESS'|'CREATE_FAILED'|'CREATE_COMPLETE'|'ROLLBACK_IN_PROGRESS'|'ROLLBACK_FAILED'|'ROLLBACK_COMPLETE'|'DELETE_IN_PROGRESS'|'DELETE_FAILED'|'DELETE_COMPLETE'|'UPDATE_IN_PROGRESS'|'UPDATE_COMPLETE_CLEANUP_IN_PROGRESS'|'UPDATE_COMPLETE'|'UPDATE_FAILED'|'UPDATE_ROLLBACK_IN_PROGRESS'|'UPDATE_ROLLBACK_FAILED'|'UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS'|'UPDATE_ROLLBACK_COMPLETE'|'REVIEW_IN_PROGRESS'|'IMPORT_IN_PROGRESS'|'IMPORT_COMPLETE'|'IMPORT_ROLLBACK_IN_PROGRESS'|'IMPORT_ROLLBACK_FAILED'|'IMPORT_ROLLBACK_COMPLETE' Ref: - https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#stack - https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/cloudformation.html#CloudFormation.Client.describe_stacks """try:response=self.cf_client.describe_stacks(StackName=name)returnresponse["Stacks"][0]["StackStatus"]exceptExceptionase:ifself._cloudformation_stack_not_exists_message_patterninstr(e):raiseCloudFormationStackNotExistelse:raisee
[docs]@logger.decoratordefwait_cloudformation_stack_success(self,name:str,period:int=5,retry:int=2,_indent:int=0,):""" Wait a cloudformation stack to reach "success" status. """logger.info(f"wait {name!r} stack to complete ... ",_indent)forithinrange(retry):logger.info(f"elapsed {ith*period} seconds ...",_indent+1)time.sleep(period)stack_status=self.get_cloudformation_stack_status(name)ifstack_statusin["CREATE_COMPLETE","UPDATE_COMPLETE","DELETE_COMPLETE",]:returnraiseTimeoutError(f"the cloudformation stack never reach success state, "f"timed out after {period*retry} seconds")