]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package plugin |
2 | ||
3 | import ( | |
4 | "net/rpc" | |
5 | ||
6 | "github.com/hashicorp/go-plugin" | |
7 | "github.com/hashicorp/terraform/terraform" | |
8 | ) | |
9 | ||
10 | // ResourceProvisionerPlugin is the plugin.Plugin implementation. | |
11 | type ResourceProvisionerPlugin struct { | |
12 | F func() terraform.ResourceProvisioner | |
13 | } | |
14 | ||
15 | func (p *ResourceProvisionerPlugin) Server(b *plugin.MuxBroker) (interface{}, error) { | |
16 | return &ResourceProvisionerServer{Broker: b, Provisioner: p.F()}, nil | |
17 | } | |
18 | ||
19 | func (p *ResourceProvisionerPlugin) Client( | |
20 | b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) { | |
21 | return &ResourceProvisioner{Broker: b, Client: c}, nil | |
22 | } | |
23 | ||
24 | // ResourceProvisioner is an implementation of terraform.ResourceProvisioner | |
25 | // that communicates over RPC. | |
26 | type ResourceProvisioner struct { | |
27 | Broker *plugin.MuxBroker | |
28 | Client *rpc.Client | |
29 | } | |
30 | ||
31 | func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) ([]string, []error) { | |
32 | var resp ResourceProvisionerValidateResponse | |
33 | args := ResourceProvisionerValidateArgs{ | |
34 | Config: c, | |
35 | } | |
36 | ||
37 | err := p.Client.Call("Plugin.Validate", &args, &resp) | |
38 | if err != nil { | |
39 | return nil, []error{err} | |
40 | } | |
41 | ||
42 | var errs []error | |
43 | if len(resp.Errors) > 0 { | |
44 | errs = make([]error, len(resp.Errors)) | |
45 | for i, err := range resp.Errors { | |
46 | errs[i] = err | |
47 | } | |
48 | } | |
49 | ||
50 | return resp.Warnings, errs | |
51 | } | |
52 | ||
53 | func (p *ResourceProvisioner) Apply( | |
54 | output terraform.UIOutput, | |
55 | s *terraform.InstanceState, | |
56 | c *terraform.ResourceConfig) error { | |
57 | id := p.Broker.NextId() | |
58 | go p.Broker.AcceptAndServe(id, &UIOutputServer{ | |
59 | UIOutput: output, | |
60 | }) | |
61 | ||
62 | var resp ResourceProvisionerApplyResponse | |
63 | args := &ResourceProvisionerApplyArgs{ | |
64 | OutputId: id, | |
65 | State: s, | |
66 | Config: c, | |
67 | } | |
68 | ||
69 | err := p.Client.Call("Plugin.Apply", args, &resp) | |
70 | if err != nil { | |
71 | return err | |
72 | } | |
73 | if resp.Error != nil { | |
74 | err = resp.Error | |
75 | } | |
76 | ||
77 | return err | |
78 | } | |
79 | ||
80 | func (p *ResourceProvisioner) Stop() error { | |
81 | var resp ResourceProvisionerStopResponse | |
82 | err := p.Client.Call("Plugin.Stop", new(interface{}), &resp) | |
83 | if err != nil { | |
84 | return err | |
85 | } | |
86 | if resp.Error != nil { | |
87 | err = resp.Error | |
88 | } | |
89 | ||
90 | return err | |
91 | } | |
92 | ||
93 | func (p *ResourceProvisioner) Close() error { | |
94 | return p.Client.Close() | |
95 | } | |
96 | ||
97 | type ResourceProvisionerValidateArgs struct { | |
98 | Config *terraform.ResourceConfig | |
99 | } | |
100 | ||
101 | type ResourceProvisionerValidateResponse struct { | |
102 | Warnings []string | |
103 | Errors []*plugin.BasicError | |
104 | } | |
105 | ||
106 | type ResourceProvisionerApplyArgs struct { | |
107 | OutputId uint32 | |
108 | State *terraform.InstanceState | |
109 | Config *terraform.ResourceConfig | |
110 | } | |
111 | ||
112 | type ResourceProvisionerApplyResponse struct { | |
113 | Error *plugin.BasicError | |
114 | } | |
115 | ||
116 | type ResourceProvisionerStopResponse struct { | |
117 | Error *plugin.BasicError | |
118 | } | |
119 | ||
120 | // ResourceProvisionerServer is a net/rpc compatible structure for serving | |
121 | // a ResourceProvisioner. This should not be used directly. | |
122 | type ResourceProvisionerServer struct { | |
123 | Broker *plugin.MuxBroker | |
124 | Provisioner terraform.ResourceProvisioner | |
125 | } | |
126 | ||
127 | func (s *ResourceProvisionerServer) Apply( | |
128 | args *ResourceProvisionerApplyArgs, | |
129 | result *ResourceProvisionerApplyResponse) error { | |
130 | conn, err := s.Broker.Dial(args.OutputId) | |
131 | if err != nil { | |
132 | *result = ResourceProvisionerApplyResponse{ | |
133 | Error: plugin.NewBasicError(err), | |
134 | } | |
135 | return nil | |
136 | } | |
137 | client := rpc.NewClient(conn) | |
138 | defer client.Close() | |
139 | ||
140 | output := &UIOutput{Client: client} | |
141 | ||
142 | err = s.Provisioner.Apply(output, args.State, args.Config) | |
143 | *result = ResourceProvisionerApplyResponse{ | |
144 | Error: plugin.NewBasicError(err), | |
145 | } | |
146 | return nil | |
147 | } | |
148 | ||
149 | func (s *ResourceProvisionerServer) Validate( | |
150 | args *ResourceProvisionerValidateArgs, | |
151 | reply *ResourceProvisionerValidateResponse) error { | |
152 | warns, errs := s.Provisioner.Validate(args.Config) | |
153 | berrs := make([]*plugin.BasicError, len(errs)) | |
154 | for i, err := range errs { | |
155 | berrs[i] = plugin.NewBasicError(err) | |
156 | } | |
157 | *reply = ResourceProvisionerValidateResponse{ | |
158 | Warnings: warns, | |
159 | Errors: berrs, | |
160 | } | |
161 | return nil | |
162 | } | |
163 | ||
164 | func (s *ResourceProvisionerServer) Stop( | |
165 | _ interface{}, | |
166 | reply *ResourceProvisionerStopResponse) error { | |
167 | err := s.Provisioner.Stop() | |
168 | *reply = ResourceProvisionerStopResponse{ | |
169 | Error: plugin.NewBasicError(err), | |
170 | } | |
171 | ||
172 | return nil | |
173 | } |