mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-07-06 10:12:39 +00:00
[TF] Remove draining and cancelling from terminal dataflow job states (#3399)
Signed-off-by: Modular Magician <magic-modules@google.com>
This commit is contained in:
parent
f67094708f
commit
0f3f1a236a
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/hashicorp/terraform/helper/schema"
|
"github.com/hashicorp/terraform/helper/schema"
|
||||||
"github.com/hashicorp/terraform/helper/validation"
|
"github.com/hashicorp/terraform/helper/validation"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/helper/resource"
|
||||||
"google.golang.org/api/dataflow/v1b3"
|
"google.golang.org/api/dataflow/v1b3"
|
||||||
"google.golang.org/api/googleapi"
|
"google.golang.org/api/googleapi"
|
||||||
)
|
)
|
||||||
|
@ -18,9 +19,7 @@ var dataflowTerminalStatesMap = map[string]struct{}{
|
||||||
"JOB_STATE_FAILED": {},
|
"JOB_STATE_FAILED": {},
|
||||||
"JOB_STATE_CANCELLED": {},
|
"JOB_STATE_CANCELLED": {},
|
||||||
"JOB_STATE_UPDATED": {},
|
"JOB_STATE_UPDATED": {},
|
||||||
"JOB_STATE_DRAINING": {},
|
|
||||||
"JOB_STATE_DRAINED": {},
|
"JOB_STATE_DRAINED": {},
|
||||||
"JOB_STATE_CANCELLING": {},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func resourceDataflowJob() *schema.Resource {
|
func resourceDataflowJob() *schema.Resource {
|
||||||
|
@ -83,6 +82,7 @@ func resourceDataflowJob() *schema.Resource {
|
||||||
"project": {
|
"project": {
|
||||||
Type: schema.TypeString,
|
Type: schema.TypeString,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
Computed: true,
|
||||||
ForceNew: true,
|
ForceNew: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ func resourceDataflowJobCreate(d *schema.ResourceData, meta interface{}) error {
|
||||||
Environment: &env,
|
Environment: &env,
|
||||||
}
|
}
|
||||||
|
|
||||||
job, err := createJob(config, project, region, &request)
|
job, err := resourceDataflowJobCreateJob(config, project, region, &request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -158,7 +158,7 @@ func resourceDataflowJobRead(d *schema.ResourceData, meta interface{}) error {
|
||||||
|
|
||||||
id := d.Id()
|
id := d.Id()
|
||||||
|
|
||||||
job, err := getJob(config, project, region, id)
|
job, err := resourceDataflowJobGetJob(config, project, region, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return handleNotFoundError(err, d, fmt.Sprintf("Dataflow job %s", id))
|
return handleNotFoundError(err, d, fmt.Sprintf("Dataflow job %s", id))
|
||||||
}
|
}
|
||||||
|
@ -191,51 +191,70 @@ func resourceDataflowJobDelete(d *schema.ResourceData, meta interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
id := d.Id()
|
id := d.Id()
|
||||||
requestedState, err := mapOnDelete(d.Get("on_delete").(string))
|
|
||||||
|
requestedState, err := resourceDataflowJobMapRequestedState(d.Get("on_delete").(string))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, ok := dataflowTerminalStatesMap[d.Get("state").(string)]; !ok; _, ok = dataflowTerminalStatesMap[d.Get("state").(string)] {
|
|
||||||
|
// Retry updating the state while the job is not ready to be canceled/drained.
|
||||||
|
err = resource.Retry(time.Minute*time.Duration(15), func() *resource.RetryError {
|
||||||
|
// To terminate a dataflow job, we update the job with a requested
|
||||||
|
// terminal state.
|
||||||
job := &dataflow.Job{
|
job := &dataflow.Job{
|
||||||
RequestedState: requestedState,
|
RequestedState: requestedState,
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = updateJob(config, project, region, id, job)
|
_, updateErr := resourceDataflowJobUpdateJob(config, project, region, id, job)
|
||||||
if err != nil {
|
if updateErr != nil {
|
||||||
if gerr, err_ok := err.(*googleapi.Error); !err_ok {
|
gerr, isGoogleErr := err.(*googleapi.Error)
|
||||||
|
if !isGoogleErr {
|
||||||
// If we have an error and it's not a google-specific error, we should go ahead and return.
|
// If we have an error and it's not a google-specific error, we should go ahead and return.
|
||||||
return err
|
return resource.NonRetryableError(err)
|
||||||
} else if err_ok && strings.Contains(gerr.Message, "not yet ready for canceling") {
|
}
|
||||||
// We'll sleep below to wait for the job to be ready to cancel.
|
|
||||||
} else {
|
if strings.Contains(gerr.Message, "not yet ready for canceling") {
|
||||||
return err
|
// Retry cancelling job if it's not ready.
|
||||||
|
// Sleep to avoid hitting update quota with repeated attempts.
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
return resource.RetryableError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(gerr.Message, "Job has terminated") {
|
||||||
|
// Job has already been terminated, skip.
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = resourceDataflowJobRead(d, meta)
|
return nil
|
||||||
postReadState := d.Get("state").(string)
|
})
|
||||||
log.Printf("[DEBUG] Job state: '%s'.", postReadState)
|
|
||||||
if _, ok := dataflowTerminalStatesMap[postReadState]; !ok {
|
|
||||||
// If we're not yet in a terminal state, we need to sleep a few seconds so we don't
|
|
||||||
// exhaust our update quota with repeated attempts.
|
|
||||||
time.Sleep(5 * time.Second)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait for state to reach terminal state (canceled/drained/done)
|
||||||
|
_, ok := dataflowTerminalStatesMap[d.Get("state").(string)]
|
||||||
|
for !ok {
|
||||||
|
log.Printf("[DEBUG] Waiting for job with job state %q to terminate...", d.Get("state").(string))
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
|
err = resourceDataflowJobRead(d, meta)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error while reading job to see if it was properly terminated: %v", err)
|
||||||
|
}
|
||||||
|
_, ok = dataflowTerminalStatesMap[d.Get("state").(string)]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only remove the job from state if it's actually successfully canceled.
|
// Only remove the job from state if it's actually successfully canceled.
|
||||||
if _, ok := dataflowTerminalStatesMap[d.Get("state").(string)]; ok {
|
if _, ok := dataflowTerminalStatesMap[d.Get("state").(string)]; ok {
|
||||||
|
log.Printf("[DEBUG] Removing dataflow job with final state %q", d.Get("state").(string))
|
||||||
d.SetId("")
|
d.SetId("")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
return fmt.Errorf("Unable to cancel the dataflow job '%s' - final state was %q.", d.Id(), d.Get("state").(string))
|
||||||
return fmt.Errorf("There was a problem canceling the dataflow job '%s' - the final state was %s.", d.Id(), d.Get("state").(string))
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func mapOnDelete(policy string) (string, error) {
|
func resourceDataflowJobMapRequestedState(policy string) (string, error) {
|
||||||
switch policy {
|
switch policy {
|
||||||
case "cancel":
|
case "cancel":
|
||||||
return "JOB_STATE_CANCELLED", nil
|
return "JOB_STATE_CANCELLED", nil
|
||||||
|
@ -246,21 +265,21 @@ func mapOnDelete(policy string) (string, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createJob(config *Config, project string, region string, request *dataflow.CreateJobFromTemplateRequest) (*dataflow.Job, error) {
|
func resourceDataflowJobCreateJob(config *Config, project string, region string, request *dataflow.CreateJobFromTemplateRequest) (*dataflow.Job, error) {
|
||||||
if region == "" {
|
if region == "" {
|
||||||
return config.clientDataflow.Projects.Templates.Create(project, request).Do()
|
return config.clientDataflow.Projects.Templates.Create(project, request).Do()
|
||||||
}
|
}
|
||||||
return config.clientDataflow.Projects.Locations.Templates.Create(project, region, request).Do()
|
return config.clientDataflow.Projects.Locations.Templates.Create(project, region, request).Do()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getJob(config *Config, project string, region string, id string) (*dataflow.Job, error) {
|
func resourceDataflowJobGetJob(config *Config, project string, region string, id string) (*dataflow.Job, error) {
|
||||||
if region == "" {
|
if region == "" {
|
||||||
return config.clientDataflow.Projects.Jobs.Get(project, id).Do()
|
return config.clientDataflow.Projects.Jobs.Get(project, id).Do()
|
||||||
}
|
}
|
||||||
return config.clientDataflow.Projects.Locations.Jobs.Get(project, region, id).Do()
|
return config.clientDataflow.Projects.Locations.Jobs.Get(project, region, id).Do()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateJob(config *Config, project string, region string, id string, job *dataflow.Job) (*dataflow.Job, error) {
|
func resourceDataflowJobUpdateJob(config *Config, project string, region string, id string, job *dataflow.Job) (*dataflow.Job, error) {
|
||||||
if region == "" {
|
if region == "" {
|
||||||
return config.clientDataflow.Projects.Jobs.Update(project, id, job).Do()
|
return config.clientDataflow.Projects.Jobs.Update(project, id, job).Do()
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user