Update EC2 instance
This Workflow allows you to streamline modifications to an existing EC2 instance.
How to use a Workflow in Cortex to update an EC2 instance with Terraform
Prerequisite
Before getting started, you should have already followed the guide to Provision an EC2 instance with Terraform.
Step 1: Start creating the Workflow
Follow the steps in the documentation to create a Workflow and configure its basic settings.
In the Workflow's basic settings, set its scope to apply to the entity type AWS::EC2::Instance
and the group terraform
. The prerequisite Workflow Provision an EC2 instance with Terraform automatically adds the group to the entities it creates.
Step 2: Add blocks to the Workflow
The instructions on this page describe how to create this Workflow in the Cortex UI, but it is also possible to copy the Workflow YAML and add it to your workspace via the Cortex CLI. This allows you to quickly set up the example configuration then iterate on it for your own use case. Expand the tile below to learn more.
Workflow YAML instructions
To upload the Workflow example YAML into your workspace:
Save the Workflow example YAML file below:
name: "[Terraform Cloud] - Update EC2 instance"
tag: update-ec2-instance
description: null
isDraft: true
filter:
entityFilter:
typeFilter:
types:
- AWS::EC2::Instance
entityGroupFilter: null
ownershipScope: ALL
type: ENTITY
runResponseTemplate: null
failedRunResponseTemplate: null
actions:
- name: Get Descriptor
slug: get-descriptor
schema:
expression: .context.entity.descriptor
type: JQ
outgoingActions:
- get-terraform-file
isRootAction: true
- name: Getting Terraform File
slug: get-terraform-file
schema:
inputs:
ref: main
path: "{{actions.get-descriptor.outputs.result.info.x-cortex-git.github.basepath}}/main.tf"
repo: "{{actions.get-descriptor.outputs.result.info.x-cortex-git.github.repository}}"
integrationAlias: cortex
actionIdentifier: github.getFile
type: ADVANCED_HTTP_REQUEST
outgoingActions:
- decoding-file-content
isRootAction: false
- name: Decoding File Content
slug: decoding-file-content
schema:
expression: .actions."get-terraform-file".outputs.response.content | gsub("\n";"")
| @base64d
type: JQ
outgoingActions:
- getting-current-properties
isRootAction: false
- name: Getting Current Properties
slug: getting-current-properties
schema:
script: |
var fileContent = actions['decoding-file-content'].outputs.result
var fileObject = hcl.parseToObject(fileContent)
return fileObject
type: JAVASCRIPT
outgoingActions:
- get-current-region
isRootAction: false
- name: Get Current Region
slug: get-current-region
schema:
expression: ".actions.\"getting-current-properties\".outputs.result[0].provider.aws[0].region"
type: JQ
outgoingActions:
- get-current-instance-type
isRootAction: false
- name: Get Current Instance Type
slug: get-current-instance-type
schema:
expression: ".actions.\"getting-current-properties\".outputs.result[0].resource.aws_instance.ubuntu[0].instance_type"
type: JQ
outgoingActions:
- get-current-instance-name
isRootAction: false
- name: Get Current Instance Name
slug: get-current-instance-name
schema:
expression: ".actions.\"getting-current-properties\".outputs.result[0].resource.aws_instance.ubuntu[0].tags.Name"
type: JQ
outgoingActions:
- setting-github-fields
isRootAction: false
- name: Setting GitHub Fields
slug: setting-github-fields
schema:
expression: |-
{
"pr_name" : "PR for " + .actions."get-current-instance-name".outputs.result ,
"branch_name" : "branch-for-" + .actions."get-current-instance-name".outputs.result ,
"repo_name" : "cremerica/sample-iac-repo",
"commit_msg": "Commit automated by Cortex"
}
type: JQ
outgoingActions:
- user-input
isRootAction: false
- name: User input
slug: user-input
schema:
inputs:
- name: Current Instance Type
description: null
key: current-instance-type
required: false
defaultValue: null
placeholder: null
validationRegex: null
type: INPUT_FIELD
- name: Instance-Type
description: null
key: instance-type
required: false
options:
- t2.micro
- t2.medium
- t2.large
defaultValue: null
placeholder: ""
allowAdditionalOptions: false
type: SELECT_FIELD
- name: Current Region
description: null
key: current-region
required: false
defaultValue: null
placeholder: null
validationRegex: null
type: INPUT_FIELD
- name: New Region
description: null
key: new-region
required: false
options:
- us-west-2
- us-west-1
- us-east-1
- us-east-2
defaultValue: null
placeholder: null
allowAdditionalOptions: false
type: SELECT_FIELD
inputOverrides:
- inputKey: current-instance-type
outputVariable: actions.get-current-instance-type.outputs.result
editable: false
type: VALUE
- inputKey: current-region
outputVariable: actions.get-current-region.outputs.result
editable: false
type: VALUE
type: USER_INPUT
outgoingActions:
- get-new-instance-type
isRootAction: false
- name: Get New instance Type
slug: get-new-instance-type
schema:
expression: if .actions."user-input".outputs."instance-type" == null then .actions."user-input".outputs."current-instance-type"
else .actions."user-input".outputs."instance-type" end
type: JQ
outgoingActions:
- get-new-region
isRootAction: false
- name: Get New Region
slug: get-new-region
schema:
expression: if .actions."user-input".outputs."new-region" == null then .actions."get-current-region".outputs.result
else .actions."user-input".outputs."new-region" end
type: JQ
outgoingActions:
- scaffolder
isRootAction: false
- name: 'Modify '
slug: scaffolder
schema:
scaffolderTemplateId: st2babdd4cc74929f2
createNewRepository: false
createService: false
inputOverrides:
- inputKey: instance_type
outputVariable: actions.get-new-instance-type.outputs.result
editable: true
type: VALUE
- inputKey: resource_name
outputVariable: actions.get-current-instance-name.outputs.result
editable: true
type: VALUE
- inputKey: project_name
outputVariable: actions.get-current-instance-name.outputs.result
editable: true
type: VALUE
- inputKey: publisherRepoFullName
outputVariable: actions.setting-github-fields.outputs.result.repo_name
editable: false
type: VALUE
- inputKey: publisherBranch
outputVariable: actions.setting-github-fields.outputs.result.branch_name
editable: true
type: VALUE
- inputKey: publisherPullRequestTitle
outputVariable: actions.setting-github-fields.outputs.result.pr_name
editable: false
type: VALUE
- inputKey: publisherPullRequestBody
outputVariable: actions.setting-github-fields.outputs.result.pr_name
editable: true
type: VALUE
- inputKey: publisherCommitMessage
outputVariable: actions.setting-github-fields.outputs.result.commit_msg
editable: false
type: VALUE
- inputKey: region
outputVariable: actions.get-new-region.outputs.result
editable: true
type: VALUE
type: SCAFFOLDER
outgoingActions: []
isRootAction: false
runRestrictionPolicies: []
iconTag: null
variables: []
Use the Cortex CLI to run this command, using the path to your Workflow YAML file:
cortex workflows create -f <path-to-your-workflow.yaml>
Expand the tiles below to learn about each block in this Workflow and how to configure them in the Cortex UI:
Data transformation
Get the entity descriptor with a data transformation block.
Click + in the center of the page. In the block library modal, choose Data transformation.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Get Descriptor
and the slugget-descriptor
.
Add a jq expression to get the entity descriptor:
.context.entity.descriptor
At the bottom of the side panel, click Save.
GitHub get file
This block gets the Terraform file you want to update.
Click + in the center of the page. In the block library modal, choose GitHub > Get file.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Getting Terraform file
and the slugget-terraform-file
.
For the Required parameters, configure the following:
Repository:
{{actions.get-descriptor.outputs.result.info.x-cortex-git.github.repository}}
Path:
{{actions.get-descriptor.outputs.result.info.x-cortex-git.github.basepath}}/main.tf
Ref:
main
Save the block.
Data transformation
Take the output from the previous block and decode its file contents.
Click + in the center of the page. In the block library modal, choose Data transformation.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Decoding file content
and the slugdecoding-file-content
.
Add a jq expression:
.actions."get-terraform-file".outputs.response.content | gsub("\n";"") | @base64d
At the bottom of the side panel, click Save.
JavaScript
Run a script to get the current properties from the file you got in previous steps of the Workflow.
Click + in the center of the page. In the block library modal, choose GitHub > Get file.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Getting current properties
and the sluggetting-current-properties
.
Add a JavaScript expression:
/*#CORTEX_IGNORE*/import {_, YAML, hcl, context, actions, variables, fetch} from './utils.js'; async () => {
var fileContent = actions['decoding-file-content'].outputs.result
var fileObject = hcl.parseToObject(fileContent)
return fileObject
/*#CORTEX_IGNORE*/}
Save the block.
Data transformations
Add four Data transformation blocks to reformat the output from previous blocks:
Get current region
Click + in the center of the page. In the block library modal, choose Data transformation.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Get current region
and the slugget-current-region
.
Add a jq expression:
.actions."getting-current-properties".outputs.result[0].provider.aws[0].region
At the bottom of the side panel, click Save.
Get current instance type
Click + in the center of the page. In the block library modal, choose Data transformation.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Get current instance type
and the slugget-current-instance-type
.
Add a jq expression:
.actions."getting-current-properties".outputs.result[0].resource.aws_instance.ubuntu[0].instance_type
At the bottom of the side panel, click Save.
Get current instance name
Click + in the center of the page. In the block library modal, choose Data transformation.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Get current instance name
and the slugget-current-instance-name
.
Add a jq expression:
.actions."getting-current-properties".outputs.result[0].resource.aws_instance.ubuntu[0].tags.Name
At the bottom of the side panel, click Save.
Set GitHub fields
Click + in the center of the page. In the block library modal, choose Data transformation.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Setting GitHub fields
and the slugsetting-github-fields
.
Add a jq expression:
{
"pr_name" : "PR for " + .actions."get-current-instance-name".outputs.result ,
"branch_name" : "branch-for-" + .actions."get-current-instance-name".outputs.result ,
"repo_name" : "cremerica/sample-iac-repo",
"commit_msg": "Commit automated by Cortex"
}
At the bottom of the side panel, click Save.
User input
In this example, we add a User Input block to gather resource details from the output of previous blocks and prompt the user to select the instance type and new region.
Click + in the center of the page. In the block library modal, choose User input.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
User input
and the sluguser-input
.
Click +Add user input. Add the following:
Name: Current instance type
Key: current-instance-type
Type: Text
Path to override value:
actions.get-current-instance-type.outputs.result
Click Add input.
Click +Add user input. Add the following:
Name: Instance type
Key: instance-type
Type: Select
Data source: Manual
Placeholder: In this example, the resource size options are t2.micro, t2.medium, and t2.large.
Click Add input.
Click +Add user input. Add the following:
Name: Current region
Key: get-current-region
Type: Text
Path to override value:
actions.get-current-region.outputs.result
Click Add input.
Click +Add user input. Add the following:
Name: New region
Key: new-region
Type: Select
Placeholder: In this example, the options are us-west-2, us-west-1, us-east-1, and us-east-2.
Click Add input.
Save the block.
Data transformations
Use two data transformations to format the new instance type and region that were entered during the previous step:
Get new instance type
Click + in the center of the page. In the block library modal, choose Data transformation.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Get new instance type
and the slugget-new-instance-type
.
Add a jq expression:
if .actions."user-input".outputs."instance-type" == null then .actions."user-input".outputs."current-instance-type" else .actions."user-input".outputs."instance-type" end
At the bottom of the side panel, click Save.
Get new region
Click + in the center of the page. In the block library modal, choose Data transformation.
In the block configuration side panel, enter a name and unique slug for this block.
In this example, we use the name
Get new region
and the slugget-new-region
.
Add a jq expression:
if .actions."user-input".outputs."new-region" == null then .actions."get-current-region".outputs.result else .actions."user-input".outputs."new-region" end
At the bottom of the side panel, click Save.
Scaffolder
Run a Scaffolder to make modifications. In this block, you will configure override variables to pre-fill parts of the Scaffolder template based on the output of previous steps.
Click + in the center of the page. In the block library modal, select the Scaffolder block.
In the side panel, enter a name and unique slug for the block.
In this example, we use the name
Modify
and the slugscaffolder
.
Under Scaffolder template, select your template. In this example, we use the
New EC2 Instance
template.Select the option to Open a pull request.
Add override variables. The Variable dropdown pulls in all the variables that are able to be overridden in the Git provider and in the Scaffolder template. In this example, we apply the following overrides:
instance_type:
actions.get-new-instance-type.outputs.result
This overrides it with the output of the "Get new instance type" block earlier in the Workflow.
resource_name:
actions.get-current-instance-name.outputs.result
This overrides it with the output of the "Get current instance name" block earlier in the Workflow.
project_name:
actions.get-current-instance-name.outputs.result
This overrides it with the output of the "Get current instance name" block earlier in the Workflow.
publisherRepoFullName:
actions.setting-github-fields.outputs.result.repo_name
This overrides it with the output of the "Setting GitHub fields" block earlier in the Workflow.
publisherBranch:
actions.setting-github-fields.outputs.result.branch_name
This overrides it with the branch_name output of the "Setting GitHub fields" block earlier in the Workflow.
publisherPullRequestTitle:
actions.setting-github-fields.outputs.result.pr_name
This overrides it with the pr_name output of the "Setting GitHub fields" block earlier in the Workflow.
publisherPullRequestBody:
actions.setting-github-fields.outputs.result.pr_name
This overrides it with the pr_name output of the "Setting GitHub fields" block earlier in the Workflow.
publisherCommitMessage:
actions.setting-github-fields.outputs.result.commit_msg
This overrides it with the commit_msg output of the "Setting GitHub fields" block earlier in the Workflow.
region:
actions.get-new-region.outputs.result
This overrides it with the output of the resource region chosen during the "Get new region" block earlier in the Workflow.
Set a timeout of 5 minutes.
At the bottom of the side panel, click Save.
Step 3: Run the Workflow
When you run the Workflow, the following events happen:
The Workflow obtains the entity descriptor and gets the Terraform file.
The Data transformation steps decode the file contents, reshape the data, then use that reformatted data to set fields in GitHub.
The User input step collects the current instance type, new instance type, and current region.
The data is transformed, and the reformatted data is used to apply modifications to the EC2 instance.
Last updated
Was this helpful?