Skip to content

Commit 456bde2

Browse files
authored
Make google_compute_project_metadata authoritative. (#2205)
1 parent c77ce97 commit 456bde2

File tree

3 files changed

+45
-136
lines changed

3 files changed

+45
-136
lines changed

google/metadata.go

+10-13
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,15 @@ func BetaMetadataUpdate(oldMDMap map[string]interface{}, newMDMap map[string]int
111111
}
112112
}
113113

114-
// expandComputeMetadata transforms a map representing computing metadata into a list of compute.MetadataItems suitable
115-
// for the GCP client.
116-
func expandComputeMetadata(m map[string]string) []*compute.MetadataItems {
114+
func expandComputeMetadata(m map[string]interface{}) []*compute.MetadataItems {
117115
metadata := make([]*compute.MetadataItems, len(m))
118-
119-
idx := 0
120-
for key, value := range m {
121-
// Make a copy of value as we need a ptr type; if we directly use 'value' then all items will reference the same
122-
// memory address
123-
vtmp := value
124-
metadata[idx] = &compute.MetadataItems{Key: key, Value: &vtmp}
125-
idx++
116+
// Append new metadata to existing metadata
117+
for key, val := range m {
118+
v := val.(string)
119+
metadata = append(metadata, &compute.MetadataItems{
120+
Key: key,
121+
Value: &v,
122+
})
126123
}
127124

128125
return metadata
@@ -140,8 +137,8 @@ func flattenMetadataBeta(metadata *computeBeta.Metadata) map[string]string {
140137
// compute.metadata rather than computeBeta.metadata as an argument. It should
141138
// be removed in favour of flattenMetadataBeta if/when all resources using it get
142139
// beta support.
143-
func flattenMetadata(metadata *compute.Metadata) map[string]string {
144-
metadataMap := make(map[string]string)
140+
func flattenMetadata(metadata *compute.Metadata) map[string]interface{} {
141+
metadataMap := make(map[string]interface{})
145142
for _, item := range metadata.Items {
146143
metadataMap[item.Key] = *item.Value
147144
}

google/resource_compute_project_metadata.go

+30-118
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ import (
1010

1111
func resourceComputeProjectMetadata() *schema.Resource {
1212
return &schema.Resource{
13-
Create: resourceComputeProjectMetadataCreate,
13+
Create: resourceComputeProjectMetadataCreateOrUpdate,
1414
Read: resourceComputeProjectMetadataRead,
15-
Update: resourceComputeProjectMetadataUpdate,
15+
Update: resourceComputeProjectMetadataCreateOrUpdate,
1616
Delete: resourceComputeProjectMetadataDelete,
1717

1818
SchemaVersion: 0,
@@ -34,55 +34,21 @@ func resourceComputeProjectMetadata() *schema.Resource {
3434
}
3535
}
3636

37-
func resourceComputeProjectMetadataCreate(d *schema.ResourceData, meta interface{}) error {
37+
func resourceComputeProjectMetadataCreateOrUpdate(d *schema.ResourceData, meta interface{}) error {
3838
config := meta.(*Config)
3939

4040
projectID, err := getProject(d, config)
4141
if err != nil {
4242
return err
4343
}
4444

45-
createMD := func() error {
46-
// Load project service
47-
log.Printf("[DEBUG] Loading project service: %s", projectID)
48-
project, err := config.clientCompute.Projects.Get(projectID).Do()
49-
if err != nil {
50-
return fmt.Errorf("Error loading project '%s': %s", projectID, err)
51-
}
52-
53-
md := project.CommonInstanceMetadata
54-
55-
newMDMap := d.Get("metadata").(map[string]interface{})
56-
// Ensure that we aren't overwriting entries that already exist
57-
for _, kv := range md.Items {
58-
if _, ok := newMDMap[kv.Key]; ok {
59-
return fmt.Errorf("Error, key '%s' already exists in project '%s'", kv.Key, projectID)
60-
}
61-
}
62-
63-
// Append new metadata to existing metadata
64-
for key, val := range newMDMap {
65-
v := val.(string)
66-
md.Items = append(md.Items, &compute.MetadataItems{
67-
Key: key,
68-
Value: &v,
69-
})
70-
}
71-
72-
op, err := config.clientCompute.Projects.SetCommonInstanceMetadata(projectID, md).Do()
73-
74-
if err != nil {
75-
return fmt.Errorf("SetCommonInstanceMetadata failed: %s", err)
76-
}
77-
78-
log.Printf("[DEBUG] SetCommonMetadata: %d (%s)", op.Id, op.SelfLink)
79-
80-
return computeOperationWait(config.clientCompute, op, project.Name, "SetCommonMetadata")
45+
md := &compute.Metadata{
46+
Items: expandComputeMetadata(d.Get("metadata").(map[string]interface{})),
8147
}
8248

83-
err = MetadataRetryWrapper(createMD)
49+
err = resourceComputeProjectMetadataSet(projectID, config, md)
8450
if err != nil {
85-
return err
51+
return fmt.Errorf("SetCommonInstanceMetadata failed: %s", err)
8652
}
8753

8854
return resourceComputeProjectMetadataRead(d, meta)
@@ -103,70 +69,13 @@ func resourceComputeProjectMetadataRead(d *schema.ResourceData, meta interface{}
10369
return handleNotFoundError(err, d, fmt.Sprintf("Project metadata for project %q", projectID))
10470
}
10571

106-
md := flattenMetadata(project.CommonInstanceMetadata)
107-
existingMetadata := d.Get("metadata").(map[string]interface{})
108-
// Remove all keys not explicitly mentioned in the terraform config
109-
for k := range md {
110-
if _, ok := existingMetadata[k]; !ok {
111-
delete(md, k)
112-
}
113-
}
114-
115-
if err = d.Set("metadata", md); err != nil {
72+
err = d.Set("metadata", flattenMetadata(project.CommonInstanceMetadata))
73+
if err != nil {
11674
return fmt.Errorf("Error setting metadata: %s", err)
11775
}
11876

11977
d.Set("project", projectID)
12078
d.SetId("common_metadata")
121-
122-
return nil
123-
}
124-
125-
func resourceComputeProjectMetadataUpdate(d *schema.ResourceData, meta interface{}) error {
126-
config := meta.(*Config)
127-
128-
projectID, err := getProject(d, config)
129-
if err != nil {
130-
return err
131-
}
132-
133-
if d.HasChange("metadata") {
134-
o, n := d.GetChange("metadata")
135-
136-
updateMD := func() error {
137-
// Load project service
138-
log.Printf("[DEBUG] Loading project service: %s", projectID)
139-
project, err := config.clientCompute.Projects.Get(projectID).Do()
140-
if err != nil {
141-
return fmt.Errorf("Error loading project '%s': %s", projectID, err)
142-
}
143-
144-
md := project.CommonInstanceMetadata
145-
146-
MetadataUpdate(o.(map[string]interface{}), n.(map[string]interface{}), md)
147-
148-
op, err := config.clientCompute.Projects.SetCommonInstanceMetadata(projectID, md).Do()
149-
150-
if err != nil {
151-
return fmt.Errorf("SetCommonInstanceMetadata failed: %s", err)
152-
}
153-
154-
log.Printf("[DEBUG] SetCommonMetadata: %d (%s)", op.Id, op.SelfLink)
155-
156-
// Optimistic locking requires the fingerprint received to match
157-
// the fingerprint we send the server, if there is a mismatch then we
158-
// are working on old data, and must retry
159-
return computeOperationWait(config.clientCompute, op, project.Name, "SetCommonMetadata")
160-
}
161-
162-
err := MetadataRetryWrapper(updateMD)
163-
if err != nil {
164-
return err
165-
}
166-
167-
return resourceComputeProjectMetadataRead(d, meta)
168-
}
169-
17079
return nil
17180
}
17281

@@ -178,30 +87,33 @@ func resourceComputeProjectMetadataDelete(d *schema.ResourceData, meta interface
17887
return err
17988
}
18089

181-
// Load project service
182-
log.Printf("[DEBUG] Loading project service: %s", projectID)
183-
project, err := config.clientCompute.Projects.Get(projectID).Do()
90+
md := &compute.Metadata{}
91+
err = resourceComputeProjectMetadataSet(projectID, config, md)
18492
if err != nil {
185-
return fmt.Errorf("Error loading project '%s': %s", projectID, err)
93+
return fmt.Errorf("SetCommonInstanceMetadata failed: %s", err)
18694
}
18795

188-
md := project.CommonInstanceMetadata
189-
190-
// Remove all items
191-
md.Items = nil
192-
193-
op, err := config.clientCompute.Projects.SetCommonInstanceMetadata(projectID, md).Do()
96+
return resourceComputeProjectMetadataRead(d, meta)
97+
}
19498

195-
if err != nil {
196-
return fmt.Errorf("Error removing metadata from project %s: %s", projectID, err)
197-
}
99+
func resourceComputeProjectMetadataSet(projectID string, config *Config, md *compute.Metadata) error {
100+
createMD := func() error {
101+
log.Printf("[DEBUG] Loading project service: %s", projectID)
102+
project, err := config.clientCompute.Projects.Get(projectID).Do()
103+
if err != nil {
104+
return fmt.Errorf("Error loading project '%s': %s", projectID, err)
105+
}
198106

199-
log.Printf("[DEBUG] SetCommonMetadata: %d (%s)", op.Id, op.SelfLink)
107+
md.Fingerprint = project.CommonInstanceMetadata.Fingerprint
108+
op, err := config.clientCompute.Projects.SetCommonInstanceMetadata(projectID, md).Do()
109+
if err != nil {
110+
return fmt.Errorf("SetCommonInstanceMetadata failed: %s", err)
111+
}
200112

201-
err = computeOperationWait(config.clientCompute, op, project.Name, "SetCommonMetadata")
202-
if err != nil {
203-
return err
113+
log.Printf("[DEBUG] SetCommonMetadata: %d (%s)", op.Id, op.SelfLink)
114+
return computeOperationWait(config.clientCompute, op, project.Name, "SetCommonMetadata")
204115
}
205116

206-
return resourceComputeProjectMetadataRead(d, meta)
117+
err := MetadataRetryWrapper(createMD)
118+
return err
207119
}

website/docs/r/compute_project_metadata.html.markdown

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ description: |-
88

99
# google\_compute\_project\_metadata
1010

11-
Manages metadata common to all instances for a project in GCE. For more information see
11+
Authoritatively manages metadata common to all instances for a project in GCE. For more information see
1212
[the official documentation](https://cloud.google.com/compute/docs/storing-retrieving-metadata)
1313
and
1414
[API](https://cloud.google.com/compute/docs/reference/latest/projects/setCommonInstanceMetadata).
1515

16-
~> **Note:** If you want to manage only single key/value pairs within the project metadata
17-
rather than the entire set, then use
16+
~> **Note:** This resource manages all project-level metadata including project-level ssh keys.
17+
Keys unset in config but set on the server will be removed. If you want to manage only single
18+
key/value pairs within the project metadata rather than the entire set, then use
1819
[google_compute_project_metadata_item](compute_project_metadata_item.html).
1920

2021
## Example Usage
@@ -33,8 +34,7 @@ resource "google_compute_project_metadata" "default" {
3334

3435
The following arguments are supported:
3536

36-
* `metadata` - (Required) A series of key value pairs. Changing this resource
37-
updates the GCE state.
37+
* `metadata` - (Required) A series of key value pairs.
3838

3939
- - -
4040

0 commit comments

Comments
 (0)