terraform: initial hook impl
This commit is contained in:
parent
d6fa7f2f6d
commit
501f926eba
|
@ -0,0 +1,42 @@
|
||||||
|
package terraform
|
||||||
|
|
||||||
|
// HookAction is an enum of actions that can be taken as a result of a hook
|
||||||
|
// callback. This allows you to modify the behavior of Terraform at runtime.
|
||||||
|
type HookAction byte
|
||||||
|
|
||||||
|
const (
|
||||||
|
// HookActionContinue continues with processing as usual.
|
||||||
|
HookActionContinue HookAction = iota
|
||||||
|
|
||||||
|
// HookActionHalt halts immediately: no more hooks are processed
|
||||||
|
// and the action that Terraform was about to take is cancelled.
|
||||||
|
HookActionHalt
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hook is the interface that must be implemented to hook into various
|
||||||
|
// parts of Terraform, allowing you to inspect or change behavior at runtime.
|
||||||
|
//
|
||||||
|
// There are MANY hook points into Terraform. If you only want to implement
|
||||||
|
// some hook points, but not all (which is the likely case), then embed the
|
||||||
|
// NilHook into your struct, which implements all of the interface but does
|
||||||
|
// nothing. Then, override only the functions you want to implement.
|
||||||
|
type Hook interface {
|
||||||
|
// PreRefresh is called before a resource is refreshed.
|
||||||
|
PreRefresh(*ResourceState) (HookAction, error)
|
||||||
|
|
||||||
|
// PostRefresh is called after a resource is refreshed.
|
||||||
|
PostRefresh(*ResourceState) (HookAction, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NilHook is a Hook implementation that does nothing. It exists only to
|
||||||
|
// simplify implementing hooks. You can embed this into your Hook implementation
|
||||||
|
// and only implement the functions you are interested in.
|
||||||
|
type NilHook struct{}
|
||||||
|
|
||||||
|
func (*NilHook) PreRefresh(*ResourceState) (HookAction, error) {
|
||||||
|
return HookActionContinue, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*NilHook) PostRefresh(*ResourceState) (HookAction, error) {
|
||||||
|
return HookActionContinue, nil
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package terraform
|
||||||
|
|
||||||
|
// MockHook is an implementation of Hook that can be used for tests.
|
||||||
|
// It records all of its function calls.
|
||||||
|
type MockHook struct {
|
||||||
|
PostRefreshCalled bool
|
||||||
|
PostRefreshState *ResourceState
|
||||||
|
PostRefreshReturn HookAction
|
||||||
|
PostRefreshError error
|
||||||
|
|
||||||
|
PreRefreshCalled bool
|
||||||
|
PreRefreshState *ResourceState
|
||||||
|
PreRefreshReturn HookAction
|
||||||
|
PreRefreshError error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *MockHook) PreRefresh(s *ResourceState) (HookAction, error) {
|
||||||
|
h.PreRefreshCalled = true
|
||||||
|
h.PreRefreshState = s
|
||||||
|
return h.PreRefreshReturn, h.PreRefreshError
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *MockHook) PostRefresh(s *ResourceState) (HookAction, error) {
|
||||||
|
h.PostRefreshCalled = true
|
||||||
|
h.PostRefreshState = s
|
||||||
|
return h.PostRefreshReturn, h.PostRefreshError
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
package terraform
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNilHook_impl(t *testing.T) {
|
||||||
|
var _ Hook = new(NilHook)
|
||||||
|
}
|
|
@ -13,6 +13,7 @@ import (
|
||||||
// Terraform from code, and can perform operations such as returning
|
// Terraform from code, and can perform operations such as returning
|
||||||
// all resources, a resource tree, a specific resource, etc.
|
// all resources, a resource tree, a specific resource, etc.
|
||||||
type Terraform struct {
|
type Terraform struct {
|
||||||
|
hooks []Hook
|
||||||
providers map[string]ResourceProviderFactory
|
providers map[string]ResourceProviderFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +24,7 @@ type genericWalkFunc func(*Resource) (map[string]string, error)
|
||||||
// Config is the configuration that must be given to instantiate
|
// Config is the configuration that must be given to instantiate
|
||||||
// a Terraform structure.
|
// a Terraform structure.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
Hooks []Hook
|
||||||
Providers map[string]ResourceProviderFactory
|
Providers map[string]ResourceProviderFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,6 +36,7 @@ type Config struct {
|
||||||
// can be properly initialized, can be configured, etc.
|
// can be properly initialized, can be configured, etc.
|
||||||
func New(c *Config) (*Terraform, error) {
|
func New(c *Config) (*Terraform, error) {
|
||||||
return &Terraform{
|
return &Terraform{
|
||||||
|
hooks: c.Hooks,
|
||||||
providers: c.Providers,
|
providers: c.Providers,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -128,6 +131,11 @@ func (t *Terraform) refreshWalkFn(result *State) depgraph.WalkFunc {
|
||||||
result.init()
|
result.init()
|
||||||
|
|
||||||
cb := func(r *Resource) (map[string]string, error) {
|
cb := func(r *Resource) (map[string]string, error) {
|
||||||
|
for _, h := range t.hooks {
|
||||||
|
// TODO: return value
|
||||||
|
h.PreRefresh(r.State)
|
||||||
|
}
|
||||||
|
|
||||||
rs, err := r.Provider.Refresh(r.State)
|
rs, err := r.Provider.Refresh(r.State)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -143,6 +151,11 @@ func (t *Terraform) refreshWalkFn(result *State) depgraph.WalkFunc {
|
||||||
result.Resources[r.Id] = rs
|
result.Resources[r.Id] = rs
|
||||||
l.Unlock()
|
l.Unlock()
|
||||||
|
|
||||||
|
for _, h := range t.hooks {
|
||||||
|
// TODO: return value
|
||||||
|
h.PostRefresh(rs)
|
||||||
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -252,6 +252,39 @@ func TestTerraformRefresh(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTerraformRefresh_hook(t *testing.T) {
|
||||||
|
rpAWS := new(MockResourceProvider)
|
||||||
|
rpAWS.ResourcesReturn = []ResourceType{
|
||||||
|
ResourceType{Name: "aws_instance"},
|
||||||
|
}
|
||||||
|
|
||||||
|
h := new(MockHook)
|
||||||
|
|
||||||
|
c := testConfig(t, "refresh-basic")
|
||||||
|
tf := testTerraform2(t, &Config{
|
||||||
|
Hooks: []Hook{h},
|
||||||
|
Providers: map[string]ResourceProviderFactory{
|
||||||
|
"aws": testProviderFuncFixed(rpAWS),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if _, err := tf.Refresh(c, nil); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
if !h.PreRefreshCalled {
|
||||||
|
t.Fatal("should be called")
|
||||||
|
}
|
||||||
|
if h.PreRefreshState.Type != "aws_instance" {
|
||||||
|
t.Fatalf("bad: %#v", h.PreRefreshState)
|
||||||
|
}
|
||||||
|
if !h.PostRefreshCalled {
|
||||||
|
t.Fatal("should be called")
|
||||||
|
}
|
||||||
|
if h.PostRefreshState.Type != "aws_instance" {
|
||||||
|
t.Fatalf("bad: %#v", h.PostRefreshState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTerraformRefresh_state(t *testing.T) {
|
func TestTerraformRefresh_state(t *testing.T) {
|
||||||
rpAWS := new(MockResourceProvider)
|
rpAWS := new(MockResourceProvider)
|
||||||
rpAWS.ResourcesReturn = []ResourceType{
|
rpAWS.ResourcesReturn = []ResourceType{
|
||||||
|
|
Loading…
Reference in New Issue