forked from hashicorp/terraform-provider-google
-
Notifications
You must be signed in to change notification settings - Fork 1
/
transport.go
175 lines (150 loc) · 4.81 KB
/
transport.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package google
import (
"bytes"
"encoding/json"
"net/http"
"reflect"
"regexp"
"strings"
"google.golang.org/api/googleapi"
)
type serializableBody struct {
body map[string]interface{}
// ForceSendFields is a list of field names (e.g. "UtilizationTarget")
// to unconditionally include in API requests. By default, fields with
// empty values are omitted from API requests. However, any non-pointer,
// non-interface field appearing in ForceSendFields will be sent to the
// server regardless of whether the field is empty or not. This may be
// used to include empty fields in Patch requests.
ForceSendFields []string
// NullFields is a list of field names (e.g. "UtilizationTarget") to
// include in API requests with the JSON null value. By default, fields
// with empty values are omitted from API requests. However, any field
// with an empty value appearing in NullFields will be sent to the
// server as null. It is an error if a field in this list has a
// non-empty value. This may be used to include null fields in Patch
// requests.
NullFields []string
}
// MarshalJSON returns a JSON encoding of schema containing only selected fields.
// A field is selected if any of the following is true:
// * it has a non-empty value
// * its field name is present in forceSendFields and it is not a nil pointer or nil interface
// * its field name is present in nullFields.
func (b *serializableBody) MarshalJSON() ([]byte, error) {
// By default, all fields in a map are added to the json output
// This changes that to remove the entry with an empty value.
// This mimics the "omitempty" behavior.
// The "omitempty" option specifies that the field should be omitted
// from the encoding if the field has an empty value, defined as
// false, 0, a nil pointer, a nil interface value, and any empty array,
// slice, map, or string.
// TODO: Add support for ForceSendFields and NullFields.
for k, v := range b.body {
if isEmptyValue(reflect.ValueOf(v)) {
delete(b.body, k)
}
}
return json.Marshal(b.body)
}
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
}
func Post(config *Config, url string, body map[string]interface{}) (map[string]interface{}, error) {
return sendRequest(config, "POST", url, body)
}
func Get(config *Config, url string) (map[string]interface{}, error) {
return sendRequest(config, "GET", url, nil)
}
func Put(config *Config, url string, body map[string]interface{}) (map[string]interface{}, error) {
return sendRequest(config, "PUT", url, body)
}
func Delete(config *Config, url string) (map[string]interface{}, error) {
return sendRequest(config, "DELETE", url, nil)
}
func sendRequest(config *Config, method, url string, body map[string]interface{}) (map[string]interface{}, error) {
reqHeaders := make(http.Header)
reqHeaders.Set("User-Agent", config.userAgent)
reqHeaders.Set("Content-Type", "application/json")
var buf bytes.Buffer
if body != nil {
err := json.NewEncoder(&buf).Encode(&serializableBody{
body: body})
if err != nil {
return nil, err
}
}
req, err := http.NewRequest(method, url+"?alt=json", &buf)
if err != nil {
return nil, err
}
req.Header = reqHeaders
res, err := config.client.Do(req)
if err != nil {
return nil, err
}
defer googleapi.CloseBody(res)
if err := googleapi.CheckResponse(res); err != nil {
return nil, err
}
result := make(map[string]interface{})
if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
return nil, err
}
return result, nil
}
func replaceVars(d TerraformResourceData, config *Config, linkTmpl string) (string, error) {
re := regexp.MustCompile("{{([[:word:]]+)}}")
var project, region, zone string
var err error
if strings.Contains(linkTmpl, "{{project}}") {
project, err = getProject(d, config)
if err != nil {
return "", err
}
}
if strings.Contains(linkTmpl, "{{region}}") {
region, err = getRegion(d, config)
if err != nil {
return "", err
}
}
if strings.Contains(linkTmpl, "{{zone}}") {
zone, err = getZone(d, config)
if err != nil {
return "", err
}
}
replaceFunc := func(s string) string {
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 {
return v.(string)
}
return ""
}
return re.ReplaceAllStringFunc(linkTmpl, replaceFunc), nil
}