Skip to content

Instantly share code, notes, and snippets.

@displague
Created May 20, 2019 14:31
Show Gist options
  • Save displague/ab50c80d44f98f3c072d415afe508f8d to your computer and use it in GitHub Desktop.
Save displague/ab50c80d44f98f3c072d415afe508f8d to your computer and use it in GitHub Desktop.

How do you use Pulumi to manage Linode Resources?

Linode Pulumi Integration

Pulumi is best described by their Founder/CEO, Joe Duffy:

Pulumi is multi-language, multi-cloud, and fully extensible. On day one, it supports JavaScript, TypeScript, Python, and Go languages, and AWS, Azure, and GCP clouds, in addition to Kubernetes targeting any public, private, or hybrid cloud. Pulumi delivers a single, consistent programming model and set of tools to program and manage any of these environments, supported by a rich ecosystem of reusable packages. Using real languages changes everything.

Linode support was added to Pulumi in May 2019. This integration enables the management of Linode infrastructure via Javascript, Typescript, Python, and Go with a common interface that is very closely tied to the Linode API and the Terraform Linode Provider. Linode Instances, NodeBalancers, Domains, StackScripts, Block Storage Volumes, Users and more can be managed and queried through Pulumi.

Installing Pulumi

The first step in getting started with Pulumi is to install the CLI.

curl -fsSL https://get.pulumi.com | sh

Starting a project

Once installed, create a new project using pulumi new and choose a template based on your preferred language. You'll be prompted to provide a project name, project description, and stack name.

Set your Linode APIv4 token from https://cloud.linode.com/profile/tokens in Pulumi's credential store.

pulumi config set --secret linode:token YOURLINODETOKEN

The Pulumi.yaml file contains the selected runtime and depending on the chosen language the project code can be found in either a index.ts, index.js, main.go, or __main__.py file.

In the case of typescript, expect the following:

import * as pulumi from "@pulumi/pulumi";

A Linode for everyone

Now Create an interesting app. This is the hard part.

How about an app that creates a Linode for every user who accesses the site, their Github username can act as their username and their Github registered SSH key can be used for authentication.

To keep things interesting, after 5 minutes, the instance should be deleted and the Github username can never be reused.

Our application code will reside in App.ts:

import * as express from 'express'

const pulumi = require("@pulumi/pulumi");
const linode = require("@pulumi/linode");

class App {
  public express

  constructor () {
    this.express = express()
    this.users = {}
    this.mountRoutes()
  }

  private mountRoutes (): void {
    const router = express.Router()
    router.get('/', (req, res) => {
      res.html({
        message: '<form method="post"><input placeholder="Github Username"></form>'
      })
    })
    router.post('/', (req, res) => {
      if (users[req.username]) {
        res.html({message: `one per customer.<br>ssh root@${users[req.username].ip_address}`})
      } else if (req.username) {
        response = await fetch(`https://github.com/${req.username}.keys`)
        keys = await response.text()

        users[req.username] = new linode.Instance(req.username, {
            instanceType: "g6-nanode-1",
            image: "linode/alpine",
            region: "us-east",
            authorizedKeys: keys,
        })
        res.html({message: `Linode for you!<br>ssh root@${users[req.username].ip_address}`})
      } else {
        res.html({
            message: '<form method="post"><input placeholder="Github Username"></form>'
        })
      }
    })
    this.express.use('/', router)
  }
}

export default new App().express

Modify index.ts to start our app.

import app from './App'
import * as pulumi from "@pulumi/pulumi";

const port = process.env.PORT || 3000

app.listen(port, (err) => {
  if (err) {
    return console.log(err)
  }

  return console.log(`server is listening on ${port}`)
})

Examples

Documentation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment