First Look - Terraform HCL vs Pulumi Programs
Let’s try creating the same resources using both Terraform HCL and a Pulumi program. This basic example will also serve to verify your cloud connectivity.
The Terraform way of doing things
In Terraform, if you wanted to query an AMI ID you might write something like this in Hashicorp Configuration Language (HCL):
data "aws_ami" "ubuntu" {
region = "us-west-2"
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
}
output "latest_ubuntu_ami_id" {
value = data.aws_ami.ubuntu.id
}
output "latest_ubuntu_ami_name" {
value = data.aws_ami.ubuntu.name
}
If you run this Terraform config, you should see output showing the latest Ubuntu AMI information. HCL is a configuration language, similar in spirit to YAML or JSON but with more expressiveness and modularization. Pulumi lets you describe the same desired state in a general-purpose programming language, in YAML, or in HCL itself, so you can choose the style that fits your team.
Pulumi programs
Let’s try creating the same resources in a Pulumi program. Pulumi lets you keep writing HCL or move to a general-purpose programming language; the engine, state management, and secrets handling are the same either way. Both approaches query the same AWS API and return identical results:
First, create a new Pulumi program:
$ mkdir pulumi-terraform-test && cd pulumi-terraform-test
$ pulumi new aws-typescript --yes
Replace the contents of index.ts with:
import * as aws from "@pulumi/aws";
// Query existing Ubuntu AMIs (read-only operation)
const ubuntu = aws.ec2.getAmiOutput({
region: "us-west-2",
mostRecent: true,
owners: ["099720109477"], // Canonical
filters: [
{
name: "name",
values: ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"],
},
],
});
export const latestUbuntuAmiId = ubuntu.id;
export const latestUbuntuAmiName = ubuntu.name;
First, create a new Pulumi program:
$ mkdir pulumi-terraform-test && cd pulumi-terraform-test
$ pulumi new aws-python --yes
Replace the contents of __main__.py with:
import pulumi
import pulumi_aws as aws
# Query existing Ubuntu AMIs (read-only operation)
ubuntu = aws.ec2.get_ami(
region="us-west-2",
most_recent=True,
owners=["099720109477"], # Canonical
filters=[
{
"name": "name",
"values": ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"],
}
],
)
pulumi.export("latestUbuntuAmiId", ubuntu.id)
pulumi.export("latestUbuntuAmiName", ubuntu.name)
First, create a new Pulumi program:
$ mkdir pulumi-terraform-test && cd pulumi-terraform-test
$ pulumi new aws-go --yes
Replace the contents of main.go with:
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// Query existing Ubuntu AMIs (read-only operation)
ubuntu, err := ec2.LookupAmi(ctx, &ec2.LookupAmiArgs{
Region: pulumi.StringRef("us-west-2"),
MostRecent: pulumi.BoolRef(true),
Owners: []string{"099720109477"}, // Canonical
Filters: []ec2.GetAmiFilter{
{
Name: "name",
Values: []string{"ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"},
},
},
})
if err != nil {
return err
}
ctx.Export("latestUbuntuAmiId", pulumi.String(ubuntu.Id))
ctx.Export("latestUbuntuAmiName", pulumi.String(ubuntu.Name))
return nil
})
}
First, create a new Pulumi program:
$ mkdir pulumi-terraform-test && cd pulumi-terraform-test
$ pulumi new aws-csharp --yes
Replace the contents of Program.cs with:
using System.Collections.Generic;
using Pulumi;
using Pulumi.Aws.Ec2;
using Pulumi.Aws.Ec2.Inputs;
return await Deployment.RunAsync(() =>
{
// Query existing Ubuntu AMIs (read-only operation)
var ubuntu = GetAmi.Invoke(new()
{
Region = "us-west-2",
MostRecent = true,
Owners = new[] { "099720109477" }, // Canonical
Filters = new[]
{
new GetAmiFilterInputArgs
{
Name = "name",
Values = new[] { "ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*" },
},
},
});
return new Dictionary<string, object?>
{
["latestUbuntuAmiId"] = ubuntu.Apply(ubuntu => ubuntu.Id),
["latestUbuntuAmiName"] = ubuntu.Apply(ubuntu => ubuntu.Name),
};
});
First, create a new Pulumi program:
$ mkdir pulumi-terraform-test && cd pulumi-terraform-test
$ pulumi new aws-java --yes
Replace the contents of src/main/java/myproject/App.java with:
package myproject;
import com.pulumi.Pulumi;
import com.pulumi.aws.ec2.Ec2Functions;
import com.pulumi.aws.ec2.inputs.GetAmiArgs;
import com.pulumi.aws.ec2.inputs.GetAmiFilterArgs;
import com.pulumi.core.Output;
import java.util.List;
public class App {
public static void main(String[] args) {
Pulumi.run(ctx -> {
// Query existing Ubuntu AMIs (read-only operation)
var ubuntu = Ec2Functions.getAmi(GetAmiArgs.builder()
.region("us-west-2")
.mostRecent(true)
.owners("099720109477") // Canonical
.filters(GetAmiFilterArgs.builder()
.name("name")
.values("ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*")
.build())
.build());
ctx.export("latestUbuntuAmiId", ubuntu.applyValue(ami -> ami.id()));
ctx.export("latestUbuntuAmiName", ubuntu.applyValue(ami -> ami.name()));
});
}
}
First, create a new Pulumi program:
$ mkdir pulumi-terraform-test && cd pulumi-terraform-test
$ pulumi new aws-yaml --yes
Replace the contents of Pulumi.yaml with:
name: pulumi-terraform-test
runtime: yaml
description: Test Pulumi and AWS connectivity
variables:
ubuntu:
fn::invoke:
function: aws:ec2:getAmi
arguments:
region: us-west-2
mostRecent: true
owners: ["099720109477"] # Canonical
filters:
- name: name
values: ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
outputs:
latestUbuntuAmiId: ${ubuntu.id}
latestUbuntuAmiName: ${ubuntu.name}
With Pulumi HCL there is nothing to rewrite: the Terraform config from the top of this page runs unchanged. Create a project directory:
$ mkdir pulumi-terraform-test && cd pulumi-terraform-test
Add a Pulumi.yaml that selects the HCL runtime:
name: pulumi-terraform-test
runtime: hcl
description: Test Pulumi and AWS connectivity
Then save the same HCL, unchanged, as main.tf:
data "aws_ami" "ubuntu" {
region = "us-west-2"
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
}
output "latest_ubuntu_ami_id" {
value = data.aws_ami.ubuntu.id
}
output "latest_ubuntu_ami_name" {
value = data.aws_ami.ubuntu.name
}
Create a stack and install the providers the program uses:
$ pulumi stack init dev
$ pulumi install
From the pulumi-terraform-test directory you created above, run the test:
$ pulumi up
You should see output showing the latest Ubuntu AMI information, confirming that Pulumi can successfully query your AWS environment.
Clean up
Remove the test resources:
$ pulumi destroy --yes
$ pulumi stack rm --yes
$ cd .. && rm -rf pulumi-terraform-test