Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reset es password #642

Merged
merged 4 commits into from
May 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/resources/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ resource "ec_deployment" "ccs" {
- `name` (String) Name for the deployment
- `observability` (Attributes) Observability settings that you can set to ship logs and metrics to a deployment. The target deployment can also be the current deployment itself by setting observability.deployment_id to `self`. (see [below for nested schema](#nestedatt--observability))
- `request_id` (String) Request ID to set when you create the deployment. Use it only when previous attempts return an error and `request_id` is returned as part of the error.
- `reset_elasticsearch_password` (Boolean) Explicitly resets the elasticsearch_password when true
- `tags` (Map of String) Optional map of deployment tags
- `traffic_filter` (Set of String) List of traffic filters rule identifiers that will be applied to the deployment.

Expand Down
40 changes: 40 additions & 0 deletions ec/acc/deployment_basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
package acc

import (
"errors"
"fmt"
"os"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
)

func TestAccDeployment_basic_tf(t *testing.T) {
Expand All @@ -33,14 +35,17 @@ func TestAccDeployment_basic_tf(t *testing.T) {
randomAlias := "alias" + acctest.RandStringFromCharSet(5, acctest.CharSetAlphaNum)
trafficFilterCfg := "testdata/deployment_basic_with_traffic_filter_2.tf"
trafficFilterUpdateCfg := "testdata/deployment_basic_with_traffic_filter_3.tf"
resetPasswordCfg := "testdata/deployment_basic_reset_password.tf"
cfg := fixtureAccDeploymentResourceBasicWithAppsAlias(t, startCfg, randomAlias, randomName, getRegion(), defaultTemplate)
cfgWithTrafficFilter := fixtureAccDeploymentResourceBasicWithTF(t, trafficFilterCfg, randomName, getRegion(), defaultTemplate)
cfgWithTrafficFilterUpdate := fixtureAccDeploymentResourceBasicWithTF(t, trafficFilterUpdateCfg, randomName, getRegion(), defaultTemplate)
cfgResetPassword := fixtureAccDeploymentResourceBasicWithAppsAlias(t, resetPasswordCfg, randomAlias, randomName, getRegion(), defaultTemplate)
deploymentVersion, err := latestStackVersion()
if err != nil {
t.Fatal(err)
}

elasticsearchPassword := ""
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: testAccProviderFactory,
Expand Down Expand Up @@ -76,12 +81,47 @@ func TestAccDeployment_basic_tf(t *testing.T) {
Config: cfg,
Check: checkBasicDeploymentResource(resName, randomName, deploymentVersion,
resource.TestCheckResourceAttr(resName, "traffic_filter.#", "0"),
func(s *terraform.State) error {
pw, ok := captureElasticsearchPassword(s, resName)
if !ok {
return errors.New("unable to capture current elasticsearch_password")
}

elasticsearchPassword = pw
return nil
},
),
},
// Reset the elasticsearch_password
{
Config: cfgResetPassword,
ExpectNonEmptyPlan: true, // reset_elasticsearch_password will always result in a non-empty plan
Check: checkBasicDeploymentResource(resName, randomName, deploymentVersion,
resource.TestCheckResourceAttr(resName, "traffic_filter.#", "0"),
func(s *terraform.State) error {
currentPw, ok := captureElasticsearchPassword(s, resName)
if !ok {
return errors.New("unable to capture current elasticsearch_password")
}

if currentPw == elasticsearchPassword {
return fmt.Errorf("expected elasticsearch_password to be reset: %s == %s", elasticsearchPassword, currentPw)
}

return nil
},
),
},
},
})
}

func captureElasticsearchPassword(s *terraform.State, resName string) (string, bool) {
res := s.RootModule().Resources[resName]
pw, ok := res.Primary.Attributes["elasticsearch_password"]
return pw, ok
}

func TestAccDeployment_basic_config(t *testing.T) {
resName := "ec_deployment.basic"
randomName := prefix + acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)
Expand Down
33 changes: 33 additions & 0 deletions ec/acc/testdata/deployment_basic_reset_password.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
data "ec_stack" "latest" {
version_regex = "latest"
region = "%s"
}

resource "ec_deployment" "basic" {
alias = "%s"
name = "%s"
region = "%s"
version = data.ec_stack.latest.version
deployment_template_id = "%s"

elasticsearch = {
hot = {
size = "1g"
autoscaling = {}
}
}

kibana = {
instance_configuration_id = "%s"
}

apm = {
instance_configuration_id = "%s"
}

enterprise_search = {
instance_configuration_id = "%s"
}

reset_elasticsearch_password = true
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,24 +38,25 @@ import (
)

type DeploymentTF struct {
Id types.String `tfsdk:"id"`
Alias types.String `tfsdk:"alias"`
Version types.String `tfsdk:"version"`
Region types.String `tfsdk:"region"`
DeploymentTemplateId types.String `tfsdk:"deployment_template_id"`
Name types.String `tfsdk:"name"`
RequestId types.String `tfsdk:"request_id"`
ElasticsearchUsername types.String `tfsdk:"elasticsearch_username"`
ElasticsearchPassword types.String `tfsdk:"elasticsearch_password"`
ApmSecretToken types.String `tfsdk:"apm_secret_token"`
TrafficFilter types.Set `tfsdk:"traffic_filter"`
Tags types.Map `tfsdk:"tags"`
Elasticsearch types.Object `tfsdk:"elasticsearch"`
Kibana types.Object `tfsdk:"kibana"`
Apm types.Object `tfsdk:"apm"`
IntegrationsServer types.Object `tfsdk:"integrations_server"`
EnterpriseSearch types.Object `tfsdk:"enterprise_search"`
Observability types.Object `tfsdk:"observability"`
Id types.String `tfsdk:"id"`
Alias types.String `tfsdk:"alias"`
Version types.String `tfsdk:"version"`
Region types.String `tfsdk:"region"`
DeploymentTemplateId types.String `tfsdk:"deployment_template_id"`
Name types.String `tfsdk:"name"`
RequestId types.String `tfsdk:"request_id"`
ElasticsearchUsername types.String `tfsdk:"elasticsearch_username"`
ElasticsearchPassword types.String `tfsdk:"elasticsearch_password"`
ApmSecretToken types.String `tfsdk:"apm_secret_token"`
TrafficFilter types.Set `tfsdk:"traffic_filter"`
Tags types.Map `tfsdk:"tags"`
Elasticsearch types.Object `tfsdk:"elasticsearch"`
Kibana types.Object `tfsdk:"kibana"`
Apm types.Object `tfsdk:"apm"`
IntegrationsServer types.Object `tfsdk:"integrations_server"`
EnterpriseSearch types.Object `tfsdk:"enterprise_search"`
Observability types.Object `tfsdk:"observability"`
ResetElasticsearchPassword types.Bool `tfsdk:"reset_elasticsearch_password"`
}

func (dep DeploymentTF) CreateRequest(ctx context.Context, client *api.API) (*models.DeploymentCreateRequest, diag.Diagnostics) {
Expand Down
37 changes: 19 additions & 18 deletions ec/ecresource/deploymentresource/deployment/v2/deployment_read.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,24 +39,25 @@ import (
)

type Deployment struct {
Id string `tfsdk:"id"`
Alias string `tfsdk:"alias"`
Version string `tfsdk:"version"`
Region string `tfsdk:"region"`
DeploymentTemplateId string `tfsdk:"deployment_template_id"`
Name string `tfsdk:"name"`
RequestId string `tfsdk:"request_id"`
ElasticsearchUsername string `tfsdk:"elasticsearch_username"`
ElasticsearchPassword string `tfsdk:"elasticsearch_password"`
ApmSecretToken *string `tfsdk:"apm_secret_token"`
TrafficFilter []string `tfsdk:"traffic_filter"`
Tags map[string]string `tfsdk:"tags"`
Elasticsearch *elasticsearchv2.Elasticsearch `tfsdk:"elasticsearch"`
Kibana *kibanav2.Kibana `tfsdk:"kibana"`
Apm *apmv2.Apm `tfsdk:"apm"`
IntegrationsServer *integrationsserverv2.IntegrationsServer `tfsdk:"integrations_server"`
EnterpriseSearch *enterprisesearchv2.EnterpriseSearch `tfsdk:"enterprise_search"`
Observability *observabilityv2.Observability `tfsdk:"observability"`
Id string `tfsdk:"id"`
Alias string `tfsdk:"alias"`
Version string `tfsdk:"version"`
Region string `tfsdk:"region"`
DeploymentTemplateId string `tfsdk:"deployment_template_id"`
Name string `tfsdk:"name"`
RequestId string `tfsdk:"request_id"`
ElasticsearchUsername string `tfsdk:"elasticsearch_username"`
ElasticsearchPassword string `tfsdk:"elasticsearch_password"`
ApmSecretToken *string `tfsdk:"apm_secret_token"`
TrafficFilter []string `tfsdk:"traffic_filter"`
Tags map[string]string `tfsdk:"tags"`
Elasticsearch *elasticsearchv2.Elasticsearch `tfsdk:"elasticsearch"`
Kibana *kibanav2.Kibana `tfsdk:"kibana"`
Apm *apmv2.Apm `tfsdk:"apm"`
IntegrationsServer *integrationsserverv2.IntegrationsServer `tfsdk:"integrations_server"`
EnterpriseSearch *enterprisesearchv2.EnterpriseSearch `tfsdk:"enterprise_search"`
Observability *observabilityv2.Observability `tfsdk:"observability"`
ResetElasticsearchPassword *bool `tfsdk:"reset_elasticsearch_password"`
}

// Nullify Elasticsearch topologies that have zero size and are not specified in plan
Expand Down
42 changes: 42 additions & 0 deletions ec/ecresource/deploymentresource/deployment/v2/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
package v2

import (
"context"

"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
"github.com/hashicorp/terraform-plugin-framework/types"
Expand Down Expand Up @@ -102,6 +105,7 @@ func DeploymentSchema() tfsdk.Schema {
Sensitive: true,
PlanModifiers: tfsdk.AttributePlanModifiers{
resource.UseStateForUnknown(),
setUnknownIfResetPasswordIsTrue{},
},
},
"apm_secret_token": {
Expand All @@ -123,6 +127,11 @@ func DeploymentSchema() tfsdk.Schema {
},
Optional: true,
},
"reset_elasticsearch_password": {
Description: "Explicitly resets the elasticsearch_password when true",
Type: types.BoolType,
Optional: true,
},
"elasticsearch": elasticsearchv2.ElasticsearchSchema(),
"kibana": kibanav2.KibanaSchema(),
"apm": apmv2.ApmSchema(),
Expand All @@ -132,3 +141,36 @@ func DeploymentSchema() tfsdk.Schema {
},
}
}

type setUnknownIfResetPasswordIsTrue struct{}

var _ tfsdk.AttributePlanModifier = setUnknownIfResetPasswordIsTrue{}

func (m setUnknownIfResetPasswordIsTrue) Description(ctx context.Context) string {
return m.MarkdownDescription(ctx)
}

func (m setUnknownIfResetPasswordIsTrue) MarkdownDescription(ctx context.Context) string {
return "Sets the planned value to unknown if the reset_elasticsearch_password config value is true"
}

func (m setUnknownIfResetPasswordIsTrue) Modify(ctx context.Context, req tfsdk.ModifyAttributePlanRequest, resp *tfsdk.ModifyAttributePlanResponse) {
if resp.AttributePlan == nil || req.AttributeConfig == nil {
return
}

// if the config is the unknown value, use the unknown value otherwise, interpolation gets messed up
if req.AttributeConfig.IsUnknown() {
return
}

var isResetting *bool
resp.Diagnostics.Append(req.Plan.GetAttribute(ctx, path.Root("reset_elasticsearch_password"), &isResetting)...)
if resp.Diagnostics.HasError() {
return
}

if isResetting != nil && *isResetting {
resp.AttributePlan = types.String{Unknown: true}
}
}
3 changes: 3 additions & 0 deletions ec/ecresource/deploymentresource/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,9 @@ func (r *Resource) read(ctx context.Context, id string, state *deploymentv2.Depl
}

deployment.RequestId = base.RequestId.Value
if !base.ResetElasticsearchPassword.IsNull() && !base.ResetElasticsearchPassword.IsUnknown() {
deployment.ResetElasticsearchPassword = &base.ResetElasticsearchPassword.Value
}

deployment.SetCredentialsIfEmpty(state)

Expand Down
28 changes: 27 additions & 1 deletion ec/ecresource/deploymentresource/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (

"github.com/elastic/cloud-sdk-go/pkg/api"
"github.com/elastic/cloud-sdk-go/pkg/api/deploymentapi"
"github.com/elastic/cloud-sdk-go/pkg/api/deploymentapi/depresourceapi"
"github.com/elastic/cloud-sdk-go/pkg/api/deploymentapi/trafficfilterapi"
v2 "github.com/elastic/terraform-provider-ec/ec/ecresource/deploymentresource/deployment/v2"
"github.com/elastic/terraform-provider-ec/ec/internal/util"
Expand Down Expand Up @@ -77,7 +78,6 @@ func (r *Resource) Update(ctx context.Context, req resource.UpdateRequest, resp
resp.Diagnostics.Append(v2.HandleRemoteClusters(ctx, r.client, plan.Id.Value, plan.Elasticsearch)...)

deployment, diags := r.read(ctx, plan.Id.Value, &state, &plan, res.Resources)

resp.Diagnostics.Append(diags...)

if deployment == nil {
Expand All @@ -86,9 +86,35 @@ func (r *Resource) Update(ctx context.Context, req resource.UpdateRequest, resp
return
}

if plan.ResetElasticsearchPassword.Value {
newPassword, diags := r.ResetElasticsearchPassword(plan.Id.Value, *deployment.Elasticsearch.RefId)
if resp.Diagnostics.Append(diags...); resp.Diagnostics.HasError() {
return
}

deployment.ElasticsearchPassword = newPassword
}

resp.Diagnostics.Append(resp.State.Set(ctx, deployment)...)
}

func (r *Resource) ResetElasticsearchPassword(deploymentID string, refID string) (string, diag.Diagnostics) {
var diags diag.Diagnostics

resetResp, err := depresourceapi.ResetElasticsearchPassword(depresourceapi.ResetElasticsearchPasswordParams{
API: r.client,
ID: deploymentID,
RefID: refID,
})

if err != nil {
diags.AddError("failed to reset elasticsearch password", err.Error())
return "", diags
}

return *resetResp.Password, diags
}

func HandleTrafficFilterChange(ctx context.Context, client *api.API, plan, state v2.DeploymentTF) diag.Diagnostics {
if plan.TrafficFilter.IsNull() || plan.TrafficFilter.Equal(state.TrafficFilter) {
return nil
Expand Down
Empty file added ec/requests.log
Empty file.