Package: cdk-ssm-documents
SSM Document CDKThis library provides a utility implement SSM Documents using code. The SSM Document objects can be used to print the document to YAML/JSON and allows you to simulate a document execution locally.Problem StatementWriting SSM documents is cumbersome because interacting with the JSON or YAML documents provides little compile time support for errors. While the SSM UI provides a rich experience for creating documents, the SSM UI provides no ability to reuse steps across documents.Testing documents can only be performed by running the SSM Execution which is time-consuming. There is also no way to mock results in SSM Execution so developers are forced to create the necessary infrastructure in the AWS account prior to executing the SSM Document.Exceptions are at times difficult to find or understand from the SSM Execution because sometimes the underlying issue is hidden and the error that is propagated is unrelated.SolutionThis library provides a high level abstraction of the SSM Documents where each step as well as the document itself are objects. The properties required for construction of these objects correspond to the settings applicable them making them intuitive to create.
You can use this library to simulate your document locally before deploying to SSM.The library is implemented using JSII and can therefore be exported to other JSII supported languages (Java, Python).You would use this if you want:Ability to test without deploying resources or running a real SSM execution on AWSAbility to reuse steps between docs by reusing available objectsBuild higher level logical groupings of reusable groups of steps ("Patterns")Easy interface for creating DocsTest existing documents by importing them from a file (or string) and simulate them locallyUsageDocument CreationTypescript usage (Execute AWS API Step)...
The below creates the AutomationDocument in an AWS CDK stack.import{AutomationDocument}from'./automation-document';exportclassHelloWorldextendsStack{constructor(app:Construct,id:string){super(app,id);//CreateAutomationDocumentconstmyDoc=newAutomationDocument(this,"MyDoc",{documentFormat:DocumentFormat.JSON,documentName:"MyDoc",docInputs:[{name:"MyInput",defaultValue:"a",inputType:DataTypeEnum.STRING}]});//Defineyoursteps...myDoc.addStep(newPauseStep(this,"MyPauseStep",{name:"MyPauseStep"}));myDoc.addStep(newExecuteScriptStep(this,"MyExecuteStep",{name:"step1",handlerName:"my_func",language:ScriptLanguage.PYTHON,fullPathToCode:resolve("test/test_file.py"),//OR.inlineCode("def my_func(args, context):\nreturn {'MyReturn': args['MyInput'] + '-suffix'}\n")outputs:[{outputType:DataTypeEnum.STRING,name:"MyFuncOut",selector:"$.Payload.MyReturn"}],inputs:["MyInput"]}));}}Document JSON/YAML Export as YAML/JSONYou can deploy the above document using CDK.
To print the above document object as a JSON (or YAML), do the following:constmyDocJson=myDoc.print();//PrintYAMLbysettingthedocumentFormattoYAMLDocument SimulationTo run the document object in simulation mode, use the below. Simulation mode does NOT hit the SSM API, rather it mimics the execution that will happen in an SSM execution. The run happens locally and allows you to mock the calls to external services (AWS APIs for example) or to invoke those services using your local credentials.import{Simulation}from'./simulation';constmyDocJson=Simulation.ofAutomation(myDoc,{}).simulate({MyInput:"FooBar"});Patterns (High-Level Constructs)In typical CDK style, you can assemble often used groups of steps into higher level Constructs.Consider if you typically create AutomationDocuments that start with logging the time and end with logging the total time taken. You can create a high-level Automation Document and extend that when you implement an Automation.See theTimedDocumentclass to see such implementation.Or consider the case of multiple steps that are always run together such as rebooting and instance and waiting for it to be active.The below example is copied from theRebootInstanceAndWaitclass:exportclassRebootInstanceAndWaitextendsCompositeAutomationStep{readonlyreboot:AwsApiStep;readonlydescribe:WaitForResourceStep;constructor(scope:Construct,id:string,instanceId:IStringVariable){super(scope,id);this.reboot=newAwsApiStep(this,'RebootInstances',{service:'ec2',pascalCaseApi:'RebootInstances',apiParams:{InstanceIds:[instanceId]},outputs:[],});this.describe=newWaitForResourceStep(this,'DescribeInstances',{service:'ec2',pascalCaseApi:'DescribeInstances',apiParams:{InstanceIds:[instanceId]},selector:'$.Reservations[0].Instances[0].State.Name',desiredValues:['running'],});}addToDocument(doc:AutomationDocumentBuilder):void{doc.addStep(this.reboot);doc.addStep(this.describe);}}Now, you can useRebootInstanceAndWaitas a step in a document and the child steps will be included.Existing DocumentsDo you have an existing document that you want to convert to code and/or test locally using the simulation?Import Existing DocumentHere is an example of how you can import an existing document and then simulate it locally with mocked AWS resources://InitializeMocksconstsleeper=newMockSleep();constawsInvoker=newMockAwsInvoker();awsInvoker.whenThen(//wheninvokedwith...{awsApi:'listBuckets',awsParams:{},service:'S3'},//thenresponsewith...{Owner:{ID:"BUCKET_ID"}})//======>Createdocumentfromfile<=======conststack:Stack=newStack();constmyAutomationDoc=StringDocument.fromFile(stack,"MyAutomationDoc",'test/myAutomation.json',{//======================});//ExecutesimulationconstsimOutput=Simulation.ofAutomation(myAutomationDoc,{sleepHook:sleeper,awsInvoker:awsInvoker}).simulate({});//Assertsimulationresultassert.deepEqual(awsInvoker.previousInvocations,[{awsApi:'listBuckets',awsParams:{},service:'S3'}]);assert.deepEqual(sleeper.sleepMilliInvocations,[3000]);assert.deepEqual(simOutput.outputs['simulationSteps'],['MySleep','GetBucketId']);Import Existing StepsYou can also grab a string step (or steps) and import them as CDK step constructs.
This can be used to convert existing documents into CDK with each step defined separately.
Doing so will allow you do modify steps and reuse them in other documents.Here's a simple example of a sleep step copy and pasted from its original yaml:StringStep.fromYaml(this,`name:sleepaction:aws:sleepinputs:Duration:PT0M`,{});The above will return the CDK construct SleepStep.What is Planned?This library currently contains AutomationDocument steps.Also planned is the ability to run Command documents.Stay tuned!SecuritySeeCONTRIBUTINGfor more information.LicenseThis project is licensed under the Apache-2.0 License.