From 5af7c7580356fc6f07fb98c0622916b802386e65 Mon Sep 17 00:00:00 2001 From: Michele Cereda Date: Tue, 11 Nov 2025 11:36:19 +0100 Subject: [PATCH] feat: step functions example --- knowledge base/cloud computing/aws/README.md | 46 ++++ knowledge base/jsonata.md | 92 ++++++++ ...ion to create clones of an rds instance.ts | 219 ++++++++++++++++++ 3 files changed, 357 insertions(+) create mode 100644 knowledge base/jsonata.md create mode 100644 snippets/pulumi/aws/step function to create clones of an rds instance.ts diff --git a/knowledge base/cloud computing/aws/README.md b/knowledge base/cloud computing/aws/README.md index c417972..89905b4 100644 --- a/knowledge base/cloud computing/aws/README.md +++ b/knowledge base/cloud computing/aws/README.md @@ -636,6 +636,52 @@ Such roles need to allow being assumed by the `states.amazonaws.com` Principal. If wanting to send logs to CloudWatch, the execution role must be able to access the log group. +
+ Example: get an RDS DB instance's information and pass it as a specific attribute + +```json +{ + "Comment": "Get an RDS DB instance's information and pass it as a specific attribute", + "StartAt": "Get RDS DB Instance information", + "States": { + "Get RDS DB Instance information": { + "Type": "Task", + "Arguments": { + "DbInstanceIdentifier": "some-rds-db-instance-identifier" + }, + "Resource": "arn:aws:states:::aws-sdk:rds:describeDBInstances", + "End": true, + "Output": { + "RdsDbInstanceInformation": "{% $states.result.DbInstances[0] %}" + } + } + }, + "QueryLanguage": "JSONata" +} +``` + +
+ +Unless one knows exactly what one is doing, prefer setting arguments from the service's Console to have _some_ level of +suggestions. + +
+ FIXME - using variables in DescribeDBSnapshots + +```json +{ + "DbInstanceIdentifier": "{% $states.input.ProdDBInstanceInfo.DbInstanceIdentifier %}" +} +``` + +```json +{ + "AvailableDBSnapshots": "{% $states.result.DbSnapshots[Status='available'] %}" +} +``` + +
+ ## Resource constraints | Data type | Component | Summary | Description | Type | Length | Pattern | Required | diff --git a/knowledge base/jsonata.md b/knowledge base/jsonata.md new file mode 100644 index 0000000..fd3f4be --- /dev/null +++ b/knowledge base/jsonata.md @@ -0,0 +1,92 @@ +# JSONata + +> TODO + +JSON query and transformation language. + + + +1. [TL;DR](#tldr) +1. [Further readings](#further-readings) + 1. [Sources](#sources) + +## TL;DR + +```plaintext +# Concatenate strings +someAttribute & 'someSuffix' +'somePrefix' & someAttribute +'somePrefix' & someAttribute & 'someSuffix' + +# Join strings +$join(['somePrefix', someAttribute, 'someSuffix'], '-') + +# Filter array of objects by attribute's value +users[role = "admin"] +users[role = "admin" and name = "Alice"].name + +# Filter events with timestamp value in the last week +events[$toMillis(timestamp) >= $toMillis($now()) - (60 * 60 * 7 * 24 * 1000)] + +# Get a random value between 0 included and 1 excluded (0<=X<1) +$random() + +# Get a random object from a list +# Lists are 0-indexed +users[$floor($random()*$count($users))] +``` + + + + + + + +## Further readings + +- [Website] +- [Codebase] + +### Sources + +- [Documentation] + + + + + + + +[Codebase]: https://github.com/jsonata-js/jsonata +[Documentation]: https://docs.jsonata.org/ +[Website]: https://jsonata.org/ + + diff --git a/snippets/pulumi/aws/step function to create clones of an rds instance.ts b/snippets/pulumi/aws/step function to create clones of an rds instance.ts new file mode 100644 index 0000000..4985a73 --- /dev/null +++ b/snippets/pulumi/aws/step function to create clones of an rds instance.ts @@ -0,0 +1,219 @@ +import * as pulumi from "@pulumi/pulumi"; +import * as aws from "@pulumi/aws"; + +const iamRole: pulumi.Output = aws.iam.getRoleOutput({ + name: 'SomeServiceRole', +}); + +// ----------------- + +/** + * Base type for Step Function states. + * + * States are elements in a state machine.\ + * A state is referred to by its name, which can be any string, but which must be unique within the scope of the entire + * state machine. + * + * States take input from their own invocation or a previous state.\ + * States can filter their input and manipulate the output that is sent to the next state. + * + * Refer . + */ +type StateMachineBaseState = { + Type: string; + Comment?: string; + Next?: string; + End?: boolean; +}; + +/** + * Choice state.\ + * Enables conditional branching. + */ +interface StateMachineChoiceState extends StateMachineBaseState { + Type: "Choice"; + Choices: Record[]; + Default: string; +}; + +/** + * Branch type for Parallel states.\ + * Itself a smaller state machine. + */ +type StateMachineParallelBranch = { + StartAt: string; + States: Record; +} +/** + * Parallel state.\ + * Runs other step states in parallel. + */ +interface StateMachineParallelState extends StateMachineBaseState { + Type: "Parallel"; + Branches: StateMachineParallelBranch[]; +}; + +/** + * Task state.\ + * Runs a service integration or Lambda function. + */ +interface StateMachineTaskState extends StateMachineBaseState { + Type: "Task"; + Resource: string; + Arguments?: Record; + Output?: Record; +}; + +/** + * Wait state.\ + * Pauses execution for a fixed duration or until a specified time or date. + */ +interface StateMachineWaitState extends StateMachineBaseState { + Type: "Wait"; + Seconds?: number; + Timestamp?: string; +}; + +/** + * Union type for Step Function states. + */ +type StateMachineStepState = + | StateMachineChoiceState + | StateMachineParallelState + | StateMachineTaskState + | StateMachineWaitState; + +/** + * Generic State Machine definition. + */ +interface StateMachineDefinition { + Comment?: string; + QueryLanguage?: string; + StartAt: string; + States: Record; +}; + +// ----------------- + +const changeClonedDbInstancePassword: StateMachineTaskState = { + Type: "Task", + Resource: "arn:aws:states:::aws-sdk:rds:modifyDBInstance", + Arguments: { + DbInstanceIdentifier: "{% $states.input.ClonedDBInstance.DbInstanceIdentifier %}", + MasterUserPassword: "some-Secur3-Password", + ApplyImmediately: true, + }, + End: true, +}; + +const checkClonedDbInstanceIsAvailable: StateMachineChoiceState = { + Type: "Choice", + Choices: [ + { + Condition: "{% $states.input.ClonedDBInstance.DBInstanceStatus in ['available'] %}", + Next: "ChangeClonedDBInstancePassword", + }, + ], + Default: "WaitForClonedDBInstanceNextCheck", +}; + +const createClonedDbInstance: StateMachineTaskState = { + Type: "Task", + Resource: "arn:aws:states:::aws-sdk:rds:restoreDBInstanceToPointInTime", + Arguments: { + SourceDBInstanceIdentifier: "{% $states.input.ExistingDBInstanceInfo.DbInstanceIdentifier %}", + UseLatestRestorableTime: true, + TargetDBInstanceIdentifier: "{% $join([$states.input.ExistingDBInstanceInfo.DbInstanceIdentifier, 'clone'], '-') %}", + Engine: "postgres", + MultiAZ: false, + AvailabilityZone: "eu-west-1a", + DbSubnetGroupName: "default", + PubliclyAccessible: false, + VpcSecurityGroupIds: [], + DbParameterGroupName: "{% $states.input.ExistingDBInstanceInfo.DbParameterGroups[0].DbParameterGroupName %}", + OptionGroupName: "{% $states.input.ExistingDBInstanceInfo.OptionGroupMemberships[0].OptionGroupName %}", + StorageType: "gp3", + DedicatedLogVolume: false, + DbInstanceClass: "db.t4g.medium", + DeletionProtection: false, + AutoMinorVersionUpgrade: false, + }, + Output: { + ClonedDBInstance: "{% $states.result.DbInstance %}", + }, + Next: "GetClonedDBInstanceState", +}; + +const getClonedDbInstanceState: StateMachineTaskState = { + Type: "Task", + Resource: "arn:aws:states:::aws-sdk:rds:describeDBInstances", + Arguments: { + DbInstanceIdentifier: "{% $states.input.ClonedDBInstance.DbInstanceIdentifier %}", + }, + Output: { + ClonedDBInstance: "{% $states.result.DbInstances[0] %}", + }, + Next: "CheckClonedDBInstanceIsAvailable", +}; + +const getExistingDbInstanceInfo: StateMachineTaskState = { + Type: "Task", + Resource: "arn:aws:states:::aws-sdk:rds:describeDBInstances", + Arguments: { + DbInstanceIdentifier: "some-existing-rds-instance", + }, + Output: { + ExistingDBInstanceInfo: "{% $states.result.DbInstances[0] %}", + }, + Next: "ParallelZone", +}; + +const waitForClonedDbInstanceNextCheck: StateMachineWaitState = { + Type: "Wait", + Seconds: 60, + Next: "GetClonedDBInstanceState", +}; + +const parallelZone: StateMachineParallelState = { + Type: "Parallel", + Branches: [ + { + StartAt: "CreateClonedDBInstance", + States: { + CreateClonedDBInstance: createClonedDbInstance, + GetClonedDBInstanceState: getClonedDbInstanceState, + CheckClonedDBInstanceIsAvailable: checkClonedDbInstanceIsAvailable, + WaitForClonedDBInstanceNextCheck: waitForClonedDbInstanceNextCheck, + ChangeClonedDBInstancePassword: changeClonedDbInstancePassword, + }, + }, + // FIXME: another branch here + ], + End: true, +}; + +const stateMachineDefinition: StateMachineDefinition = { + QueryLanguage: "JSONata", + States: { + GetExistingDBInstanceInfo: getExistingDbInstanceInfo, + ParallelZone: parallelZone, + }, + StartAt: "GetExistingDBInstanceInfo", +}; +// pulumi.jsonStringify(stateMachineDefinition).apply(s => console.log(s)) + +const dbCloner_stateMachine: aws.sfn.StateMachine = new aws.sfn.StateMachine( + 'dbCloner', + { + name: 'DBCloner', + roleArn: iamRole.arn, + loggingConfiguration: { + level: "OFF", + }, + encryptionConfiguration: { + type: "AWS_OWNED_KEY", + }, + publish: false, + definition: pulumi.jsonStringify(stateMachineDefinition), + }, +);