Search code examples
jsonpython-3.xamazon-web-servicesboto3aws-step-functions

Pass variable into Step Function start_execution() input parameter


I am using boto3 with Python 3.6 to start a Step Function execution. The Step Function is designed to share my base AMI across all my accounts. I have 4 variables I need to pass to the input parameter to kick off the execution. These are the AMI ID, the account list of accounts I own, the source account, and the KMS key. The AMI ID and the account list are constructed in my code and are the variables that need to get passed dynamically. According to the documentation, input is a string that contains the JSON input data for the execution and gives the following example: "input": "{\"ami_id\" : \"ami_id\"}". My question is how do I pass the variables in question to this parameter as the value? My code is below with the traceback:

CODE:

import boto3
import json

#   Get an STS token to assume roles into AWS accounts
def get_sts_token(**kwargs):
    role_arn = kwargs['RoleArn']
    region_name = kwargs['RegionName']
    sts = boto3.client(
        'sts',
    region_name=region_name,
    )
    token = sts.assume_role(
        RoleArn=role_arn,
        RoleSessionName='GetInstances',
        DurationSeconds=900,
    )
    return token["Credentials"]

def get_accounts():
    role_arn = "arn:aws:iam::xxxxxxxxxx:role/list-accounts-role"
    region_name = "us-east-1"

    token = get_sts_token(RoleArn=role_arn, RegionName=region_name)

    access_key = token['AccessKeyId']
    secret_key = token['SecretAccessKey']       
    session_token = token['SessionToken']

    client = boto3.client('organizations', 
    aws_access_key_id=access_key,
    aws_secret_access_key=secret_key,
    aws_session_token=session_token)

    moreAccounts=True
    nexttoken=''
    global accountList
    accountList =[]

    while moreAccounts:
        if (len(nexttoken)>0):
            accounts=client.list_accounts(NextToken=nexttoken)
        else:
            accounts=client.list_accounts()
        if 'NextToken' in accounts:
            nexttoken=accounts['NextToken']
        else:
            moreAccounts=False
        for account in accounts['Accounts']:
            if account['Status'] != 'SUSPENDED' and account['Status'] != 'CLOSED' :
                account_id = account['Id']
                accountList.append(account_id)


    print(accountList)

def trigger_sfn():
    ssm = boto3.client('ssm')
    role_arn = "arn:aws:iam::xxxxxxxx:role/execute-sfn"
    region_name = "us-east-1"

    ami_id = ssm.get_parameter(Name='/BaseAMI/newest')['Parameter']['Value']
    print(ami_id)

    token = get_sts_token(RoleArn=role_arn, RegionName=region_name)
    print(token)

    access_key = token['AccessKeyId']
    secret_key = token['SecretAccessKey']       
    session_token = token['SessionToken']

    sfn = boto3.client('stepfunctions', 
    aws_access_key_id=access_key,
    aws_secret_access_key=secret_key,
    aws_session_token=session_token)

    response = sfn.start_execution(
    stateMachineArn='arn:aws:states:us-east-1:xxxxxxxx:stateMachine:ami-share',
    input="{\"ami_id\": ami_id, \"source_account_id\": \"112233445566\", \"accountList\": accountList, \"kms_key_arn\": \"alias/aws/ebs\"}"
)

    print(response)

TRACE:

An error occurred (InvalidExecutionInput) when calling the 
StartExecution operation: Invalid State Machine Execution Input: 
'com.fasterxml.jackson.core.JsonParseException: Unrecognized token 
'ami_id': was expecting ('true', 'false' or 'null')
at [Source: (String)"{"ami_id": ami_id, "source_account_id": 
"112233445566", "accountList": accountList, "kms_key_arn": 
"alias/aws/ebs"}"; line: 1, column: 18]': InvalidExecutionInput
Traceback (most recent call last):
File "/var/task/lambda_function.py", line 6, in lambda_handler
trigger_sfn()
File "/var/task/lambda_function.py", line 96, in trigger_sfn
input="{\"ami_id\": ami_id, \"source_account_id\": \"112233445566\", 
\"accountList\": accountList, \"kms_key_arn\": \"alias/aws/ebs\"}"
File "/var/runtime/botocore/client.py", line 314, in _api_call
return self._make_api_call(operation_name, kwargs)
File "/var/runtime/botocore/client.py", line 612, in _make_api_call
raise error_class(parsed_response, operation_name)
botocore.errorfactory.InvalidExecutionInput: An error occurred 
(InvalidExecutionInput) when calling the StartExecution operation: 
Invalid State Machine Execution Input: 
'com.fasterxml.jackson.core.JsonParseException: Unrecognized token 
'ami_id': was expecting ('true', 'false' or 'null')
at [Source: (String)"{"ami_id": ami_id, "source_account_id": 
"112233445566", "accountList": accountList, "kms_key_arn": 
"alias/aws/ebs"}"; line: 1, column: 18]'

Solution

  • You can add the value of the variable to the string like this:

    input="{\"ami_id\": \"" + ami_id + "\", \"source_account_id\": \"112233445566\", \"accountList\": accountList, \"kms_key_arn\": \"alias/aws/ebs\"}"
    

    Your code currently sends the literal string "ami_id", instead of the variable value of ami_id