Skip to content

Commit

Permalink
Unify AWS/Azure/GCP resource logics (#36)
Browse files Browse the repository at this point in the history
  • Loading branch information
gregito authored Jul 26, 2023
1 parent d71019b commit 1c24414
Show file tree
Hide file tree
Showing 6 changed files with 255 additions and 306 deletions.
104 changes: 104 additions & 0 deletions resources/environments/environment_action_util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright 2023 Cloudera. All Rights Reserved.
//
// This file is licensed under the Apache License Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
//
// This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
// OF ANY KIND, either express or implied. Refer to the License for the specific
// permissions and limitations governing your use of the file.

package environments

import (
"context"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-log/tflog"
"time"

"github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/cdp"
"github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/gen/environments/client/operations"
environmentsmodels "github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/gen/environments/models"
"github.com/cloudera/terraform-provider-cdp/utils"
)

const (
describeLogPrefix = "Result of describe environment: "
timeoutOneHour = time.Hour * 1
)

func describeEnvironmentWithDiagnosticHandle(envName string, id string, ctx context.Context, client *cdp.Client, resp *resource.ReadResponse) (*environmentsmodels.Environment, error) {
tflog.Info(ctx, "About to describe environment '"+envName+"'.")
params := operations.NewDescribeEnvironmentParamsWithContext(ctx)
params.WithInput(&environmentsmodels.DescribeEnvironmentRequest{
EnvironmentName: &envName,
})
descEnvResp, err := client.Environments.Operations.DescribeEnvironment(params)
if err != nil {
tflog.Warn(ctx, "Something happened during environment fetch: "+err.Error())
if isEnvNotFoundError(err) {
resp.Diagnostics.AddWarning("Resource not found on provider", "Environment not found, removing from state.")
tflog.Warn(ctx, "Environment not found, removing from state", map[string]interface{}{
"id": id,
})
resp.State.RemoveResource(ctx)
return nil, err
}
utils.AddEnvironmentDiagnosticsError(err, &resp.Diagnostics, "read Environment")
return nil, err
}
return utils.LogEnvironmentSilently(ctx, descEnvResp.GetPayload().Environment, describeLogPrefix), nil
}

func deleteEnvironmentWithDiagnosticHandle(environmentName string, ctx context.Context, client *cdp.Client, resp *resource.DeleteResponse) error {
params := operations.NewDeleteEnvironmentParamsWithContext(ctx)
params.WithInput(&environmentsmodels.DeleteEnvironmentRequest{EnvironmentName: &environmentName})
_, err := client.Environments.Operations.DeleteEnvironment(params)
if err != nil {
utils.AddEnvironmentDiagnosticsError(err, &resp.Diagnostics, "delete AWS Environment")
return err
}

err = waitForEnvironmentToBeDeleted(environmentName, timeoutOneHour, client.Environments, ctx)
if err != nil {
utils.AddEnvironmentDiagnosticsError(err, &resp.Diagnostics, "delete AWS Environment")
return err
}
return nil
}

func isEnvNotFoundError(err error) bool {
if envErr, ok := err.(*operations.DescribeEnvironmentDefault); ok {
if cdp.IsEnvironmentsError(envErr.GetPayload(), "NOT_FOUND", "") {
return true
}
}
return false
}

func waitForCreateEnvironmentWithDiagnosticHandle(ctx context.Context, client *cdp.Client, id string, envName string, resp *resource.CreateResponse) (*operations.DescribeEnvironmentOK, error) {
if err := waitForEnvironmentToBeAvailable(id, timeoutOneHour, client.Environments, ctx); err != nil {
utils.AddEnvironmentDiagnosticsError(err, &resp.Diagnostics, "create AWS Environment")
return nil, err
}

environmentName := envName
descParams := operations.NewDescribeEnvironmentParamsWithContext(ctx)
descParams.WithInput(&environmentsmodels.DescribeEnvironmentRequest{
EnvironmentName: &environmentName,
})
descEnvResp, err := client.Environments.Operations.DescribeEnvironment(descParams)
if err != nil {
if isEnvNotFoundError(err) {
resp.Diagnostics.AddWarning("Resource not found on provider", "Environment not found, removing from state.")
tflog.Warn(ctx, "Environment not found, removing from state", map[string]interface{}{
"id": id,
})
resp.State.RemoveResource(ctx)
return nil, err
}
utils.AddEnvironmentDiagnosticsError(err, &resp.Diagnostics, "create AWS Environment")
return nil, err
}
return descEnvResp, nil
}
119 changes: 119 additions & 0 deletions resources/environments/polling.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Copyright 2023 Cloudera. All Rights Reserved.
//
// This file is licensed under the Apache License Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
//
// This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
// OF ANY KIND, either express or implied. Refer to the License for the specific
// permissions and limitations governing your use of the file.

package environments

import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"log"
"time"

"github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/gen/environments/client"
"github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/gen/environments/client/operations"
environmentsmodels "github.com/cloudera/terraform-provider-cdp/cdp-sdk-go/gen/environments/models"
"github.com/cloudera/terraform-provider-cdp/utils"
)

func waitForEnvironmentToBeDeleted(environmentName string, timeout time.Duration, client *client.Environments, ctx context.Context) error {
stateConf := &retry.StateChangeConf{
Pending: []string{"STORAGE_CONSUMPTION_COLLECTION_UNSCHEDULING_IN_PROGRESS",
"NETWORK_DELETE_IN_PROGRESS",
"FREEIPA_DELETE_IN_PROGRESS",
"RDBMS_DELETE_IN_PROGRESS",
"IDBROKER_MAPPINGS_DELETE_IN_PROGRESS",
"S3GUARD_TABLE_DELETE_IN_PROGRESS",
"CLUSTER_DEFINITION_DELETE_PROGRESS",
"CLUSTER_DEFINITION_CLEANUP_PROGRESS",
"UMS_RESOURCE_DELETE_IN_PROGRESS",
"DELETE_INITIATED",
"DATAHUB_CLUSTERS_DELETE_IN_PROGRESS",
"DATALAKE_CLUSTERS_DELETE_IN_PROGRESS",
"PUBLICKEY_DELETE_IN_PROGRESS",
"EVENT_CLEANUP_IN_PROGRESS",
"EXPERIENCE_DELETE_IN_PROGRESS",
"ENVIRONMENT_RESOURCE_ENCRYPTION_DELETE_IN_PROGRESS",
"ENVIRONMENT_ENCRYPTION_RESOURCES_DELETED"},
Target: []string{},
Delay: 5 * time.Second,
Timeout: timeout,
PollInterval: 10 * time.Second,
Refresh: func() (interface{}, string, error) {
log.Printf("About to describe environment")
params := operations.NewDescribeEnvironmentParamsWithContext(ctx)
params.WithInput(&environmentsmodels.DescribeEnvironmentRequest{EnvironmentName: &environmentName})
resp, err := client.Operations.DescribeEnvironment(params)
if err != nil {
log.Printf("Error describing environment: %s", err)
if envErr, ok := err.(*operations.DescribeEnvironmentDefault); ok {
if isEnvNotFoundError(envErr) {
return nil, "", nil
}
}
return nil, "", err
}
if resp.GetPayload().Environment == nil {
log.Printf("Described environment. No environment.")
return nil, "", nil
}
log.Printf("Described environment's status: %s", *resp.GetPayload().Environment.Status)
return checkResponseStatusForError(resp)
},
}
_, err := stateConf.WaitForStateContext(ctx)

return err
}

func waitForEnvironmentToBeAvailable(environmentName string, timeout time.Duration, client *client.Environments, ctx context.Context) error {
stateConf := &retry.StateChangeConf{
Pending: []string{"CREATION_INITIATED",
"NETWORK_CREATION_IN_PROGRESS",
"PUBLICKEY_CREATE_IN_PROGRESS",
"ENVIRONMENT_RESOURCE_ENCRYPTION_INITIALIZATION_IN_PROGRESS",
"ENVIRONMENT_VALIDATION_IN_PROGRESS",
"ENVIRONMENT_INITIALIZATION_IN_PROGRESS",
"FREEIPA_CREATION_IN_PROGRESS"},
Target: []string{"AVAILABLE"},
Delay: 5 * time.Second,
Timeout: timeout,
PollInterval: 10 * time.Second,
Refresh: func() (interface{}, string, error) {
log.Printf("[DEBUG] About to describe environment %s", environmentName)
params := operations.NewDescribeEnvironmentParamsWithContext(ctx)
params.WithInput(&environmentsmodels.DescribeEnvironmentRequest{EnvironmentName: &environmentName})
resp, err := client.Operations.DescribeEnvironment(params)
if err != nil {
// Envs that have just been created may not be returned from Describe Environment request because of eventual
// consistency. We return an empty state to retry.

if isEnvNotFoundError(err) {
log.Printf("[DEBUG] Recoverable error describing environment: %s", err)
return nil, "", nil
}
log.Printf("Error describing environment: %s", err)
return nil, "", err
}
log.Printf("Described environment's status: %s", *resp.GetPayload().Environment.Status)
return checkResponseStatusForError(resp)
},
}
_, err := stateConf.WaitForStateContext(ctx)

return err
}

func checkResponseStatusForError(resp *operations.DescribeEnvironmentOK) (interface{}, string, error) {
if utils.ContainsAsSubstring([]string{"FAILED", "ERROR"}, *resp.GetPayload().Environment.Status) {
return nil, "", fmt.Errorf("unexpected Enviornment status: %s. Reason: %s", *resp.GetPayload().Environment.Status, resp.GetPayload().Environment.StatusReason)
}
return resp, *resp.GetPayload().Environment.Status, nil
}
Loading

0 comments on commit 1c24414

Please sign in to comment.