Skip to content

Commit bd73d42

Browse files
authored
Support updating API keys (elastic#843)
* Move fromErr to utils * Migrate api_key to plugin framework * Support updating api keys * Generate docs * Changelog
1 parent e694471 commit bd73d42

File tree

19 files changed

+862
-446
lines changed

19 files changed

+862
-446
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
## [Unreleased]
22

3+
- Support updating `elasticstack_elasticsearch_security_api_key` when supported by the backing cluster ([#843](https://github.com/elastic/terraform-provider-elasticstack/pull/843))
34
- Fix validation of `throttle`, and `interval` attributes in `elasticstack_kibana_alerting_rule` allowing all Elastic duration values ([#846](https://github.com/elastic/terraform-provider-elasticstack/pull/846))
45
- Fix boolean setting parsing for `elasticstack_elasticsearch_indices` data source. ([#842](https://github.com/elastic/terraform-provider-elasticstack/pull/842))
56

docs/resources/elasticsearch_security_api_key.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ output "api_key" {
8787

8888
### Optional
8989

90-
- `elasticsearch_connection` (Block List, Max: 1, Deprecated) Elasticsearch connection configuration block. This property will be removed in a future provider version. Configure the Elasticsearch connection via the provider configuration instead. (see [below for nested schema](#nestedblock--elasticsearch_connection))
90+
- `elasticsearch_connection` (Block List, Deprecated) Elasticsearch connection configuration block. (see [below for nested schema](#nestedblock--elasticsearch_connection))
9191
- `expiration` (String) Expiration time for the API key. By default, API keys never expire.
9292
- `metadata` (String) Arbitrary metadata that you want to associate with the API key.
9393
- `role_descriptors` (String) Role descriptors for this API key.

internal/clients/elasticsearch/security.go

Lines changed: 55 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/elastic/terraform-provider-elasticstack/internal/clients"
1111
"github.com/elastic/terraform-provider-elasticstack/internal/models"
1212
"github.com/elastic/terraform-provider-elasticstack/internal/utils"
13+
fwdiag "github.com/hashicorp/terraform-plugin-framework/diag"
1314
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
1415
)
1516

@@ -292,83 +293,101 @@ func DeleteRoleMapping(ctx context.Context, apiClient *clients.ApiClient, roleMa
292293
return nil
293294
}
294295

295-
func PutApiKey(apiClient *clients.ApiClient, apikey *models.ApiKey) (*models.ApiKeyResponse, diag.Diagnostics) {
296-
var diags diag.Diagnostics
296+
func CreateApiKey(apiClient *clients.ApiClient, apikey *models.ApiKey) (*models.ApiKeyCreateResponse, fwdiag.Diagnostics) {
297297
apikeyBytes, err := json.Marshal(apikey)
298298
if err != nil {
299-
return nil, diag.FromErr(err)
299+
return nil, utils.FrameworkDiagFromError(err)
300300
}
301301

302302
esClient, err := apiClient.GetESClient()
303303
if err != nil {
304-
return nil, diag.FromErr(err)
304+
return nil, utils.FrameworkDiagFromError(err)
305305
}
306306
res, err := esClient.Security.CreateAPIKey(bytes.NewReader(apikeyBytes))
307307
if err != nil {
308-
return nil, diag.FromErr(err)
308+
return nil, utils.FrameworkDiagFromError(err)
309309
}
310310
defer res.Body.Close()
311311
if diags := utils.CheckError(res, "Unable to create apikey"); diags.HasError() {
312-
return nil, diags
312+
return nil, utils.FrameworkDiagsFromSDK(diags)
313313
}
314314

315-
var apiKey models.ApiKeyResponse
315+
var apiKey models.ApiKeyCreateResponse
316316

317317
if err := json.NewDecoder(res.Body).Decode(&apiKey); err != nil {
318-
return nil, diag.FromErr(err)
318+
return nil, utils.FrameworkDiagFromError(err)
319319
}
320320

321-
return &apiKey, diags
321+
return &apiKey, nil
322322
}
323323

324-
func GetApiKey(apiClient *clients.ApiClient, id string) (*models.ApiKeyResponse, diag.Diagnostics) {
325-
var diags diag.Diagnostics
324+
func UpdateApiKey(apiClient *clients.ApiClient, apikey models.ApiKey) fwdiag.Diagnostics {
325+
id := apikey.ID
326+
327+
apikey.Expiration = ""
328+
apikey.Name = ""
329+
apikey.ID = ""
330+
apikeyBytes, err := json.Marshal(apikey)
331+
if err != nil {
332+
return utils.FrameworkDiagFromError(err)
333+
}
334+
326335
esClient, err := apiClient.GetESClient()
327336
if err != nil {
328-
return nil, diag.FromErr(err)
337+
return utils.FrameworkDiagFromError(err)
338+
}
339+
res, err := esClient.Security.UpdateAPIKey(id, esClient.Security.UpdateAPIKey.WithBody(bytes.NewReader(apikeyBytes)))
340+
if err != nil {
341+
return utils.FrameworkDiagFromError(err)
342+
}
343+
defer res.Body.Close()
344+
if diags := utils.CheckError(res, "Unable to create apikey"); diags.HasError() {
345+
return utils.FrameworkDiagsFromSDK(diags)
346+
}
347+
348+
return nil
349+
}
350+
351+
func GetApiKey(apiClient *clients.ApiClient, id string) (*models.ApiKeyResponse, fwdiag.Diagnostics) {
352+
esClient, err := apiClient.GetESClient()
353+
if err != nil {
354+
return nil, utils.FrameworkDiagFromError(err)
329355
}
330356
req := esClient.Security.GetAPIKey.WithID(id)
331357
res, err := esClient.Security.GetAPIKey(req)
332358
if err != nil {
333-
return nil, diag.FromErr(err)
359+
return nil, utils.FrameworkDiagFromError(err)
334360
}
335361
defer res.Body.Close()
336362
if res.StatusCode == http.StatusNotFound {
337-
diags := append(diags, diag.Diagnostic{
338-
Severity: diag.Error,
339-
Summary: "Unable to find an apikey in the cluster.",
340-
Detail: fmt.Sprintf("Unable to get apikey: '%s' from the cluster.", id),
341-
})
342-
return nil, diags
363+
return nil, nil
343364
}
344365
if diags := utils.CheckError(res, "Unable to get an apikey."); diags.HasError() {
345-
return nil, diags
366+
return nil, utils.FrameworkDiagsFromSDK(diags)
346367
}
347368

348369
// unmarshal our response to proper type
349370
var apiKeys struct {
350371
ApiKeys []models.ApiKeyResponse `json:"api_keys"`
351372
}
352373
if err := json.NewDecoder(res.Body).Decode(&apiKeys); err != nil {
353-
return nil, diag.FromErr(err)
374+
return nil, utils.FrameworkDiagFromError(err)
354375
}
355376

356377
if len(apiKeys.ApiKeys) != 1 {
357-
diags = append(diags, diag.Diagnostic{
358-
Severity: diag.Error,
359-
Summary: "Unable to find an apikey in the cluster",
360-
Detail: fmt.Sprintf(`Unable to find "%s" apikey in the cluster`, id),
361-
})
362-
return nil, diags
378+
return nil, fwdiag.Diagnostics{
379+
fwdiag.NewErrorDiagnostic(
380+
"Unable to find an apikey in the cluster",
381+
fmt.Sprintf(`Unable to find "%s" apikey in the cluster`, id),
382+
),
383+
}
363384
}
364385

365386
apiKey := apiKeys.ApiKeys[0]
366-
return &apiKey, diags
387+
return &apiKey, nil
367388
}
368389

369-
func DeleteApiKey(apiClient *clients.ApiClient, id string) diag.Diagnostics {
370-
var diags diag.Diagnostics
371-
390+
func DeleteApiKey(apiClient *clients.ApiClient, id string) fwdiag.Diagnostics {
372391
apiKeys := struct {
373392
Ids []string `json:"ids"`
374393
}{
@@ -377,19 +396,19 @@ func DeleteApiKey(apiClient *clients.ApiClient, id string) diag.Diagnostics {
377396

378397
apikeyBytes, err := json.Marshal(apiKeys)
379398
if err != nil {
380-
return diag.FromErr(err)
399+
return utils.FrameworkDiagFromError(err)
381400
}
382401
esClient, err := apiClient.GetESClient()
383402
if err != nil {
384-
return diag.FromErr(err)
403+
return utils.FrameworkDiagFromError(err)
385404
}
386405
res, err := esClient.Security.InvalidateAPIKey(bytes.NewReader(apikeyBytes))
387406
if err != nil && res.IsError() {
388-
return diag.FromErr(err)
407+
return utils.FrameworkDiagFromError(err)
389408
}
390409
defer res.Body.Close()
391410
if diags := utils.CheckError(res, "Unable to delete an apikey"); diags.HasError() {
392-
return diags
411+
return utils.FrameworkDiagsFromSDK(diags)
393412
}
394-
return diags
413+
return nil
395414
}

0 commit comments

Comments
 (0)