-
Notifications
You must be signed in to change notification settings - Fork 14
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
Feat: add wait_for_destroy option when destroying and environment #946
Conversation
@@ -63,5 +63,4 @@ func TestAgentValues(t *testing.T) { | |||
}, | |||
) | |||
}) | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ignore all these changes... there are thousands of changes required to successfully add a new linter, so I slowly fix these with each PR I make.
env0/resource_environment.go
Outdated
@@ -368,6 +370,12 @@ func resourceEnvironment() *schema.Resource { | |||
Description: "variable set id", | |||
}, | |||
}, | |||
"wait_for_destroy": { | |||
Type: schema.TypeBool, | |||
Description: "during destroy, waits for the environment status to be 'INACTIVE'. Times out after 30 minutes.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hope the description is clear enough.
env0/resource_environment.go
Outdated
if err != nil { | ||
if frerr, ok := err.(*http.FailedResponseError); ok && frerr.BadRequest() { | ||
tflog.Warn(ctx, "Could not delete environment. Already deleted?", map[string]interface{}{"id": d.Id(), "error": frerr.Error()}) | ||
return nil | ||
} | ||
return diag.Errorf("could not delete environment: %v", err) | ||
} | ||
|
||
if environment.Status != "INACTIVE" && d.Get("wait_for_destroy").(bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the wait will only be applied if 'wait_for_destroy' is enabled.
timer := time.NewTimer(timeout) // When invoked - time out | ||
results := make(chan error) | ||
|
||
go func() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is some golang specific stuff (channels) not very common in other languages.
https://go.dev/tour/concurrency/2
env0/resource_environment.go
Outdated
|
||
environment = &latestEnvironment | ||
|
||
if environment.Status == "INACTIVE" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
destroy successful...
timeout := time.Minute * 30 | ||
if os.Getenv("TF_ACC") == "1" { // For acceptance tests. | ||
waitInteval = time.Second | ||
timeout = time.Second * 10 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does it mean that it's 10 seconds?
Would it fail if environment couldn't destroy in 10 seconds?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is for unit tests...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
but yes...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it's for UTs - does it mean that test will hang for 10s?
What about harness tests?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes... but unit tests run in parallel so it doesn't really cause much problems. (max timeout it 10 seconds)
Harness tests - at least 10 seconds (time between intervals). But harness also run in parallel, so no issues IMHO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having 10 seconds timeout for harness tests is too low. Usually deployments take about 5-10 seconds only to start (i.e schedule a worker that handles the deployment), so I suggest we keep it as 3 minutes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the 10 seconds timeout is for acceptance tests, not harness tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify - for harness tests it'd keep the original behavior, correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct!
env0/resource_environment.go
Outdated
return | ||
} | ||
|
||
environment = &latestEnvironment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this extra assignment needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoids a few lines of code for the first iteration... but I can check if it can be avoided.
env0/resource_environment.go
Outdated
@@ -929,17 +937,69 @@ func resourceEnvironmentDelete(ctx context.Context, d *schema.ResourceData, meta | |||
return diag.Errorf(`must enable "force_destroy" safeguard in order to destroy`) | |||
} | |||
|
|||
_, err := apiClient.EnvironmentDestroy(d.Id()) | |||
environment, err := apiClient.EnvironmentDestroy(d.Id()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The destroy API returns the deployment log of the new destroy deployment, and not the environment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmmm if that's the case - sounds like a long standing bug...
I'll fix it....
@@ -66,7 +66,7 @@ type ApiClientInterface interface { | |||
Environment(id string) (Environment, error) | |||
EnvironmentCreate(payload EnvironmentCreate) (Environment, error) | |||
EnvironmentCreateWithoutTemplate(payload EnvironmentCreateWithoutTemplate) (Environment, error) | |||
EnvironmentDestroy(id string) (Environment, error) | |||
EnvironmentDestroy(id string) (*EnvironmentDestroyResponse, error) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was an old 'bug'.
@@ -91,6 +93,7 @@ type DeploymentLog struct { | |||
Output json.RawMessage `json:"output,omitempty"` | |||
Error json.RawMessage `json:"error,omitempty"` | |||
Type string `json:"type"` | |||
Status string `json:"status"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added Status to the DeploymentLog sruct.
@@ -283,13 +299,13 @@ func (client *ApiClient) EnvironmentCreateWithoutTemplate(payload EnvironmentCre | |||
return result, nil | |||
} | |||
|
|||
func (client *ApiClient) EnvironmentDestroy(id string) (Environment, error) { | |||
var result Environment | |||
func (client *ApiClient) EnvironmentDestroy(id string) (*EnvironmentDestroyResponse, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
old bug fixed...
env0/resource_environment.go
Outdated
results <- nil | ||
return | ||
} | ||
if slices.Contains([]string{"WAITING_FOR_USER", "TIMEOUT", "FAILURE", "CANCELLED", "INTERNAL_FAILURE", "ABORTING", "ABORTED", "SKIPPED", "NEVER_DEPLOYED"}, deployment.Status) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(fast) fail on any of these status.
if environment.Status == "DESTROY_IN_PROGRESS" { | ||
continue | ||
} | ||
if deployment.Status == "SUCCESS" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
happy path. After waiting...
return | ||
case <-ticker.C: | ||
continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
keep waiting...
@@ -49,6 +49,7 @@ resource "env0_environment" "auto_glob_envrironment" { | |||
approve_plan_automatically = true | |||
deploy_on_push = true | |||
force_destroy = true | |||
wait_for_destroy = true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added the flag to one of the harness tests...
@TomerHeber can you please resolve all conflicts before I review? |
8988667
to
e12d69b
Compare
@yaronya - done! |
e12d69b
to
bc20d5b
Compare
client/environment.go
Outdated
@@ -256,6 +263,15 @@ func (client *ApiClient) Environment(id string) (Environment, error) { | |||
return result, nil | |||
} | |||
|
|||
func (client *ApiClient) EnvironmentDeployment(id string) (*DeploymentLog, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to call it EnvironmentDeploymentLog
so it'd be clearer to the dev that it's different from EnvironmentDeploy
env0/resource_environment.go
Outdated
return | ||
} | ||
|
||
if slices.Contains([]string{"WAITING_FOR_USER", "TIMEOUT", "FAILURE", "CANCELLED", "INTERNAL_FAILURE", "ABORTING", "ABORTED", "SKIPPED", "NEVER_DEPLOYED"}, deployment.Status) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to not fail on WAITING_FOR_USER
but rather keep on waiting, and maybe write something back to the user that the deployment is waiting for an approval
This is actually something to consider for other statuses as well, like QUEUED
, so how about we print the current status on every iteration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added additional messages, and no longer fast failing with WAITING_FOR_USER
timeout := time.Minute * 30 | ||
if os.Getenv("TF_ACC") == "1" { // For acceptance tests. | ||
waitInteval = time.Second | ||
timeout = time.Second * 10 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having 10 seconds timeout for harness tests is too low. Usually deployments take about 5-10 seconds only to start (i.e schedule a worker that handles the deployment), so I suggest we keep it as 3 minutes.
timeout := time.Minute * 30 | ||
if os.Getenv("TF_ACC") == "1" { // For acceptance tests. | ||
waitInteval = time.Second | ||
timeout = time.Second * 10 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to clarify - for harness tests it'd keep the original behavior, correct?
Issue & Steps to Reproduce / Feature Request
resolves #686
Solution