Use this as a guide for migrating between major versions of Substation.
Multiple AWS Lambda handlers were renamed to better reflect the AWS service they interact with:
- Renamed
AWS_KINESIS_DATA_FIREHOSEtoAWS_DATA_FIREHOSE. - Renamed
AWS_KINESIStoAWS_KINESIS_DATA_STREAM. - Renamed
AWS_DYNAMODBtoAWS_DYNAMODB_STREAM.
v1.x.x:
module "node" {
source = "build/terraform/aws/lambda"
config = {
name = "node"
description = "Substation node that is invoked by a Kinesis Data Stream."
image_uri = "123456789012.dkr.ecr.us-east-1.amazonaws.com/substation:v1.0.0"
image_arm = true
env = {
"SUBSTATION_CONFIG" : "http://localhost:2772/applications/substation/environments/example/configurations/node"
"SUBSTATION_LAMBDA_HANDLER" : "AWS_KINESIS"
}
}
}v2.x.x:
module "node" {
source = "build/terraform/aws/lambda"
config = {
name = "node"
description = "Substation node that is invoked by a Kinesis Data Stream."
image_uri = "123456789012.dkr.ecr.us-east-1.amazonaws.com/substation:v2.0.0"
image_arm = true
env = {
"SUBSTATION_CONFIG" : "http://localhost:2772/applications/substation/environments/example/configurations/node"
"SUBSTATION_LAMBDA_HANDLER" : "AWS_KINESIS_DATA_STREAM"
}
}
}The Inspector interface was renamed to Conditioner to standardize the naming convention used across the project.
This is replaced by the meta.all, meta.any, and meta.none conditions.
v1.x.x:
sub.cnd.all([
sub.cnd.str.eq({ value: 'FOO' }),
sub.cnd.meta.condition({ condition: sub.cnd.any([
sub.cnd.str.eq({ value: 'BAR' }),
sub.cnd.str.eq({ value: 'BAZ' }),
]) }),
]),v2.x.x:
sub.cnd.all([
sub.cnd.str.eq({ value: 'FOO' }),
sub.cnd.any([
sub.cnd.str.eq({ value: 'BAR' }),
sub.cnd.str.eq({ value: 'BAZ' }),
]),
]),This is replaced by the meta.all, meta.any, and meta.none conditions. If the object.source_key value is an array, then the data is treated as a list of elements.
v1.x.x:
sub.cnd.meta.for_each({
object: { source_key: 'field' },
type: 'any',
inspector: sub.cnd.str.eq({ value: 'FOO' }),
})v2.x.x:
sub.cnd.meta.any({
object: { source_key: 'field' },
conditions: [ sub.cnd.str.eq({ value: 'FOO' }) ],
})This is replaced by the meta.none Condition.
v1.x.x:
sub.cnd.meta.negate({ inspector: sub.cnd.str.eq({ value: 'FOO' }) })v2.x.x:
sub.cnd.meta.none({ conditions: [ sub.cnd.str.eq({ value: 'FOO' }) ] })sub.cnd.none([ sub.cnd.str.eq({ value: 'FOO' }) ])This is removed and was not replaced. Remove any references to this inspector.
The AWS resource fields were replaced by an aws object field that contains the sub-fields arn and assume_role_arn. The region for each AWS client is derived from either the resource ARN or assumed role ARN.
v1.x.x:
sub.tf.send.aws.s3({
bucket_name: 'substation',
file_path: { time_format: '2006/01/02/15', uuid: true, suffix: '.json' },
}),v2.x.x:
sub.tf.send.aws.s3({
aws: { arn: 'arn:aws:s3:::substation' },
file_path: { time_format: '2006/01/02/15', uuid: true, suffix: '.json' },
}),NOTE: This change also applies to every configuration that relies on an AWS resource.
The transform field is removed from all transforms and was replaced with the transforms field.
v1.x.x:
sub.tf.meta.switch({ cases: [
{
condition: sub.cnd.all([
sub.cnd.str.eq({ obj: { source_key: 'field' }, value: 'FOO' }),
]),
transform: sub.tf.obj.insert({ object: { target_key: 'field' }, value: 'BAR' }),
},
]})v2.x.x:
sub.tf.meta.switch({ cases: [
{
condition: sub.cnd.str.eq({ obj: { source_key: 'field' }, value: 'FOO' }),
transforms: [
sub.tf.obj.insert({ object: { target_key: 'field' }, value: 'BAR' })
],
},
]})Retry settings were removed from all transforms and replaced by the meta.retry transform. It is recommended to create a reusable pattern for common retry scenarios.
v1.x.x:
sub.tf.send.aws.sqs({
arn: 'arn:aws:sqs:us-east-1:123456789012:substation',
retry: { count: 3 },
})v2.x.x:
sub.tf.meta.retry({
retry: { count: 3, delay: '1s' },
transforms: [
sub.tf.send.aws.sqs({
aws: { arn: 'arn:aws:sqs:us-east-1:123456789012:substation' },
}),
],
})NOTE: For AWS services, retries for the client can be configured in Terraform by using the AWS_MAX_ATTEMPTS environment variable. This is used in addition the meta.retry transform.
This is removed and was not replaced. Remove any references to this transform and replace it with the transforms field used in other meta transforms.
The send.aws.dynamodb transform was renamed to send.aws.dynamodb.put.
v1.x.x:
sub.tf.send.aws.dynamodb({
table_name: 'substation',
}),v2.x.x:
sub.tf.send.aws.dynamodb.put({
aws: { arn: 'arn:aws:dynamodb:us-east-1:123456789012:table/substation' },
}),The enrich.aws.dynamodb transform was renamed to enrich.aws.dynamodb.query, and had these additional changes:
PartitionKeyandSortKeynow reference the column names in the DynamoDB table and are nested under theAttributesfield.- By default, the value retrieved from
Object.SourceKeyis used as thePartitionKeyvalue. If theSortKeyis provided and the value fromObject.SourceKeyis an array, then the first element is used as thePartitionKeyvalue and the second element is used as theSortKeyvalue. - The
KeyConditionExpressionfield was removed because this is now a derived value.
v1.x.x:
// In v1.x.x, the DynamoDB column names must always be 'PK' and/or 'SK'.
sub.tf.obj.cp({ object: { src: 'id', trg: 'meta ddb.PK' } }),
sub.transform.enrich.aws.dynamodb({
object: { source_key: 'meta ddb', target_key: 'user' },
table_name: 'substation',
partition_key: 'PK',
key_condition_expression: 'PK = :PK',
}),v2.x.x:
sub.transform.enrich.aws.dynamodb.query({
object: { source_key: 'id', target_key: 'user' },
aws: { arn: 'arn:aws:dynamodb:us-east-1:123456789012:table/substation' },
attributes: {
partition_key: 'PK',
},
}),The send.aws.kinesis_data_firehose transform was renamed to send.aws.data_firehose.
v1.x.x:
sub.tf.send.aws.kinesis_data_firehose({
stream_name: 'substation',
}),v2.x.x:
sub.tf.send.aws.data_firehose({
aws: { arn: 'arn:aws:kinesis:us-east-1:123456789012:stream/substation' },
}),