forked from hashicorp/terraform-provider-google
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for google_compute_project_metadata_item (hashicorp#176)
* Add support for google_compute_project_metadata_item This allows terraform users to manage single key/value items within the project metadata map, rather than the entire map itself. * Update CHANGELOG.md * Add details about import
- Loading branch information
Showing
9 changed files
with
417 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package google | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
) | ||
|
||
func TestAccComputeProjectMetadataItem_importBasic(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckProjectMetadataItemDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccProjectMetadataItem_basic("myKey", "myValue"), | ||
}, | ||
{ | ||
ResourceName: "google_compute_project_metadata_item.foobar", | ||
ImportState: true, | ||
ImportStateVerify: true, | ||
}, | ||
}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
|
||
"github.com/hashicorp/terraform/helper/schema" | ||
"google.golang.org/api/compute/v1" | ||
) | ||
|
||
func resourceComputeProjectMetadataItem() *schema.Resource { | ||
return &schema.Resource{ | ||
Create: resourceComputeProjectMetadataItemCreate, | ||
Read: resourceComputeProjectMetadataItemRead, | ||
Update: resourceComputeProjectMetadataItemUpdate, | ||
Delete: resourceComputeProjectMetadataItemDelete, | ||
Importer: &schema.ResourceImporter{ | ||
State: schema.ImportStatePassthrough, | ||
}, | ||
|
||
Schema: map[string]*schema.Schema{ | ||
"key": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
ForceNew: true, | ||
}, | ||
"value": { | ||
Type: schema.TypeString, | ||
Required: true, | ||
}, | ||
"project": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ForceNew: true, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func resourceComputeProjectMetadataItemCreate(d *schema.ResourceData, meta interface{}) error { | ||
config := meta.(*Config) | ||
|
||
projectID, err := getProject(d, config) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
key := d.Get("key").(string) | ||
val := d.Get("value").(string) | ||
|
||
err = updateComputeCommonInstanceMetadata(config, projectID, key, &val) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
d.SetId(key) | ||
|
||
return nil | ||
} | ||
|
||
func resourceComputeProjectMetadataItemRead(d *schema.ResourceData, meta interface{}) error { | ||
config := meta.(*Config) | ||
|
||
projectID, err := getProject(d, config) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
log.Printf("[DEBUG] Loading project metadata: %s", projectID) | ||
project, err := config.clientCompute.Projects.Get(projectID).Do() | ||
if err != nil { | ||
return fmt.Errorf("Error loading project '%s': %s", projectID, err) | ||
} | ||
|
||
md := flattenComputeMetadata(project.CommonInstanceMetadata.Items) | ||
val, ok := md[d.Id()] | ||
if !ok { | ||
// Resource no longer exists | ||
d.SetId("") | ||
return nil | ||
} | ||
|
||
d.Set("key", d.Id()) | ||
d.Set("value", val) | ||
|
||
return nil | ||
} | ||
|
||
func resourceComputeProjectMetadataItemUpdate(d *schema.ResourceData, meta interface{}) error { | ||
config := meta.(*Config) | ||
|
||
projectID, err := getProject(d, config) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if d.HasChange("value") { | ||
key := d.Get("key").(string) | ||
_, n := d.GetChange("value") | ||
new := n.(string) | ||
|
||
err = updateComputeCommonInstanceMetadata(config, projectID, key, &new) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func resourceComputeProjectMetadataItemDelete(d *schema.ResourceData, meta interface{}) error { | ||
config := meta.(*Config) | ||
|
||
projectID, err := getProject(d, config) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
key := d.Get("key").(string) | ||
|
||
err = updateComputeCommonInstanceMetadata(config, projectID, key, nil) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
d.SetId("") | ||
return nil | ||
} | ||
|
||
func updateComputeCommonInstanceMetadata(config *Config, projectID string, key string, afterVal *string) error { | ||
updateMD := func() error { | ||
log.Printf("[DEBUG] Loading project metadata: %s", projectID) | ||
project, err := config.clientCompute.Projects.Get(projectID).Do() | ||
if err != nil { | ||
return fmt.Errorf("Error loading project '%s': %s", projectID, err) | ||
} | ||
|
||
md := flattenComputeMetadata(project.CommonInstanceMetadata.Items) | ||
|
||
val, ok := md[key] | ||
|
||
if !ok { | ||
if afterVal == nil { | ||
// Asked to set no value and we didn't find one - we're done | ||
return nil | ||
} | ||
} else { | ||
if afterVal != nil && *afterVal == val { | ||
// Asked to set a value and it's already set - we're done. | ||
return nil | ||
} | ||
} | ||
|
||
if afterVal == nil { | ||
delete(md, key) | ||
} else { | ||
md[key] = *afterVal | ||
} | ||
|
||
// Attempt to write the new value now | ||
op, err := config.clientCompute.Projects.SetCommonInstanceMetadata( | ||
projectID, | ||
&compute.Metadata{ | ||
Fingerprint: project.CommonInstanceMetadata.Fingerprint, | ||
Items: expandComputeMetadata(md), | ||
}, | ||
).Do() | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
log.Printf("[DEBUG] SetCommonInstanceMetadata: %d (%s)", op.Id, op.SelfLink) | ||
|
||
return computeOperationWaitGlobal(config, op, project.Name, "SetCommonInstanceMetadata") | ||
} | ||
|
||
return MetadataRetryWrapper(updateMD) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
"github.com/hashicorp/terraform/terraform" | ||
) | ||
|
||
func TestAccComputeProjectMetadataItem_basic(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckProjectMetadataItemDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccProjectMetadataItem_basic("myKey", "myValue"), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckProjectMetadataItem_hasMetadata("myKey", "myValue"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccComputeProjectMetadataItem_basicWithEmptyVal(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckProjectMetadataItemDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccProjectMetadataItem_basic("myKey", ""), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckProjectMetadataItem_hasMetadata("myKey", ""), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccComputeProjectMetadataItem_basicUpdate(t *testing.T) { | ||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
CheckDestroy: testAccCheckProjectMetadataItemDestroy, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccProjectMetadataItem_basic("myKey", "myValue"), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckProjectMetadataItem_hasMetadata("myKey", "myValue"), | ||
), | ||
}, | ||
{ | ||
Config: testAccProjectMetadataItem_basic("myKey", "myUpdatedValue"), | ||
Check: resource.ComposeTestCheckFunc( | ||
testAccCheckProjectMetadataItem_hasMetadata("myKey", "myUpdatedValue"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckProjectMetadataItem_hasMetadata(key, value string) resource.TestCheckFunc { | ||
return func(s *terraform.State) error { | ||
config := testAccProvider.Meta().(*Config) | ||
|
||
project, err := config.clientCompute.Projects.Get(config.Project).Do() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
metadata := flattenComputeMetadata(project.CommonInstanceMetadata.Items) | ||
|
||
val, ok := metadata[key] | ||
if !ok { | ||
return fmt.Errorf("Unable to find a value for key '%s'", key) | ||
} | ||
if val != value { | ||
return fmt.Errorf("Value for key '%s' does not match. Expected '%s' but found '%s'", key, value, val) | ||
} | ||
return nil | ||
} | ||
} | ||
|
||
func testAccCheckProjectMetadataItemDestroy(s *terraform.State) error { | ||
config := testAccProvider.Meta().(*Config) | ||
|
||
project, err := config.clientCompute.Projects.Get(config.Project).Do() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
metadata := flattenComputeMetadata(project.CommonInstanceMetadata.Items) | ||
|
||
for _, rs := range s.RootModule().Resources { | ||
if rs.Type != "google_compute_project_metadata_item" { | ||
continue | ||
} | ||
|
||
_, ok := metadata[rs.Primary.ID] | ||
if ok { | ||
return fmt.Errorf("Metadata key/value '%s': '%s' still exist", rs.Primary.Attributes["key"], rs.Primary.Attributes["value"]) | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func testAccProjectMetadataItem_basic(key, val string) string { | ||
return fmt.Sprintf(` | ||
resource "google_compute_project_metadata_item" "foobar" { | ||
key = "%s" | ||
value = "%s" | ||
} | ||
`, key, val) | ||
} |
Oops, something went wrong.