2

I am attempting to execute a script on one of our instances whenever a container's state changes. I am creating a target SSM Run Command with the document being AWS-RunShellScript (Linux)

I would have thought I could somehow pass data from the event into the script, however I cannot find a way to do so. The way I thought it could be done was using an Input Transformer

Input Path: {"lastStatus":"$.detail.lastStatus"}

Template: { "commands":["/path/to/script <lastStatus>"] }

but I get the following error

InputTemplate for target [id] contains placeholder within quotes

I was trying to not add an additional component to this with Lambda.

Tyler Clendenin
  • 197
  • 1
  • 1
  • 10
  • Facing a similar issue for a custom RunCommand document. I need to to pass the instance ID form the event to the run command. unsure of how to use the transformations. – Shurmajee Jun 17 '20 at 18:29

2 Answers2

1

The InputTemplate value needs to be a valid JSON string. Therefore, your Input Template needs to be escaped JSON.

Here is an example of an escaped JSON string as a JSON value (taken from an aws batch state change event):

"InputPathsMap": {
    "job_number" : "$.detail.container.environment.JOB_NUMBER",
    "status" : "$.detail.status"
},
"InputTemplate": "\"{ \\\"job\\\": \\\"StatusChangeJob\\\", \\\"payload\\\": { \\\"job_number\\\": \\\"<job_number>\\\", \\\"status\\\": \\\"<status>\\\" } }\""
Matt Lampe
  • 11
  • 2
1

I don't know if you ever ended up figuring this out, but I'll post my solution for anyone else who runs across this question while googling.

I ended up creating a custom command document with an extra parameter specifically for the value I was interested in. That way I didn't have to quote the placeholder when specifying it in the template, I could just pass it directly. Example, based on the existing RunShellScript command document:

{
    "schemaVersion": "2.2",
    "description": "Pass previous status to local script.",
    "parameters": {
        "scriptPath": {
            "type": "String",
            "descripton": "(Required) The absolute path to the local script.",
            "maxChars": 4096
        },
        "lastStatus": {
            "type": "String",
            "description": "The previous status of the container.",
            "maxChars": 100
        }
        "workingDirectory": {
            "type": "String",
            "default": "",
            "description": "(Optional) The path to the working directory on your instance.",
            "maxChars": 4096
        },
        "executionTimeout": {
            "type": "String",
            "default": "3600",
            "description": "(Optional) The time in seconds for a command to complete before it is considered to have failed. Default is 3600 (1 hour). Maximum is 172800 (48 hours).",
            "allowedPattern": "([1-9][0-9]{0,4})|(1[0-6][0-9]{4})|(17[0-1][0-9]{3})|(172[0-7][0-9]{2})|(172800)"
        }
    },
    "mainSteps": [{
        "action": "aws:runShellScript",
        "name": "runShellScript",
        "inputs": {
            "runCommand": [
                "{{ scriptPath }} '{{ lastStatus }}'"
            ],
            "workingDirectory": "{{ workingDirectory }}",
            "executionTimeout": "{{ executionTimeout }}"
        }
    }]
}

Then you can just set "lastStatus": "$.detail.lastStatus" in the input path, and {scriptPath: "/path/to/script", "lastStatus": <lastStatus>} (note the absence of quotes) in the template, and you should be good to go.

I haven't tested this arrangement exactly, but I have tested a similar one (what I wanted to extract was the event time), and that worked perfectly.

Joseph Montanaro
  • 518
  • 4
  • 13
  • Annoyingly this doesnt seem to work on the current version. Seems they may have updated the underlying script executed to accept multiple commands and it breaks this solution to passing parameters into the shell script. Seems a pretty basic requirement. – Trevor North Jul 31 '19 at 09:03
  • The existing AWS-RunShellScript document has a parameter "commands" which is a StringList rather than scriptPath which is a String . The Error i get is "----------ERROR------- Invalid format in plugin properties map[timeoutSeconds:3600 workingDirectory: id:0.aws:runShellScript runCommand:'/home/ubuntu/aws/ssc/update_status.sh i-01d3636f74a7a0c17 running']; error json: cannot unmarshal string into Go struct field RunScriptPluginInput.RunCommand of type []string" – Trevor North Jul 31 '19 at 09:08
  • The schema version you mention is v2.2 whereas the AWS-RunShellScript is schema v1.2 but i have tried several variations and just cannot find the right combination of quotes and brackets to get it to work - still only wasted a couple of days so far so maybe i will get there by luck but the documentation is useless. – Trevor North Jul 31 '19 at 09:08
  • combining the two so runCommands is a STRINGLIST like this "mainSteps": [{ "action": "aws:runShellScript", "name": "runShellScript", "inputs": { "runCommand": [ "{{ commands }} '{{ instance }} {{state}}'" ], "workingDirectory": "{{ workingDirectory }}", "executionTimeout": "{{ executionTimeout }}" } } ] gets an error InvalidDocumentContent: Parameter "commands" is "STRING_LIST" type and can't be used as a substring parameter. – Trevor North Jul 31 '19 at 09:12
  • and same happens if put single quotes around the whole command including parameters - "runCommand": [ " ' {{ commands }} {{ instance }} {{state}} ' " ], and the same error if omit single quotes altogether "runCommand": [ "{{ commands }} {{ instance }} {{state}}" ], – Trevor North Jul 31 '19 at 09:14
  • going to raise a support ticket to see if AWS can resolve it – Trevor North Jul 31 '19 at 09:16
  • @TrevorNorth Did you find a solution for this? – Shobit Mahajan Jun 08 '22 at 12:31