cfncustomresource

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jan 27, 2023 License: MIT Imports: 10 Imported by: 0

README

cfn-custom-resource-go

A Go library for implementing CloudFormation custom resources

Quick start

go get github.com/MinneapolisStarTribune/cfn-custom-resource-go@latest
package main

import (
	"encoding/json"
	"fmt"
	"math/rand"
	"os"
	"time"

	cfncustomresource "github.com/MinneapolisStarTribune/cfn-custom-resource-go"
)

func GreeterResource(r *cfncustomresource.Request) error {
	type Props struct {
		YourName   string
		Salutation string `json:",omitempty"` // optional, default "Hello"
	}
	n := &Props{}
	if err := json.Unmarshal(r.ResourceProperties, n); err != nil {
		return err
	}
	if n.YourName == "" {
		return fmt.Errorf("missing YourName property")
	}
	if n.Salutation == "" {
		n.Salutation = "Hello"
	}
	type Attrs struct {
		Greeting string
	}
	attrs := &Attrs{Greeting: fmt.Sprintf("%s, %s!", n.Salutation, n.YourName)}
	switch r.RequestType {
	case "Create":
		phid := r.RandomPhysicalId(rand.New(rand.NewSource(time.Now().UnixNano())))
		return r.CreatedResponse(phid, attrs).Send()
	case "Update":
		return r.UpdatedResponse(attrs).Send()
	case "Delete":
		return r.DeletedResponse().Send()
	}
	panic("invalid request type")
}

func main() {
	for {
		r := &cfncustomresource.Request{} // from your request handler
		if err := r.Try(GreeterResource); err != nil {
			fmt.Fprintf(os.Stderr, "%v\n", err)
		}
	}
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ReqHandler

type ReqHandler func(*Request) error

A ReqHandler is a func that processes a single Request and returns an error or nil.

type Request

type Request struct {
	RequestType        string // "Create", "Update", or "Delete"
	ResponseURL        string
	StackId            string
	RequestId          string
	ResourceType       string
	LogicalResourceId  string
	ResourceProperties json.RawMessage

	// PhysicalResourceId is only provided with Update and Delete requests. When
	// responding to a Create request, you must provide a PhysicalResourceId for
	// future requests to reference.
	PhysicalResourceId string `json:",omitempty"`

	// OldResourceProperties is only provided with Update requests, and reflects
	// the properties of the resource prior to this update request.
	OldResourceProperties json.RawMessage `json:",omitempty"`

	// Ctx is an optional way to limit runtime for each request
	Ctx context.Context `json:"-"`
	// contains filtered or unexported fields
}

Request represents a CloudFormation request object.

func SimulatedRequest added in v0.2.0

func SimulatedRequest(reqtype string, log io.Writer) *Request

SimulatedRequest returns a Request that will not attempt to send a real response to CloudFormation. reqtype must be one of "Create", "Update", or "Delete". log is an optional Writer that will receive one or more Write calls (via fmt.Fprintf) with the result that would have been sent to CloudFormation. log may be nil.

func (*Request) CreatedResponse

func (req *Request) CreatedResponse(physicalid string, attr interface{}) *Response

A CreatedResponse to a request tells CloudFormation that the resource was created successfully. A Physical ID must be provided, uniquely identifying the created resource. CloudFormation does not inspect this value, but does expect it to be unique in an AWS account and will provide it with any future update or delete requests. If attr is non-nil, its values will be available via !GetAtt in the stack.

func (*Request) DeletedResponse

func (req *Request) DeletedResponse() *Response

A DeletedResponse to a request tells CloudFormation that the resource was successfully deleted.

func (*Request) FailureResponse

func (req *Request) FailureResponse(reason string) *Response

A FailureResponse to a request tells CloudFormation that the request wasn't able to be completed. In most cases, this will result in a stack rollback. A reason must be provided; err.Error() is a good place to start.

func (*Request) RandomPhysicalId

func (req *Request) RandomPhysicalId(src *rand.Rand) string

RandomPhysicalId returns a string suitable for using as a physical id if there are no other suitable ids created as a natural consequence of the resource. This is particularly useful for virtual resources that don't actually create anything.

You must provide a random source. This may be:

x := r.RandomPhysicalId(rand.New(rand.NewSource(time.Now().UnixNano())))

func (*Request) ReplacedResponse

func (req *Request) ReplacedResponse(physicalid string, attr interface{}) *Response

A ReplacedResponse to a request tells CloudFormation that a new resource was created to satisfy an Update request. A new Physical ID must be provided. This will trigger a Delete request for the previous Physical ID. If attr is non-nil, its values will be available via !GetAtt in the stack.

func (*Request) Try

func (req *Request) Try(f ReqHandler) (err error)

Try runs f with this request, catching panics and returned errors, turning them into failure responses. f must call one of the Response methods before it returns, or Try will generate a failure.

func (*Request) UpdatedResponse

func (req *Request) UpdatedResponse(attr interface{}) *Response

A UpdatedResponse to a request tells CloudFormation that the resource was successfully updated in-place. If attr is non-nil, its values will be available via !GetAtt in the stack.

type Response

type Response struct {
	Status             string
	Reason             string `json:",omitempty"`
	PhysicalResourceId string
	StackId            string
	RequestId          string
	LogicalResourceId  string
	NoEcho             bool        `json:",omitempty"`
	Data               interface{} `json:",omitempty"`

	Ctx context.Context `json:"-"`
	// contains filtered or unexported fields
}

func (*Response) Send

func (resp *Response) Send() error

Send encodes the Response as a JSON payload and POSTs it to the URL provided by CloudFormation in the Request. Note that the response payload must be no more than 4096 bytes (per documentation in 2022) and so any larger payload will be rejected.

This method is intended to be chained, for example:

func MyStubHandler(r *Request) error {
	return r.FailureResponse("not implemented yet").Send()
}

func (*Response) Sensitive

func (resp *Response) Sensitive() *Response

Sensitive marks this response as containing potentially sensitive values that should not be included in console or API output. This is purely advisory, however; values may leak in other ways, such as being used as attributes for other resources where masking the value is not possible (eg an IAM policy) and so this function is of dubious utility. Use with caution. Consider passing sensitive data out of band, such as via Systems Manager Parameters or Secrets Manager.

This can be chained for convenience, such as:

func MyDomainHandler(r *Request) error {
	type Attrs struct {
		DomainTransferUnlockKey string
	}
	// ... etc ...
	// Sensitive() returns the same request object
	return r.UpdatedResponse(&Attrs{DomainTransferUnlockKey: "secret"}).Sensitive().Send()
}

type YAMLBool added in v0.1.2

type YAMLBool bool

YAMLBool represents a boolean value from a YAML template. This type is important because CloudFormation will take a YAML value of true and pass it to your resource as a string, which the json unmarshaler refuses to parse into a bool. In your attribute types, use YAMLBool.

func (*YAMLBool) UnmarshalText added in v0.1.3

func (yb *YAMLBool) UnmarshalText(b []byte) error

UnmarshalText implements TextUnmarshaler to satisfy json.Unmarshal.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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