mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-25 16:31:10 -06:00
terraform: initial hook impl
This commit is contained in:
parent
d6fa7f2f6d
commit
501f926eba
42
terraform/hook.go
Normal file
42
terraform/hook.go
Normal file
@ -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
|
||||
}
|
27
terraform/hook_mock.go
Normal file
27
terraform/hook_mock.go
Normal file
@ -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
|
||||
}
|
9
terraform/hook_test.go
Normal file
9
terraform/hook_test.go
Normal file
@ -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
|
||||
// all resources, a resource tree, a specific resource, etc.
|
||||
type Terraform struct {
|
||||
hooks []Hook
|
||||
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
|
||||
// a Terraform structure.
|
||||
type Config struct {
|
||||
Hooks []Hook
|
||||
Providers map[string]ResourceProviderFactory
|
||||
}
|
||||
|
||||
@ -34,6 +36,7 @@ type Config struct {
|
||||
// can be properly initialized, can be configured, etc.
|
||||
func New(c *Config) (*Terraform, error) {
|
||||
return &Terraform{
|
||||
hooks: c.Hooks,
|
||||
providers: c.Providers,
|
||||
}, nil
|
||||
}
|
||||
@ -128,6 +131,11 @@ func (t *Terraform) refreshWalkFn(result *State) depgraph.WalkFunc {
|
||||
result.init()
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -143,6 +151,11 @@ func (t *Terraform) refreshWalkFn(result *State) depgraph.WalkFunc {
|
||||
result.Resources[r.Id] = rs
|
||||
l.Unlock()
|
||||
|
||||
for _, h := range t.hooks {
|
||||
// TODO: return value
|
||||
h.PostRefresh(rs)
|
||||
}
|
||||
|
||||
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) {
|
||||
rpAWS := new(MockResourceProvider)
|
||||
rpAWS.ResourcesReturn = []ResourceType{
|
||||
|
Loading…
Reference in New Issue
Block a user