Add support for CloudFormation resource AWS::StepFunctions::StateMachine
(#3429)
Closes #3402 Co-authored-by: Bert Blommers <bblommers@users.noreply.github.com>
This commit is contained in:
parent
53c3eb6240
commit
171130fe7b
@ -38,6 +38,7 @@ from moto.s3 import models as s3_models, s3_backend # noqa
|
|||||||
from moto.s3.utils import bucket_and_name_from_url
|
from moto.s3.utils import bucket_and_name_from_url
|
||||||
from moto.sns import models as sns_models # noqa
|
from moto.sns import models as sns_models # noqa
|
||||||
from moto.sqs import models as sqs_models # noqa
|
from moto.sqs import models as sqs_models # noqa
|
||||||
|
from moto.stepfunctions import models as stepfunctions_models # noqa
|
||||||
|
|
||||||
# End ugly list of imports
|
# End ugly list of imports
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ from datetime import datetime
|
|||||||
|
|
||||||
from boto3 import Session
|
from boto3 import Session
|
||||||
|
|
||||||
from moto.core import ACCOUNT_ID, BaseBackend
|
from moto.core import ACCOUNT_ID, BaseBackend, CloudFormationModel
|
||||||
from moto.core.utils import iso_8601_datetime_with_milliseconds
|
from moto.core.utils import iso_8601_datetime_with_milliseconds
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from .exceptions import (
|
from .exceptions import (
|
||||||
@ -18,7 +18,7 @@ from .exceptions import (
|
|||||||
from .utils import paginate
|
from .utils import paginate
|
||||||
|
|
||||||
|
|
||||||
class StateMachine:
|
class StateMachine(CloudFormationModel):
|
||||||
def __init__(self, arn, name, definition, roleArn, tags=None):
|
def __init__(self, arn, name, definition, roleArn, tags=None):
|
||||||
self.creation_date = iso_8601_datetime_with_milliseconds(datetime.now())
|
self.creation_date = iso_8601_datetime_with_milliseconds(datetime.now())
|
||||||
self.arn = arn
|
self.arn = arn
|
||||||
@ -27,6 +27,45 @@ class StateMachine:
|
|||||||
self.roleArn = roleArn
|
self.roleArn = roleArn
|
||||||
self.tags = tags
|
self.tags = tags
|
||||||
|
|
||||||
|
@property
|
||||||
|
def physical_resource_id(self):
|
||||||
|
return self.arn
|
||||||
|
|
||||||
|
def get_cfn_attribute(self, attribute_name):
|
||||||
|
from moto.cloudformation.exceptions import UnformattedGetAttTemplateException
|
||||||
|
|
||||||
|
if attribute_name == "Name":
|
||||||
|
return self.name
|
||||||
|
raise UnformattedGetAttTemplateException()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def cloudformation_name_type():
|
||||||
|
return "StateMachine"
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def cloudformation_type():
|
||||||
|
return "AWS::StepFunctions::StateMachine"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def create_from_cloudformation_json(
|
||||||
|
cls, resource_name, cloudformation_json, region_name
|
||||||
|
):
|
||||||
|
properties = cloudformation_json["Properties"]
|
||||||
|
name = properties.get("StateMachineName", resource_name)
|
||||||
|
definition = properties.get("DefinitionString", "")
|
||||||
|
role_arn = properties.get("RoleArn", "")
|
||||||
|
tags = properties.get("Tags", [])
|
||||||
|
tags_xform = [{k.lower(): v for k, v in d.items()} for d in tags]
|
||||||
|
sf_backend = stepfunction_backends[region_name]
|
||||||
|
return sf_backend.create_state_machine(
|
||||||
|
name, definition, role_arn, tags=tags_xform
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def delete_from_cloudformation_json(cls, resource_name, _, region_name):
|
||||||
|
sf_backend = stepfunction_backends[region_name]
|
||||||
|
sf_backend.delete_state_machine(resource_name)
|
||||||
|
|
||||||
|
|
||||||
class Execution:
|
class Execution:
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -8,7 +8,7 @@ from datetime import datetime
|
|||||||
from botocore.exceptions import ClientError
|
from botocore.exceptions import ClientError
|
||||||
from nose.tools import assert_raises
|
from nose.tools import assert_raises
|
||||||
|
|
||||||
from moto import mock_sts, mock_stepfunctions
|
from moto import mock_cloudformation, mock_sts, mock_stepfunctions
|
||||||
from moto.core import ACCOUNT_ID
|
from moto.core import ACCOUNT_ID
|
||||||
|
|
||||||
region = "us-east-1"
|
region = "us-east-1"
|
||||||
@ -709,6 +709,58 @@ def test_state_machine_describe_execution_after_stoppage():
|
|||||||
description["stopDate"].should.be.a(datetime)
|
description["stopDate"].should.be.a(datetime)
|
||||||
|
|
||||||
|
|
||||||
|
@mock_stepfunctions
|
||||||
|
@mock_cloudformation
|
||||||
|
def test_state_machine_cloudformation():
|
||||||
|
sf = boto3.client("stepfunctions", region_name="us-east-1")
|
||||||
|
cf = boto3.resource("cloudformation", region_name="us-east-1")
|
||||||
|
definition = '{"StartAt": "HelloWorld", "States": {"HelloWorld": {"Type": "Task", "Resource": "arn:aws:lambda:us-east-1:111122223333;:function:HelloFunction", "End": true}}}'
|
||||||
|
role_arn = (
|
||||||
|
"arn:aws:iam::111122223333:role/service-role/StatesExecutionRole-us-east-1;"
|
||||||
|
)
|
||||||
|
template = {
|
||||||
|
"AWSTemplateFormatVersion": "2010-09-09",
|
||||||
|
"Description": "An example template for a Step Functions state machine.",
|
||||||
|
"Resources": {
|
||||||
|
"MyStateMachine": {
|
||||||
|
"Type": "AWS::StepFunctions::StateMachine",
|
||||||
|
"Properties": {
|
||||||
|
"StateMachineName": "HelloWorld-StateMachine",
|
||||||
|
"StateMachineType": "STANDARD",
|
||||||
|
"DefinitionString": definition,
|
||||||
|
"RoleArn": role_arn,
|
||||||
|
"Tags": [
|
||||||
|
{"Key": "key1", "Value": "value1"},
|
||||||
|
{"Key": "key2", "Value": "value2"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Outputs": {
|
||||||
|
"StateMachineArn": {"Value": {"Ref": "MyStateMachine"}},
|
||||||
|
"StateMachineName": {"Value": {"Fn::GetAtt": ["MyStateMachine", "Name"]}},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cf.create_stack(StackName="test_stack", TemplateBody=json.dumps(template))
|
||||||
|
outputs_list = cf.Stack("test_stack").outputs
|
||||||
|
output = {item["OutputKey"]: item["OutputValue"] for item in outputs_list}
|
||||||
|
state_machine = sf.describe_state_machine(stateMachineArn=output["StateMachineArn"])
|
||||||
|
state_machine["stateMachineArn"].should.equal(output["StateMachineArn"])
|
||||||
|
state_machine["name"].should.equal(output["StateMachineName"])
|
||||||
|
state_machine["roleArn"].should.equal(role_arn)
|
||||||
|
state_machine["definition"].should.equal(definition)
|
||||||
|
tags = sf.list_tags_for_resource(resourceArn=output["StateMachineArn"]).get("tags")
|
||||||
|
for i, tag in enumerate(tags, 1):
|
||||||
|
tag["key"].should.equal("key{}".format(i))
|
||||||
|
tag["value"].should.equal("value{}".format(i))
|
||||||
|
|
||||||
|
cf.Stack("test_stack").delete()
|
||||||
|
with assert_raises(ClientError) as ex:
|
||||||
|
sf.describe_state_machine(stateMachineArn=output["StateMachineArn"])
|
||||||
|
ex.exception.response["Error"]["Code"].should.equal("StateMachineDoesNotExist")
|
||||||
|
ex.exception.response["Error"]["Message"].should.contain("Does Not Exist")
|
||||||
|
|
||||||
|
|
||||||
def _get_account_id():
|
def _get_account_id():
|
||||||
global account_id
|
global account_id
|
||||||
if account_id:
|
if account_id:
|
||||||
|
Loading…
Reference in New Issue
Block a user