goconstruct

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 21, 2020 License: MIT Imports: 6 Imported by: 0

README

goconstruct

PkgGoDev GoReport GoLang .github/workflows/main.yml semantic-release Conventional Commits KeepAChangelog License

A "go" version of github.com/aws/constructs, based on functions instead of classes.

Quick Start

go get -u github.com/brad-jones/goconstruct

package main

import (
    "encoding/json"
    "fmt"

    "github.com/brad-jones/goconstruct"
)

// -- START: File Construct
// based on: https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file

type FileProps struct {
    SensitiveContent    string
    ContentBase64       string
    Filename            string
    FilePermission      string
    DirectoryPermission string
    Source              string
    Content             string
}

type FileOutputs struct {
    *FileProps
}

func File(parent *goconstruct.Construct, id string, props *FileProps) *FileOutputs {
    return goconstruct.New(id,
        goconstruct.Scope(parent),
        goconstruct.Type("Local/File"),
        goconstruct.Props(props),
        goconstruct.Outputs(&FileOutputs{}),
    ).Outputs.(*FileOutputs)
}

// -- START: FileData Construct
// based on: https://registry.terraform.io/providers/hashicorp/local/latest/docs/data-sources/file

type FileDataProps struct {
    Filename string
}

type FileDataOutputs struct {
    *FileDataProps
    Content       string
    ContentBase64 string
}

func FileData(parent *goconstruct.Construct, id string, props *FileDataProps) *FileDataOutputs {
    return goconstruct.New(id,
        goconstruct.Scope(parent),
        goconstruct.Type("Local/FileData"),
        goconstruct.Props(props),
        goconstruct.Outputs(&FileDataOutputs{}),
    ).Outputs.(*FileDataOutputs)
}

// -- START: Construct Usage

func main() {
    root := goconstruct.New("/", goconstruct.Type("Root"),
        goconstruct.Constructor(func(c *goconstruct.Construct) {
            src := FileData(c, "MyFileData", &FileDataProps{
                Filename: "./go.mod",
            })
            File(c, "MyFile", &FileProps{
                Filename: "./foo.txt",
                Content:  src.Content,
            })
        }),
    )

    dat, _ := json.MarshalIndent(root, "", "    ")
    fmt.Println(string(dat))
}

Outputs the following JSON:

{
    "id": "/",
    "type": "Root",
    "props": null,
    "children": [
        {
            "id": "/MyFileData",
            "type": "Local/FileData",
            "props": {
                "Filename": "./go.mod"
            },
            "children": []
        },
        {
            "id": "/MyFile",
            "type": "Local/File",
            "props": {
                "SensitiveContent": "",
                "ContentBase64": "",
                "Filename": "./foo.txt",
                "FilePermission": "",
                "DirectoryPermission": "",
                "Source": "",
                "Content": "/MyFileData.Content"
            },
            "children": []
        }
    ]
}

The idea being that this JSON would then be passed on to a parser/generator which understands how to convert it into Terraform JSON/HCL or Cloudformation or say Github Actions YAML as the case may be.

Also see further working examples under: https://github.com/brad-jones/goconstruct/tree/master/examples

Motivation

This project started life because I wanted the AWS CDK experience but with Terraform. I had played with https://www.pulumi.com/ but found that it had strayed too far from what terraform is, ie: I couldn't pulumi synth and see some terraform.

I later discovered https://github.com/hashicorp/terraform-cdk however decided to continue with this mainly because "go" still isn't supported by https://github.com/aws/jsii.

This RFC PR https://github.com/aws/aws-cdk-rfcs/pull/206 details the specifics of "go" support in the CDK and to quote the RFC:

The programming model for Go differs significantly from that of Typescript. Imposing an object-oriented philosophy on a procedural language may result in non-idiomatic constructs and APIs in the target language. However, the tradeoff for having CDK constructs available in more languages outweighs this disadvantage.

I then asked myself, "Well what would it look like in go if I started from scratch?" And this is the result. As it is largely based on functions instead of classes it should translate well to almost any language.

It is in use (or will be) at https://github.com/brad-jones/tdk

My ultimate goal is to be able to define a stack using go and compile it all down to a single binary. eg: mystack-v1.0.0 plan && mystack-v1.0.0 apply.

My immediate itch that I am scratching with all of this is to be able to download that single binary on a new development machine, be it Linux/MacOS or Windows and have my dev environment automatically configured. I have tried out various home directory "dot-file" managers (latest being https://www.chezmoi.io) but they have always left something to be desired.

At work (Xero) I can also see other advantages of being able to create a binary artifact in a CI/CD pipeline that represents a particular version of a stack.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Constructor

func Constructor(builder func(*Construct)) func(*Construct)

Constructor expects a function that will be called with the Construct instance as it's only parameter in order to add new children to it.

func ConstructorWithOutputs

func ConstructorWithOutputs(builder func(*Construct) interface{}) func(*Construct)

ConstructorWithOutputs expects a function that will be called with the Construct instance as it's only parameter in order to add new children to it. It also expects a value to be returned with will be assigned to the Outputs.

func Outputs

func Outputs(v interface{}) func(*Construct)

Outputs will take a pointer to a struct and ensure it is initialized with reference strings (a bit like a JSON Pointer). These strings will later be used by a generator to connect resources together in the appropriate order.

func Props

func Props(v interface{}) func(*Construct)

Props allows you to assign any arbitrary object, usually a struct specifically defined for your construct. So long as it can be marshalled to JSON that is all that matters.

func Scope

func Scope(parent *Construct) func(*Construct)

Scope defines the parent child relationship between constructs

func Type

func Type(t string) func(*Construct)

Type sets the Type field of a Construct

Types

type Construct

type Construct struct {
	ID       string
	Type     string
	Props    interface{}
	Outputs  interface{}
	Parent   *Construct
	Children []*Construct
}

Construct is a class like object, create new instances with `New`.

func New

func New(id string, options ...func(*Construct)) *Construct

New is the constructor for Construct.

It uses a functional options based API, see: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis

Example Usage:

goconstruct.New("MyThing", goconstruct.Scope(parentThing),
	goconstruct.Props(&MyThingProps{}),
)

func (*Construct) AddChild

func (c *Construct) AddChild(child *Construct)

AddChild will create the parent and child relationship between all Constructs

func (*Construct) MarshalJSON

func (c *Construct) MarshalJSON() ([]byte, error)

MarshalJSON implements the Marshaler interface see https://golang.org/pkg/encoding/json/#Marshaler

func (*Construct) Synth

func (c *Construct) Synth() *orderedmap.OrderedMap

Synth will convert the Construct graph into a serializable map

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL