# A First Look at Pulumi

> Pulumi provides open source infrastructure as code SDKs for creating, deploying, and managing infrastructure on multiple clouds in multiple languages

- **Collection:** Blog post
- **Published:** 2021-09-27
- **Author:** Anthony Campolo
- **Canonical URL:** https://ajcwebdev.com/first-look-pulumi/
- **Markdown URL:** https://ajcwebdev.com/first-look-pulumi/index.md
- **JSON URL:** https://ajcwebdev.com/first-look-pulumi/index.json

---

> ___All of this project's code can be found in the [First Look monorepo](https://github.com/ajcwebdev/a-first-look/tree/main/deployment/pulumi/) on my GitHub.___

## Introduction

[Pulumi](https://www.pulumi.com) provides open source infrastructure as code SDKs that enable you to create, deploy, and manage infrastructure on numerous popular clouds in multiple programming languages.

## Setup

In this tutorial, we'll show you how to write a Pulumi program that creates a serverless app serving static content with dynamic routes in AWS Lambda.

### Install Pulumi CLI

Instructions for downloading the CLI will [vary depending on your operating system](https://www.pulumi.com/docs/install/). This tutorial will use [Homebrew](https://brew.sh/) on MacOS.

```bash wrap=false
brew install pulumi
```

Subsequent updates can be installed with `brew upgrade`.

```bash wrap=false
brew upgrade pulumi
```

### Configure AWS Credentials

Make sure you have the [AWS CLI](https://aws.amazon.com/cli/) installed and an [AWS account](https://aws.amazon.com/). For general use, [`aws configure`](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html) is recommended as the fastest way to set up your AWS CLI installation.

```bash wrap=false
aws configure
```

When you enter this command, the AWS CLI prompts you for four pieces of information:
* Access key ID
* Secret access key
* AWS Region
* Output format

Go to [My Security Credentials](https://console.aws.amazon.com/iam/home?#/security_credentials) to find your Access Key ID, Secret Access Key, and default region. You can leave the output format blank.

```
AWS Access Key ID: <YOUR_ACCESS_KEY_ID>
AWS Secret Access Key: <YOUR_SECRET_ACCESS_KEY>
Default region name: <YOUR_REGION_NAME>
Default output format [None]: 
```

### Login to Pulumi

```bash wrap=false
pulumi login
```

You will be asked to hit `<ENTER>` to log in with your browser.

```
Manage your Pulumi stacks by logging in.

Run `pulumi login --help` for alternative login options.

Enter your access token from https://app.pulumi.com/account/tokens
    or hit <ENTER> to log in using your browser
```

## Create a New Pulumi Project

We'll use the [pulumi new](https://www.pulumi.com/docs/iac/cli/commands/pulumi_new/) command and generate a new project with the `hello-aws-javascript` template. It will be named `ajcwebdev-pulumi` with the `--name` flag.

```bash wrap=false
mkdir ajcwebdev-pulumi
cd ajcwebdev-pulumi
pulumi new hello-aws-javascript --name ajcwebdev-pulumi
```

You will be asked to provide a description, stack name, and AWS region. I selected the default option for each.

### Pulumi Yaml Files

A Pulumi project is any folder which contains a `Pulumi.yaml` file specifying metadata about your project. The project file must begin with a capitalized P and can use either `.yml` or `.yaml` extensions.

```yaml
# Pulumi.yaml

name: ajcwebdev-pulumi
runtime: nodejs
description: A simple AWS serverless JavaScript Pulumi program
```

The key-value pairs for any given stack are stored in your project's stack settings file, which is automatically named `Pulumi.<stack-name>.yaml`.

```yaml
# Pulumi.dev.yaml

config:
  aws:region: us-west-1
```

### Index File

Import the [pulumi/aws](https://www.pulumi.com/registry/packages/aws/) package. Create a public HTTP endpoint using AWS API Gateway that serves static files from the `www` folder using AWS S3 with a REST API served on `GET /name` with AWS Lambda. Finally, export the public URL for the HTTP service with `exports.url = endpoint.url`.

```js wrap=false
// index.js

const pulumi = require("@pulumi/pulumi")
const aws = require("@pulumi/aws")
const awsx = require("@pulumi/awsx")

const endpoint = new awsx.apigateway.API("hello", {
  routes: [
    {
      path: "/",
      localPath: "www",
    },
    {
      path: "/source",
      method: "GET",
      eventHandler: (req, ctx, cb) => {
        cb(undefined, {
          statusCode: 200,
          body: Buffer.from(JSON.stringify({ name: "AWS" }), "utf8").toString("base64"),
          isBase64Encoded: true,
          headers: { "content-type": "application/json" },
        })
      },
    },
  ],
})

exports.url = endpoint.url
```

### HTML Index File

The project comes with a hello world example in the `index.html` file.

```html wrap=false
<!-- www/index.html -->

<!DOCTYPE html>

<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Hello Pulumi</title>
    <link rel="shortcut icon" href="favicon.png" type="image/png">
  </head>

  <body>
    <p>Hello, world!</p>
    <p>Made with ❤️ using <a href="https://pulumi.com">Pulumi</a></p>
    <p>Served from: <span id="source"></span></p>
  </body>

  <script>
    fetch("source")
      .then(response => response.json())
      .then(json => {
        document.getElementById("source").innerText = json.name;
      });
  </script>
</html>
```

## Deploy to Pulumi Cloud

Create or update the resources in a stack with `pulumi up`.

```bash wrap=false
pulumi up
```

```
Do you want to perform this update?  [Use arrows to move, enter to select, type to filter]
> yes
  no
  details
```

Select yes.

```
Outputs:
    url: "https://2inuue6w0a.execute-api.us-west-1.amazonaws.com/stage/"

Resources:
    + 22 created

Duration: 26s
```

Open the output's URL, (`2inuue6w0a.execute-api.us-west-1.amazonaws.com/stage/` in my case) to see your site.

![01 - pulumi-boilerplate](https://ajc.pics/2021/09/27/01-pulumi-boilerplate.webp)

### Update HTML File

Change stuff.

```html wrap=false
<!-- www/index.html -->

<!DOCTYPE html>

<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>ajcwebdev-pulumi</title>
    <link rel="shortcut icon" href="favicon.png" type="image/png">
  </head>

  <body>
    <h2>ajcwebdev-pulumi</h2>
    <p>Served from: <span id="source"></span></p>
  </body>

  <script>
    fetch("source")
      .then(response => response.json())
      .then(json => {
        document.getElementById("source").innerText = json.name;
      });
  </script>
</html>
```

Run `pulumi up` again to deploy your changes.

```bash wrap=false
pulumi up
```

Check back to your URL.

![02 - ajcwebdev-pulumi](https://ajc.pics/2021/09/27/02-ajcwebdev-pulumi.webp)

## Discover Related Content

- [A First Look at AWS CDK](https://ajcwebdev.com/first-look-aws-cdk/)
- [A First Look at AWS SAM](https://ajcwebdev.com/first-look-aws-sam/)
- [A First Look at the Serverless Framework](https://ajcwebdev.com/first-look-serverless-framework/)
- [A First Look at Architect](https://ajcwebdev.com/first-look-architect/)
- [Talking Serverless with Josh Proto](https://ajcwebdev.com/podcasts/talking-serverless-josh-proto/) (Podcast)
