forked from jonmorehouse/terraform-provisioner-ansible
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathresource_provisioner.go
134 lines (113 loc) · 3.04 KB
/
resource_provisioner.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package main
import (
"fmt"
"github.com/hashicorp/terraform/communicator"
"github.com/hashicorp/terraform/terraform"
"github.com/mitchellh/mapstructure"
"log"
"time"
)
type ResourceProvisioner struct {
playbook string // filepath for the
inventory string
groups []string // list of group-vars to be passed to the provisioner
hosts []string // list of host groups to apply to the provisioner
extraVars map[string]string // extra variables that can be passed to the provisioner
}
func (r *ResourceProvisioner) Apply(
o terraform.UIOutput,
s *terraform.InstanceState,
c *terraform.ResourceConfig) error {
provisioner, err := r.decodeConfig(c)
if err != nil {
o.Output("erred out here")
return err
}
err = provisioner.Validate()
if err != nil {
o.Output("Invalid provisioner configuration settings")
return err
}
provisioner.useSudo = true
provisioner.ansibleLocalScript = fmt.Sprintf("https://raw.githubusercontent.com/jonmorehouse/terraform-provisioner-ansible/%s/ansible-local.py", VERSION)
// ensure that this is a linux machine
if s.Ephemeral.ConnInfo["type"] != "ssh" {
return fmt.Errorf("Unsupported connection type: %s. This provisioner currently only supports linux", s.Ephemeral.ConnInfo["type"])
}
// build a communicator for the provisioner to use
comm, err := communicator.New(s)
if err != nil {
o.Output("erred out here 3")
return err
}
err = retryFunc(comm.Timeout(), func() error {
err := comm.Connect(o)
return err
})
if err != nil {
return err
}
defer comm.Disconnect()
err = provisioner.Run(o, comm)
if err != nil {
o.Output("erred out here 4")
return err
}
return nil
}
func (r *ResourceProvisioner) Validate(c *terraform.ResourceConfig) (ws []string, es []error) {
provisioner, err := r.decodeConfig(c)
if err != nil {
es = append(es, err)
return ws, es
}
err = provisioner.Validate()
if err != nil {
es = append(es, err)
return ws, es
}
return ws, es
}
func (r *ResourceProvisioner) decodeConfig(c *terraform.ResourceConfig) (*Provisioner, error) {
// decodes configuration from terraform and builds out a provisioner
p := new(Provisioner)
decoderConfig := &mapstructure.DecoderConfig{
ErrorUnused: true,
WeaklyTypedInput: true,
Result: p,
}
decoder, err := mapstructure.NewDecoder(decoderConfig)
if err != nil {
return nil, err
}
// build a map of all configuration values, by default this is going to
// pass in all configuration elements for the base configuration as
// well as extra values. Build a single value and then from there, continue forth!
m := make(map[string]interface{})
for k, v := range c.Raw {
m[k] = v
}
for k, v := range c.Config {
m[k] = v
}
err = decoder.Decode(m)
if err != nil {
return nil, err
}
return p, nil
}
func retryFunc(timeout time.Duration, f func() error) error {
finish := time.After(timeout)
for {
err := f()
if err == nil {
return nil
}
log.Printf("Retryable error: %v", err)
select {
case <-finish:
return err
case <-time.After(3 * time.Second):
}
}
}