forked from hashicorp/terraform-provider-google
-
Notifications
You must be signed in to change notification settings - Fork 0
/
metadata.go
174 lines (155 loc) · 4.72 KB
/
metadata.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
package google
import (
"errors"
"fmt"
"log"
"sort"
"google.golang.org/api/compute/v1"
)
const METADATA_FINGERPRINT_RETRIES = 10
// Since the google compute API uses optimistic locking, there is a chance
// we need to resubmit our updated metadata. To do this, you need to provide
// an update function that attempts to submit your metadata
func MetadataRetryWrapper(update func() error) error {
attempt := 0
for attempt < METADATA_FINGERPRINT_RETRIES {
err := update()
if err == nil {
return nil
}
if ok, _ := isFingerprintError(err); !ok {
// Something else went wrong, don't retry
return err
}
log.Printf("[DEBUG] Dismissed an error as retryable as a fingerprint mismatch: %s", err)
attempt++
}
return fmt.Errorf("Failed to update metadata after %d retries", attempt)
}
// Update the metadata (serverMD) according to the provided diff (oldMDMap v
// newMDMap).
func MetadataUpdate(oldMDMap map[string]interface{}, newMDMap map[string]interface{}, serverMD *compute.Metadata) {
curMDMap := make(map[string]string)
// Load metadata on server into map
for _, kv := range serverMD.Items {
// If the server state has a key that we had in our old
// state, but not in our new state, we should delete it
_, okOld := oldMDMap[kv.Key]
_, okNew := newMDMap[kv.Key]
if okOld && !okNew {
continue
} else {
curMDMap[kv.Key] = *kv.Value
}
}
// Insert new metadata into existing metadata (overwriting when needed)
for key, val := range newMDMap {
curMDMap[key] = val.(string)
}
// Reformat old metadata into a list
serverMD.Items = nil
for key, val := range curMDMap {
v := val
serverMD.Items = append(serverMD.Items, &compute.MetadataItems{
Key: key,
Value: &v,
})
}
}
// Update the beta metadata (serverMD) according to the provided diff (oldMDMap v
// newMDMap).
func BetaMetadataUpdate(oldMDMap map[string]interface{}, newMDMap map[string]interface{}, serverMD *compute.Metadata) {
curMDMap := make(map[string]string)
// Load metadata on server into map
for _, kv := range serverMD.Items {
// If the server state has a key that we had in our old
// state, but not in our new state, we should delete it
_, okOld := oldMDMap[kv.Key]
_, okNew := newMDMap[kv.Key]
if okOld && !okNew {
continue
} else {
curMDMap[kv.Key] = *kv.Value
}
}
// Insert new metadata into existing metadata (overwriting when needed)
for key, val := range newMDMap {
curMDMap[key] = val.(string)
}
// Reformat old metadata into a list
serverMD.Items = nil
for key, val := range curMDMap {
v := val
serverMD.Items = append(serverMD.Items, &compute.MetadataItems{
Key: key,
Value: &v,
})
}
}
func expandComputeMetadata(m map[string]interface{}) []*compute.MetadataItems {
metadata := make([]*compute.MetadataItems, len(m))
var keys []string
for key := range m {
keys = append(keys, key)
}
sort.Strings(keys)
// Append new metadata to existing metadata
for _, key := range keys {
v := m[key].(string)
metadata = append(metadata, &compute.MetadataItems{
Key: key,
Value: &v,
})
}
return metadata
}
func flattenMetadataBeta(metadata *compute.Metadata) map[string]string {
metadataMap := make(map[string]string)
for _, item := range metadata.Items {
metadataMap[item.Key] = *item.Value
}
return metadataMap
}
// This function differs from flattenMetadataBeta only in that it takes
// compute.metadata rather than compute.metadata as an argument. It should
// be removed in favour of flattenMetadataBeta if/when all resources using it get
// beta support.
func flattenMetadata(metadata *compute.Metadata) map[string]interface{} {
metadataMap := make(map[string]interface{})
for _, item := range metadata.Items {
metadataMap[item.Key] = *item.Value
}
return metadataMap
}
func resourceInstanceMetadata(d TerraformResourceData) (*compute.Metadata, error) {
m := &compute.Metadata{}
mdMap := d.Get("metadata").(map[string]interface{})
if v, ok := d.GetOk("metadata_startup_script"); ok && v.(string) != "" {
if w, ok := mdMap["startup-script"]; ok {
// metadata.startup-script could be from metadata_startup_script in the first place
if v != w {
return nil, errors.New("Cannot provide both metadata_startup_script and metadata.startup-script.")
}
}
mdMap["startup-script"] = v
}
if len(mdMap) > 0 {
m.Items = make([]*compute.MetadataItems, 0, len(mdMap))
var keys []string
for k := range mdMap {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
v := mdMap[k].(string)
m.Items = append(m.Items, &compute.MetadataItems{
Key: k,
Value: &v,
})
}
// Set the fingerprint. If the metadata has never been set before
// then this will just be blank.
m.Fingerprint = d.Get("metadata_fingerprint").(string)
}
return m, nil
}