in ec/ecresource/deploymentresource/read.go [84:259]
func (r *Resource) read(ctx context.Context, id string, state *deploymentv2.DeploymentTF, plan *deploymentv2.DeploymentTF, deploymentResources []*models.DeploymentResource, privateFilters []string, readResponse *resource.ReadResponse) (*deploymentv2.Deployment, diag.Diagnostics) {
var diags diag.Diagnostics
var base deploymentv2.DeploymentTF
switch {
case plan != nil:
base = *plan
case state != nil:
base = *state
default:
diags.AddError("both state and plan are empty", "please specify at least one of them")
return nil, diags
}
response, err := deploymentapi.Get(deploymentapi.GetParams{
API: r.client,
DeploymentID: id,
QueryParams: deputil.QueryParams{
ShowSettings: true,
ShowPlans: true,
ShowMetadata: true,
ShowPlanDefaults: true,
ShowInstanceConfigurations: true,
},
})
if err != nil {
if deploymentNotFound(err) {
diags.AddError("Deployment not found", err.Error())
return nil, diags
}
diags.AddError("Deployment get error", err.Error())
return nil, diags
}
if readResponse != nil {
UpdatePrivateStateInstanceConfigurations(ctx, readResponse.Private, response.InstanceConfigurations)
}
if !HasRunningResources(response) {
return nil, nil
}
if response.Resources == nil || len(response.Resources.Elasticsearch) == 0 {
diags.AddError("Get resource error", "cannot find Elasticsearch in response resources")
return nil, diags
}
if response.Resources.Elasticsearch[0].Info.PlanInfo.Current != nil && response.Resources.Elasticsearch[0].Info.PlanInfo.Current.Plan != nil {
if err := checkVersion(response.Resources.Elasticsearch[0].Info.PlanInfo.Current.Plan.Elasticsearch.Version); err != nil {
diags.AddError("Get resource error", err.Error())
return nil, diags
}
}
refId := ""
var baseElasticsearch *elasticsearchv2.ElasticsearchTF
if diags = tfsdk.ValueAs(ctx, base.Elasticsearch, &baseElasticsearch); diags.HasError() {
return nil, diags
}
if baseElasticsearch != nil {
refId = baseElasticsearch.RefId.ValueString()
}
remotes, err := esremoteclustersapi.Get(esremoteclustersapi.GetParams{
API: r.client, DeploymentID: id,
RefID: refId,
})
if err != nil {
diags.AddError("Remote clusters read error", err.Error())
return nil, diags
}
if remotes == nil {
remotes = &models.RemoteResources{}
}
deployment, err := deploymentv2.ReadDeployment(response, remotes, deploymentResources)
if err != nil {
diags.AddError("Deployment read error", err.Error())
return nil, diags
}
deployment.RequestId = base.RequestId.ValueString()
if !base.ResetElasticsearchPassword.IsNull() && !base.ResetElasticsearchPassword.IsUnknown() {
deployment.ResetElasticsearchPassword = base.ResetElasticsearchPassword.ValueBoolPointer()
}
if !base.MigrateToLatestHardware.IsNull() && !base.MigrateToLatestHardware.IsUnknown() {
deployment.MigrateToLatestHardware = base.MigrateToLatestHardware.ValueBoolPointer()
}
diags.Append(deployment.IncludePrivateStateTrafficFilters(ctx, base, privateFilters)...)
deployment.SetCredentialsIfEmpty(state)
diags.Append(deployment.ProcessSelfInObservability(ctx, base)...)
deployment.NullifyUnusedEsTopologies(ctx, baseElasticsearch)
diags.Append(deployment.PersistSnapshotSource(ctx, baseElasticsearch)...)
if !deployment.HasNodeTypes() {
// The MigrateDeploymentTemplate request can only be performed for deployments that use node roles.
// We'll skip this logic for deployments with node types.
migrateTemplateRequest, err := r.client.V1API.Deployments.MigrateDeploymentTemplate(
deployments.NewMigrateDeploymentTemplateParams().WithDeploymentID(deployment.Id).WithTemplateID(deployment.DeploymentTemplateId),
r.client.AuthWriter,
)
if err != nil {
diags.AddError("Template migrate request error", err.Error())
return nil, diags
}
// Store migrate request in private state
if readResponse != nil {
UpdatePrivateStateMigrateTemplateRequest(ctx, readResponse.Private, migrateTemplateRequest)
}
deployment.SetLatestInstanceConfigInfo(migrateTemplateRequest)
} else {
// Set latest_instance_configuration_* fields to current values
// If this isn't done, when migrating a deployment to node roles, these fields will contain inconsistent values
deployment.SetLatestInstanceConfigInfoToCurrent()
}
// Set Elasticsearch `strategy` to the one from plan.
// We don't care about backend current `strategy`'s value and should not trigger a change,
// if the backend's value differs from the local state.
if baseElasticsearch != nil && !baseElasticsearch.Strategy.IsNull() {
deployment.Elasticsearch.Strategy = baseElasticsearch.Strategy.ValueStringPointer()
}
// sync Elasticsearch keystore contents if plan or state defines it:
// - all keystore entries that are not managed by the resource are left alone
// - if backend doesn't contain some keystore entry, the entry should be removed from the future state as well
if baseElasticsearch != nil && deployment.Elasticsearch != nil && !baseElasticsearch.KeystoreContents.IsNull() {
ds := baseElasticsearch.KeystoreContents.ElementsAs(ctx, &deployment.Elasticsearch.KeystoreContents, true)
diags.Append(ds...)
keystoreContents, err := eskeystoreapi.Get(eskeystoreapi.GetParams{
API: r.client,
DeploymentID: id,
})
if err != nil {
diags.AddError("Deployment keystore read error", err.Error())
return nil, diags
}
for entryName, entryVal := range deployment.Elasticsearch.KeystoreContents {
secret, ok := keystoreContents.Secrets[entryName]
if !ok {
delete(deployment.Elasticsearch.KeystoreContents, entryName)
continue
}
if secret.AsFile != nil {
entryVal.AsFile = secret.AsFile
deployment.Elasticsearch.KeystoreContents[entryName] = entryVal
}
}
}
// ReadDeployment returns empty config struct if there is no config, so we have to nullify it if plan doesn't contain it
// we use state for plan in Read and there is no state during import so we need to check elasticsearchPlan against nil
if baseElasticsearch != nil &&
baseElasticsearch.Config.IsNull() &&
deployment.Elasticsearch != nil &&
deployment.Elasticsearch.Config != nil &&
deployment.Elasticsearch.Config.IsEmpty() {
deployment.Elasticsearch.Config = nil
}
return deployment, diags
}