Skip to content

Commit 037edca

Browse files
author
Adrian Bruinhout
authored
Dry up NewApiClient (#220)
* Refactor NewApiClient to return diagnostics over errors * Extract setting es connection * Check for elastic_connection * Extract const * PR feedback
1 parent 35acc57 commit 037edca

21 files changed

+294
-387
lines changed

internal/clients/api_client.go

+129-189
Original file line numberDiff line numberDiff line change
@@ -60,121 +60,7 @@ type ApiClient struct {
6060

6161
func NewApiClientFunc(version string) func(context.Context, *schema.ResourceData) (interface{}, diag.Diagnostics) {
6262
return func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
63-
var diags diag.Diagnostics
64-
config := elasticsearch.Config{}
65-
config.Header = http.Header{"User-Agent": []string{fmt.Sprintf("elasticstack-terraform-provider/%s", version)}}
66-
67-
if v, ok := d.GetOk("elasticsearch"); ok {
68-
// if defined we must have only one entry
69-
if esc := v.([]interface{})[0]; esc != nil {
70-
esConfig := esc.(map[string]interface{})
71-
if username, ok := esConfig["username"]; ok {
72-
config.Username = username.(string)
73-
}
74-
if password, ok := esConfig["password"]; ok {
75-
config.Password = password.(string)
76-
}
77-
if apikey, ok := esConfig["api_key"]; ok {
78-
config.APIKey = apikey.(string)
79-
}
80-
81-
// default endpoints taken from Env if set
82-
if es := os.Getenv("ELASTICSEARCH_ENDPOINTS"); es != "" {
83-
endpoints := make([]string, 0)
84-
for _, e := range strings.Split(es, ",") {
85-
endpoints = append(endpoints, strings.TrimSpace(e))
86-
}
87-
config.Addresses = endpoints
88-
}
89-
// setting endpoints from config block if provided
90-
if eps, ok := esConfig["endpoints"]; ok && len(eps.([]interface{})) > 0 {
91-
endpoints := make([]string, 0)
92-
for _, e := range eps.([]interface{}) {
93-
endpoints = append(endpoints, e.(string))
94-
}
95-
config.Addresses = endpoints
96-
}
97-
98-
if insecure, ok := esConfig["insecure"]; ok && insecure.(bool) {
99-
tlsClientConfig := ensureTLSClientConfig(&config)
100-
tlsClientConfig.InsecureSkipVerify = true
101-
}
102-
103-
if caFile, ok := esConfig["ca_file"]; ok && caFile.(string) != "" {
104-
caCert, err := os.ReadFile(caFile.(string))
105-
if err != nil {
106-
diags = append(diags, diag.Diagnostic{
107-
Severity: diag.Error,
108-
Summary: "Unable to read CA File",
109-
Detail: err.Error(),
110-
})
111-
return nil, diags
112-
}
113-
config.CACert = caCert
114-
}
115-
if caData, ok := esConfig["ca_data"]; ok && caData.(string) != "" {
116-
config.CACert = []byte(caData.(string))
117-
}
118-
119-
if certFile, ok := esConfig["cert_file"]; ok && certFile.(string) != "" {
120-
if keyFile, ok := esConfig["key_file"]; ok && keyFile.(string) != "" {
121-
cert, err := tls.LoadX509KeyPair(certFile.(string), keyFile.(string))
122-
if err != nil {
123-
diags = append(diags, diag.Diagnostic{
124-
Severity: diag.Error,
125-
Summary: "Unable to read certificate or key file",
126-
Detail: err.Error(),
127-
})
128-
return nil, diags
129-
}
130-
tlsClientConfig := ensureTLSClientConfig(&config)
131-
tlsClientConfig.Certificates = []tls.Certificate{cert}
132-
} else {
133-
diags = append(diags, diag.Diagnostic{
134-
Severity: diag.Error,
135-
Summary: "Unable to read key file",
136-
Detail: "Path to key file has not been configured or is empty",
137-
})
138-
return nil, diags
139-
}
140-
}
141-
if certData, ok := esConfig["cert_data"]; ok && certData.(string) != "" {
142-
if keyData, ok := esConfig["key_data"]; ok && keyData.(string) != "" {
143-
cert, err := tls.X509KeyPair([]byte(certData.(string)), []byte(keyData.(string)))
144-
if err != nil {
145-
diags = append(diags, diag.Diagnostic{
146-
Severity: diag.Error,
147-
Summary: "Unable to parse certificate or key",
148-
Detail: err.Error(),
149-
})
150-
return nil, diags
151-
}
152-
tlsClientConfig := ensureTLSClientConfig(&config)
153-
tlsClientConfig.Certificates = []tls.Certificate{cert}
154-
} else {
155-
diags = append(diags, diag.Diagnostic{
156-
Severity: diag.Error,
157-
Summary: "Unable to parse key",
158-
Detail: "Key data has not been configured or is empty",
159-
})
160-
return nil, diags
161-
}
162-
}
163-
}
164-
}
165-
166-
es, err := elasticsearch.NewClient(config)
167-
if err != nil {
168-
diags = append(diags, diag.Diagnostic{
169-
Severity: diag.Error,
170-
Summary: "Unable to create Elasticsearch client",
171-
Detail: err.Error(),
172-
})
173-
}
174-
if logging.IsDebugOrHigher() {
175-
es.Transport = newDebugTransport("elasticsearch", es.Transport)
176-
}
177-
return &ApiClient{es, version}, diags
63+
return newEsApiClient(d, "elasticsearch", version, true)
17864
}
17965
}
18066

@@ -205,83 +91,16 @@ func NewAcceptanceTestingClient() (*ApiClient, error) {
20591
return &ApiClient{es, "acceptance-testing"}, nil
20692
}
20793

208-
func NewApiClient(d *schema.ResourceData, meta interface{}) (*ApiClient, error) {
209-
defaultClient := meta.(*ApiClient)
210-
// if the config provided let's use it
211-
if esConn, ok := d.GetOk("elasticsearch_connection"); ok {
212-
config := elasticsearch.Config{}
213-
config.Header = http.Header{"User-Agent": []string{fmt.Sprintf("elasticstack-terraform-provider/%s", defaultClient.version)}}
214-
215-
// there is always only 1 connection per resource
216-
conn := esConn.([]interface{})[0].(map[string]interface{})
217-
218-
if u := conn["username"]; u != nil {
219-
config.Username = u.(string)
220-
}
221-
if p := conn["password"]; p != nil {
222-
config.Password = p.(string)
223-
}
224-
if k := conn["api_key"]; k != nil {
225-
config.APIKey = k.(string)
226-
}
227-
if endpoints := conn["endpoints"]; endpoints != nil {
228-
var addrs []string
229-
for _, e := range endpoints.([]interface{}) {
230-
addrs = append(addrs, e.(string))
231-
}
232-
config.Addresses = addrs
233-
}
234-
if insecure := conn["insecure"]; insecure.(bool) {
235-
tlsClientConfig := ensureTLSClientConfig(&config)
236-
tlsClientConfig.InsecureSkipVerify = true
237-
}
238-
if caFile, ok := conn["ca_file"]; ok && caFile.(string) != "" {
239-
caCert, err := os.ReadFile(caFile.(string))
240-
if err != nil {
241-
return nil, fmt.Errorf("Unable to read ca_file: %w", err)
242-
}
243-
config.CACert = caCert
244-
}
245-
if caData, ok := conn["ca_data"]; ok && caData.(string) != "" {
246-
config.CACert = []byte(caData.(string))
247-
}
94+
const esConnectionKey string = "elasticsearch_connection"
24895

249-
if certFile, ok := conn["cert_file"]; ok && certFile.(string) != "" {
250-
if keyFile, ok := conn["key_file"]; ok && keyFile.(string) != "" {
251-
cert, err := tls.LoadX509KeyPair(certFile.(string), keyFile.(string))
252-
if err != nil {
253-
return nil, fmt.Errorf("Unable to read certificate or key file: %w", err)
254-
}
255-
tlsClientConfig := ensureTLSClientConfig(&config)
256-
tlsClientConfig.Certificates = []tls.Certificate{cert}
257-
} else {
258-
return nil, fmt.Errorf("Unable to read key file: Path to key file has not been configured or is empty")
259-
}
260-
}
261-
if certData, ok := conn["cert_data"]; ok && certData.(string) != "" {
262-
if keyData, ok := conn["key_data"]; ok && keyData.(string) != "" {
263-
cert, err := tls.X509KeyPair([]byte(certData.(string)), []byte(keyData.(string)))
264-
if err != nil {
265-
return nil, fmt.Errorf("Unable to parse certificate or key: %w", err)
266-
}
267-
tlsClientConfig := ensureTLSClientConfig(&config)
268-
tlsClientConfig.Certificates = []tls.Certificate{cert}
269-
} else {
270-
return nil, fmt.Errorf("Unable to parse key: Key data has not been configured or is empty")
271-
}
272-
}
96+
func NewApiClient(d *schema.ResourceData, meta interface{}) (*ApiClient, diag.Diagnostics) {
97+
defaultClient := meta.(*ApiClient)
27398

274-
es, err := elasticsearch.NewClient(config)
275-
if err != nil {
276-
return nil, fmt.Errorf("Unable to create Elasticsearch client")
277-
}
278-
if logging.IsDebugOrHigher() {
279-
es.Transport = newDebugTransport("elasticsearch", es.Transport)
280-
}
281-
return &ApiClient{es, defaultClient.version}, nil
282-
} else { // or return the default client
283-
return defaultClient, nil
99+
if _, ok := d.GetOk(esConnectionKey); ok {
100+
return newEsApiClient(d, esConnectionKey, defaultClient.version, false)
284101
}
102+
103+
return defaultClient, nil
285104
}
286105

287106
func ensureTLSClientConfig(config *elasticsearch.Config) *tls.Config {
@@ -360,3 +179,124 @@ func (a *ApiClient) ClusterID(ctx context.Context) (*string, diag.Diagnostics) {
360179
})
361180
return nil, diags
362181
}
182+
183+
func newEsApiClient(d *schema.ResourceData, key string, version string, useEnvAsDefault bool) (*ApiClient, diag.Diagnostics) {
184+
var diags diag.Diagnostics
185+
config := elasticsearch.Config{}
186+
config.Header = http.Header{"User-Agent": []string{fmt.Sprintf("elasticstack-terraform-provider/%s", version)}}
187+
188+
if esConn, ok := d.GetOk(key); ok {
189+
// if defined, then we only have a single entry
190+
if es := esConn.([]interface{})[0]; es != nil {
191+
esConfig := es.(map[string]interface{})
192+
193+
if username, ok := esConfig["username"]; ok {
194+
config.Username = username.(string)
195+
}
196+
if password, ok := esConfig["password"]; ok {
197+
config.Password = password.(string)
198+
}
199+
if apikey, ok := esConfig["api_key"]; ok {
200+
config.APIKey = apikey.(string)
201+
}
202+
203+
if useEnvAsDefault {
204+
if endpoints := os.Getenv("ELASTICSEARCH_ENDPOINTS"); endpoints != "" {
205+
var addrs []string
206+
for _, e := range strings.Split(endpoints, ",") {
207+
addrs = append(addrs, strings.TrimSpace(e))
208+
}
209+
config.Addresses = addrs
210+
}
211+
}
212+
213+
if endpoints, ok := esConfig["endpoints"]; ok && len(endpoints.([]interface{})) > 0 {
214+
var addrs []string
215+
for _, e := range endpoints.([]interface{}) {
216+
addrs = append(addrs, e.(string))
217+
}
218+
config.Addresses = addrs
219+
}
220+
221+
if insecure, ok := esConfig["insecure"]; ok && insecure.(bool) {
222+
tlsClientConfig := ensureTLSClientConfig(&config)
223+
tlsClientConfig.InsecureSkipVerify = true
224+
}
225+
226+
if caFile, ok := esConfig["ca_file"]; ok && caFile.(string) != "" {
227+
caCert, err := os.ReadFile(caFile.(string))
228+
if err != nil {
229+
diags = append(diags, diag.Diagnostic{
230+
Severity: diag.Error,
231+
Summary: "Unable to read CA File",
232+
Detail: err.Error(),
233+
})
234+
return nil, diags
235+
}
236+
config.CACert = caCert
237+
}
238+
if caData, ok := esConfig["ca_data"]; ok && caData.(string) != "" {
239+
config.CACert = []byte(caData.(string))
240+
}
241+
242+
if certFile, ok := esConfig["cert_file"]; ok && certFile.(string) != "" {
243+
if keyFile, ok := esConfig["key_file"]; ok && keyFile.(string) != "" {
244+
cert, err := tls.LoadX509KeyPair(certFile.(string), keyFile.(string))
245+
if err != nil {
246+
diags = append(diags, diag.Diagnostic{
247+
Severity: diag.Error,
248+
Summary: "Unable to read certificate or key file",
249+
Detail: err.Error(),
250+
})
251+
return nil, diags
252+
}
253+
tlsClientConfig := ensureTLSClientConfig(&config)
254+
tlsClientConfig.Certificates = []tls.Certificate{cert}
255+
} else {
256+
diags = append(diags, diag.Diagnostic{
257+
Severity: diag.Error,
258+
Summary: "Unable to read key file",
259+
Detail: "Path to key file has not been configured or is empty",
260+
})
261+
return nil, diags
262+
}
263+
}
264+
if certData, ok := esConfig["cert_data"]; ok && certData.(string) != "" {
265+
if keyData, ok := esConfig["key_data"]; ok && keyData.(string) != "" {
266+
cert, err := tls.X509KeyPair([]byte(certData.(string)), []byte(keyData.(string)))
267+
if err != nil {
268+
diags = append(diags, diag.Diagnostic{
269+
Severity: diag.Error,
270+
Summary: "Unable to parse certificate or key",
271+
Detail: err.Error(),
272+
})
273+
return nil, diags
274+
}
275+
tlsClientConfig := ensureTLSClientConfig(&config)
276+
tlsClientConfig.Certificates = []tls.Certificate{cert}
277+
} else {
278+
diags = append(diags, diag.Diagnostic{
279+
Severity: diag.Error,
280+
Summary: "Unable to parse key",
281+
Detail: "Key data has not been configured or is empty",
282+
})
283+
return nil, diags
284+
}
285+
}
286+
}
287+
}
288+
289+
es, err := elasticsearch.NewClient(config)
290+
if err != nil {
291+
diags = append(diags, diag.Diagnostic{
292+
Severity: diag.Error,
293+
Summary: "Unable to create Elasticsearch client",
294+
Detail: err.Error(),
295+
})
296+
}
297+
if logging.IsDebugOrHigher() {
298+
es.Transport = newDebugTransport("elasticsearch", es.Transport)
299+
}
300+
301+
return &ApiClient{es, version}, diags
302+
}

internal/elasticsearch/cluster/script.go

+10-11
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,9 @@ func ResourceScript() *schema.Resource {
6666
}
6767

6868
func resourceScriptRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
69-
var diags diag.Diagnostics
70-
client, err := clients.NewApiClient(d, meta)
71-
if err != nil {
72-
return diag.FromErr(err)
69+
client, diags := clients.NewApiClient(d, meta)
70+
if diags.HasError() {
71+
return diags
7372
}
7473

7574
id := d.Id()
@@ -101,9 +100,9 @@ func resourceScriptRead(ctx context.Context, d *schema.ResourceData, meta interf
101100
}
102101

103102
func resourceScriptPut(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
104-
client, err := clients.NewApiClient(d, meta)
105-
if err != nil {
106-
return diag.FromErr(err)
103+
client, diags := clients.NewApiClient(d, meta)
104+
if diags.HasError() {
105+
return diags
107106
}
108107

109108
scriptID := d.Get("script_id").(string)
@@ -120,7 +119,7 @@ func resourceScriptPut(ctx context.Context, d *schema.ResourceData, meta interfa
120119
if paramsJSON, ok := d.GetOk("params"); ok {
121120
var params map[string]interface{}
122121
bytes := []byte(paramsJSON.(string))
123-
err = json.Unmarshal(bytes, &params)
122+
err := json.Unmarshal(bytes, &params)
124123
if err != nil {
125124
return diag.FromErr(err)
126125
}
@@ -138,9 +137,9 @@ func resourceScriptPut(ctx context.Context, d *schema.ResourceData, meta interfa
138137
}
139138

140139
func resourceScriptDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
141-
client, err := clients.NewApiClient(d, meta)
142-
if err != nil {
143-
return diag.FromErr(err)
140+
client, diags := clients.NewApiClient(d, meta)
141+
if diags.HasError() {
142+
return diags
144143
}
145144

146145
compId, diags := clients.CompositeIdFromStr(d.Id())

0 commit comments

Comments
 (0)