Add support for setting labels to google_project (#383)

This commit is contained in:
Raúl Naveiras 2017-09-14 18:39:21 +01:00 committed by Joe Selman
parent 5f86f52d1f
commit eee011fc99
3 changed files with 186 additions and 0 deletions

View File

@ -74,6 +74,12 @@ func resourceGoogleProject() *schema.Resource {
Type: schema.TypeString,
Optional: true,
},
"labels": &schema.Schema{
Type: schema.TypeMap,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Set: schema.HashString,
},
},
}
}
@ -95,6 +101,10 @@ func resourceGoogleProjectCreate(d *schema.ResourceData, meta interface{}) error
},
}
if _, ok := d.GetOk("labels"); ok {
project.Labels = expandLabels(d)
}
op, err := config.clientResourceManager.Projects.Create(project).Do()
if err != nil {
return fmt.Errorf("Error creating project %s (%s): %s.", project.ProjectId, project.Name, err)
@ -142,6 +152,7 @@ func resourceGoogleProjectRead(d *schema.ResourceData, meta interface{}) error {
d.Set("project_id", pid)
d.Set("number", strconv.FormatInt(int64(p.ProjectNumber), 10))
d.Set("name", p.Name)
d.Set("labels", p.Labels)
if p.Parent != nil {
d.Set("org_id", p.Parent.Id)
@ -213,6 +224,17 @@ func resourceGoogleProjectUpdate(d *schema.ResourceData, meta interface{}) error
return fmt.Errorf("Error updating billing account %q for project %q: %v", name, prefixedProject(pid), err)
}
}
// Project Labels have changed
if ok := d.HasChange("labels"); ok {
p.Labels = expandLabels(d)
// Do Update on project
p, err = config.clientResourceManager.Projects.Update(p.ProjectId, p).Do()
if err != nil {
return fmt.Errorf("Error updating project %q: %s", p.Name, err)
}
}
return nil
}

View File

@ -3,9 +3,12 @@ package google
import (
"fmt"
"os"
"reflect"
"strconv"
"strings"
"testing"
"github.com/davecgh/go-spew/spew"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
@ -67,6 +70,23 @@ func TestAccGoogleProject_createBilling(t *testing.T) {
})
}
// Test that a Project resource can be created with labels
func TestAccGoogleProject_createLabels(t *testing.T) {
pid := "terraform-" + acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
{
Config: testAccGoogleProject_createLabels(pid, pname, org, "test", "that"),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleProjectHasLabels("google_project.acceptance", pid, map[string]string{"test": "that"}),
),
},
},
})
}
// Test that a Project resource can be created and updated
// with billing account information
func TestAccGoogleProject_updateBilling(t *testing.T) {
@ -145,6 +165,48 @@ func TestAccGoogleProject_merge(t *testing.T) {
})
}
// Test that a Project resource can be updated with labels
func TestAccGoogleProject_updateLabels(t *testing.T) {
pid := "terraform-" + acctest.RandString(10)
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
Steps: []resource.TestStep{
// create project without labels
{
Config: testAccGoogleProject_create(pid, pname, org),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleProjectExists("google_project.acceptance", pid),
),
},
// update project with labels
{
Config: testAccGoogleProject_updateLabels(pid, pname, org, map[string]string{"label": "label-value"}),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleProjectExists("google_project.acceptance", pid),
testAccCheckGoogleProjectHasLabels("google_project.acceptance", pid, map[string]string{"label": "label-value"}),
),
},
// update project with other labels
{
Config: testAccGoogleProject_updateLabels(pid, pname, org, map[string]string{"empty-label": ""}),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleProjectExists("google_project.acceptance", pid),
testAccCheckGoogleProjectHasLabels("google_project.acceptance", pid, map[string]string{"empty-label": ""}),
),
},
// update project delete labels
{
Config: testAccGoogleProject_create(pid, pname, org),
Check: resource.ComposeTestCheckFunc(
testAccCheckGoogleProjectExists("google_project.acceptance", pid),
testAccCheckGoogleProjectHasNoLabels("google_project.acceptance", pid),
),
},
},
})
}
func testAccCheckGoogleProjectExists(r, pid string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[r]
@ -203,6 +265,77 @@ func testAccCheckGoogleProjectHasMoreBindingsThan(pid string, count int) resourc
}
}
func testAccCheckGoogleProjectHasLabels(r, pid string, expected map[string]string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[r]
if !ok {
return fmt.Errorf("Not found: %s", r)
}
// State should have the same number of labels
if rs.Primary.Attributes["labels.%"] != strconv.Itoa(len(expected)) {
return fmt.Errorf("Expected %d labels, got %s", len(expected), rs.Primary.Attributes["labels.%"])
}
// Actual value in API should match state and expected
config := testAccProvider.Meta().(*Config)
found, err := config.clientResourceManager.Projects.Get(pid).Do()
if err != nil {
return err
}
actual := found.Labels
if !reflect.DeepEqual(actual, expected) {
// Determine only the different attributes
for k, v := range expected {
if av, ok := actual[k]; ok && v == av {
delete(expected, k)
delete(actual, k)
}
}
spewConf := spew.NewDefaultConfig()
spewConf.SortKeys = true
return fmt.Errorf(
"Labels not equivalent. Difference is shown below. Top is actual, bottom is expected."+
"\n\n%s\n\n%s",
spewConf.Sdump(actual), spewConf.Sdump(expected),
)
}
return nil
}
}
func testAccCheckGoogleProjectHasNoLabels(r, pid string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[r]
if !ok {
return fmt.Errorf("Not found: %s", r)
}
// State should have zero labels
if rs.Primary.Attributes["labels.%"] != "0" {
return fmt.Errorf("Expected 0 labels, got %s", rs.Primary.Attributes["labels.%"])
}
// Actual value in API should match state and expected
config := testAccProvider.Meta().(*Config)
found, err := config.clientResourceManager.Projects.Get(pid).Do()
if err != nil {
return err
}
spewConf := spew.NewDefaultConfig()
spewConf.SortKeys = true
if found.Labels != nil {
return fmt.Errorf("Labels should be empty. Actual \n%s", spewConf.Sdump(found.Labels))
}
return nil
}
}
func testAccGoogleProject_toMerge(pid, name, org string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
@ -235,6 +368,35 @@ resource "google_project" "acceptance" {
}`, pid, name, org)
}
func testAccGoogleProject_createLabels(pid, name, org, key, value string) string {
return fmt.Sprintf(`
resource "google_project" "acceptance" {
project_id = "%s"
name = "%s"
org_id = "%s"
labels {
"%s" = "%s"
}
}`, pid, name, org, key, value)
}
func testAccGoogleProject_updateLabels(pid, name, org string, labels map[string]string) string {
r := fmt.Sprintf(`
resource "google_project" "acceptance" {
project_id = "%s"
name = "%s"
org_id = "%s"
labels {`, pid, name, org)
l := ""
for key, value := range labels {
l += fmt.Sprintf("%q = %q\n", key, value)
}
l += fmt.Sprintf("}\n}")
return r + l
}
func skipIfEnvNotSet(t *testing.T, envs ...string) {
for _, k := range envs {
if os.Getenv(k) == "" {

View File

@ -80,6 +80,8 @@ The following arguments are supported:
This argument is no longer supported, and will be removed in a future version
of Terraform. It should be replaced with a `google_project_iam_policy` resource.
* `labels` - (Optional) A set of key/value label pairs to assign to the project.
## Attributes Reference
In addition to the arguments listed above, the following computed attributes are