Get started with Pulumi and AWS
Create a component
Components are infrastructure abstractions that encapsulate complexity and enable sharing and reuse. Instead of copy-pasting common patterns, you can encode them as components.
You will now create your first component that packages up your S3 website so you can stamp out entire websites in a few lines of code:
const website = new AwsS3Website("my-website", {
files: [ "index.html" ],
});
website = AwsS3Website('my-website', files=['index.html'])
website, err := NewAwsS3Website(ctx, "my-website", AwsS3WebsiteArgs{
Files: []string{"index.html"},
})
if err != nil {
return err
}
var website = new AwsS3Website("my-website", new AwsS3WebsiteArgs()
{
Files = new[] { "index.html" }
});
var website = new AwsS3Website("my-website",
new AwsS3WebsiteArgs(new String[] { "index.html" }));
module "my-website" {
source = "./website"
files = ["index.html"]
}
Using components here also has the benefit that, as the requirements for S3 websites change, you can update the one component definition and have all uses of it benefit.
Define a new component
To define a new component, create a class called AwsS3Website that derives from ComponentResource. Its constructor
starts out empty except for the base call, and you will add the AWS S3 resources to it in the next step. You’ll also define the
component’s inputs – the files to add to the website – and its outputs – a single property with the website url.
In HCL a component is a module: a directory of .tf files that a program instantiates with a module block. It starts out
with only its input declared, and you will add the AWS S3 resources to it in the next step. The module’s variable blocks
declare the inputs for the component – the files to add to the website – and its output blocks declare the outputs –
a single website url.
To get going, create a new file website.jswebsite.tswebsite.pywebsite.goWebsite.csWebsite.javawebsite/main.tfindex.jsindex.ts__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tf
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";
// Arguments for the AWS S3 hosted static website component.
export interface AwsS3WebsiteArgs {
files: string[]; // a list of files to serve.
}
// A component that encapsulates creating an AWS S3 hosted static website.
export class AwsS3Website extends pulumi.ComponentResource {
public readonly url: pulumi.Output<string>; // the S3 website url.
constructor(name: string, args: AwsS3WebsiteArgs, opts?: pulumi.ComponentResourceOptions) {
super("quickstart:index:AwsS3Website", name, args, opts);
// Component initialization will go here next...
this.registerOutputs({}); // Signal component completion.
}
}
import pulumi
from pulumi_aws import s3
from typing import List
# A component that encapsulates creating an AWS S3 hosted static website.
class AwsS3Website(pulumi.ComponentResource):
def __init__(self, name: str, files: List[str] = None, opts = None):
super().__init__('quickstart:index:AwsS3Website', name, { 'files': files }, opts)
# Component initialization will go here next...
self.register_outputs({}) # Signal component completion.
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
type AwsS3Website struct {
pulumi.ResourceState
Url pulumi.StringOutput // the S3 website url.
}
type AwsS3WebsiteArgs struct {
Files []string // a list of files to serve.
}
func NewAwsS3Website(ctx *pulumi.Context, name string, args AwsS3WebsiteArgs, opts ...pulumi.ResourceOption) (*AwsS3Website, error) {
self := &AwsS3Website{}
err := ctx.RegisterComponentResource("quickstart:index:AwsS3Website", name, self, opts...)
if err != nil {
return nil, err
}
// Component initialization will go here next...
ctx.RegisterResourceOutputs(self, pulumi.Map{}) // Signal component completion.
return self, nil
}
using Pulumi;
using Pulumi.Aws.S3;
using Pulumi.Aws.S3.Inputs;
using System.Collections.Generic;
public class AwsS3WebsiteArgs
{
public string[]? Files { get; set; }
}
public class AwsS3Website : Pulumi.ComponentResource
{
public Output<string> Url { get; private set; }
public AwsS3Website(string name, AwsS3WebsiteArgs args, ComponentResourceOptions? opts = null)
: base("quickstart:index:AwsS3Website", name, opts)
{
// Component initialization will go here next...
this.RegisterOutputs(new Dictionary<string, object>{}); // Signal component completion.
}
}
package myproject;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.s3.Bucket;
import com.pulumi.resources.ComponentResource;
import com.pulumi.resources.ComponentResourceOptions;
import com.pulumi.resources.ResourceArgs;
import java.util.Map;
class AwsS3WebsiteArgs extends ResourceArgs {
public String[] files;
public AwsS3WebsiteArgs(String[] files) {
this.files = files;
}
}
class AwsS3Website extends ComponentResource {
public Output<String> url;
public AwsS3Website(String name, AwsS3WebsiteArgs args, ComponentResourceOptions opts) {
super("quickstart:index:AwsS3Website", name, args, opts);
// Component initialization will go here next...
this.registerOutputs(Map.of());
}
}
terraform {
required_providers {
aws = {
source = "pulumi/aws"
}
}
}
# A list of files to serve.
variable "files" {
type = list(string)
}
# The AWS S3 resources and the website url output will go here next...
This defines a component but it doesn’t do much yet.
Refactor your code into the component
Next, make four changes:
- Move all resources from
into the component’s constructorindex.jsindex.tsmain.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tf - Change each resource to use the component as the
parent - Generalize the creation of bucket objects by looping over the list of
files - Assign the resulting website URL to the
urlproperty of the component
Next, make three changes:
- Move all resources from
into the moduleindex.jsindex.tsmain.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tf - Generalize the creation of bucket objects by looping over the list of
fileswithfor_each - Return the resulting website URL as the module’s
urloutput
Nothing needs reparenting: everything a module declares is automatically a child of the component resource that Pulumi creates for the module instance.
The resulting website.jswebsite.tswebsite.pywebsite.goWebsite.csWebsite.javawebsite/main.tfwebsite.jswebsite.tswebsite.pywebsite.goWebsite.csWebsite.javawebsite/main.tf
import * as aws from "@pulumi/aws";
import * as pulumi from "@pulumi/pulumi";
// Arguments for the AWS S3 hosted static website component.
export interface AwsS3WebsiteArgs {
files: string[]; // a list of files to serve.
}
// A component that encapsulates creating an AWS S3 hosted static website.
export class AwsS3Website extends pulumi.ComponentResource {
public readonly url: pulumi.Output<string>; // the S3 website url.
constructor(name: string, args: AwsS3WebsiteArgs, opts?: pulumi.ComponentResourceOptions) {
super("quickstart:index:AwsS3Website", name, args, opts);
// Create an AWS resource (S3 Bucket)
const bucket = new aws.s3.Bucket("my-bucket", {}, {
// Set the parent to the component (step #2) above.
// Also, do the same for all other resources below.
parent: this,
});
// Turn the bucket into a website:
const website = new aws.s3.BucketWebsiteConfiguration("website", {
bucket: bucket.id,
indexDocument: {
suffix: "index.html",
},
}, { parent: this });
// Permit access control configuration:
const ownershipControls = new aws.s3.BucketOwnershipControls("ownership-controls", {
bucket: bucket.id,
rule: {
objectOwnership: "ObjectWriter"
}
}, { parent: this });
// Enable public access to the website:
const publicAccessBlock = new aws.s3.BucketPublicAccessBlock("public-access-block", {
bucket: bucket.id,
blockPublicAcls: false,
}, { parent: this });
// Create an S3 Bucket object for each file; note the changes to name/source:
for (const file of args.files) {
new aws.s3.BucketObject(file, {
bucket: bucket.id,
source: new pulumi.asset.FileAsset(file),
contentType: "text/html",
acl: "public-read",
}, {
dependsOn: [ownershipControls, publicAccessBlock],
parent: this,
});
}
// Capture the URL and make it available as a component property and output:
this.url = pulumi.interpolate`http://${website.websiteEndpoint}`;
this.registerOutputs({ url: this.url }); // Signal component completion.
}
}
import pulumi
from pulumi_aws import s3
from typing import List
# A component that encapsulates creating an AWS S3 hosted static website.
class AwsS3Website(pulumi.ComponentResource):
def __init__(self, name: str, files: List[str] = None, opts = None):
super().__init__('quickstart:index:AwsS3Website', name, { 'files': files }, opts)
# Create an AWS resource (S3 Bucket)
bucket = s3.Bucket('my-bucket',
# Set the parent to the component (step #2) above.
# Also, do the same for all other resources below.
opts=pulumi.ResourceOptions(parent=self),
)
# Turn the bucket into a website:
website = s3.BucketWebsiteConfiguration("website",
bucket=bucket.id,
index_document={
"suffix": "index.html",
},
opts=pulumi.ResourceOptions(parent=self),
)
# Permit access control configuration:
ownership_controls = s3.BucketOwnershipControls(
'ownership-controls',
bucket=bucket.id,
rule={
"object_ownership": 'ObjectWriter',
},
opts=pulumi.ResourceOptions(parent=self),
)
# Enable public access to the website:
public_access_block = s3.BucketPublicAccessBlock(
'public-access-block', bucket=bucket.id, block_public_acls=False,
opts=pulumi.ResourceOptions(parent=self),
)
# Create an S3 Bucket object for each file; note the changes to name/source:
for file in files:
s3.BucketObject(
file,
bucket=bucket.id,
source=pulumi.FileAsset(file),
content_type='text/html',
acl='public-read',
opts=pulumi.ResourceOptions(
depends_on=[ownership_controls, public_access_block],
parent=self,
),
)
# Capture the URL and make it available as a component property and output:
self.url = pulumi.Output.concat('http://', website.website_endpoint)
self.register_outputs({ 'url': self.url }) # Signal component completion.
package main
import (
"fmt"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/s3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
type AwsS3Website struct {
pulumi.ResourceState
Url pulumi.StringOutput // the S3 website url.
}
type AwsS3WebsiteArgs struct {
Files []string // a list of files to serve.
}
func NewAwsS3Website(ctx *pulumi.Context, name string, args AwsS3WebsiteArgs, opts ...pulumi.ResourceOption) (*AwsS3Website, error) {
self := &AwsS3Website{}
err := ctx.RegisterComponentResource("quickstart:index:AwsS3Website", name, self, opts...)
if err != nil {
return nil, err
}
// Create an AWS resource (S3 Bucket)
bucket, err := s3.NewBucket(ctx, "my-bucket", nil,
// Set the parent to the component (step #2) above.
// Also, do the same for all other resources below.
pulumi.Parent(self))
if err != nil {
return nil, err
}
// Turn the bucket into a website:
website, err := s3.NewBucketWebsiteConfiguration(ctx, "website", &s3.BucketWebsiteConfigurationArgs{
Bucket: bucket.ID(),
IndexDocument: &s3.BucketWebsiteConfigurationIndexDocumentArgs{
Suffix: pulumi.String("index.html"),
},
}, pulumi.Parent(self))
if err != nil {
return nil, err
}
// Permit access control configuration:
ownershipControls, err := s3.NewBucketOwnershipControls(ctx, "ownership-controls", &s3.BucketOwnershipControlsArgs{
Bucket: bucket.ID(),
Rule: &s3.BucketOwnershipControlsRuleArgs{
ObjectOwnership: pulumi.String("ObjectWriter"),
},
}, pulumi.Parent(self))
if err != nil {
return nil, err
}
// Enable public access to the website:
publicAccessBlock, err := s3.NewBucketPublicAccessBlock(ctx, "public-access-block", &s3.BucketPublicAccessBlockArgs{
Bucket: bucket.ID(),
BlockPublicAcls: pulumi.Bool(false),
}, pulumi.Parent(self))
if err != nil {
return nil, err
}
// Create an S3 Bucket object for each file; note the changes to name/source:
for _, file := range args.Files {
_, err = s3.NewBucketObject(ctx, file, &s3.BucketObjectArgs{
Bucket: bucket.ID(),
Source: pulumi.NewFileAsset(file),
ContentType: pulumi.String("text/html"),
Acl: pulumi.String("public-read"),
}, pulumi.DependsOn([]pulumi.Resource{ownershipControls, publicAccessBlock}), pulumi.Parent(self))
if err != nil {
return nil, err
}
}
// Export the bucket's autoassigned URL:
self.Url = website.WebsiteEndpoint.ApplyT(func(websiteEndpoint string) (string, error) {
return fmt.Sprintf("http://%v", websiteEndpoint), nil
}).(pulumi.StringOutput)
ctx.RegisterResourceOutputs(self, pulumi.Map{"url": self.Url}) // Signal component completion.
return self, nil
}
using Pulumi;
using Pulumi.Aws.S3;
using Pulumi.Aws.S3.Inputs;
using System.Collections.Generic;
public class AwsS3WebsiteArgs
{
public string[]? Files { get; set; }
}
public class AwsS3Website : Pulumi.ComponentResource
{
public Output<string> Url { get; private set; }
public AwsS3Website(string name, AwsS3WebsiteArgs args, ComponentResourceOptions? opts = null)
: base("quickstart:index:AwsS3Website", name, opts)
{
// Create an AWS resource (S3 Bucket)
var bucket = new Bucket("my-bucket", new(), new CustomResourceOptions
{
// Set the parent to the component (step #2) above.
// Also, do the same for all other resources below.
Parent = this,
});
// Turn the bucket into a website:
var website = new BucketWebsiteConfiguration("website", new()
{
Bucket = bucket.Id,
IndexDocument = new BucketWebsiteConfigurationIndexDocumentArgs
{
Suffix = "index.html",
},
}, new CustomResourceOptions
{
Parent = this,
});
// Permit access control configuration:
var ownershipControls = new BucketOwnershipControls("ownership-controls", new()
{
Bucket = bucket.Id,
Rule = new BucketOwnershipControlsRuleArgs
{
ObjectOwnership = "ObjectWriter",
},
}, new CustomResourceOptions
{
Parent = this,
});
// Enable public access to the website:
var publicAccessBlock = new BucketPublicAccessBlock("public-access-block", new()
{
Bucket = bucket.Id,
BlockPublicAcls = false,
}, new CustomResourceOptions
{
Parent = this,
});
// Create an S3 Bucket object for each file; note the changes to name/source:
foreach (var file in args.Files ?? []) {
new BucketObject(file, new()
{
Bucket = bucket.Id,
Source = new FileAsset(file),
ContentType = "text/html",
Acl = "public-read",
}, new CustomResourceOptions
{
DependsOn = new Resource[]
{
ownershipControls,
publicAccessBlock,
},
Parent = this,
});
}
// Export the bucket's autoassigned URL:
this.Url = website.WebsiteEndpoint.Apply(websiteEndpoint => $"http://{websiteEndpoint}");
this.RegisterOutputs(new Dictionary<string, object?>{
["url"] = this.Url
});
}
}
package myproject;
import com.pulumi.*;
import com.pulumi.core.*;
import com.pulumi.asset.FileAsset;
import com.pulumi.resources.*;
import com.pulumi.aws.s3.*;
import com.pulumi.aws.s3.inputs.*;
import java.util.Map;
class AwsS3WebsiteArgs extends ResourceArgs {
public String[] files;
public AwsS3WebsiteArgs(String[] files) {
this.files = files;
}
}
class AwsS3Website extends ComponentResource {
public Output<String> url;
public AwsS3Website(String name, AwsS3WebsiteArgs args) {
this(name, args, null);
}
public AwsS3Website(String name, AwsS3WebsiteArgs args, ComponentResourceOptions opts) {
super("quickstart:index:AwsS3Website", name, args, opts);
// Create an AWS resource (S3 Bucket)
var bucket = new Bucket("my-bucket", null,
// Set the parent to the component (step #2) above.
// Also, do the same for all other resources below.
CustomResourceOptions.builder().parent(this).build());
// Turn the bucket into a website:
var website = new BucketWebsiteConfiguration("website", BucketWebsiteConfigurationArgs.builder()
.bucket(bucket.id())
.indexDocument(BucketWebsiteConfigurationIndexDocumentArgs.builder()
.suffix("index.html")
.build())
.build(), CustomResourceOptions.builder().parent(this).build());
// Permit access control configuration:
var ownershipControls = new BucketOwnershipControls("ownership-controls", BucketOwnershipControlsArgs.builder()
.bucket(bucket.id())
.rule(BucketOwnershipControlsRuleArgs.builder()
.objectOwnership("ObjectWriter")
.build())
.build(), CustomResourceOptions.builder().parent(this).build());
// Enable public access to the website:
var publicAccessBlock = new BucketPublicAccessBlock("public-access-block", BucketPublicAccessBlockArgs.builder()
.bucket(bucket.id())
.blockPublicAcls(false)
.build(), CustomResourceOptions.builder().parent(this).build());
// Create an S3 Bucket object for each file; note the changes to name/source:
for (var file : args.files) {
new BucketObject(file, BucketObjectArgs.builder()
.bucket(bucket.id())
.source(new FileAsset(file))
.contentType("text/html")
.acl("public-read")
.build(), CustomResourceOptions.builder()
.dependsOn(
ownershipControls,
publicAccessBlock)
.parent(this)
.build());
}
// Export the bucket's autoassigned URL:
this.url = website.websiteEndpoint().applyValue(
websiteEndpoint -> String.format("http://%s", websiteEndpoint));
this.registerOutputs(Map.of("url", this.url));
}
}
terraform {
required_providers {
aws = {
source = "pulumi/aws"
}
}
}
# A list of files to serve.
variable "files" {
type = list(string)
}
# Create an AWS resource (S3 Bucket)
resource "aws_s3_bucket" "my-bucket" {
# A module prefixes the Pulumi names of the resources it contains, so set each
# name explicitly (here and below) to keep the names free of that prefix.
pulumi {
name = "my-bucket"
}
}
# Turn the bucket into a website:
resource "aws_s3_bucket_website_configuration" "website" {
bucket = aws_s3_bucket.my-bucket.id
index_document {
suffix = "index.html"
}
pulumi {
name = "website"
}
}
# Permit access control configuration:
resource "aws_s3_bucket_ownership_controls" "ownership-controls" {
bucket = aws_s3_bucket.my-bucket.id
rule {
object_ownership = "ObjectWriter"
}
pulumi {
name = "ownership-controls"
}
}
# Enable public access to the website:
resource "aws_s3_bucket_public_access_block" "public-access-block" {
bucket = aws_s3_bucket.my-bucket.id
block_public_acls = false
pulumi {
name = "public-access-block"
}
}
# Create an S3 Bucket object for each file:
resource "aws_s3_bucket_object" "files" {
for_each = toset(var.files)
bucket = aws_s3_bucket.my-bucket.id
source = fileasset(each.value)
content_type = "text/html"
acl = "public-read"
depends_on = [
aws_s3_bucket_ownership_controls.ownership-controls,
aws_s3_bucket_public_access_block.public-access-block,
]
pulumi {
name = each.value
}
}
# Capture the URL and make it available as a component output:
output "url" {
value = "http://${aws_s3_bucket_website_configuration.website.website_endpoint}"
}
Instantiate the component
Now go back to your original file index.jsindex.ts__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tf
Add this to your now-empty index.jsindex.ts__main__.pymain.goProgram.csProgram.fsProgram.vbApp.javaPulumi.yamlmain.tf
// Import from the new component module:
import { AwsS3Website } from "./website";
// Create an instance of the component with the same files as before:
const website = new AwsS3Website("my-website", {
files: [ "index.html" ],
});
// And export its autoassigned URL:
export const url = website.url;
import pulumi
# Import from the new component module:
from website import AwsS3Website
# Create an instance of the component with the same files as before:
website = AwsS3Website('my-website', files=['index.html'])
# And export its autoassigned URL:
pulumi.export("url", website.url)
package main
import (
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// Create an instance of the component with the same files as before:
website, err := NewAwsS3Website(ctx, "my-website", AwsS3WebsiteArgs{
Files: []string{"index.html"},
})
if err != nil {
return err
}
// And export its autoassigned URL:
ctx.Export("url", website.Url)
return nil
})
}
using Pulumi;
using Pulumi.Aws.S3;
using System.Collections.Generic;
return await Pulumi.Deployment.RunAsync(() =>
{
// Create an instance of the component with the same files as before:
var website = new AwsS3Website("my-website", new AwsS3WebsiteArgs()
{
Files = new[] { "index.html" }
});
// And export its autoassigned URL:
return new Dictionary<string, object?>
{
["url"] = website.Url
};
});
package myproject;
import com.pulumi.Pulumi;
public class App {
public static void main(String[] args) {
Pulumi.run(ctx -> {
// Create an instance of the component with the same files as before:
var website = new AwsS3Website("my-website",
new AwsS3WebsiteArgs(new String[] { "index.html" }));
// And export its autoassigned URL:
ctx.export("url", website.url);
});
}
}
# Instantiate the new component with the same files as before; the source is the
# directory the module lives in:
module "my-website" {
source = "./website"
files = ["index.html"]
}
# And export its autoassigned URL:
output "url" {
value = module.my-website.url
}
Deploy the component
Now deploy the resulting component instantiation. To do so, run pulumi up as usual:
$ pulumi up
Previewing update (dev)
Type Name Plan
pulumi:pulumi:Stack quickstart-dev
+ ├─ quickstart:index:AwsS3Website my-website create
+ │ ├─ aws:s3:Bucket my-bucket create
+ │ ├─ aws:s3:BucketWebsiteConfiguration website create
+ │ ├─ aws:s3:BucketOwnershipControls ownership-controls create
+ │ ├─ aws:s3:BucketPublicAccessBlock public-access-block create
+ │ └─ aws:s3:BucketObject index.html create
- ├─ aws:s3:BucketObject index.html delete
- ├─ aws:s3:BucketPublicAccessBlock public-access-block delete
- ├─ aws:s3:BucketOwnershipControls ownership-controls delete
- ├─ aws:s3:BucketWebsiteConfiguration website delete
- └─ aws:s3:Bucket my-bucket delete
Resources:
+ 6 to create
- 5 to delete
11 changes. 1 unchanged
Do you want to perform this update? [Use arrows to move, type to filter]
yes
> no
details
$ pulumi up
Previewing update (dev)
Type Name Plan
pulumi:pulumi:Stack quickstart-dev
+ ├─ components:index:Website my-website create
+ │ ├─ aws:s3:Bucket my-bucket create
+ │ ├─ aws:s3:BucketWebsiteConfiguration website create
+ │ ├─ aws:s3:BucketOwnershipControls ownership-controls create
+ │ ├─ aws:s3:BucketPublicAccessBlock public-access-block create
+ │ └─ aws:s3:BucketObject index.html create
- ├─ aws:s3:BucketObject index.html delete
- ├─ aws:s3:BucketPublicAccessBlock public-access-block delete
- ├─ aws:s3:BucketOwnershipControls ownership-controls delete
- ├─ aws:s3:BucketWebsiteConfiguration website delete
- └─ aws:s3:Bucket my-bucket delete
Resources:
+ 6 to create
- 5 to delete
11 changes. 1 unchanged
Do you want to perform this update? [Use arrows to move, type to filter]
yes
> no
details
The Website segment of the component’s type, components:index:Website, is the title-cased name of the
directory the module lives in; the components:index: prefix is fixed.
This preview shows you a few things. First, you’ll see your new website component with all its child resources neatly parented underneath it, which makes it easy to see which resources belong to which component. Next, you’ll see that your old resources are being destroyed.
Accept the changes by selecting yes and the deployment will occur:
Updating (dev)
Type Name Status
pulumi:pulumi:Stack quickstart-dev
+ ├─ quickstart:index:AwsS3Website my-website created (0.16s)
+ │ ├─ aws:s3:Bucket my-bucket created (1s)
+ │ ├─ aws:s3:BucketWebsiteConfiguration website created (0.24s)
+ │ ├─ aws:s3:BucketPublicAccessBlock public-access-block created (0.49s)
+ │ ├─ aws:s3:BucketOwnershipControls ownership-controls created (0.63s)
+ │ └─ aws:s3:BucketObject index.html created (0.19s)
- ├─ aws:s3:BucketObject index.html deleted (0.18s)
- ├─ aws:s3:BucketOwnershipControls ownership-controls deleted (0.58s)
- ├─ aws:s3:BucketPublicAccessBlock public-access-block deleted (0.18s)
- ├─ aws:s3:BucketWebsiteConfiguration website deleted (0.27s)
- └─ aws:s3:Bucket my-bucket deleted (0.51s)
Outputs:
~ url: "http://my-bucket-b531107.s3-website-us-west-2.amazonaws.com" => "http://my-bucket-d05c30a.s3-website-us-west-2.amazonaws.com"
Resources:
+ 6 created
- 5 deleted
11 changes. 1 unchanged
Duration: 10s
Updating (dev)
Type Name Status
pulumi:pulumi:Stack quickstart-dev
+ ├─ components:index:Website my-website created (0.16s)
+ │ ├─ aws:s3:Bucket my-bucket created (1s)
+ │ ├─ aws:s3:BucketWebsiteConfiguration website created (0.24s)
+ │ ├─ aws:s3:BucketPublicAccessBlock public-access-block created (0.49s)
+ │ ├─ aws:s3:BucketOwnershipControls ownership-controls created (0.63s)
+ │ └─ aws:s3:BucketObject index.html created (0.19s)
- ├─ aws:s3:BucketObject index.html deleted (0.18s)
- ├─ aws:s3:BucketOwnershipControls ownership-controls deleted (0.58s)
- ├─ aws:s3:BucketPublicAccessBlock public-access-block deleted (0.18s)
- ├─ aws:s3:BucketWebsiteConfiguration website deleted (0.27s)
- └─ aws:s3:Bucket my-bucket deleted (0.51s)
Outputs:
~ url: "http://my-bucket-b531107.s3-website-us-west-2.amazonaws.com" => "http://my-bucket-d05c30a.s3-website-us-west-2.amazonaws.com"
Resources:
+ 6 created
- 5 deleted
11 changes. 1 unchanged
Duration: 10s
Now test out your new website – it works like before, just with a tidier codebase now!
$ curl $(pulumi stack output url)
<html>
<body>
<h1>Hello, Pulumi!</h1>
</body>
</html>
> curl (pulumi stack output url)
<html>
<body>
<h1>Hello, Pulumi!</h1>
</body>
</html>
Once you are ready to move on, destroy everything you’ve spun up in this tutorial.