diff --git a/mmv1/third_party/terraform/utils/datastream_operation.go b/mmv1/third_party/terraform/utils/datastream_operation.go index 0078bd8fb191..7f18cb3c3fd7 100644 --- a/mmv1/third_party/terraform/utils/datastream_operation.go +++ b/mmv1/third_party/terraform/utils/datastream_operation.go @@ -4,14 +4,16 @@ import ( "bytes" "encoding/json" "fmt" - datastream "google.golang.org/api/datastream/v1" "time" + + datastream "google.golang.org/api/datastream/v1" ) type DatastreamOperationWaiter struct { Config *Config UserAgent string Project string + Op datastream.Operation CommonOperationWaiter } @@ -20,14 +22,22 @@ func (w *DatastreamOperationWaiter) QueryOp() (interface{}, error) { return nil, fmt.Errorf("Cannot query operation, it's unset or nil.") } // Returns the proper get. - url := fmt.Sprintf("%s%s", w.Config.DatastreamBasePath, w.CommonOperationWaiter.Op.Name) + url := fmt.Sprintf("%s%s", w.Config.DatastreamBasePath, w.Op.Name) return sendRequest(w.Config, "GET", w.Project, url, w.UserAgent, nil) } func (w *DatastreamOperationWaiter) Error() error { if w != nil && w.Op.Error != nil { - return DatastreamError(*w.Op.Error) + return &DatastreamOperationError{Op: w.Op} + } + return nil +} + +func (w *DatastreamOperationWaiter) SetOp(op interface{}) error { + w.CommonOperationWaiter.SetOp(op) + if err := Convert(op, &w.Op); err != nil { + return err } return nil } @@ -38,7 +48,7 @@ func createDatastreamWaiter(config *Config, op map[string]interface{}, project, UserAgent: userAgent, Project: project, } - if err := w.CommonOperationWaiter.SetOp(op); err != nil { + if err := w.SetOp(op); err != nil { return nil, err } return w, nil @@ -53,7 +63,7 @@ func datastreamOperationWaitTimeWithResponse(config *Config, op map[string]inter if err := OperationWait(w, activity, timeout, config.PollInterval); err != nil { return err } - return json.Unmarshal([]byte(w.CommonOperationWaiter.Op.Response), response) + return json.Unmarshal([]byte(w.Op.Response), response) } func datastreamOperationWaitTime(config *Config, op map[string]interface{}, project, activity, userAgent string, timeout time.Duration) error { @@ -69,17 +79,52 @@ func datastreamOperationWaitTime(config *Config, op map[string]interface{}, proj return OperationWait(w, activity, timeout, config.PollInterval) } -// DatastreamError wraps datastream.Status and implements the +// DatastreamOperationError wraps datastream.Status and implements the // error interface so it can be returned. -type DatastreamError datastream.Status +type DatastreamOperationError struct { + Op datastream.Operation +} -func (e DatastreamError) Error() string { +func (e DatastreamOperationError) Error() string { var buf bytes.Buffer - for _, err := range e.Details { + for _, err := range e.Op.Error.Details { buf.Write(err) buf.WriteString("\n") } + if validations := e.extractFailedValidationResult(); validations != nil { + buf.Write(validations) + buf.WriteString("\n") + } return buf.String() } + +// extractFailedValidationResult extracts the internal failed validations +// if there are any. +func (e DatastreamOperationError) extractFailedValidationResult() []byte { + var metadata datastream.OperationMetadata + data, err := e.Op.Metadata.MarshalJSON() + if err != nil { + return nil + } + err = json.Unmarshal(data, &metadata) + if err != nil { + return nil + } + if metadata.ValidationResult == nil { + return nil + } + var res []byte + for _, v := range metadata.ValidationResult.Validations { + if v.State == "FAILED" { + data, err := v.MarshalJSON() + if err != nil { + return nil + } + res = append(res, data...) + res = append(res, []byte("\n")...) + } + } + return res +}