Skip to content

How to format an SSM Runbook to execute a script from S3?

0

I have scoured the documentation from top to bottom at this point and I still can't figure out how to abstract my python scripts to s3 so I don't have to include them inline in my runbook. The SSM documentation does say that it is possible to attach and execute a script straight from s3.

I have inline script execution down, but attached script execution is always met with this result:

Failure message Step fails when it is Poll action status for completion. Traceback (most recent call last): AttributeError: module 'test' has no attribute 'main' Handler main is not found in provided script. Please refer to Automation Service Troubleshooting Guide for more diagnosis details.

Here is the code I am trying:

description: A simple SSM runbook that calls a templated script to print and output a message.
schemaVersion: '0.3'
parameters:
  Message:
    type: String
    description: The message to print and output.
    default: "Hello from the runbook!"
mainSteps:
  - name: ExecuteTemplateScript
    action: aws:executeScript
    isEnd: true
    inputs:
      Runtime: python3.10
      Handler: test.main  # [file].[function] format
      InputPayload:
        Message: '{{ Message }}'
      Script: ''
      Attachment: test.py  # Name of the attached file
    outputs:
      - Name: OutputMessage
        Selector: $.Payload.OutputMessage
        Type: String
files:
  test.py:
    checksums:
      sha256: 590708757b79b9438bf299ee496a121c98cf865899db8fea5d788d0cb616d1f5

I have tried variations of:

handler: test.py.main handler: test handler: test.main handler: main

Here is the test script.

#!/usr/bin/env python3
"""Simple templated script for SSM that prints and outputs a message."""

import json

def process_message(payload: dict) -> dict:
    """Process the input message and return it."""
    message = payload.get('Message', 'No message provided')
    print(f"Message received: {message}")  # Printed to SSM logs
    return {'OutputMessage': message}

def main(events, context):
    """Main function for SSM execution."""
    # SSM passes InputPayload as 'events'
    payload = events
    result = process_message(payload)
    return result  # SSM captures this as output

if __name__ == "__main__":
    # For local testing, simulate SSM input
    import sys
    if not sys.stdin.isatty():
        payload = json.load(sys.stdin)
    else:
        payload = {'Message': 'Hello, world!'}
    result = process_message(payload)
    print(json.dumps(result))

Here are the docs I have tried parsing:

https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_AttachmentsSource.html https://docs.aws.amazon.com/systems-manager/latest/userguide/automation-authoring-runbooks-scripted-example.html https://docs.aws.amazon.com/systems-manager/latest/userguide/automation-document-script-considerations.html https://docs.aws.amazon.com/systems-manager/latest/userguide/automation-action-executeScript.html

The script is attached and the checksum checks out.

So I have come to my last resort. Asking the experts directly. Help please.

asked a year ago336 views

1 Answer
1

To execute a script from S3 in an SSM Runbook, you need to use the aws:executeScript action with the appropriate configuration. Here's how you can modify your runbook to execute a script stored in S3:

  1. First, upload your Python script (test.py) to an S3 bucket.

  2. Modify your SSM Runbook YAML as follows:

description: A simple SSM runbook that calls a script from S3 to print and output a message.
schemaVersion: '0.3'
parameters:
  Message:
    type: String
    description: The message to print and output.
    default: "Hello from the runbook!"
mainSteps:
  - name: ExecuteS3Script
    action: aws:executeScript
    isEnd: true
    inputs:
      Runtime: python3.10
      Handler: main
      InputPayload:
        Message: '{{ Message }}'
      Script: |
        import boto3
        import json

        s3 = boto3.client('s3')

        def main(events, context):
            # Download the script from S3
            bucket = 'your-s3-bucket-name'
            key = 'path/to/test.py'
            response = s3.get_object(Bucket=bucket, Key=key)
            script_content = response['Body'].read().decode('utf-8')

            # Execute the downloaded script
            exec(script_content, globals())

            # Call the process_message function from the downloaded script
            return process_message(events)

The key changes in this configuration are:

1. The Handler is set to 'main', which refers to the main function in the inline script.
2. The Script section now contains an inline Python script that downloads your actual script from S3 and executes it.
3. Remove the 'files' section from your runbook as it's no longer needed.

Make sure to replace 'your-s3-bucket-name' and 'path/to/test.py' with the actual S3 bucket name and the path to your script in S3.

This approach allows you to keep your main script logic in S3 while using a small inline script in the runbook to fetch and execute it. The inline script downloads your Python file from S3, executes it in the global namespace, and then calls the process_message function from your original script.

Remember to ensure that the IAM role associated with your SSM execution has permissions to read from the S3 bucket where your script is stored.

This method should resolve the "Handler main is not found" error you were encountering, as the handler 'main' now refers to the function in the inline script, which in turn executes your S3-stored script.  
**Sources**  
[Using scripts in runbooks - AWS Systems Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/automation-document-script-considerations.html)  
[Example 2: Scripted runbook - AWS Systems Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/automation-authoring-runbooks-scripted-example.html)

answered a year ago

EXPERT

reviewed a year ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.