2018-02-09 01:58:20 +00:00
package google
import (
"bytes"
"encoding/json"
2018-12-07 19:18:37 +00:00
"fmt"
2018-02-09 01:58:20 +00:00
"net/http"
2018-05-17 23:33:30 +00:00
"net/url"
2018-03-10 01:14:32 +00:00
"reflect"
2018-02-09 01:58:20 +00:00
"regexp"
"strings"
2018-12-07 19:18:37 +00:00
"time"
2018-02-09 01:58:20 +00:00
"google.golang.org/api/googleapi"
)
2019-03-22 23:38:34 +00:00
var DefaultRequestTimeout = 5 * time . Minute
2018-02-09 01:58:20 +00:00
func isEmptyValue ( v reflect . Value ) bool {
switch v . Kind ( ) {
case reflect . Array , reflect . Map , reflect . Slice , reflect . String :
return v . Len ( ) == 0
case reflect . Bool :
return ! v . Bool ( )
case reflect . Int , reflect . Int8 , reflect . Int16 , reflect . Int32 , reflect . Int64 :
return v . Int ( ) == 0
case reflect . Uint , reflect . Uint8 , reflect . Uint16 , reflect . Uint32 , reflect . Uint64 , reflect . Uintptr :
return v . Uint ( ) == 0
case reflect . Float32 , reflect . Float64 :
return v . Float ( ) == 0
case reflect . Interface , reflect . Ptr :
return v . IsNil ( )
}
return false
}
2018-05-17 23:33:30 +00:00
func sendRequest ( config * Config , method , rawurl string , body map [ string ] interface { } ) ( map [ string ] interface { } , error ) {
2019-03-22 23:38:34 +00:00
return sendRequestWithTimeout ( config , method , rawurl , body , DefaultRequestTimeout )
2018-12-13 01:28:44 +00:00
}
func sendRequestWithTimeout ( config * Config , method , rawurl string , body map [ string ] interface { } , timeout time . Duration ) ( map [ string ] interface { } , error ) {
2018-02-09 01:58:20 +00:00
reqHeaders := make ( http . Header )
reqHeaders . Set ( "User-Agent" , config . userAgent )
reqHeaders . Set ( "Content-Type" , "application/json" )
2018-12-17 20:53:06 +00:00
if timeout == 0 {
timeout = time . Duration ( 1 ) * time . Hour
}
2018-12-07 19:18:37 +00:00
var res * http . Response
err := retryTimeDuration (
func ( ) error {
var buf bytes . Buffer
if body != nil {
err := json . NewEncoder ( & buf ) . Encode ( body )
if err != nil {
return err
}
}
2018-02-09 01:58:20 +00:00
2018-12-07 19:18:37 +00:00
u , err := addQueryParams ( rawurl , map [ string ] string { "alt" : "json" } )
if err != nil {
return err
}
req , err := http . NewRequest ( method , u , & buf )
if err != nil {
return err
}
req . Header = reqHeaders
res , err = config . client . Do ( req )
if err != nil {
return err
}
if err := googleapi . CheckResponse ( res ) ; err != nil {
googleapi . CloseBody ( res )
return err
}
2018-05-17 23:33:30 +00:00
2018-12-07 19:18:37 +00:00
return nil
} ,
2018-12-13 01:28:44 +00:00
timeout ,
2018-12-07 19:18:37 +00:00
)
2018-02-09 01:58:20 +00:00
if err != nil {
return nil , err
}
2018-12-07 19:18:37 +00:00
if res == nil {
return nil , fmt . Errorf ( "Unable to parse server response. This is most likely a terraform problem, please file a bug at https://github.com/terraform-providers/terraform-provider-google/issues." )
2018-02-09 01:58:20 +00:00
}
2018-12-13 01:28:44 +00:00
2018-12-07 19:18:37 +00:00
// The defer call must be made outside of the retryFunc otherwise it's closed too soon.
2018-02-09 01:58:20 +00:00
defer googleapi . CloseBody ( res )
2018-10-17 22:38:59 +00:00
// 204 responses will have no body, so we're going to error with "EOF" if we
// try to parse it. Instead, we can just return nil.
if res . StatusCode == 204 {
return nil , nil
}
2018-02-09 01:58:20 +00:00
result := make ( map [ string ] interface { } )
if err := json . NewDecoder ( res . Body ) . Decode ( & result ) ; err != nil {
return nil , err
}
return result , nil
}
2018-06-05 00:41:48 +00:00
func addQueryParams ( rawurl string , params map [ string ] string ) ( string , error ) {
u , err := url . Parse ( rawurl )
if err != nil {
return "" , err
}
q := u . Query ( )
for k , v := range params {
q . Set ( k , v )
}
u . RawQuery = q . Encode ( )
return u . String ( ) , nil
}
2018-02-09 01:58:20 +00:00
func replaceVars ( d TerraformResourceData , config * Config , linkTmpl string ) ( string , error ) {
re := regexp . MustCompile ( "{{([[:word:]]+)}}" )
2019-03-28 21:32:14 +00:00
f , err := buildReplacementFunc ( re , d , config , linkTmpl )
if err != nil {
return "" , err
}
return re . ReplaceAllStringFunc ( linkTmpl , f ) , nil
}
func buildReplacementFunc ( re * regexp . Regexp , d TerraformResourceData , config * Config , linkTmpl string ) ( func ( string ) string , error ) {
2018-02-09 01:58:20 +00:00
var project , region , zone string
var err error
if strings . Contains ( linkTmpl , "{{project}}" ) {
project , err = getProject ( d , config )
if err != nil {
2019-03-28 21:32:14 +00:00
return nil , err
2018-02-09 01:58:20 +00:00
}
}
if strings . Contains ( linkTmpl , "{{region}}" ) {
region , err = getRegion ( d , config )
if err != nil {
2019-03-28 21:32:14 +00:00
return nil , err
2018-02-09 01:58:20 +00:00
}
}
if strings . Contains ( linkTmpl , "{{zone}}" ) {
zone , err = getZone ( d , config )
if err != nil {
2019-03-28 21:32:14 +00:00
return nil , err
2018-02-09 01:58:20 +00:00
}
}
2019-03-28 21:32:14 +00:00
f := func ( s string ) string {
2018-02-09 01:58:20 +00:00
m := re . FindStringSubmatch ( s ) [ 1 ]
if m == "project" {
return project
}
if m == "region" {
return region
}
if m == "zone" {
return zone
}
v , ok := d . GetOk ( m )
if ok {
2019-01-03 00:44:08 +00:00
return fmt . Sprintf ( "%v" , v )
2018-02-09 01:58:20 +00:00
}
return ""
}
2019-03-28 21:32:14 +00:00
return f , nil
2018-02-09 01:58:20 +00:00
}