Git Product home page Git Product logo

terra's Introduction

Terra

Terra lets you write Terraform configurations using pure Clojure.

Motivation

  1. Have the full power of Clojure at your fingertips when defining Terraform configurations.
  2. Do you need to iterate through something? Or maybe you need to automate part of the configuration creation? Just use the tools you are used to.
  3. No need to learn a separate configuration language in details. A simple Clojure EDN will do.

Table of Contents

Getting Started

Add the following dependency to your project.clj file:

Clojars Project

Add the following plugin to your :plugins in your project.clj file:

Clojars Project

Usage

Create a namespace in your project and require terra.core on your stateful component:

(ns my-project.infrastructure.core
  (:require [terra.core :as terra :refer [defterra $]))

Notice we are also referring the macros defterra and $.

We are going to create an example_ec2 definition using defterra. If you have done any Terraform before, this should be familiar to you.

(defterra example_ec2 {:provider {:aws {:region :us-east-1}}
                       :resource {:aws_instance {:example {:ami :ami-2757f631
                                                           :instance_type :t2.micro}}}})

According to this definiation, example_ec2 uses AWS in the us-east-1 region. It is a t2.micro instance using ami-2757f631. We have used keywords but strings also work if you prefer.

The next step is creating a handler function for trigering the generation of your Terraform file. Usually you just want to call terra/generate in it.

(defn handler []
  (terra/generate))

Then add the following to your project.clj:

:terra {:handler my-project.infrastructure.core/handler}

Head to your terminal and type:

$ lein terra

You should see:

Terra: generating...
Terra: terraform/my-project.infrastructure.core/example_ec2.tf.json
Terra: done!

You can now plan and then apply your Terraform configuration by:

$ cd terraform/my-project.infrastructure.core
$ terraform plan
...
$ terraform apply
...

Since the terraform files are always generated, it is recommended that you add the terraform directory to your .gitignore.

Advanced

The $ macro is a small utility helper to write Terraform interpolations in a more Clojure-like way.

For instance, in order to interpolate a variable, simply use:

:count ($ var.count)

If you want the entry :us-east-1 from the list var.amis, simply use:

:ami ($ (:us-east-1 var.amis))

The traditional get also works here:

:ami ($ (get var.amis :us-east-1))

This also works for indexes:

:ami ($ (get var.amis 0))

Last but not least, you can specify a call to Terraform's functions as if they were Clojure functions with:

:file ($ (file "path.txt"))

One last trick that might be interesting for you is that the defterra macro is just syntax sugar for a simple def. You can also specify your Terraform definitions by using the meta ^:terraform:

(def ^:terraform example_ec2 {:provider {:aws {:region :us-east-1}}
                              :resource {:aws_instance {:example {:ami :ami-2757f631
                                                                  :instance_type :t2.micro}}}})

Bugs

If you find a bug, submit a Github issue.

Help

This project is looking for team members who can help this project succeed! If you are interested in becoming a team member please open an issue.

License

Copyright © 2017 Tiago Luchini

Distributed under the MIT License.

terra's People

Stargazers

 avatar James Davidson avatar Renier Strydom avatar Neil Hooey avatar Justin Tirrell avatar Logan Linn avatar Burin avatar Adam Moore avatar 胡雨軒 Петр avatar  avatar  avatar  avatar Paul Rutledge avatar Alex Kapranoff avatar Rafael ChOkO avatar Ian Fernandez avatar Murilo Paixão avatar Eva Pace avatar Alan Grosskurth avatar  avatar  avatar  avatar Max Savchenko avatar Michael Bravo avatar Andrew Foltz-Morrison avatar Romain Leroux avatar Kenji Nakamura avatar Jason Walsh avatar Miguel Bermudez avatar  avatar Will Acton avatar Alex Gunnarson avatar David Hodge avatar swlkr avatar Nik Peric avatar Jason Pepas (FloSports.tv) avatar Andrejs Agejevs avatar Mihael Konjević avatar Burin Choomnuan avatar Aleh Suprunovich avatar Brandon Adams avatar  avatar Koji Yusa avatar Josef Pospíšil avatar Shaun Mahood avatar Maciej Łotysz avatar M.Jerger avatar

Watchers

James Cloos avatar Aliaksandr Kolesen avatar  avatar

terra's Issues

Some kind of "spread operator"

Here is a common use-case.

Let's say we have two modules:

module "infrastructure" {
  source = "./infrastructure"
}

module "pipeline" {
  source                           = "./pipeline"
  dev_google_analytics_topic_arn   = "${module.infrastructure.dev_google_analytics_topic_arn}"
  dev_report_cursors_queue_arn     = "${module.infrastructure.dev_report_cursors_queue_arn}"
  dev_report_cursors_queue_url     = "${module.infrastructure.dev_report_cursors_queue_url}"
  stage_google_analytics_topic_arn = "${module.infrastructure.stage_google_analytics_topic_arn}"
  stage_report_cursors_queue_arn   = "${module.infrastructure.stage_report_cursors_queue_arn}"
  stage_report_cursors_queue_url   = "${module.infrastructure.stage_report_cursors_queue_url}"
  prod_google_analytics_topic_arn  = "${module.infrastructure.prod_google_analytics_topic_arn}"
  prod_report_cursors_queue_arn    = "${module.infrastructure.prod_report_cursors_queue_arn}"
  prod_report_cursors_queue_url    = "${module.infrastructure.prod_report_cursors_queue_url}"
}

Infrastructure is exposing:

output "dev_google_analytics_topic_arn" {
  value = "${module.dev.google_analytics_topic_arn}"
}

output "dev_report_cursors_queue_arn" {
  value = "${module.dev.report_cursors_queue_arn}"
}

output "dev_report_cursors_queue_url" {
  value = "${module.dev.report_cursors_queue_url}"
}

output "dev_report_cursor_failures_queue_arn" {
  value = "${module.dev.report_cursor_failures_queue_arn}"
}

output "dev_report_cursor_failures_queue_url" {
  value = "${module.dev.report_cursor_failures_queue_url}"
}

output "stage_google_analytics_topic_arn" {
  value = "${module.stage.google_analytics_topic_arn}"
}

output "stage_report_cursors_queue_arn" {
  value = "${module.stage.report_cursors_queue_arn}"
}

output "stage_report_cursors_queue_url" {
  value = "${module.stage.report_cursors_queue_url}"
}

output "stage_report_cursor_failures_queue_arn" {
  value = "${module.stage.report_cursor_failures_queue_arn}"
}

output "stage_report_cursor_failures_queue_url" {
  value = "${module.stage.report_cursor_failures_queue_url}"
}

output "prod_google_analytics_topic_arn" {
  value = "${module.prod.google_analytics_topic_arn}"
}

output "prod_report_cursors_queue_arn" {
  value = "${module.prod.report_cursors_queue_arn}"
}

output "prod_report_cursors_queue_url" {
  value = "${module.prod.report_cursors_queue_url}"
}

output "prod_report_cursor_failures_queue_arn" {
  value = "${module.prod.report_cursor_failures_queue_arn}"
}

output "prod_report_cursor_failures_queue_url" {
  value = "${module.prod.report_cursor_failures_queue_url}"
}

And, as seen above, these get "piped" out by pipeline.

This is a lot of repetitive work. Some kind of helper function/macro would be highly appreciated.

Make `$` support a simple form of conditionals

It could accept something like :count ($ (if (== "dev" var.env) 1 10))

The challenge here is supporting nested forms plus extra support for each Terraform operator (i.e. should we use Terraform's == instead of =?)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.